From 265897f9e15162ee5264d4e569f6d01626186c4c Mon Sep 17 00:00:00 2001 From: Maruno17 Date: Sat, 27 Aug 2022 20:11:01 +0100 Subject: [PATCH] Made AI function code-specific MoveFailureCheck handlers --- .../003_Move/004_Move_BaseEffects.rb | 10 + .../003_Move/005_MoveEffects_Misc.rb | 2 + .../003_Move/006_MoveEffects_BattlerStats.rb | 4 +- .../003_Move/007_MoveEffects_BattlerOther.rb | 4 +- .../008_MoveEffects_MoveAttributes.rb | 2 - .../003_Move/011_MoveEffects_Items.rb | 3 +- .../012_MoveEffects_ChangeMoveEffect.rb | 10 + .../013_MoveEffects_SwitchingActing.rb | 4 + .../011_Battle/005_AI/001_Battle_AI.rb | 9 +- Data/Scripts/011_Battle/005_AI/004_AI_Move.rb | 78 ++- .../005_AI/051_AI_MoveHandlers_Misc.rb | 212 +++++-- .../052_AI_MoveHandlers_BattlerStats.rb | 558 +++++++++++----- .../053_AI_MoveHandlers_BattlerOther.rb | 598 +++++++++--------- .../054_AI_MoveHandlers_MoveAttributes.rb | 174 +++-- .../005_AI/055_AI_MoveHandlers_MultiHit.rb | 51 +- .../005_AI/056_AI_MoveHandlers_Healing.rb | 200 +++--- .../005_AI/057_AI_MoveHandlers_Items.rb | 149 +++-- .../058_AI_MoveHandlers_ChangeMoveEffect.rb | 199 +++--- .../059_AI_MoveHandlers_SwitchingActing.rb | 271 +++++--- .../011_Battle/005_AI/101_AITrainer.rb | 5 +- Data/Scripts/011_Battle/005_AI/103_AIMove.rb | 15 +- .../002_ShadowPokemon_Other.rb | 15 + PBS/Gen 8/moves.txt | 2 +- PBS/moves.txt | 2 +- 24 files changed, 1653 insertions(+), 924 deletions(-) diff --git a/Data/Scripts/011_Battle/003_Move/004_Move_BaseEffects.rb b/Data/Scripts/011_Battle/003_Move/004_Move_BaseEffects.rb index 54562ed7f..bb2cbe2ea 100644 --- a/Data/Scripts/011_Battle/003_Move/004_Move_BaseEffects.rb +++ b/Data/Scripts/011_Battle/003_Move/004_Move_BaseEffects.rb @@ -85,6 +85,8 @@ end # Raise one of user's stats. #=============================================================================== class Battle::Move::StatUpMove < Battle::Move + attr_reader :statUp + def canSnatch?; return true; end def pbMoveFailed?(user, targets) @@ -108,6 +110,8 @@ end # Raise multiple of user's stats. #=============================================================================== class Battle::Move::MultiStatUpMove < Battle::Move + attr_reader :statUp + def canSnatch?; return true; end def pbMoveFailed?(user, targets) @@ -167,6 +171,8 @@ end # Lower one of target's stats. #=============================================================================== class Battle::Move::TargetStatDownMove < Battle::Move + attr_reader :statDown + def canMagicCoat?; return true; end def pbFailsAgainstTarget?(user, target, show_message) @@ -190,6 +196,8 @@ end # Lower multiple of target's stats. #=============================================================================== class Battle::Move::TargetMultiStatDownMove < Battle::Move + attr_reader :statDown + def canMagicCoat?; return true; end def pbFailsAgainstTarget?(user, target, show_message) @@ -479,6 +487,8 @@ end # Weather-inducing move. #=============================================================================== class Battle::Move::WeatherMove < Battle::Move + attr_reader :weatherType + def initialize(battle, move) super @weatherType = :None diff --git a/Data/Scripts/011_Battle/003_Move/005_MoveEffects_Misc.rb b/Data/Scripts/011_Battle/003_Move/005_MoveEffects_Misc.rb index 32ef6761c..0641569ed 100644 --- a/Data/Scripts/011_Battle/003_Move/005_MoveEffects_Misc.rb +++ b/Data/Scripts/011_Battle/003_Move/005_MoveEffects_Misc.rb @@ -459,6 +459,8 @@ end # side. (Court Change) #=============================================================================== class Battle::Move::SwapSideEffects < Battle::Move + attr_reader :number_effects, :boolean_effects + def initialize(battle, move) super @number_effects = [ diff --git a/Data/Scripts/011_Battle/003_Move/006_MoveEffects_BattlerStats.rb b/Data/Scripts/011_Battle/003_Move/006_MoveEffects_BattlerStats.rb index 875018ff7..828d2db36 100644 --- a/Data/Scripts/011_Battle/003_Move/006_MoveEffects_BattlerStats.rb +++ b/Data/Scripts/011_Battle/003_Move/006_MoveEffects_BattlerStats.rb @@ -407,6 +407,8 @@ end # (Shell Smash) #=============================================================================== class Battle::Move::LowerUserDefSpDef1RaiseUserAtkSpAtkSpd2 < Battle::Move + attr_reader :statUp, :statDown + def canSnatch?; return true; end def initialize(battle, move) @@ -1397,7 +1399,7 @@ end # Raises the Attack and Defense of all user's allies by 1 stage each. Bypasses # protections, including Crafty Shield. Fails if there is no ally. (Coaching) #=============================================================================== -class Battle::Move::RaiseUserAndAlliesAtkDef1 < Battle::Move +class Battle::Move::RaiseAlliesAtkDef1 < Battle::Move def ignoresSubstitute?(user); return true; end def canSnatch?; return true; end diff --git a/Data/Scripts/011_Battle/003_Move/007_MoveEffects_BattlerOther.rb b/Data/Scripts/011_Battle/003_Move/007_MoveEffects_BattlerOther.rb index ba4a447a6..9d6170fe7 100644 --- a/Data/Scripts/011_Battle/003_Move/007_MoveEffects_BattlerOther.rb +++ b/Data/Scripts/011_Battle/003_Move/007_MoveEffects_BattlerOther.rb @@ -957,7 +957,7 @@ class Battle::Move::SetTargetAbilityToSimple < Battle::Move end def pbFailsAgainstTarget?(user, target, show_message) - if target.unstoppableAbility? || [:TRUANT, :SIMPLE].include?(target.ability) + if target.unstoppableAbility? || [:TRUANT, :SIMPLE].include?(target.ability_id) @battle.pbDisplay(_INTL("But it failed!")) if show_message return true end @@ -1165,7 +1165,7 @@ class Battle::Move::NegateTargetAbility < Battle::Move def canMagicCoat?; return true; end def pbFailsAgainstTarget?(user, target, show_message) - if target.unstoppableAbility? + if target.unstoppableAbility? || target.effects[PBEffects::GastroAcid] @battle.pbDisplay(_INTL("But it failed!")) if show_message return true end diff --git a/Data/Scripts/011_Battle/003_Move/008_MoveEffects_MoveAttributes.rb b/Data/Scripts/011_Battle/003_Move/008_MoveEffects_MoveAttributes.rb index 71cd0e56a..ccb642a52 100644 --- a/Data/Scripts/011_Battle/003_Move/008_MoveEffects_MoveAttributes.rb +++ b/Data/Scripts/011_Battle/003_Move/008_MoveEffects_MoveAttributes.rb @@ -453,8 +453,6 @@ class Battle::Move::DoublePowerIfTargetPoisoned < Battle::Move end end - - #=============================================================================== # Power is doubled if the target is paralyzed. Cures the target of paralysis. # (Smelling Salts) diff --git a/Data/Scripts/011_Battle/003_Move/011_MoveEffects_Items.rb b/Data/Scripts/011_Battle/003_Move/011_MoveEffects_Items.rb index 4c02d025d..a0a08642b 100644 --- a/Data/Scripts/011_Battle/003_Move/011_MoveEffects_Items.rb +++ b/Data/Scripts/011_Battle/003_Move/011_MoveEffects_Items.rb @@ -137,7 +137,7 @@ class Battle::Move::RestoreUserConsumedItem < Battle::Move def canSnatch?; return true; end def pbMoveFailed?(user, targets) - if !user.recycleItem + if !user.recycleItem || user.item @battle.pbDisplay(_INTL("But it failed!")) return true end @@ -317,6 +317,7 @@ class Battle::Move::UserConsumeBerryRaiseDefense2 < Battle::Move::StatUpMove @battle.pbDisplay(_INTL("But it failed!")) return true end + # TODO: Should this return super? It can consume the berry at this point. return super end diff --git a/Data/Scripts/011_Battle/003_Move/012_MoveEffects_ChangeMoveEffect.rb b/Data/Scripts/011_Battle/003_Move/012_MoveEffects_ChangeMoveEffect.rb index bd4e9b07a..337ab0b1c 100644 --- a/Data/Scripts/011_Battle/003_Move/012_MoveEffects_ChangeMoveEffect.rb +++ b/Data/Scripts/011_Battle/003_Move/012_MoveEffects_ChangeMoveEffect.rb @@ -668,6 +668,8 @@ end # Uses the last move that was used. (Copycat) #=============================================================================== class Battle::Move::UseLastMoveUsed < Battle::Move + attr_reader :moveBlacklist + def callsAnotherMove?; return true; end def initialize(battle, move) @@ -983,6 +985,8 @@ end # Uses a random move known by any non-user Pokémon in the user's party. (Assist) #=============================================================================== class Battle::Move::UseRandomMoveFromUserParty < Battle::Move + attr_reader :moveBlacklist + def callsAnotherMove?; return true; end def initialize(battle, move) @@ -1098,6 +1102,8 @@ end # Uses a random move the user knows. Fails if user is not asleep. (Sleep Talk) #=============================================================================== class Battle::Move::UseRandomUserMoveIfAsleep < Battle::Move + attr_reader :moveBlacklist + def usableWhenAsleep?; return true; end def callsAnotherMove?; return true; end @@ -1192,6 +1198,8 @@ end # out. (Mimic) #=============================================================================== class Battle::Move::ReplaceMoveThisBattleWithTargetLastMoveUsed < Battle::Move + attr_reader :moveBlacklist + def ignoresSubstitute?(user); return true; end def initialize(battle, move) @@ -1243,6 +1251,8 @@ end # This move permanently turns into the last move used by the target. (Sketch) #=============================================================================== class Battle::Move::ReplaceMoveWithTargetLastMoveUsed < Battle::Move + attr_reader :moveBlacklist + def ignoresSubstitute?(user); return true; end def initialize(battle, move) diff --git a/Data/Scripts/011_Battle/003_Move/013_MoveEffects_SwitchingActing.rb b/Data/Scripts/011_Battle/003_Move/013_MoveEffects_SwitchingActing.rb index aa819e356..ce54da1a9 100644 --- a/Data/Scripts/011_Battle/003_Move/013_MoveEffects_SwitchingActing.rb +++ b/Data/Scripts/011_Battle/003_Move/013_MoveEffects_SwitchingActing.rb @@ -540,6 +540,8 @@ end # The target uses its most recent move again. (Instruct) #=============================================================================== class Battle::Move::TargetUsesItsLastUsedMoveAgain < Battle::Move + attr_reader :moveBlacklist + def ignoresSubstitute?(user); return true; end def initialize(battle, move) @@ -757,6 +759,8 @@ end # For 4 rounds, the target must use the same move each round. (Encore) #=============================================================================== class Battle::Move::DisableTargetUsingDifferentMove < Battle::Move + attr_reader :moveBlacklist + def ignoresSubstitute?(user); return true; end def canMagicCoat?; return true; end diff --git a/Data/Scripts/011_Battle/005_AI/001_Battle_AI.rb b/Data/Scripts/011_Battle/005_AI/001_Battle_AI.rb index 6794c36b2..a89ecfb8c 100644 --- a/Data/Scripts/011_Battle/005_AI/001_Battle_AI.rb +++ b/Data/Scripts/011_Battle/005_AI/001_Battle_AI.rb @@ -63,8 +63,9 @@ end # #=============================================================================== module Battle::AI::Handlers - MoveEffectScore = HandlerHash.new - MoveBasePower = HandlerHash.new + MoveEffectScore = HandlerHash.new + MoveBasePower = HandlerHash.new + MoveFailureCheck = HandlerHash.new # Move type # Move accuracy # Move target @@ -72,6 +73,10 @@ module Battle::AI::Handlers # Move unselectable check # Move failure check + def self.move_will_fail?(function_code, *args) + return MoveFailureCheck.trigger(function_code, *args) || false + end + def self.apply_move_effect_score(function_code, score, *args) ret = MoveEffectScore.trigger(function_code, score, *args) return (ret.nil?) ? score : ret diff --git a/Data/Scripts/011_Battle/005_AI/004_AI_Move.rb b/Data/Scripts/011_Battle/005_AI/004_AI_Move.rb index 1bc02b779..da5c3e90b 100644 --- a/Data/Scripts/011_Battle/005_AI/004_AI_Move.rb +++ b/Data/Scripts/011_Battle/005_AI/004_AI_Move.rb @@ -43,10 +43,10 @@ class Battle::AI def pbRegisterMoveWild(idxMove, choices) battler = @user.battler score = 100 + choices.push([idxMove, score, -1]) # Move index, score, target # Doubly prefer one of the user's moves (the choice is random but consistent # and does not correlate to any other property of the user) - score *= 2 if battler.pokemon.personalID % battler.moves.length == idxMove - choices.push([idxMove, 100, -1]) # Move index, score, target + choices.push([idxMove, score, -1]) if battler.pokemon.personalID % battler.moves.length == idxMove end # Trainer Pokémon calculate how much they want to use each of their moves. @@ -100,6 +100,55 @@ class Battle::AI @user_faster = @user.faster_than?(@target) end + #============================================================================= + # Returns whether the move will definitely fail (assuming no battle conditions + # change between now and using the move) + #============================================================================= + def pbPredictMoveFailure + return false if !@trainer.has_skill_flag?("PredictMoveFailure") + # TODO: Something involving pbCanChooseMove? (see Assault Vest). + # TODO: Something involving user.usingMultiTurnAttack? (perhaps earlier than + # this?). + # User is asleep and will not wake up + return true if @trainer.medium_skill? && @user.battler.asleep? && + @user.statusCount > 1 && !@move.move.usableWhenAsleep? + # User will be truanting + return true if @user.has_active_ability?(:TRUANT) && @user.effects[PBEffects::Truant] + # Move effect-specific checks + return true if Battle::AI::Handlers.move_will_fail?(@move.function, @move, @user, @target, self, @battle) + # Immunity to priority moves because of Psychic Terrain + return true if @battle.field.terrain == :Psychic && @target.battler.affectedByTerrain? && + @target.opposes?(@user) && @move.rough_priority(@user) > 0 + # Immunity because of ability (intentionally before type immunity check) + # TODO: Check for target-redirecting abilities that also provide immunity. + # If an ally has such an ability, may want to just not prefer the move + # instead of predicting its failure, as might want to hit the ally + # after all. + return true if @move.move.pbImmunityByAbility(@user.battler, @target.battler, false) + # Type immunity + calc_type = @move.pbCalcType(@user.battler) + typeMod = @move.move.pbCalcTypeMod(calc_type, @user.battler, @target.battler) + return true if @move.move.pbDamagingMove? && Effectiveness.ineffective?(typeMod) + # Dark-type immunity to moves made faster by Prankster + return true if Settings::MECHANICS_GENERATION >= 7 && @user.has_active_ability?(:PRANKSTER) && + @target.has_type?(:DARK) && @target.opposes?(@user) + # Airborne-based immunity to Ground moves + return true if @move.damagingMove? && calc_type == :GROUND && + @target.battler.airborne? && !@move.move.hitsFlyingTargets? + # Immunity to powder-based moves + if @move.move.powderMove? + return true if @target.has_type?(:GRASS) && Settings::MORE_TYPE_EFFECTS + if Settings::MECHANICS_GENERATION >= 6 + return true if @target.has_active_ability?(:OVERCOAT) || + @target.has_active_item?(:SAFETYGOGGLES) + end + end + # Substitute + return true if @target.effects[PBEffects::Substitute] > 0 && @move.statusMove? && + !@move.move.ignoresSubstitute?(@user.battler) && @user.index != @target.index + return false + end + #============================================================================= # Get a score for the given move being used against the given target #============================================================================= @@ -108,8 +157,11 @@ class Battle::AI user_battler = @user.battler target_battler = @target.battler + # Predict whether the move will fail + return 10 if pbPredictMoveFailure + # Get the base score for the move - if @move.move.damagingMove? + if @move.damagingMove? # Is also the predicted damage amount as a percentage of target's current HP score = pbGetDamagingMoveBaseScore else # Status moves @@ -153,16 +205,8 @@ class Battle::AI # don't prefer move if it's Normal-type and target is immune because # of its ability (Lightning Rod, etc.). - # TODO: Discard move if it can be redirected by a non-target's ability - # (Lightning Rod/Storm Drain). Include checking for a previous use of - # Ion Deluge and this move being Normal-type. - # => If non-target is a user's ally, don't prefer move (rather than discarding - # it) - - # TODO: Discard move if it's sound-based and user has been Throat Chopped. - # Don't prefer move if user hasn't been Throat Chopped but target has - # previously used Throat Chop. The first part of this would probably - # go elsewhere (damage calc?). + # TODO: Don't prefer sound move if user hasn't been Throat Chopped but + # target has previously used Throat Chop. # TODO: Prefer move if it has a high critical hit rate, critical hits are # possible but not certain, and target has raised defences/user has @@ -248,12 +292,6 @@ class Battle::AI end end - # If user is asleep, don't prefer moves that can't be used while asleep - if @trainer.medium_skill? && user_battler.asleep? && user_battler.statusCount > 1 && - !@move.move.usableWhenAsleep? - score *= 0.2 - end - # If user is frozen, prefer a move that can thaw the user if @trainer.medium_skill? && user_battler.status == :FROZEN if @move.move.thawsUser? @@ -261,7 +299,7 @@ class Battle::AI else user_battler.eachMove do |m| next unless m.thawsUser? - score = 0 # Discard this move if user knows another move that thaws + score -= 30 # Don't prefer this move if user knows another move that thaws break end end diff --git a/Data/Scripts/011_Battle/005_AI/051_AI_MoveHandlers_Misc.rb b/Data/Scripts/011_Battle/005_AI/051_AI_MoveHandlers_Misc.rb index 53a17c500..22857fbc7 100644 --- a/Data/Scripts/011_Battle/005_AI/051_AI_MoveHandlers_Misc.rb +++ b/Data/Scripts/011_Battle/005_AI/051_AI_MoveHandlers_Misc.rb @@ -12,42 +12,63 @@ Battle::AI::Handlers::MoveEffectScore.add("DoesNothingCongratulations", } ) +Battle::AI::Handlers::MoveFailureCheck.add("DoesNothingFailsIfNoAlly", + proc { |move, user, target, ai, battle| + next true if user.battler.allAllies.length == 0 + } +) +Battle::AI::Handlers::MoveEffectScore.copy("DoesNothingCongratulations", + "DoesNothingFailsIfNoAlly") + Battle::AI::Handlers::MoveEffectScore.copy("DoesNothingCongratulations", - "DoesNothingFailsIfNoAlly", "DoesNothingUnusableInGravity", "DoubleMoneyGainedFromBattle") # AddMoneyGainedFromBattle -Battle::AI::Handlers::MoveEffectScore.add("FailsIfNotUserFirstTurn", - proc { |score, move, user, target, ai, battle| - next score - 90 if user.turnCount > 0 +Battle::AI::Handlers::MoveFailureCheck.add("FailsIfNotUserFirstTurn", + proc { |move, user, target, ai, battle| + next true if user.turnCount > 0 } ) -# FailsIfUserHasUnusedMove - -Battle::AI::Handlers::MoveEffectScore.add("FailsIfUserNotConsumedBerry", - proc { |score, move, user, target, ai, battle| - next score - 90 if !user.battler.belched? +Battle::AI::Handlers::MoveFailureCheck.add("FailsIfUserHasUnusedMove", + proc { |move, user, target, ai, battle| + has_another_move = false + has_unused_move = false + user.battler.eachMove do |m| + next if m.id == move.id + has_another_move = true + next if user.battler.movesUsed.include?(m.id) + has_unused_move = true + break + end + next true if !has_another_move || has_unused_move } ) +Battle::AI::Handlers::MoveFailureCheck.add("FailsIfUserNotConsumedBerry", + proc { |move, user, target, ai, battle| + next true if !user.battler.belched? + } +) + +Battle::AI::Handlers::MoveFailureCheck.add("FailsIfTargetHasNoItem", + proc { |move, user, target, ai, battle| + next true if !target.item || !target.item_active? + } +) Battle::AI::Handlers::MoveEffectScore.add("FailsIfTargetHasNoItem", proc { |score, move, user, target, ai, battle| - if ai.trainer.medium_skill? - next score - 90 if !target.item || !target.item_active? - next score + 50 - end + next score + 50 if ai.trainer.medium_skill? } ) -Battle::AI::Handlers::MoveEffectScore.add("FailsUnlessTargetSharesTypeWithUser", - proc { |score, move, user, target, ai, battle| - if !(user.types[0] && target.has_type?(user.types[0])) && - !(user.types[1] && target.has_type?(user.types[1])) - next score - 90 - end +Battle::AI::Handlers::MoveFailureCheck.add("FailsUnlessTargetSharesTypeWithUser", + proc { |move, user, target, ai, battle| + user_types = user.battler.pbTypes(true) + target_types = target.battler.pbTypes(true) + next true if (user_types & target_types).empty? } ) @@ -68,13 +89,17 @@ Battle::AI::Handlers::MoveEffectScore.add("CrashDamageIfFailsUnusableInGravity", } ) +Battle::AI::Handlers::MoveFailureCheck.add("StartSunWeather", + proc { |move, user, target, ai, battle| + next true if [:HarshSun, :HeavyRain, :StrongWinds, + move.move.weatherType].include?(battle.field.weather) + } +) Battle::AI::Handlers::MoveEffectScore.add("StartSunWeather", proc { |score, move, user, target, ai, battle| if battle.pbCheckGlobalAbility(:AIRLOCK) || battle.pbCheckGlobalAbility(:CLOUDNINE) - next score - 90 - elsif battle.field.weather == :Sun - next score - 90 + next score - 50 else user.battler.eachMove do |m| next if !m.damagingMove? || m.type != :FIRE @@ -85,13 +110,13 @@ Battle::AI::Handlers::MoveEffectScore.add("StartSunWeather", } ) +Battle::AI::Handlers::MoveFailureCheck.copy("StartSunWeather", + "StartRainWeather") Battle::AI::Handlers::MoveEffectScore.add("StartRainWeather", proc { |score, move, user, target, ai, battle| if battle.pbCheckGlobalAbility(:AIRLOCK) || battle.pbCheckGlobalAbility(:CLOUDNINE) - next score - 90 - elsif battle.field.weather == :Rain - next score - 90 + next score - 50 else user.battler.eachMove do |m| next if !m.damagingMove? || m.type != :WATER @@ -102,47 +127,66 @@ Battle::AI::Handlers::MoveEffectScore.add("StartRainWeather", } ) +Battle::AI::Handlers::MoveFailureCheck.copy("StartSunWeather", + "StartSandstormWeather") Battle::AI::Handlers::MoveEffectScore.add("StartSandstormWeather", proc { |score, move, user, target, ai, battle| if battle.pbCheckGlobalAbility(:AIRLOCK) || battle.pbCheckGlobalAbility(:CLOUDNINE) - next score - 90 - elsif battle.field.weather == :Rain - next score - 90 + next score - 50 end } ) +Battle::AI::Handlers::MoveFailureCheck.copy("StartSunWeather", + "StartHailWeather") Battle::AI::Handlers::MoveEffectScore.add("StartHailWeather", proc { |score, move, user, target, ai, battle| if battle.pbCheckGlobalAbility(:AIRLOCK) || battle.pbCheckGlobalAbility(:CLOUDNINE) - next score - 90 - elsif battle.field.weather == :Hail - next score - 90 + next score - 50 end } ) -# StartElectricTerrain - -# StartGrassyTerrain - -# StartMistyTerrain - -# StartPsychicTerrain - -Battle::AI::Handlers::MoveEffectScore.add("RemoveTerrain", - proc { |score, move, user, target, ai, battle| - next 0 if battle.field.terrain == :None +Battle::AI::Handlers::MoveFailureCheck.add("StartElectricTerrain", + proc { |move, user, target, ai, battle| + next true if battle.field.terrain == :Electric } ) +Battle::AI::Handlers::MoveFailureCheck.add("StartGrassyTerrain", + proc { |move, user, target, ai, battle| + next true if battle.field.terrain == :Grassy + } +) + +Battle::AI::Handlers::MoveFailureCheck.add("StartMistyTerrain", + proc { |move, user, target, ai, battle| + next true if battle.field.terrain == :Misty + } +) + +Battle::AI::Handlers::MoveFailureCheck.add("StartPsychicTerrain", + proc { |move, user, target, ai, battle| + next true if battle.field.terrain == :Psychic + } +) + +Battle::AI::Handlers::MoveFailureCheck.add("RemoveTerrain", + proc { |move, user, target, ai, battle| + next true if battle.field.terrain == :None + } +) + +Battle::AI::Handlers::MoveFailureCheck.add("AddSpikesToFoeSide", + proc { |move, user, target, ai, battle| + next true if user.pbOpposingSide.effects[PBEffects::Spikes] >= 3 + } +) Battle::AI::Handlers::MoveEffectScore.add("AddSpikesToFoeSide", proc { |score, move, user, target, ai, battle| - if user.pbOpposingSide.effects[PBEffects::Spikes] >= 3 - next score - 90 - elsif user.battler.allOpposing.none? { |b| battle.pbCanChooseNonActive?(b.index) } + if user.battler.allOpposing.none? { |b| battle.pbCanChooseNonActive?(b.index) } next score - 90 # Opponent can't switch in any Pokemon else score += 10 * battle.pbAbleNonActiveCount(user.idxOpposingSide) @@ -152,11 +196,14 @@ Battle::AI::Handlers::MoveEffectScore.add("AddSpikesToFoeSide", } ) +Battle::AI::Handlers::MoveFailureCheck.add("AddToxicSpikesToFoeSide", + proc { |move, user, target, ai, battle| + next true if user.pbOpposingSide.effects[PBEffects::ToxicSpikes] >= 2 + } +) Battle::AI::Handlers::MoveEffectScore.add("AddToxicSpikesToFoeSide", proc { |score, move, user, target, ai, battle| - if user.pbOpposingSide.effects[PBEffects::ToxicSpikes] >= 2 - next score - 90 - elsif user.battler.allOpposing.none? { |b| battle.pbCanChooseNonActive?(b.index) } + if user.battler.allOpposing.none? { |b| battle.pbCanChooseNonActive?(b.index) } next score - 90 # Opponent can't switch in any Pokemon else score += 8 * battle.pbAbleNonActiveCount(user.idxOpposingSide) @@ -166,11 +213,14 @@ Battle::AI::Handlers::MoveEffectScore.add("AddToxicSpikesToFoeSide", } ) +Battle::AI::Handlers::MoveFailureCheck.add("AddStealthRocksToFoeSide", + proc { |move, user, target, ai, battle| + next true if user.pbOpposingSide.effects[PBEffects::StealthRock] + } +) Battle::AI::Handlers::MoveEffectScore.add("AddStealthRocksToFoeSide", proc { |score, move, user, target, ai, battle| - if user.pbOpposingSide.effects[PBEffects::StealthRock] - next score - 90 - elsif user.battler.allOpposing.none? { |b| battle.pbCanChooseNonActive?(b.index) } + if user.battler.allOpposing.none? { |b| battle.pbCanChooseNonActive?(b.index) } next score - 90 # Opponent can't switch in any Pokemon else next score + 10 * battle.pbAbleNonActiveCount(user.idxOpposingSide) @@ -178,12 +228,33 @@ Battle::AI::Handlers::MoveEffectScore.add("AddStealthRocksToFoeSide", } ) -Battle::AI::Handlers::MoveEffectScore.add("AddStickyWebToFoeSide", - proc { |score, move, user, target, ai, battle| - next score - 95 if user.pbOpposingSide.effects[PBEffects::StickyWeb] +Battle::AI::Handlers::MoveFailureCheck.add("AddStickyWebToFoeSide", + proc { |move, user, target, ai, battle| + next true if user.pbOpposingSide.effects[PBEffects::StickyWeb] } ) +Battle::AI::Handlers::MoveFailureCheck.add("SwapSideEffects", + proc { |move, user, target, ai, battle| + has_effect = false + 2.times do |side| + effects = battle.sides[side].effects + move.move.number_effects.each do |e| + next if effects[e] == 0 + has_effect = true + break + end + break if has_effect + move.move.boolean_effects.each do |e| + next if !effects[e] + has_effect = true + break + end + break if has_effect + end + next !has_effect + } +) Battle::AI::Handlers::MoveEffectScore.add("SwapSideEffects", proc { |score, move, user, target, ai, battle| if ai.trainer.medium_skill? @@ -206,13 +277,10 @@ Battle::AI::Handlers::MoveEffectScore.add("SwapSideEffects", } ) -Battle::AI::Handlers::MoveEffectScore.add("UserMakeSubstitute", - proc { |score, move, user, target, ai, battle| - if user.effects[PBEffects::Substitute] > 0 - next score - 90 - elsif user.hp <= user.totalhp / 4 - next score - 90 - end +Battle::AI::Handlers::MoveFailureCheck.add("UserMakeSubstitute", + proc { |move, user, target, ai, battle| + next true if user.effects[PBEffects::Substitute] > 0 + next true if user.hp <= [user.totalhp / 4, 1].max } ) @@ -229,18 +297,32 @@ Battle::AI::Handlers::MoveEffectScore.add("RemoveUserBindingAndEntryHazards", } ) +Battle::AI::Handlers::MoveFailureCheck.add("AttackTwoTurnsLater", + proc { |move, user, target, ai, battle| + next true if battle.positions[target.index].effects[PBEffects::FutureSightCounter] > 0 + } +) Battle::AI::Handlers::MoveEffectScore.add("AttackTwoTurnsLater", proc { |score, move, user, target, ai, battle| - if battle.positions[target.index].effects[PBEffects::FutureSightCounter] > 0 - next 0 - elsif battle.pbAbleNonActiveCount(user.idxOwnSide) == 0 + if battle.pbAbleNonActiveCount(user.idxOwnSide) == 0 # Future Sight tends to be wasteful if down to last Pokemon next score - 70 end } ) -# UserSwapsPositionsWithAlly +Battle::AI::Handlers::MoveFailureCheck.add("UserSwapsPositionsWithAlly", + proc { |move, user, target, ai, battle| + num_targets = 0 + idxUserOwner = battle.pbGetOwnerIndexFromBattlerIndex(user.index) + user.battler.allAllies.each do |b| + next if battle.pbGetOwnerIndexFromBattlerIndex(b.index) != idxUserOwner + next if !b.near?(user) + num_targets += 1 + end + next num_targets != 1 + } +) Battle::AI::Handlers::MoveEffectScore.add("BurnAttackerBeforeUserActs", proc { |score, move, user, target, ai, battle| diff --git a/Data/Scripts/011_Battle/005_AI/052_AI_MoveHandlers_BattlerStats.rb b/Data/Scripts/011_Battle/005_AI/052_AI_MoveHandlers_BattlerStats.rb index da66fdd61..6144d27c0 100644 --- a/Data/Scripts/011_Battle/005_AI/052_AI_MoveHandlers_BattlerStats.rb +++ b/Data/Scripts/011_Battle/005_AI/052_AI_MoveHandlers_BattlerStats.rb @@ -1,10 +1,15 @@ #=============================================================================== # #=============================================================================== +Battle::AI::Handlers::MoveFailureCheck.add("RaiseUserAttack1", + proc { |move, user, target, ai, battle| + next true if move.statusMove? && + !user.battler.pbCanRaiseStatStage?(move.move.statUp[0], user.battler, move.move) + } +) Battle::AI::Handlers::MoveEffectScore.add("RaiseUserAttack1", proc { |score, move, user, target, ai, battle| if move.statusMove? - next score - 90 if user.statStageAtMax?(:ATTACK) score -= user.stages[:ATTACK] * 20 if ai.trainer.medium_skill? hasPhysicalAttack = false @@ -35,6 +40,8 @@ Battle::AI::Handlers::MoveEffectScore.add("RaiseUserAttack1", } ) +Battle::AI::Handlers::MoveFailureCheck.copy("RaiseUserAttack1", + "RaiseUserAttack2") Battle::AI::Handlers::MoveEffectScore.add("RaiseUserAttack2", proc { |score, move, user, target, ai, battle| if move.statusMove? @@ -72,13 +79,24 @@ Battle::AI::Handlers::MoveEffectScore.add("RaiseUserAttack2", ) Battle::AI::Handlers::MoveEffectScore.copy("RaiseUserAttack2", - "RaiseUserAttack2IfTargetFaints", - "RaiseUserAttack3", + "RaiseUserAttack2IfTargetFaints") + +Battle::AI::Handlers::MoveFailureCheck.copy("RaiseUserAttack2", + "RaiseUserAttack3") +Battle::AI::Handlers::MoveEffectScore.copy("RaiseUserAttack2", + "RaiseUserAttack3") + +Battle::AI::Handlers::MoveEffectScore.copy("RaiseUserAttack2IfTargetFaints", "RaiseUserAttack3IfTargetFaints") +Battle::AI::Handlers::MoveFailureCheck.add("MaxUserAttackLoseHalfOfTotalHP", + proc { |move, user, target, ai, battle| + next true if user.hp <= [user.totalhp / 2, 1].max + next true if !user.battler.pbCanRaiseStatStage?(:ATTACK, user.battler, move.move) + } +) Battle::AI::Handlers::MoveEffectScore.add("MaxUserAttackLoseHalfOfTotalHP", proc { |score, move, user, target, ai, battle| - next 0 if user.statStageAtMax?(:ATTACK) || user.hp <= user.totalhp / 2 score += (6 - user.stages[:ATTACK]) * 10 if ai.trainer.medium_skill? hasPhysicalAttack = false @@ -97,10 +115,11 @@ Battle::AI::Handlers::MoveEffectScore.add("MaxUserAttackLoseHalfOfTotalHP", } ) +Battle::AI::Handlers::MoveFailureCheck.copy("RaiseUserAttack1", + "RaiseUserDefense1") Battle::AI::Handlers::MoveEffectScore.add("RaiseUserDefense1", proc { |score, move, user, target, ai, battle| if move.statusMove? - next 0 if user.statStageAtMax?(:DEFENSE) next score - user.stages[:DEFENSE] * 20 elsif user.stages[:DEFENSE] < 0 next score + 20 @@ -108,13 +127,16 @@ Battle::AI::Handlers::MoveEffectScore.add("RaiseUserDefense1", } ) +Battle::AI::Handlers::MoveFailureCheck.copy("RaiseUserDefense1", + "RaiseUserDefense1CurlUpUser") Battle::AI::Handlers::MoveEffectScore.copy("RaiseUserDefense1", "RaiseUserDefense1CurlUpUser") +Battle::AI::Handlers::MoveFailureCheck.copy("RaiseUserDefense1", + "RaiseUserDefense2") Battle::AI::Handlers::MoveEffectScore.add("RaiseUserDefense2", proc { |score, move, user, target, ai, battle| if move.statusMove? - next 0 if user.statStageAtMax?(:DEFENSE) score += 40 if user.turnCount == 0 score -= user.stages[:DEFENSE] * 20 else @@ -125,10 +147,11 @@ Battle::AI::Handlers::MoveEffectScore.add("RaiseUserDefense2", } ) +Battle::AI::Handlers::MoveFailureCheck.copy("RaiseUserDefense1", + "RaiseUserDefense3") Battle::AI::Handlers::MoveEffectScore.add("RaiseUserDefense3", proc { |score, move, user, target, ai, battle| if move.statusMove? - next 0 if user.statStageAtMax?(:DEFENSE) score += 40 if user.turnCount == 0 score -= user.stages[:DEFENSE] * 30 else @@ -139,10 +162,11 @@ Battle::AI::Handlers::MoveEffectScore.add("RaiseUserDefense3", } ) +Battle::AI::Handlers::MoveFailureCheck.copy("RaiseUserAttack1", + "RaiseUserSpAtk1") Battle::AI::Handlers::MoveEffectScore.add("RaiseUserSpAtk1", proc { |score, move, user, target, ai, battle| if move.statusMove? - next 0 if user.statStageAtMax?(:SPECIAL_ATTACK) score -= user.stages[:SPECIAL_ATTACK] * 20 if ai.trainer.medium_skill? hasSpecicalAttack = false @@ -173,10 +197,11 @@ Battle::AI::Handlers::MoveEffectScore.add("RaiseUserSpAtk1", } ) +Battle::AI::Handlers::MoveFailureCheck.copy("RaiseUserSpAtk1", + "RaiseUserSpAtk2") Battle::AI::Handlers::MoveEffectScore.add("RaiseUserSpAtk2", proc { |score, move, user, target, ai, battle| if move.statusMove? - next 0 if user.statStageAtMax?(:SPECIAL_ATTACK) score += 40 if user.turnCount == 0 score -= user.stages[:SPECIAL_ATTACK] * 20 if ai.trainer.medium_skill? @@ -209,10 +234,11 @@ Battle::AI::Handlers::MoveEffectScore.add("RaiseUserSpAtk2", } ) +Battle::AI::Handlers::MoveFailureCheck.copy("RaiseUserSpAtk1", + "RaiseUserSpAtk3") Battle::AI::Handlers::MoveEffectScore.add("RaiseUserSpAtk3", proc { |score, move, user, target, ai, battle| if move.statusMove? - next 0 if user.statStageAtMax?(:SPECIAL_ATTACK) score += 40 if user.turnCount == 0 score -= user.stages[:SPECIAL_ATTACK] * 30 if ai.trainer.medium_skill? @@ -245,10 +271,11 @@ Battle::AI::Handlers::MoveEffectScore.add("RaiseUserSpAtk3", } ) +Battle::AI::Handlers::MoveFailureCheck.copy("RaiseUserDefense1", + "RaiseUserSpDef1") Battle::AI::Handlers::MoveEffectScore.add("RaiseUserSpDef1", proc { |score, move, user, target, ai, battle| if move.statusMove? - next 0 if user.statStageAtMax?(:SPECIAL_DEFENSE) score += 40 if user.turnCount == 0 score -= user.stages[:SPECIAL_DEFENSE] * 20 else @@ -259,10 +286,8 @@ Battle::AI::Handlers::MoveEffectScore.add("RaiseUserSpDef1", } ) -Battle::AI::Handlers::MoveEffectScore.copy("RaiseUserSpDef1", - "RaiseUserSpDef2", - "RaiseUserSpDef3") - +Battle::AI::Handlers::MoveFailureCheck.copy("RaiseUserSpDef1", + "RaiseUserSpDef1PowerUpElectricMove") Battle::AI::Handlers::MoveEffectScore.add("RaiseUserSpDef1PowerUpElectricMove", proc { |score, move, user, target, ai, battle| foundMove = false @@ -273,11 +298,7 @@ Battle::AI::Handlers::MoveEffectScore.add("RaiseUserSpDef1PowerUpElectricMove", end score += 20 if foundMove if move.statusMove? - if user.statStageAtMax?(:SPECIAL_DEFENSE) - score -= 90 - else - score -= user.stages[:SPECIAL_DEFENSE] * 20 - end + score -= user.stages[:SPECIAL_DEFENSE] * 20 elsif user.stages[:SPECIAL_DEFENSE] < 0 score += 20 end @@ -285,10 +306,18 @@ Battle::AI::Handlers::MoveEffectScore.add("RaiseUserSpDef1PowerUpElectricMove", } ) +Battle::AI::Handlers::MoveFailureCheck.copy("RaiseUserSpDef1", + "RaiseUserSpDef2", + "RaiseUserSpDef3") +Battle::AI::Handlers::MoveEffectScore.copy("RaiseUserSpDef1", + "RaiseUserSpDef2", + "RaiseUserSpDef3") + +Battle::AI::Handlers::MoveFailureCheck.copy("RaiseUserSpDef1", + "RaiseUserSpeed1") Battle::AI::Handlers::MoveEffectScore.add("RaiseUserSpeed1", proc { |score, move, user, target, ai, battle| if move.statusMove? - next 0 if user.statStageAtMax?(:SPEED) score -= user.stages[:SPEED] * 10 if ai.trainer.high_skill? aspeed = user.rough_stat(:SPEED) @@ -302,10 +331,11 @@ Battle::AI::Handlers::MoveEffectScore.add("RaiseUserSpeed1", } ) +Battle::AI::Handlers::MoveFailureCheck.copy("RaiseUserSpeed1", + "RaiseUserSpeed2") Battle::AI::Handlers::MoveEffectScore.add("RaiseUserSpeed2", proc { |score, move, user, target, ai, battle| if move.statusMove? - next 0 if user.statStageAtMax?(:SPEED) score += 20 if user.turnCount == 0 score -= user.stages[:SPEED] * 10 if ai.trainer.high_skill? @@ -321,14 +351,18 @@ Battle::AI::Handlers::MoveEffectScore.add("RaiseUserSpeed2", } ) +Battle::AI::Handlers::MoveFailureCheck.copy("RaiseUserSpeed2", + "RaiseUserSpeed2LowerUserWeight", + "RaiseUserSpeed3") Battle::AI::Handlers::MoveEffectScore.copy("RaiseUserSpeed2", "RaiseUserSpeed2LowerUserWeight", "RaiseUserSpeed3") +Battle::AI::Handlers::MoveFailureCheck.copy("RaiseUserSpeed1", + "RaiseUserAccuracy1") Battle::AI::Handlers::MoveEffectScore.add("RaiseUserAccuracy1", proc { |score, move, user, target, ai, battle| if move.statusMove? - next 0 if user.statStageAtMax?(:ACCURACY) score += 40 if user.turnCount == 0 score -= user.stages[:ACCURACY] * 20 else @@ -339,14 +373,18 @@ Battle::AI::Handlers::MoveEffectScore.add("RaiseUserAccuracy1", } ) +Battle::AI::Handlers::MoveFailureCheck.copy("RaiseUserAccuracy1", + "RaiseUserAccuracy2", + "RaiseUserAccuracy3") Battle::AI::Handlers::MoveEffectScore.copy("RaiseUserAccuracy1", "RaiseUserAccuracy2", "RaiseUserAccuracy3") +Battle::AI::Handlers::MoveFailureCheck.copy("RaiseUserAccuracy1", + "RaiseUserEvasion1") Battle::AI::Handlers::MoveEffectScore.add("RaiseUserEvasion1", proc { |score, move, user, target, ai, battle| if move.statusMove? - next 0 if user.statStageAtMax?(:EVASION) score -= user.stages[:EVASION] * 10 elsif user.stages[:EVASION] < 0 score += 20 @@ -355,10 +393,11 @@ Battle::AI::Handlers::MoveEffectScore.add("RaiseUserEvasion1", } ) +Battle::AI::Handlers::MoveFailureCheck.copy("RaiseUserEvasion1", + "RaiseUserEvasion2") Battle::AI::Handlers::MoveEffectScore.add("RaiseUserEvasion2", proc { |score, move, user, target, ai, battle| if move.statusMove? - next 0 if user.statStageAtMax?(:EVASION) score += 40 if user.turnCount == 0 score -= user.stages[:EVASION] * 10 else @@ -369,25 +408,41 @@ Battle::AI::Handlers::MoveEffectScore.add("RaiseUserEvasion2", } ) +Battle::AI::Handlers::MoveFailureCheck.copy("RaiseUserEvasion2", + "RaiseUserEvasion2MinimizeUser", + "RaiseUserEvasion3") Battle::AI::Handlers::MoveEffectScore.copy("RaiseUserEvasion2", "RaiseUserEvasion2MinimizeUser", "RaiseUserEvasion3") +Battle::AI::Handlers::MoveFailureCheck.add("RaiseUserCriticalHitRate2", + proc { |move, user, target, ai, battle| + next true if user.effects[PBEffects::FocusEnergy] >= 2 + } +) Battle::AI::Handlers::MoveEffectScore.add("RaiseUserCriticalHitRate2", proc { |score, move, user, target, ai, battle| - if move.statusMove? - next 0 if user.effects[PBEffects::FocusEnergy] >= 2 - next score + 30 - elsif user.effects[PBEffects::FocusEnergy] < 2 + if move.statusMove? || user.effects[PBEffects::FocusEnergy] < 2 next score + 30 end } ) +Battle::AI::Handlers::MoveFailureCheck.add("RaiseUserAtkDef1", + proc { |move, user, target, ai, battle| + if move.statusMove? + will_fail = true + (move.move.statUp.length / 2).times do |i| + next if !user.battler.pbCanRaiseStatStage?(move.move.statUp[i * 2], user.battler, move.move) + will_fail = false + break + end + next will_fail + end + } +) Battle::AI::Handlers::MoveEffectScore.add("RaiseUserAtkDef1", proc { |score, move, user, target, ai, battle| - next score - 90 if user.statStageAtMax?(:ATTACK) && - user.statStageAtMax?(:DEFENSE) score -= user.stages[:ATTACK] * 10 score -= user.stages[:DEFENSE] * 10 if ai.trainer.medium_skill? @@ -407,11 +462,10 @@ Battle::AI::Handlers::MoveEffectScore.add("RaiseUserAtkDef1", } ) +Battle::AI::Handlers::MoveFailureCheck.copy("RaiseUserAtkDef1", + "RaiseUserAtkDefAcc1") Battle::AI::Handlers::MoveEffectScore.add("RaiseUserAtkDefAcc1", proc { |score, move, user, target, ai, battle| - next score - 90 if user.statStageAtMax?(:ATTACK) && - user.statStageAtMax?(:DEFENSE) && - user.statStageAtMax?(:ACCURACY) score -= user.stages[:ATTACK] * 10 score -= user.stages[:DEFENSE] * 10 score -= user.stages[:ACCURACY] * 10 @@ -432,10 +486,10 @@ Battle::AI::Handlers::MoveEffectScore.add("RaiseUserAtkDefAcc1", } ) -Battle::AI::Handlers::MoveEffectScore.add("RaiseUserAtkDefAcc1", +Battle::AI::Handlers::MoveFailureCheck.copy("RaiseUserAtkDef1", + "RaiseUserAtkSpAtk1") +Battle::AI::Handlers::MoveEffectScore.add("RaiseUserAtkSpAtk1", proc { |score, move, user, target, ai, battle| - next score - 90 if user.statStageAtMax?(:ATTACK) && - user.statStageAtMax?(:SPECIAL_ATTACK) score -= user.stages[:ATTACK] * 10 score -= user.stages[:SPECIAL_ATTACK] * 10 if ai.trainer.medium_skill? @@ -458,9 +512,27 @@ Battle::AI::Handlers::MoveEffectScore.add("RaiseUserAtkDefAcc1", } ) +Battle::AI::Handlers::MoveFailureCheck.copy("RaiseUserAtkSpAtk1", + "RaiseUserAtkSpAtk1Or2InSun") Battle::AI::Handlers::MoveEffectScore.copy("RaiseUserAtkSpAtk1", "RaiseUserAtkSpAtk1Or2InSun") +Battle::AI::Handlers::MoveFailureCheck.add("LowerUserDefSpDef1RaiseUserAtkSpAtkSpd2", + proc { |move, user, target, ai, battle| + will_fail = true + (move.move.statUp.length / 2).times do |i| + next if !user.battler.pbCanRaiseStatStage?(move.move.statUp[i * 2], user.battler, move.move) + will_fail = false + break + end + (move.move.statDown.length / 2).times do |i| + next if !user.battler.pbCanLowerStatStage?(move.move.statDown[i * 2], user.battler, move.move) + will_fail = false + break + end + next will_fail + } +) Battle::AI::Handlers::MoveEffectScore.add("LowerUserDefSpDef1RaiseUserAtkSpAtkSpd2", proc { |score, move, user, target, ai, battle| score -= user.stages[:ATTACK] * 20 @@ -481,10 +553,10 @@ Battle::AI::Handlers::MoveEffectScore.add("LowerUserDefSpDef1RaiseUserAtkSpAtkSp } ) +Battle::AI::Handlers::MoveFailureCheck.copy("RaiseUserAtkSpAtk1", + "RaiseUserAtkSpd1") Battle::AI::Handlers::MoveEffectScore.add("RaiseUserAtkSpd1", proc { |score, move, user, target, ai, battle| - next score - 90 if user.statStageAtMax?(:ATTACK) && - user.statStageAtMax?(:SPEED) score += 40 if user.turnCount == 0 # Dragon Dance tends to be popular score -= user.stages[:ATTACK] * 10 score -= user.stages[:SPEED] * 10 @@ -510,10 +582,10 @@ Battle::AI::Handlers::MoveEffectScore.add("RaiseUserAtkSpd1", } ) +Battle::AI::Handlers::MoveFailureCheck.copy("RaiseUserAtkSpAtk1", + "RaiseUserAtk1Spd2") Battle::AI::Handlers::MoveEffectScore.add("RaiseUserAtk1Spd2", proc { |score, move, user, target, ai, battle| - next score - 90 if user.statStageAtMax?(:ATTACK) && - user.statStageAtMax?(:SPEED) score -= user.stages[:ATTACK] * 10 score -= user.stages[:SPEED] * 10 if ai.trainer.medium_skill? @@ -538,10 +610,10 @@ Battle::AI::Handlers::MoveEffectScore.add("RaiseUserAtk1Spd2", } ) +Battle::AI::Handlers::MoveFailureCheck.copy("RaiseUserAtkSpAtk1", + "RaiseUserAtkAcc1") Battle::AI::Handlers::MoveEffectScore.add("RaiseUserAtkAcc1", proc { |score, move, user, target, ai, battle| - next score - 90 if user.statStageAtMax?(:ATTACK) && - user.statStageAtMax?(:ACCURACY) score -= user.stages[:ATTACK] * 10 score -= user.stages[:ACCURACY] * 10 if ai.trainer.medium_skill? @@ -561,20 +633,20 @@ Battle::AI::Handlers::MoveEffectScore.add("RaiseUserAtkAcc1", } ) +Battle::AI::Handlers::MoveFailureCheck.copy("RaiseUserAtkSpAtk1", + "RaiseUserDefSpDef1") Battle::AI::Handlers::MoveEffectScore.add("RaiseUserDefSpDef1", proc { |score, move, user, target, ai, battle| - next score - 90 if user.statStageAtMax?(:DEFENSE) && - user.statStageAtMax?(:SPECIAL_DEFENSE) score -= user.stages[:DEFENSE] * 10 score -= user.stages[:SPECIAL_DEFENSE] * 10 next score } ) +Battle::AI::Handlers::MoveFailureCheck.copy("RaiseUserAtkSpAtk1", + "RaiseUserSpAtkSpDef1") Battle::AI::Handlers::MoveEffectScore.add("RaiseUserSpAtkSpDef1", proc { |score, move, user, target, ai, battle| - next score - 90 if user.statStageAtMax?(:SPECIAL_ATTACK) && - user.statStageAtMax?(:SPECIAL_DEFENSE) score += 40 if user.turnCount == 0 # Calm Mind tends to be popular score -= user.stages[:SPECIAL_ATTACK] * 10 score -= user.stages[:SPECIAL_DEFENSE] * 10 @@ -595,11 +667,10 @@ Battle::AI::Handlers::MoveEffectScore.add("RaiseUserSpAtkSpDef1", } ) +Battle::AI::Handlers::MoveFailureCheck.copy("RaiseUserAtkSpAtk1", + "RaiseUserSpAtkSpDefSpd1") Battle::AI::Handlers::MoveEffectScore.add("RaiseUserSpAtkSpDefSpd1", proc { |score, move, user, target, ai, battle| - next score - 90 if user.statStageAtMax?(:SPECIAL_ATTACK) && - user.statStageAtMax?(:SPECIAL_DEFENSE) && - user.statStageAtMax?(:SPEED) score += 40 if user.turnCount == 0 # Calm Mind tends to be popular score -= user.stages[:SPECIAL_ATTACK] * 10 score -= user.stages[:SPECIAL_DEFENSE] * 10 @@ -626,6 +697,8 @@ Battle::AI::Handlers::MoveEffectScore.add("RaiseUserSpAtkSpDefSpd1", } ) +Battle::AI::Handlers::MoveFailureCheck.copy("RaiseUserAtkSpAtk1", + "RaiseUserMainStats1") Battle::AI::Handlers::MoveEffectScore.add("RaiseUserMainStats1", proc { |score, move, user, target, ai, battle| GameData::Stat.each_main_battle { |s| score += 10 if user.stages[s.id] < 0 } @@ -642,17 +715,21 @@ Battle::AI::Handlers::MoveEffectScore.add("RaiseUserMainStats1", } ) -Battle::AI::Handlers::MoveEffectScore.add("RaiseUserMainStats1LoseThirdOfTotalHP", - proc { |score, move, user, target, ai, battle| - next 0 if user.hp <= user.totalhp / 2 - next 0 if user.has_active_ability?(:CONTRARY) - stats_maxed = true - GameData::Stat.each_main_battle do |s| - next if user.statStageAtMax?(s.id) - stats_maxed = false +Battle::AI::Handlers::MoveFailureCheck.add("RaiseUserMainStats1LoseThirdOfTotalHP", + proc { |move, user, target, ai, battle| + next true if user.hp <= [user.totalhp / 3, 1].max + will_fail = true + (move.move.statUp.length / 2).times do |i| + next if !user.battler.pbCanRaiseStatStage?(move.move.statUp[i * 2], user.battler, move.move) + will_fail = false break end - next 0 if stats_maxed + next will_fail + } +) +Battle::AI::Handlers::MoveEffectScore.add("RaiseUserMainStats1LoseThirdOfTotalHP", + proc { |score, move, user, target, ai, battle| + next 0 if user.has_active_ability?(:CONTRARY) score += 30 if ai.trainer.high_skill? && user.hp >= user.totalhp * 0.75 GameData::Stat.each_main_battle { |s| score += 10 if user.stages[s.id] <= 0 } if ai.trainer.medium_skill? @@ -663,17 +740,21 @@ Battle::AI::Handlers::MoveEffectScore.add("RaiseUserMainStats1LoseThirdOfTotalHP } ) -Battle::AI::Handlers::MoveEffectScore.add("RaiseUserMainStats1TrapUserInBattle", - proc { |score, move, user, target, ai, battle| - next 0 if user.effects[PBEffects::NoRetreat] - next 0 if user.has_active_ability?(:CONTRARY) - stats_maxed = true - GameData::Stat.each_main_battle do |s| - next if user.statStageAtMax?(s.id) - stats_maxed = false +Battle::AI::Handlers::MoveFailureCheck.add("RaiseUserMainStats1TrapUserInBattle", + proc { |move, user, target, ai, battle| + next true if user.effects[PBEffects::NoRetreat] + will_fail = true + (move.move.statUp.length / 2).times do |i| + next if !user.battler.pbCanRaiseStatStage?(move.move.statUp[i * 2], user.battler, move.move) + will_fail = false break end - next 0 if stats_maxed + next will_fail + } +) +Battle::AI::Handlers::MoveEffectScore.add("RaiseUserMainStats1TrapUserInBattle", + proc { |score, move, user, target, ai, battle| + next 0 if user.has_active_ability?(:CONTRARY) if ai.trainer.high_skill? score -= 50 if user.hp <= user.totalhp / 2 score += 30 if user.battler.trappedInBattle? @@ -763,8 +844,19 @@ Battle::AI::Handlers::MoveEffectScore.add("LowerUserDefSpDefSpd1", } ) -# RaiseTargetAttack1 +Battle::AI::Handlers::MoveFailureCheck.add("RaiseTargetAttack1", + proc { |move, user, target, ai, battle| + next true if move.statusMove? && + !target.battler.pbCanRaiseStatStage?(:ATTACK, user.battler, move.move) + } +) +Battle::AI::Handlers::MoveFailureCheck.add("RaiseTargetAttack2ConfuseTarget", + proc { |move, user, target, ai, battle| + next true if !target.battler.pbCanRaiseStatStage?(:ATTACK, user.battler, move.move) && + !target.battler.pbCanConfuse?(user.battler, false, move.move) + } +) Battle::AI::Handlers::MoveEffectScore.add("RaiseTargetAttack2ConfuseTarget", proc { |score, move, user, target, ai, battle| next score - 90 if !target.battler.pbCanConfuse?(user.battler, false) @@ -772,6 +864,12 @@ Battle::AI::Handlers::MoveEffectScore.add("RaiseTargetAttack2ConfuseTarget", } ) +Battle::AI::Handlers::MoveFailureCheck.add("RaiseTargetSpAtk1ConfuseTarget", + proc { |move, user, target, ai, battle| + next true if !target.battler.pbCanRaiseStatStage?(:SPECIAL_ATTACK, user.battler, move.move) && + !target.battler.pbCanConfuse?(user.battler, false, move.move) + } +) Battle::AI::Handlers::MoveEffectScore.add("RaiseTargetSpAtk1ConfuseTarget", proc { |score, move, user, target, ai, battle| next score - 90 if !target.battler.pbCanConfuse?(user.battler, false) @@ -779,31 +877,44 @@ Battle::AI::Handlers::MoveEffectScore.add("RaiseTargetSpAtk1ConfuseTarget", } ) +Battle::AI::Handlers::MoveFailureCheck.add("RaiseTargetSpDef1", + proc { |move, user, target, ai, battle| + next true if !target.battler.pbCanRaiseStatStage?(:SPECIAL_DEFENSE, user.battler, move.move) + } +) Battle::AI::Handlers::MoveEffectScore.add("RaiseTargetSpDef1", proc { |score, move, user, target, ai, battle| - next score + 30 if target.statStageAtMax?(:SPECIAL_DEFENSE) next score - target.stages[:SPECIAL_DEFENSE] * 10 } ) +Battle::AI::Handlers::MoveFailureCheck.add("RaiseTargetRandomStat2", + proc { |move, user, target, ai, battle| + will_fail = true + GameData::Stat.each_battle do |s| + next if !target.battler.pbCanRaiseStatStage?(s.id, user.battler, move.move) + will_fail = false + end + next will_fail + } +) Battle::AI::Handlers::MoveEffectScore.add("RaiseTargetRandomStat2", proc { |score, move, user, target, ai, battle| avgStat = 0 - canChangeStat = false GameData::Stat.each_battle do |s| - next if target.statStageAtMax?(s.id) - avgStat -= target.stages[s.id] - canChangeStat = true - end - if canChangeStat - avgStat = avgStat / 2 if avgStat < 0 # More chance of getting even better - next + avgStat * 10 - else - next score - 90 + avgStat -= target.stages[s.id] if !target.statStageAtMax?(s.id) end + avgStat = avgStat / 2 if avgStat < 0 # More chance of getting even better + next + avgStat * 10 } ) +Battle::AI::Handlers::MoveFailureCheck.add("RaiseTargetAtkSpAtk2", + proc { |move, user, target, ai, battle| + next true if !target.battler.pbCanRaiseStatStage?(:ATTACK, user.battler, move.move) && + !target.battler.pbCanRaiseStatStage?(:SPECIAL_ATTACK, user.battler, move.move) + } +) Battle::AI::Handlers::MoveEffectScore.add("RaiseTargetAtkSpAtk2", proc { |score, move, user, target, ai, battle| next 0 if target.opposes?(user) @@ -814,10 +925,15 @@ Battle::AI::Handlers::MoveEffectScore.add("RaiseTargetAtkSpAtk2", } ) +Battle::AI::Handlers::MoveFailureCheck.add("LowerTargetAttack1", + proc { |move, user, target, ai, battle| + next true if move.statusMove? && + !target.battler.pbCanLowerStatStage?(move.move.statDown[0], user.battler, move.move) + } +) Battle::AI::Handlers::MoveEffectScore.add("LowerTargetAttack1", proc { |score, move, user, target, ai, battle| if move.statusMove? - next 0 if !target.battler.pbCanLowerStatStage?(:ATTACK, user.battler) score += target.stages[:ATTACK] * 20 if ai.trainer.medium_skill? hasPhysicalAttack = false @@ -848,9 +964,10 @@ Battle::AI::Handlers::MoveEffectScore.add("LowerTargetAttack1", } ) +Battle::AI::Handlers::MoveFailureCheck.copy("LowerTargetAttack1", + "LowerTargetAttack1BypassSubstitute") Battle::AI::Handlers::MoveEffectScore.add("LowerTargetAttack1BypassSubstitute", proc { |score, move, user, target, ai, battle| - next 0 if !target.battler.pbCanLowerStatStage?(:ATTACK, user.battler) score += target.stages[:ATTACK] * 20 if ai.trainer.medium_skill? hasPhysicalAttack = false @@ -869,10 +986,11 @@ Battle::AI::Handlers::MoveEffectScore.add("LowerTargetAttack1BypassSubstitute", } ) +Battle::AI::Handlers::MoveFailureCheck.copy("LowerTargetAttack1", + "LowerTargetAttack2") Battle::AI::Handlers::MoveEffectScore.add("LowerTargetAttack2", proc { |score, move, user, target, ai, battle| if move.statusMove? - next 0 if !target.battler.pbCanLowerStatStage?(:ATTACK, user.battler) score += 40 if user.turnCount == 0 score += target.stages[:ATTACK] * 20 if ai.trainer.medium_skill? @@ -905,13 +1023,16 @@ Battle::AI::Handlers::MoveEffectScore.add("LowerTargetAttack2", } ) +Battle::AI::Handlers::MoveFailureCheck.copy("LowerTargetAttack2", + "LowerTargetAttack3") Battle::AI::Handlers::MoveEffectScore.copy("LowerTargetAttack2", "LowerTargetAttack3") +Battle::AI::Handlers::MoveFailureCheck.copy("LowerTargetAttack1", + "LowerTargetDefense1") Battle::AI::Handlers::MoveEffectScore.add("LowerTargetDefense1", proc { |score, move, user, target, ai, battle| if move.statusMove? - next 0 if !target.battler.pbCanLowerStatStage?(:DEFENSE, user.battler) score += target.stages[:DEFENSE] * 20 elsif target.stages[:DEFENSE] > 0 score += 20 @@ -920,28 +1041,29 @@ Battle::AI::Handlers::MoveEffectScore.add("LowerTargetDefense1", } ) +Battle::AI::Handlers::MoveFailureCheck.copy("LowerTargetDefense1", + "LowerTargetDefense1PowersUpInGravity") Battle::AI::Handlers::MoveBasePower.add("LowerTargetDefense1PowersUpInGravity", proc { |power, move, user, target, ai, battle| next move.pbBaseDamage(power, user.battler, target.battler) } -} +) Battle::AI::Handlers::MoveEffectScore.add("LowerTargetDefense1PowersUpInGravity", proc { |score, move, user, target, ai, battle| if move.statusMove? - next 0 if !target.battler.pbCanLowerStatStage?(:DEFENSE, user.battler) score += target.stages[:DEFENSE] * 20 elsif target.stages[:DEFENSE] > 0 score += 20 end - score += 30 if battle.field.effects[PBEffects::Gravity] > 0 next score } ) +Battle::AI::Handlers::MoveFailureCheck.copy("LowerTargetDefense1", + "LowerTargetDefense2") Battle::AI::Handlers::MoveEffectScore.add("LowerTargetDefense2", proc { |score, move, user, target, ai, battle| if move.statusMove? - next 0 if !target.battler.pbCanLowerStatStage?(:DEFENSE, user.battler) score += 40 if user.turnCount == 0 score += target.stages[:DEFENSE] * 20 else @@ -952,13 +1074,16 @@ Battle::AI::Handlers::MoveEffectScore.add("LowerTargetDefense2", } ) +Battle::AI::Handlers::MoveFailureCheck.copy("LowerTargetDefense2", + "LowerTargetDefense3") Battle::AI::Handlers::MoveEffectScore.copy("LowerTargetDefense2", "LowerTargetDefense3") +Battle::AI::Handlers::MoveFailureCheck.copy("LowerTargetAttack1", + "LowerTargetSpAtk1") Battle::AI::Handlers::MoveEffectScore.add("LowerTargetSpAtk1", proc { |score, move, user, target, ai, battle| if move.statusMove? - next 0 if !target.battler.pbCanLowerStatStage?(:SPECIAL_ATTACK, user.battler) score += user.stages[:SPECIAL_ATTACK] * 20 if ai.trainer.medium_skill? hasSpecicalAttack = false @@ -989,21 +1114,27 @@ Battle::AI::Handlers::MoveEffectScore.add("LowerTargetSpAtk1", } ) +Battle::AI::Handlers::MoveFailureCheck.copy("LowerTargetSpAtk1", + "LowerTargetSpAtk2") Battle::AI::Handlers::MoveEffectScore.add("LowerTargetSpAtk2", proc { |score, move, user, target, ai, battle| - next 0 if !target.battler.pbCanLowerStatStage?(:SPECIAL_ATTACK, user.battler) score += 40 if user.turnCount == 0 score += target.stages[:SPECIAL_ATTACK] * 20 next score } ) +Battle::AI::Handlers::MoveFailureCheck.add("LowerTargetSpAtk2IfCanAttract", + proc { |move, user, target, ai, battle| + next true if move.statusMove? && + !target.battler.pbCanLowerStatStage?(move.move.statDown[0], user.battler, move.move) + next true if user.gender == 2 || target.gender == 2 || user.gender == target.gender + next true if target.has_active_ability?(:OBLIVIOUS) + } +) Battle::AI::Handlers::MoveEffectScore.add("LowerTargetSpAtk2IfCanAttract", proc { |score, move, user, target, ai, battle| - next 0 if user.gender == 2 || target.gender == 2 || - user.gender == target.gender || target.has_active_ability?(:OBLIVIOUS) if move.statusMove? - next 0 if !target.battler.pbCanLowerStatStage?(:SPECIAL_ATTACK, user.battler) score += 40 if user.turnCount == 0 score += target.stages[:SPECIAL_ATTACK] * 20 if ai.trainer.medium_skill? @@ -1036,19 +1167,21 @@ Battle::AI::Handlers::MoveEffectScore.add("LowerTargetSpAtk2IfCanAttract", } ) -Battle::AI::Handlers::MoveEffectScore.add("LowerTargetSpAtk2", +Battle::AI::Handlers::MoveFailureCheck.copy("LowerTargetSpAtk1", + "LowerTargetSpAtk3") +Battle::AI::Handlers::MoveEffectScore.add("LowerTargetSpAtk3", proc { |score, move, user, target, ai, battle| - next 0 if !target.battler.pbCanLowerStatStage?(:SPECIAL_ATTACK, user.battler) score += 40 if user.turnCount == 0 score += target.stages[:SPECIAL_ATTACK] * 20 next score } ) +Battle::AI::Handlers::MoveFailureCheck.copy("LowerTargetDefense1", + "LowerTargetSpDef1") Battle::AI::Handlers::MoveEffectScore.add("LowerTargetSpDef1", proc { |score, move, user, target, ai, battle| if move.statusMove? - next 0 if !target.battler.pbCanLowerStatStage?(:SPECIAL_DEFENSE, user.battler) score += target.stages[:SPECIAL_DEFENSE] * 20 elsif target.stages[:SPECIAL_DEFENSE] > 0 score += 20 @@ -1057,10 +1190,11 @@ Battle::AI::Handlers::MoveEffectScore.add("LowerTargetSpDef1", } ) +Battle::AI::Handlers::MoveFailureCheck.copy("LowerTargetSpDef1", + "LowerTargetSpDef2") Battle::AI::Handlers::MoveEffectScore.add("LowerTargetSpDef2", proc { |score, move, user, target, ai, battle| if move.statusMove? - next 0 if !target.battler.pbCanLowerStatStage?(:SPECIAL_DEFENSE, user.battler) score += 40 if user.turnCount == 0 score += target.stages[:SPECIAL_DEFENSE] * 20 else @@ -1071,13 +1205,16 @@ Battle::AI::Handlers::MoveEffectScore.add("LowerTargetSpDef2", } ) +Battle::AI::Handlers::MoveFailureCheck.copy("LowerTargetSpDef2", + "LowerTargetSpDef3") Battle::AI::Handlers::MoveEffectScore.copy("LowerTargetSpDef2", "LowerTargetSpDef3") +Battle::AI::Handlers::MoveFailureCheck.copy("LowerTargetSpDef1", + "LowerTargetSpeed1") Battle::AI::Handlers::MoveEffectScore.add("LowerTargetSpeed1", proc { |score, move, user, target, ai, battle| if move.statusMove? - next 0 if !target.battler.pbCanLowerStatStage?(:SPEED, user.battler) score += target.stages[:SPEED] * 10 if ai.trainer.high_skill? aspeed = user.rough_stat(:SPEED) @@ -1091,19 +1228,25 @@ Battle::AI::Handlers::MoveEffectScore.add("LowerTargetSpeed1", } ) -Battle::AI::Handlers::MoveEffectScore.copy("LowerTargetSpeed1", - "LowerTargetSpeed1WeakerInGrassyTerrain") - +Battle::AI::Handlers::MoveFailureCheck.copy("LowerTargetSpeed1", + "LowerTargetSpeed1WeakerInGrassyTerrain") Battle::AI::Handlers::MoveBasePower.add("LowerTargetSpeed1WeakerInGrassyTerrain", proc { |power, move, user, target, ai, battle| next move.pbBaseDamage(power, user.battler, target.battler) } -} +) +Battle::AI::Handlers::MoveEffectScore.copy("LowerTargetSpeed1", + "LowerTargetSpeed1WeakerInGrassyTerrain") +Battle::AI::Handlers::MoveFailureCheck.add("LowerTargetSpeed1MakeTargetWeakerToFire", + proc { |move, user, target, ai, battle| + next false if !target.effects[PBEffects::TarShot] + next true if move.statusMove? && + !target.battler.pbCanLowerStatStage?(move.move.statDown[0], user.battler, move.move) + } +) Battle::AI::Handlers::MoveEffectScore.add("LowerTargetSpeed1MakeTargetWeakerToFire", proc { |score, move, user, target, ai, battle| - next 0 if !target.battler.pbCanLowerStatStage?(:SPEED, user.battler) && - target.effects[PBEffects::TarShot] score += target.stages[:SPEED] * 10 if ai.trainer.high_skill? aspeed = user.rough_stat(:SPEED) @@ -1115,10 +1258,11 @@ Battle::AI::Handlers::MoveEffectScore.add("LowerTargetSpeed1MakeTargetWeakerToFi } ) +Battle::AI::Handlers::MoveFailureCheck.copy("LowerTargetSpeed1", + "LowerTargetSpeed2") Battle::AI::Handlers::MoveEffectScore.add("LowerTargetSpeed2", proc { |score, move, user, target, ai, battle| if move.statusMove? - next 0 if !target.battler.pbCanLowerStatStage?(:SPEED, user.battler) score += 20 if user.turnCount == 0 score += target.stages[:SPEED] * 20 if ai.trainer.high_skill? @@ -1134,13 +1278,16 @@ Battle::AI::Handlers::MoveEffectScore.add("LowerTargetSpeed2", } ) +Battle::AI::Handlers::MoveFailureCheck.copy("LowerTargetSpeed2", + "LowerTargetSpeed3") Battle::AI::Handlers::MoveEffectScore.copy("LowerTargetSpeed2", "LowerTargetSpeed3") +Battle::AI::Handlers::MoveFailureCheck.copy("LowerTargetSpeed1", + "LowerTargetAccuracy1") Battle::AI::Handlers::MoveEffectScore.add("LowerTargetAccuracy1", proc { |score, move, user, target, ai, battle| if move.statusMove? - return 0 if !target.battler.pbCanLowerStatStage?(:ACCURACY, user.battler) score += target.stages[:ACCURACY] * 10 elsif target.stages[:ACCURACY] > 0 score += 20 @@ -1149,14 +1296,18 @@ Battle::AI::Handlers::MoveEffectScore.add("LowerTargetAccuracy1", } ) +Battle::AI::Handlers::MoveFailureCheck.copy("LowerTargetAccuracy1", + "LowerTargetAccuracy2", + "LowerTargetAccuracy3") Battle::AI::Handlers::MoveEffectScore.copy("LowerTargetAccuracy1", "LowerTargetAccuracy2", "LowerTargetAccuracy3") +Battle::AI::Handlers::MoveFailureCheck.copy("LowerTargetAccuracy1", + "LowerTargetEvasion1") Battle::AI::Handlers::MoveEffectScore.add("LowerTargetEvasion1", proc { |score, move, user, target, ai, battle| if move.statusMove? - return 0 if !target.battler.pbCanLowerStatStage?(:EVASION, user.battler) score += target.stages[:EVASION] * 10 elsif target.stages[:EVASION] > 0 score += 20 @@ -1165,10 +1316,32 @@ Battle::AI::Handlers::MoveEffectScore.add("LowerTargetEvasion1", } ) +Battle::AI::Handlers::MoveFailureCheck.add("LowerTargetEvasion1RemoveSideEffects", + proc { |move, user, target, ai, battle| + target_side = target.pbOwnSide + target_opposing_side = target.pbOpposingSide + next false if target_side.effects[PBEffects::AuroraVeil] > 0 || + target_side.effects[PBEffects::LightScreen] > 0 || + target_side.effects[PBEffects::Reflect] > 0 || + target_side.effects[PBEffects::Mist] > 0 || + target_side.effects[PBEffects::Safeguard] > 0 + next false if target_side.effects[PBEffects::StealthRock] || + target_side.effects[PBEffects::Spikes] > 0 || + target_side.effects[PBEffects::ToxicSpikes] > 0 || + target_side.effects[PBEffects::StickyWeb] + next false if Settings::MECHANICS_GENERATION >= 6 && + (target_opposing_side.effects[PBEffects::StealthRock] || + target_opposing_side.effects[PBEffects::Spikes] > 0 || + target_opposing_side.effects[PBEffects::ToxicSpikes] > 0 || + target_opposing_side.effects[PBEffects::StickyWeb]) + next false if Settings::MECHANICS_GENERATION >= 8 && battle.field.terrain != :None + next true if move.statusMove? && + !target.battler.pbCanLowerStatStage?(move.move.statDown[0], user.battler, move.move) + } +) Battle::AI::Handlers::MoveEffectScore.add("LowerTargetEvasion1RemoveSideEffects", proc { |score, move, user, target, ai, battle| if move.statusMove? - next 0 if !target.battler.pbCanLowerStatStage?(:EVASION, user.battler) score += target.stages[:EVASION] * 10 elsif target.stages[:EVASION] > 0 score += 20 @@ -1185,10 +1358,11 @@ Battle::AI::Handlers::MoveEffectScore.add("LowerTargetEvasion1RemoveSideEffects" } ) +Battle::AI::Handlers::MoveFailureCheck.copy("LowerTargetEvasion1", + "LowerTargetEvasion2") Battle::AI::Handlers::MoveEffectScore.add("LowerTargetEvasion2", proc { |score, move, user, target, ai, battle| if move.statusMove? - return 0 if !target.battler.pbCanLowerStatStage?(:EVASION, user.battler) score += target.stages[:EVASION] * 10 elsif target.stages[:EVASION] > 0 score += 20 @@ -1197,9 +1371,22 @@ Battle::AI::Handlers::MoveEffectScore.add("LowerTargetEvasion2", } ) +Battle::AI::Handlers::MoveFailureCheck.copy("LowerTargetEvasion2", + "LowerTargetEvasion3") Battle::AI::Handlers::MoveEffectScore.copy("LowerTargetEvasion2", "LowerTargetEvasion3") +Battle::AI::Handlers::MoveFailureCheck.add("LowerTargetAtkDef1", + proc { |move, user, target, ai, battle| + will_fail = true + (move.move.statDown.length / 2).times do |i| + next if !target.battler.pbCanLowerStatStage?(move.move.statDown[i * 2], user.battler, move.move) + will_fail = false + break + end + next will_fail + } +) Battle::AI::Handlers::MoveEffectScore.add("LowerTargetAtkDef1", proc { |score, move, user, target, ai, battle| avg = target.stages[:ATTACK] * 10 @@ -1208,6 +1395,8 @@ Battle::AI::Handlers::MoveEffectScore.add("LowerTargetAtkDef1", } ) +Battle::AI::Handlers::MoveFailureCheck.copy("LowerTargetAtkDef1", + "LowerTargetAtkSpAtk1") Battle::AI::Handlers::MoveEffectScore.add("LowerTargetAtkSpAtk1", proc { |score, move, user, target, ai, battle| avg = target.stages[:ATTACK] * 10 @@ -1216,36 +1405,43 @@ Battle::AI::Handlers::MoveEffectScore.add("LowerTargetAtkSpAtk1", } ) +Battle::AI::Handlers::MoveFailureCheck.add("LowerPoisonedTargetAtkSpAtkSpd1", + proc { |move, user, target, ai, battle| + next true if !target.battler.poisoned? + next true if !target.battler.pbCanLowerStatStage?(:ATTACK, user.battler, move.move) && + !target.battler.pbCanLowerStatStage?(:SPECIAL_ATTACK, user.battler, move.move) && + !target.battler.pbCanLowerStatStage?(:SPEED, user.battler, move.move) + } +) Battle::AI::Handlers::MoveEffectScore.add("LowerPoisonedTargetAtkSpAtkSpd1", proc { |score, move, user, target, ai, battle| - count = 0 - battle.allBattlers.each do |b| - if b.poisoned? && - (!b.statStageAtMin?(:ATTACK) || - !b.statStageAtMin?(:SPECIAL_ATTACK) || - !b.statStageAtMin?(:SPEED)) - count += 1 - if user.battler.opposes?(b) - score += user.stages[:ATTACK] * 10 - score += user.stages[:SPECIAL_ATTACK] * 10 - score += user.stages[:SPEED] * 10 - else - score -= 20 - end - end + if target.opposes?(user) + score += target.stages[:ATTACK] * 10 + score += target.stages[:SPECIAL_ATTACK] * 10 + score += target.stages[:SPEED] * 10 + else + score -= 20 end - next 0 if count == 0 next score } ) -Battle::AI::Handlers::MoveEffectScore.add("RaiseUserAndAlliesAtkDef1", +Battle::AI::Handlers::MoveFailureCheck.add("RaiseAlliesAtkDef1", + proc { |move, user, target, ai, battle| + will_fail = true + battle.allSameSideBattlers(user.battler).each do |b| + next if b.index == user.index + next if !b.pbCanRaiseStatStage?(:ATTACK, user.battler, move.move) && + !b.pbCanRaiseStatStage?(:DEFENSE, user.battler, move.move) + will_fail = false + break + end + next will_fail + } +) +Battle::AI::Handlers::MoveEffectScore.add("RaiseAlliesAtkDef1", proc { |score, move, user, target, ai, battle| - has_ally = false user.battler.allAllies.each do |b| - next if !b.pbCanLowerStatStage?(:ATTACK, user.battler) && - !b.pbCanLowerStatStage?(:SPECIAL_ATTACK, user.battler) - has_ally = true if b.hasActiveAbility?(:CONTRARY) score -= 90 else @@ -1254,53 +1450,78 @@ Battle::AI::Handlers::MoveEffectScore.add("RaiseUserAndAlliesAtkDef1", score -= b.stages[:SPECIAL_ATTACK] * 20 end end - next 0 if !has_ally next score } ) +Battle::AI::Handlers::MoveFailureCheck.add("RaisePlusMinusUserAndAlliesAtkSpAtk1", + proc { |move, user, target, ai, battle| + will_fail = true + battle.allSameSideBattlers(user.battler).each do |b| + next if !b.hasActiveAbility?([:MINUS, :PLUS]) + next if !b.pbCanRaiseStatStage?(:ATTACK, user.battler, move.move) && + !b.pbCanRaiseStatStage?(:SPECIAL_ATTACK, user.battler, move.move) + will_fail = false + break + end + next will_fail + } +) Battle::AI::Handlers::MoveEffectScore.add("RaisePlusMinusUserAndAlliesAtkSpAtk1", proc { |score, move, user, target, ai, battle| - hasEffect = user.statStageAtMax?(:ATTACK) && - user.statStageAtMax?(:SPECIAL_ATTACK) user.battler.allAllies.each do |b| next if b.statStageAtMax?(:ATTACK) && b.statStageAtMax?(:SPECIAL_ATTACK) - hasEffect = true score -= b.stages[:ATTACK] * 10 score -= b.stages[:SPECIAL_ATTACK] * 10 end - next 0 if !hasEffect score -= user.stages[:ATTACK] * 10 score -= user.stages[:SPECIAL_ATTACK] * 10 next score } ) +Battle::AI::Handlers::MoveFailureCheck.add("RaisePlusMinusUserAndAlliesAtkSpAtk1", + proc { |move, user, target, ai, battle| + will_fail = true + battle.allSameSideBattlers(user.battler).each do |b| + next if !b.hasActiveAbility?([:MINUS, :PLUS]) + next if !b.pbCanRaiseStatStage?(:DEFENSE, user.battler, move.move) && + !b.pbCanRaiseStatStage?(:SPECIAL_DEFENSE, user.battler, move.move) + will_fail = false + break + end + next will_fail + } +) Battle::AI::Handlers::MoveEffectScore.add("RaisePlusMinusUserAndAlliesDefSpDef1", proc { |score, move, user, target, ai, battle| - hasEffect = user.statStageAtMax?(:DEFENSE) && - user.statStageAtMax?(:SPECIAL_DEFENSE) user.battler.allAllies.each do |b| next if b.statStageAtMax?(:DEFENSE) && b.statStageAtMax?(:SPECIAL_DEFENSE) - hasEffect = true score -= b.stages[:DEFENSE] * 10 score -= b.stages[:SPECIAL_DEFENSE] * 10 end - next 0 if !hasEffect score -= user.stages[:DEFENSE] * 10 score -= user.stages[:SPECIAL_DEFENSE] * 10 next score } ) +Battle::AI::Handlers::MoveFailureCheck.add("RaiseGroundedGrassBattlersAtkSpAtk1", + proc { |move, user, target, ai, battle| + will_fail = true + battle.allBattlers.each do |b| + next if !b.pbHasType?(:GRASS) || b.airborne? || b.semiInvulnerable? + next if !b.pbCanRaiseStatStage?(:ATTACK, user.battler, move.move) && + !b.pbCanRaiseStatStage?(:SPECIAL_ATTACK, user.battler, move.move) + will_fail = false + break + end + next will_fail + } +) Battle::AI::Handlers::MoveEffectScore.add("RaiseGroundedGrassBattlersAtkSpAtk1", proc { |score, move, user, target, ai, battle| - count = 0 battle.allBattlers.each do |b| - next if !b.pbHasType?(:GRASS) - next if b.airborne? - next if b.statStageAtMax?(:ATTACK) && b.statStageAtMax?(:SPECIAL_ATTACK) - count += 1 if user.battler.opposes?(b) score -= 20 else @@ -1308,25 +1529,31 @@ Battle::AI::Handlers::MoveEffectScore.add("RaiseGroundedGrassBattlersAtkSpAtk1", score -= user.stages[:SPECIAL_ATTACK] * 10 end end - next 0 if count == 0 next score } ) +Battle::AI::Handlers::MoveFailureCheck.add("RaiseGrassBattlersDef1", + proc { |move, user, target, ai, battle| + will_fail = true + battle.allBattlers.each do |b| + next if !b.pbHasType?(:GRASS) || b.semiInvulnerable? + next if !b.pbCanRaiseStatStage?(:DEFENSE, user.battler, move.move) + will_fail = false + break + end + next will_fail + } +) Battle::AI::Handlers::MoveEffectScore.add("RaiseGrassBattlersDef1", proc { |score, move, user, target, ai, battle| - count = 0 battle.allBattlers.each do |b| - if b.pbHasType?(:GRASS) && !b.statStageAtMax?(:DEFENSE) - count += 1 - if user.battler.opposes?(b) - score -= 20 - else - score -= user.stages[:DEFENSE] * 10 - end + if user.battler.opposes?(b) + score -= 20 + else + score -= user.stages[:DEFENSE] * 10 end end - next 0 if count == 0 next score } ) @@ -1417,6 +1644,11 @@ Battle::AI::Handlers::MoveEffectScore.add("UserStealTargetPositiveStatStages", } ) +Battle::AI::Handlers::MoveFailureCheck.add("InvertTargetStatStages", + proc { |move, user, target, ai, battle| + next true if !target.battler.hasAlteredStatStages? + } +) Battle::AI::Handlers::MoveEffectScore.add("InvertTargetStatStages", proc { |score, move, user, target, ai, battle| next 0 if target.effects[PBEffects::Substitute] > 0 @@ -1426,7 +1658,6 @@ Battle::AI::Handlers::MoveEffectScore.add("InvertTargetStatStages", numpos += target.stages[s.id] if target.stages[s.id] > 0 numneg += target.stages[s.id] if target.stages[s.id] < 0 end - next 0 if numpos == 0 && numneg == 0 next score + (numpos - numneg) * 10 } ) @@ -1446,6 +1677,11 @@ Battle::AI::Handlers::MoveEffectScore.add("ResetTargetStatStages", } ) +Battle::AI::Handlers::MoveFailureCheck.add("ResetAllBattlersStatStages", + proc { |move, user, target, ai, battle| + next true if battle.allBattlers.none? { |b| b.hasAlteredStatStages? } + } +) Battle::AI::Handlers::MoveEffectScore.add("ResetAllBattlersStatStages", proc { |score, move, user, target, ai, battle| if ai.trainer.medium_skill? @@ -1464,9 +1700,9 @@ Battle::AI::Handlers::MoveEffectScore.add("ResetAllBattlersStatStages", } ) -Battle::AI::Handlers::MoveEffectScore.add("StartUserSideImmunityToStatStageLowering", - proc { |score, move, user, target, ai, battle| - next score - 80 if user.pbOwnSide.effects[PBEffects::Mist] > 0 +Battle::AI::Handlers::MoveFailureCheck.add("StartUserSideImmunityToStatStageLowering", + proc { |move, user, target, ai, battle| + next true if user.pbOwnSide.effects[PBEffects::Mist] > 0 } ) @@ -1558,9 +1794,9 @@ Battle::AI::Handlers::MoveEffectScore.add("UserTargetAverageHP", } ) -Battle::AI::Handlers::MoveEffectScore.add("StartUserSideDoubleSpeed", - proc { |score, move, user, target, ai, battle| - next score - 90 if user.pbOwnSide.effects[PBEffects::Tailwind] > 0 +Battle::AI::Handlers::MoveFailureCheck.add("StartUserSideDoubleSpeed", + proc { |move, user, target, ai, battle| + next true if user.pbOwnSide.effects[PBEffects::Tailwind] > 0 } ) diff --git a/Data/Scripts/011_Battle/005_AI/053_AI_MoveHandlers_BattlerOther.rb b/Data/Scripts/011_Battle/005_AI/053_AI_MoveHandlers_BattlerOther.rb index 318b7f8a8..55b23a1ce 100644 --- a/Data/Scripts/011_Battle/005_AI/053_AI_MoveHandlers_BattlerOther.rb +++ b/Data/Scripts/011_Battle/005_AI/053_AI_MoveHandlers_BattlerOther.rb @@ -1,35 +1,48 @@ #=============================================================================== # #=============================================================================== +Battle::AI::Handlers::MoveFailureCheck.add("SleepTarget", + proc { |move, user, target, ai, battle| + next true if move.statusMove? && !target.pbCanSleep?(user.battler, false, move.move) + } +) Battle::AI::Handlers::MoveEffectScore.add("SleepTarget", proc { |score, move, user, target, ai, battle| - if target.battler.pbCanSleep?(user.battler, false) - score += 30 - if ai.trainer.medium_skill? - score -= 30 if target.effects[PBEffects::Yawn] > 0 + score += 30 + if ai.trainer.medium_skill? + score -= 30 if target.effects[PBEffects::Yawn] > 0 + end + score -= 30 if target.has_active_ability?(:MARVELSCALE) + if ai.trainer.best_skill? + if target.battler.pbHasMoveFunction?("FlinchTargetFailsIfUserNotAsleep", + "UseRandomUserMoveIfAsleep") # Snore, Sleep Talk + score -= 50 end - score -= 30 if target.has_active_ability?(:MARVELSCALE) - if ai.trainer.best_skill? - if target.battler.pbHasMoveFunction?("FlinchTargetFailsIfUserNotAsleep", - "UseRandomUserMoveIfAsleep") # Snore, Sleep Talk - score -= 50 - end - end - else - next 0 if move.statusMove? end next score } ) +Battle::AI::Handlers::MoveFailureCheck.add("SleepTargetIfUserDarkrai", + proc { |move, user, target, ai, battle| + next true if !user.battler.isSpecies?(:DARKRAI) && user.effects[PBEffects::TransformSpecies] != :DARKRAI + next true if move.statusMove? && !target.pbCanSleep?(user.battler, false, move.move) + } +) +Battle::AI::Handlers::MoveEffectScore.copy("SleepTarget", + "SleepTargetIfUserDarkrai") + Battle::AI::Handlers::MoveEffectScore.copy("SleepTarget", - "SleepTargetIfUserDarkrai", "SleepTargetChangeUserMeloettaForm") +Battle::AI::Handlers::MoveFailureCheck.add("SleepTargetNextTurn", + proc { |move, user, target, ai, battle| + next true if target.effects[PBEffects::Yawn] > 0 + next true if !target.pbCanSleep?(user.battler, false, move.move) + } +) Battle::AI::Handlers::MoveEffectScore.add("SleepTargetNextTurn", proc { |score, move, user, target, ai, battle| - next 0 if target.effects[PBEffects::Yawn] > 0 || - !target.battler.pbCanSleep?(user.battler, false) score += 30 score -= 30 if target.has_active_ability?(:MARVELSCALE) if ai.trainer.best_skill? @@ -42,31 +55,36 @@ Battle::AI::Handlers::MoveEffectScore.add("SleepTargetNextTurn", } ) +Battle::AI::Handlers::MoveFailureCheck.add("PoisonTarget", + proc { |move, user, target, ai, battle| + next true if move.statusMove? && !target.pbCanPoison?(user.battler, false, move.move) + } +) Battle::AI::Handlers::MoveEffectScore.add("PoisonTarget", proc { |score, move, user, target, ai, battle| - if target.battler.pbCanPoison?(user.battler, false) - score += 30 - if ai.trainer.medium_skill? - score += 30 if target.hp <= target.totalhp / 4 - score += 50 if target.hp <= target.totalhp / 8 - score -= 40 if target.effects[PBEffects::Yawn] > 0 - end - if ai.trainer.high_skill? - score += 10 if target.rough_stat(:DEFENSE) > 100 - score += 10 if target.rough_stat(:SPECIAL_DEFENSE) > 100 - end - score -= 40 if target.has_active_ability?([:GUTS, :MARVELSCALE, :TOXICBOOST]) - else - next 0 if move.statusMove? + score += 30 + if ai.trainer.medium_skill? + score += 30 if target.hp <= target.totalhp / 4 + score += 50 if target.hp <= target.totalhp / 8 + score -= 40 if target.effects[PBEffects::Yawn] > 0 end + if ai.trainer.high_skill? + score += 10 if target.rough_stat(:DEFENSE) > 100 + score += 10 if target.rough_stat(:SPECIAL_DEFENSE) > 100 + end + score -= 40 if target.has_active_ability?([:GUTS, :MARVELSCALE, :TOXICBOOST]) next score } ) +Battle::AI::Handlers::MoveFailureCheck.add("PoisonTargetLowerTargetSpeed1", + proc { |move, user, target, ai, battle| + next true if !target.pbCanPoison?(user.battler, false, move.move) && + !target.battler.pbCanLowerStatStage?(:SPEED, user.battler, move.move) + } +) Battle::AI::Handlers::MoveEffectScore.add("PoisonTargetLowerTargetSpeed1", proc { |score, move, user, target, ai, battle| - next 0 if !target.battler.pbCanPoison?(user.battler, false) && - !target.battler.pbCanLowerStatStage?(:SPEED, user.battler) if target.battler.pbCanPoison?(user.battler, false) score += 30 if ai.trainer.medium_skill? @@ -92,64 +110,70 @@ Battle::AI::Handlers::MoveEffectScore.add("PoisonTargetLowerTargetSpeed1", } ) +Battle::AI::Handlers::MoveFailureCheck.copy("PoisonTarget", + "BadPoisonTarget") Battle::AI::Handlers::MoveEffectScore.add("BadPoisonTarget", proc { |score, move, user, target, ai, battle| - if target.battler.pbCanPoison?(user.battler, false) - score += 30 - if ai.trainer.medium_skill? - score += 30 if target.hp <= target.totalhp / 4 - score += 50 if target.hp <= target.totalhp / 8 - score -= 40 if target.effects[PBEffects::Yawn] > 0 - end - if ai.trainer.high_skill? - score += 10 if target.rough_stat(:DEFENSE) > 100 - score += 10 if target.rough_stat(:SPECIAL_DEFENSE) > 100 - end - score -= 40 if target.has_active_ability?([:GUTS, :MARVELSCALE, :TOXICBOOST]) - else - score -= 90 if move.statusMove? + score += 30 + if ai.trainer.medium_skill? + score += 30 if target.hp <= target.totalhp / 4 + score += 50 if target.hp <= target.totalhp / 8 + score -= 40 if target.effects[PBEffects::Yawn] > 0 end + if ai.trainer.high_skill? + score += 10 if target.rough_stat(:DEFENSE) > 100 + score += 10 if target.rough_stat(:SPECIAL_DEFENSE) > 100 + end + score -= 40 if target.has_active_ability?([:GUTS, :MARVELSCALE, :TOXICBOOST]) next score } ) +Battle::AI::Handlers::MoveFailureCheck.add("ParalyzeTarget", + proc { |move, user, target, ai, battle| + next true if move.statusMove? && !target.pbCanParalyze?(user.battler, false, move.move) + } +) Battle::AI::Handlers::MoveEffectScore.add("ParalyzeTarget", proc { |score, move, user, target, ai, battle| - if target.battler.pbCanParalyze?(user.battler, false) && - !(ai.trainer.medium_skill? && - move.id == :THUNDERWAVE && - Effectiveness.ineffective?(target.effectiveness_of_type_against_battler(move.type, user))) - score += 30 - if ai.trainer.medium_skill? - aspeed = user.rough_stat(:SPEED) - ospeed = target.rough_stat(:SPEED) - if aspeed < ospeed - score += 30 - elsif aspeed > ospeed - score -= 40 - end + score += 30 + if ai.trainer.medium_skill? + aspeed = user.rough_stat(:SPEED) + ospeed = target.rough_stat(:SPEED) + if aspeed < ospeed + score += 30 + elsif aspeed > ospeed + score -= 40 end - score -= 40 if target.has_active_ability?([:GUTS, :MARVELSCALE, :QUICKFEET]) - else - score -= 90 if move.statusMove? end + score -= 40 if target.has_active_ability?([:GUTS, :MARVELSCALE, :QUICKFEET]) next score } ) +Battle::AI::Handlers::MoveFailureCheck.add("ParalyzeTargetIfNotTypeImmune", + proc { |move, user, target, ai, battle| + eff = target.effectiveness_of_type_against_battler(move.rough_type, user) + next true if Effectiveness.ineffective?(eff) + next true if move.statusMove? && !target.pbCanParalyze?(user.battler, false, move.move) + } +) +Battle::AI::Handlers::MoveEffectScore.copy("ParalyzeTarget", + "ParalyzeTargetIfNotTypeImmune") + Battle::AI::Handlers::MoveEffectScore.copy("ParalyzeTarget", - "ParalyzeTargetIfNotTypeImmune", "ParalyzeTargetAlwaysHitsInRainHitsTargetInSky", "ParalyzeFlinchTarget") +Battle::AI::Handlers::MoveFailureCheck.add("BurnTarget", + proc { |move, user, target, ai, battle| + next true if move.statusMove? && !target.pbCanBurn?(user.battler, false, move.move) + } +) Battle::AI::Handlers::MoveEffectScore.add("BurnTarget", proc { |score, move, user, target, ai, battle| - if target.battler.pbCanBurn?(user.battler, false) - score += 30 - score -= 40 if target.has_active_ability?([:GUTS, :MARVELSCALE, :QUICKFEET, :FLAREBOOST]) - else - score -= 90 if move.statusMove? - end + score += 30 + score -= 40 if target.has_active_ability?([:GUTS, :MARVELSCALE, :QUICKFEET, :FLAREBOOST]) next score } ) @@ -158,14 +182,15 @@ Battle::AI::Handlers::MoveEffectScore.copy("BurnTarget", "BurnTargetIfTargetStatsRaisedThisTurn", "BurnFlinchTarget") +Battle::AI::Handlers::MoveFailureCheck.add("FreezeTarget", + proc { |move, user, target, ai, battle| + next true if move.statusMove? && !target.pbCanFreeze?(user.battler, false, move.move) + } +) Battle::AI::Handlers::MoveEffectScore.add("FreezeTarget", proc { |score, move, user, target, ai, battle| - if target.battler.pbCanFreeze?(user.battler, false) - score += 30 - score -= 20 if target.has_active_ability?(:MARVELSCALE) - else - score -= 90 if move.statusMove? - end + score += 30 + score -= 20 if target.has_active_ability?(:MARVELSCALE) next score } ) @@ -201,13 +226,23 @@ Battle::AI::Handlers::MoveEffectScore.add("ParalyzeBurnOrFreezeTarget", } ) +Battle::AI::Handlers::MoveFailureCheck.add("GiveUserStatusToTarget", + proc { |move, user, target, ai, battle| + next true if user.status == :NONE + next true if !target.battler.pbCanInflictStatus?(user.status, user.battler, false, move.move) + } +) Battle::AI::Handlers::MoveEffectScore.add("GiveUserStatusToTarget", proc { |score, move, user, target, ai, battle| - next 0 if user.status == :NONE next score + 40 } ) +Battle::AI::Handlers::MoveFailureCheck.add("CureUserBurnPoisonParalysis", + proc { |move, user, target, ai, battle| + next true if ![:BURN, :POISON, :PARALYSIS].include?(user.status) + } +) Battle::AI::Handlers::MoveEffectScore.add("CureUserBurnPoisonParalysis", proc { |score, move, user, target, ai, battle| case user.status @@ -223,24 +258,27 @@ Battle::AI::Handlers::MoveEffectScore.add("CureUserBurnPoisonParalysis", end when :BURN, :PARALYSIS score += 40 - else - score -= 90 end next score } ) +Battle::AI::Handlers::MoveFailureCheck.add("CureUserPartyStatus", + proc { |move, user, target, ai, battle| + has_effect = battle.allSameSideBattlers(user.battler).any? { |b| b.status != :NONE } + if !has_effect + has_effect = battle.pbParty(user.index).any? { |pkmn| pkmn&.able? && pkmn.status != :NONE } + end + next !has_effect + } +) Battle::AI::Handlers::MoveEffectScore.add("CureUserPartyStatus", proc { |score, move, user, target, ai, battle| statuses = 0 battle.pbParty(user.index).each do |pkmn| statuses += 1 if pkmn && pkmn.status != :NONE end - if statuses == 0 - score -= 80 - else - score += 20 * statuses - end + score += 20 * statuses next score } ) @@ -256,11 +294,14 @@ Battle::AI::Handlers::MoveEffectScore.add("CureTargetBurn", } ) +Battle::AI::Handlers::MoveFailureCheck.add("StartUserSideImmunityToInflictedStatus", + proc { |move, user, target, ai, battle| + next true if user.pbOwnSide.effects[PBEffects::Safeguard] > 0 + } +) Battle::AI::Handlers::MoveEffectScore.add("StartUserSideImmunityToInflictedStatus", proc { |score, move, user, target, ai, battle| - if user.pbOwnSide.effects[PBEffects::Safeguard] > 0 - score -= 80 - elsif user.status != :NONE + if user.status != :NONE score -= 40 else score += 30 @@ -271,16 +312,18 @@ Battle::AI::Handlers::MoveEffectScore.add("StartUserSideImmunityToInflictedStatu Battle::AI::Handlers::MoveEffectScore.add("FlinchTarget", proc { |score, move, user, target, ai, battle| - score += 30 - score += 30 if !target.has_active_ability?(:INNERFOCUS) && - target.effects[PBEffects::Substitute] == 0 - next score + next score + 30 if !target.has_active_ability?(:INNERFOCUS) && + target.effects[PBEffects::Substitute] == 0 } ) +Battle::AI::Handlers::MoveFailureCheck.add("FlinchTargetFailsIfUserNotAsleep", + proc { |move, user, target, ai, battle| + next true if !user.asleep? + } +) Battle::AI::Handlers::MoveEffectScore.add("FlinchTargetFailsIfUserNotAsleep", proc { |score, move, user, target, ai, battle| - next 0 if !user.battler.asleep? score += 100 # Because it can only be used while asleep score += 30 if !target.has_active_ability?(:INNERFOCUS) && target.effects[PBEffects::Substitute] == 0 @@ -288,12 +331,15 @@ Battle::AI::Handlers::MoveEffectScore.add("FlinchTargetFailsIfUserNotAsleep", } ) +Battle::AI::Handlers::MoveFailureCheck.add("FlinchTargetFailsIfNotUserFirstTurn", + proc { |move, user, target, ai, battle| + next true if user.turnCount > 0 + } +) Battle::AI::Handlers::MoveEffectScore.add("FlinchTargetFailsIfNotUserFirstTurn", proc { |score, move, user, target, ai, battle| - next 0 if user.turnCount != 0 - score += 30 if !target.has_active_ability?(:INNERFOCUS) && - target.effects[PBEffects::Substitute] == 0 - next score + next score + 30 if !target.has_active_ability?(:INNERFOCUS) && + target.effects[PBEffects::Substitute] == 0 } ) @@ -301,7 +347,7 @@ Battle::AI::Handlers::MoveBasePower.add("FlinchTargetDoublePowerIfTargetInSky", proc { |power, move, user, target, ai, battle| next move.pbBaseDamage(power, user.battler, target.battler) } -} +) Battle::AI::Handlers::MoveEffectScore.add("FlinchTargetDoublePowerIfTargetInSky", proc { |score, move, user, target, ai, battle| score += 30 if !target.has_active_ability?(:INNERFOCUS) && @@ -310,9 +356,13 @@ Battle::AI::Handlers::MoveEffectScore.add("FlinchTargetDoublePowerIfTargetInSky" } ) +Battle::AI::Handlers::MoveFailureCheck.add("ConfuseTarget", + proc { |move, user, target, ai, battle| + next true if move.statusMove? && !target.battler.pbCanConfuse?(user.battler, false, move.move) + } +) Battle::AI::Handlers::MoveEffectScore.add("ConfuseTarget", proc { |score, move, user, target, ai, battle| - next 0 if !target.battler.pbCanConfuse?(user.battler, false) next score + 30 } ) @@ -320,22 +370,15 @@ Battle::AI::Handlers::MoveEffectScore.add("ConfuseTarget", Battle::AI::Handlers::MoveEffectScore.copy("ConfuseTarget", "ConfuseTargetAlwaysHitsInRainHitsTargetInSky") +Battle::AI::Handlers::MoveFailureCheck.add("AttractTarget", + proc { |move, user, target, ai, battle| + next true if move.statusMove? && !target.battler.pbCanAttract?(user.battler, false) + } +) Battle::AI::Handlers::MoveEffectScore.add("AttractTarget", proc { |score, move, user, target, ai, battle| - canattract = true - agender = user.gender - ogender = target.gender - if agender == 2 || ogender == 2 || agender == ogender - score -= 90 - canattract = false - elsif target.effects[PBEffects::Attract] >= 0 - score -= 80 - canattract = false - elsif target.has_active_ability?(:OBLIVIOUS) - score -= 80 - canattract = false - end - if canattract && target.has_active_item?(:DESTINYKNOT) && + score += 30 + if target.has_active_item?(:DESTINYKNOT) && user.battler.pbCanAttract?(target.battler, false) score -= 30 end @@ -343,66 +386,55 @@ Battle::AI::Handlers::MoveEffectScore.add("AttractTarget", } ) -Battle::AI::Handlers::MoveEffectScore.add("SetUserTypesBasedOnEnvironment", - proc { |score, move, user, target, ai, battle| - if !user.battler.canChangeType? - score -= 90 - elsif ai.trainer.medium_skill? - new_type = nil - case battle.field.terrain - when :Electric - new_type = :ELECTRIC if GameData::Type.exists?(:ELECTRIC) - when :Grassy - new_type = :GRASS if GameData::Type.exists?(:GRASS) - when :Misty - new_type = :FAIRY if GameData::Type.exists?(:FAIRY) - when :Psychic - new_type = :PSYCHIC if GameData::Type.exists?(:PSYCHIC) - end - if !new_type - envtypes = { - :None => :NORMAL, - :Grass => :GRASS, - :TallGrass => :GRASS, - :MovingWater => :WATER, - :StillWater => :WATER, - :Puddle => :WATER, - :Underwater => :WATER, - :Cave => :ROCK, - :Rock => :GROUND, - :Sand => :GROUND, - :Forest => :BUG, - :ForestGrass => :BUG, - :Snow => :ICE, - :Ice => :ICE, - :Volcano => :FIRE, - :Graveyard => :GHOST, - :Sky => :FLYING, - :Space => :DRAGON, - :UltraSpace => :PSYCHIC - } - new_type = envtypes[battle.environment] - new_type = nil if !GameData::Type.exists?(new_type) - new_type ||= :NORMAL - end - score -= 90 if !user.battler.pbHasOtherType?(new_type) +Battle::AI::Handlers::MoveFailureCheck.add("SetUserTypesBasedOnEnvironment", + proc { |move, user, target, ai, battle| + next true if !user.battler.canChangeType? + new_type = nil + case battle.field.terrain + when :Electric + new_type = :ELECTRIC if GameData::Type.exists?(:ELECTRIC) + when :Grassy + new_type = :GRASS if GameData::Type.exists?(:GRASS) + when :Misty + new_type = :FAIRY if GameData::Type.exists?(:FAIRY) + when :Psychic + new_type = :PSYCHIC if GameData::Type.exists?(:PSYCHIC) end - next score + if !new_type + envtypes = { + :None => :NORMAL, + :Grass => :GRASS, + :TallGrass => :GRASS, + :MovingWater => :WATER, + :StillWater => :WATER, + :Puddle => :WATER, + :Underwater => :WATER, + :Cave => :ROCK, + :Rock => :GROUND, + :Sand => :GROUND, + :Forest => :BUG, + :ForestGrass => :BUG, + :Snow => :ICE, + :Ice => :ICE, + :Volcano => :FIRE, + :Graveyard => :GHOST, + :Sky => :FLYING, + :Space => :DRAGON, + :UltraSpace => :PSYCHIC + } + new_type = envtypes[battle.environment] + new_type = nil if !GameData::Type.exists?(new_type) + new_type ||= :NORMAL + end + next true if !user.battler.pbHasOtherType?(new_type) } ) -Battle::AI::Handlers::MoveEffectScore.add("SetUserTypesToResistLastAttack", - proc { |score, move, user, target, ai, battle| - next 0 if !user.battler.canChangeType? - next 0 if !target.battler.lastMoveUsed || !target.battler.lastMoveUsedType || - GameData::Type.get(target.battler.lastMoveUsedType).pseudo_type - aType = nil - target.battler.eachMove do |m| - next if m.id != target.battler.lastMoveUsed - aType = m.pbCalcType(user.battler) - break - end - next 0 if !aType +Battle::AI::Handlers::MoveFailureCheck.add("SetUserTypesToResistLastAttack", + proc { |move, user, target, ai, battle| + next true if !user.battler.canChangeType? + next true if !target.battler.lastMoveUsed || !target.battler.lastMoveUsedType || + GameData::Type.get(target.battler.lastMoveUsedType).pseudo_type has_possible_type = false GameData::Type.each do |t| next if t.pseudo_type || user.has_type?(t.id) || @@ -410,21 +442,22 @@ Battle::AI::Handlers::MoveEffectScore.add("SetUserTypesToResistLastAttack", has_possible_type = true break end - next 0 if !has_possible_type + next !has_possible_type } ) -Battle::AI::Handlers::MoveEffectScore.add("SetUserTypesToTargetTypes", - proc { |score, move, user, target, ai, battle| - next 0 if !user.battler.canChangeType? || target.battler.pbTypes(true).length == 0 - next 0 if user.battler.pbTypes == target.battler.pbTypes && - user.effects[PBEffects::Type3] == target.effects[PBEffects::Type3] +Battle::AI::Handlers::MoveFailureCheck.add("SetUserTypesToTargetTypes", + proc { |move, user, target, ai, battle| + next true if !user.battler.canChangeType? + next true if target.battler.pbTypes(true).empty? + next true if user.battler.pbTypes == target.battler.pbTypes && + user.effects[PBEffects::Type3] == target.effects[PBEffects::Type3] } ) -Battle::AI::Handlers::MoveEffectScore.add("SetUserTypesToUserMoveType", - proc { |score, move, user, target, ai, battle| - next 0 if !user.battler.canChangeType? +Battle::AI::Handlers::MoveFailureCheck.add("SetUserTypesToUserMoveType", + proc { |move, user, target, ai, battle| + next true if !user.battler.canChangeType? has_possible_type = false user.battler.eachMoveWithIndex do |m, i| break if Settings::MECHANICS_GENERATION >= 6 && i > 0 @@ -433,147 +466,121 @@ Battle::AI::Handlers::MoveEffectScore.add("SetUserTypesToUserMoveType", has_possible_type = true break end - next 0 if !has_possible_type + next !has_possible_type } ) -Battle::AI::Handlers::MoveEffectScore.add("SetTargetTypesToPsychic", - proc { |score, move, user, target, ai, battle| - if !target.battler.canChangeType? - score -= 90 - elsif !target.battler.pbHasOtherType?(:PSYCHIC) - score -= 90 - end - next score +Battle::AI::Handlers::MoveFailureCheck.add("SetTargetTypesToPsychic", + proc { |move, user, target, ai, battle| + next true if !target.battler.canChangeType? + next true if !GameData::Type.exists?(:PSYCHIC) || !target.battler.pbHasOtherType?(:PSYCHIC) + next true if !target.battler.affectedByPowder? } ) -Battle::AI::Handlers::MoveEffectScore.add("SetTargetTypesToWater", - proc { |score, move, user, target, ai, battle| - if !target.battler.canChangeType? || target.effects[PBEffects::Substitute] > 0 - score -= 90 - elsif !target.battler.pbHasOtherType?(:WATER) - score -= 90 - end - next score +Battle::AI::Handlers::MoveFailureCheck.add("SetTargetTypesToWater", + proc { |move, user, target, ai, battle| + next true if !target.battler.canChangeType? + next true if !GameData::Type.exists?(:WATER) || !target.battler.pbHasOtherType?(:WATER) } ) -Battle::AI::Handlers::MoveEffectScore.add("AddGhostTypeToTarget", - proc { |score, move, user, target, ai, battle| - next 0 if target.has_type?(:GHOST) +Battle::AI::Handlers::MoveFailureCheck.add("AddGhostTypeToTarget", + proc { |move, user, target, ai, battle| + next true if !target.battler.canChangeType? + next true if !GameData::Type.exists?(:GHOST) || target.has_type?(:GHOST) } ) -Battle::AI::Handlers::MoveEffectScore.add("AddGrassTypeToTarget", - proc { |score, move, user, target, ai, battle| - next 0 if target.has_type?(:GRASS) +Battle::AI::Handlers::MoveFailureCheck.add("AddGrassTypeToTarget", + proc { |move, user, target, ai, battle| + next true if !target.battler.canChangeType? + next true if !GameData::Type.exists?(:GRASS) || target.has_type?(:GRASS) } ) -Battle::AI::Handlers::MoveEffectScore.add("UserLosesFireType", - proc { |score, move, user, target, ai, battle| - next 0 if !user.has_type?(:FIRE) +Battle::AI::Handlers::MoveFailureCheck.add("UserLosesFireType", + proc { |move, user, target, ai, battle| + next true if !user.has_type?(:FIRE) } ) -Battle::AI::Handlers::MoveEffectScore.add("SetTargetAbilityToSimple", - proc { |score, move, user, target, ai, battle| - next 0 if target.effects[PBEffects::Substitute] > 0 - if ai.trainer.medium_skill? - next 0 if target.battler.unstoppableAbility? || - [:TRUANT, :SIMPLE].include?(target.ability) - end +Battle::AI::Handlers::MoveFailureCheck.add("SetTargetAbilityToSimple", + proc { |move, user, target, ai, battle| + next true if !GameData::Ability.exists?(:SIMPLE) + next true if target.battler.unstoppableAbility? || + [:TRUANT, :SIMPLE].include?(target.ability_id) } ) -Battle::AI::Handlers::MoveEffectScore.add("SetTargetAbilityToInsomnia", - proc { |score, move, user, target, ai, battle| - next 0 if target.effects[PBEffects::Substitute] > 0 - if ai.trainer.medium_skill? - next 0 if target.battler.unstoppableAbility? || - [:TRUANT, :INSOMNIA].include?(target.ability) - end +Battle::AI::Handlers::MoveFailureCheck.add("SetTargetAbilityToInsomnia", + proc { |move, user, target, ai, battle| + next true if !GameData::Ability.exists?(:INSOMNIA) + next true if target.battler.unstoppableAbility? || + [:TRUANT, :INSOMNIA].include?(target.ability_id) } ) +Battle::AI::Handlers::MoveFailureCheck.add("SetUserAbilityToTargetAbility", + proc { |move, user, target, ai, battle| + next true if user.battle.unstoppableAbility? + next true if !target.ability || user.ability_id == target.ability_id + next true if target.battler.ungainableAbility? || + [:POWEROFALCHEMY, :RECEIVER, :TRACE, :WONDERGUARD].include?(target.ability_id) + } +) Battle::AI::Handlers::MoveEffectScore.add("SetUserAbilityToTargetAbility", proc { |score, move, user, target, ai, battle| score -= 40 # don't prefer this move - if ai.trainer.medium_skill? - if !target.ability || user.ability == target.ability || - [:MULTITYPE, :RKSSYSTEM].include?(user.ability_id) || - [:FLOWERGIFT, :FORECAST, :ILLUSION, :IMPOSTER, :MULTITYPE, :RKSSYSTEM, - :TRACE, :WONDERGUARD, :ZENMODE].include?(target.ability_id) - score -= 90 - end - end - if ai.trainer.high_skill? - if target.ability == :TRUANT && user.opposes?(target) - score -= 90 - elsif target.ability == :SLOWSTART && user.opposes?(target) - score -= 90 - end + if ai.trainer.medium_skill? && user.opposes?(target) + score -= 50 if [:TRUANT, :SLOWSTART].include?(target.ability_id) end next score } ) +Battle::AI::Handlers::MoveFailureCheck.add("SetTargetAbilityToUserAbility", + proc { |move, user, target, ai, battle| + next true if !user.ability || user.ability_id == target.ability_id + next true if user.battler.ungainableAbility? || + [:POWEROFALCHEMY, :RECEIVER, :TRACE].include?(user.ability_id) + next true if target.battle.unstoppableAbility? || target.ability_id == :TRUANT + } +) Battle::AI::Handlers::MoveEffectScore.add("SetTargetAbilityToUserAbility", proc { |score, move, user, target, ai, battle| score -= 40 # don't prefer this move - if target.effects[PBEffects::Substitute] > 0 - score -= 90 - elsif ai.trainer.medium_skill? - if !user.ability || user.ability == target.ability || - [:MULTITYPE, :RKSSYSTEM, :TRUANT].include?(target.ability_id) || - [:FLOWERGIFT, :FORECAST, :ILLUSION, :IMPOSTER, :MULTITYPE, :RKSSYSTEM, - :TRACE, :ZENMODE].include?(user.ability_id) - score -= 90 - end - if ai.trainer.high_skill? - if user.ability == :TRUANT && user.opposes?(target) - score += 90 - elsif user.ability == :SLOWSTART && user.opposes?(target) - score += 90 - end - end + if ai.trainer.medium_skill? && user.opposes?(target) + score += 90 if [:TRUANT, :SLOWSTART].include?(user.ability_id) end next score } ) +Battle::AI::Handlers::MoveFailureCheck.add("UserTargetSwapAbilities", + proc { |move, user, target, ai, battle| + next true if !user.ability || !target.ability + next true if Settings::MECHANICS_GENERATION <= 5 && user.ability_id == target.ability_id + next true if user.battle.unstoppableAbility? || user.battler.ungainableAbility? || + user.ability_id == :WONDERGUARD + next true if target.battle.unstoppableAbility? || target.battler.ungainableAbility? || + target.ability_id == :WONDERGUARD + } +) Battle::AI::Handlers::MoveEffectScore.add("UserTargetSwapAbilities", proc { |score, move, user, target, ai, battle| score -= 40 # don't prefer this move - if ai.trainer.medium_skill? - if (!user.ability && !target.ability) || - user.ability == target.ability || - [:ILLUSION, :MULTITYPE, :RKSSYSTEM, :WONDERGUARD].include?(user.ability_id) || - [:ILLUSION, :MULTITYPE, :RKSSYSTEM, :WONDERGUARD].include?(target.ability_id) - score -= 90 - end - end - if ai.trainer.high_skill? - if target.ability == :TRUANT && user.opposes?(target) - score -= 90 - elsif target.ability == :SLOWSTART && user.opposes?(target) - score -= 90 - end + if ai.trainer.high_skill? && user.opposes?(target) + score -= 90 if [:TRUANT, :SLOWSTART].include?(target.ability_id) end next score } ) -Battle::AI::Handlers::MoveEffectScore.add("NegateTargetAbility", - proc { |score, move, user, target, ai, battle| - if target.effects[PBEffects::Substitute] > 0 || - target.effects[PBEffects::GastroAcid] - score -= 90 - elsif ai.trainer.high_skill? - score -= 90 if [:MULTITYPE, :RKSSYSTEM, :SLOWSTART, :TRUANT].include?(target.ability_id) - end - next score +Battle::AI::Handlers::MoveFailureCheck.add("NegateTargetAbility", + proc { |move, user, target, ai, battle| + next true if target.unstoppableAbility? || + target.effects[PBEffects::GastroAcid] } ) @@ -590,25 +597,24 @@ Battle::AI::Handlers::MoveEffectScore.add("NegateTargetAbilityIfTargetActed", # IgnoreTargetAbility -Battle::AI::Handlers::MoveEffectScore.add("StartUserAirborne", - proc { |score, move, user, target, ai, battle| - if user.effects[PBEffects::MagnetRise] > 0 || - user.effects[PBEffects::Ingrain] || - user.effects[PBEffects::SmackDown] - score -= 90 - end - next score +Battle::AI::Handlers::MoveFailureCheck.add("StartUserAirborne", + proc { |move, user, target, ai, battle| + next true if user.effects[PBEffects::Ingrain] || + user.effects[PBEffects::SmackDown] || + user.effects[PBEffects::MagnetRise] > 0 } ) -Battle::AI::Handlers::MoveEffectScore.add("StartTargetAirborneAndAlwaysHitByMoves", - proc { |score, move, user, target, ai, battle| - if target.effects[PBEffects::Telekinesis] > 0 || - target.effects[PBEffects::Ingrain] || - target.effects[PBEffects::SmackDown] - score -= 90 - end - next score +Battle::AI::Handlers::MoveFailureCheck.add("StartTargetAirborneAndAlwaysHitByMoves", + proc { |move, user, target, ai, battle| + next true if target.effects[PBEffects::Ingrain] || + target.effects[PBEffects::SmackDown] || + target.effects[PBEffects::Telekinesis] > 0 + next true if target.battler.isSpecies?(:DIGLETT) || + target.battler.isSpecies?(:DUGTRIO) || + target.battler.isSpecies?(:SANDYGAST) || + target.battler.isSpecies?(:PALOSSAND) || + (target.battler.isSpecies?(:GENGAR) && target.battler.mega?) } ) @@ -629,11 +635,14 @@ Battle::AI::Handlers::MoveEffectScore.add("HitsTargetInSkyGroundsTarget", } ) +Battle::AI::Handlers::MoveFailureCheck.add("StartGravity", + proc { |move, user, target, ai, battle| + next true if battle.field.effects[PBEffects::Gravity] > 0 + } +) Battle::AI::Handlers::MoveEffectScore.add("StartGravity", proc { |score, move, user, target, ai, battle| - if battle.field.effects[PBEffects::Gravity] > 0 - score -= 90 - elsif ai.trainer.medium_skill? + if ai.trainer.medium_skill? score -= 30 score -= 20 if user.effects[PBEffects::SkyDrop] >= 0 score -= 20 if user.effects[PBEffects::MagnetRise] > 0 @@ -655,8 +664,15 @@ Battle::AI::Handlers::MoveEffectScore.add("StartGravity", } ) -Battle::AI::Handlers::MoveEffectScore.add("TransformUserIntoTarget", - proc { |score, move, user, target, ai, battle| - next score - 70 +Battle::AI::Handlers::MoveFailureCheck.add("TransformUserIntoTarget", + proc { |move, user, target, ai, battle| + next true if user.effects[PBEffects::Transform] + next true if target.effects[PBEffects::Transform] || + target.effects[PBEffects::Illusion] + } +) +Battle::AI::Handlers::MoveEffectScore.add("TransformUserIntoTarget", + proc { |score, move, user, target, ai, battle| + next score - 40 } ) diff --git a/Data/Scripts/011_Battle/005_AI/054_AI_MoveHandlers_MoveAttributes.rb b/Data/Scripts/011_Battle/005_AI/054_AI_MoveHandlers_MoveAttributes.rb index e5ad53cc2..570070b4d 100644 --- a/Data/Scripts/011_Battle/005_AI/054_AI_MoveHandlers_MoveAttributes.rb +++ b/Data/Scripts/011_Battle/005_AI/054_AI_MoveHandlers_MoveAttributes.rb @@ -5,7 +5,7 @@ Battle::AI::Handlers::MoveBasePower.add("FixedDamage20", proc { |power, move, user, target, ai, battle| next move.pbFixedDamage(user.battler, target.battler) } -} +) Battle::AI::Handlers::MoveEffectScore.add("FixedDamage20", proc { |score, move, user, target, ai, battle| if target.hp <= 20 @@ -21,7 +21,7 @@ Battle::AI::Handlers::MoveBasePower.add("FixedDamage40", proc { |power, move, user, target, ai, battle| next move.pbFixedDamage(user.battler, target.battler) } -} +) Battle::AI::Handlers::MoveEffectScore.add("FixedDamage40", proc { |score, move, user, target, ai, battle| next score + 80 if target.hp <= 40 @@ -32,7 +32,7 @@ Battle::AI::Handlers::MoveBasePower.add("FixedDamageHalfTargetHP", proc { |power, move, user, target, ai, battle| next move.pbFixedDamage(user.battler, target.battler) } -} +) Battle::AI::Handlers::MoveEffectScore.add("FixedDamageHalfTargetHP", proc { |score, move, user, target, ai, battle| score -= 50 @@ -44,7 +44,7 @@ Battle::AI::Handlers::MoveBasePower.add("FixedDamageUserLevel", proc { |power, move, user, target, ai, battle| next move.pbFixedDamage(user.battler, target.battler) } -} +) Battle::AI::Handlers::MoveEffectScore.add("FixedDamageUserLevel", proc { |score, move, user, target, ai, battle| next score + 80 if target.hp <= user.level @@ -55,18 +55,23 @@ Battle::AI::Handlers::MoveBasePower.add("FixedDamageUserLevelRandom", proc { |power, move, user, target, ai, battle| next user.level # Average power } -} +) Battle::AI::Handlers::MoveEffectScore.add("FixedDamageUserLevelRandom", proc { |score, move, user, target, ai, battle| next score + 30 if target.hp <= user.level } ) +Battle::AI::Handlers::MoveFailureCheck.add("LowerTargetHPToUserHP", + proc { |move, user, target, ai, battle| + next true if user.hp >= target.hp + } +) Battle::AI::Handlers::MoveBasePower.add("LowerTargetHPToUserHP", proc { |power, move, user, target, ai, battle| next move.pbFixedDamage(user.battler, target.battler) } -} +) Battle::AI::Handlers::MoveEffectScore.add("LowerTargetHPToUserHP", proc { |score, move, user, target, ai, battle| if user.hp >= target.hp @@ -78,23 +83,33 @@ Battle::AI::Handlers::MoveEffectScore.add("LowerTargetHPToUserHP", } ) +Battle::AI::Handlers::MoveFailureCheck.add("OHKO", + proc { |move, user, target, ai, battle| + next true if target.level > user.level + next true if target.has_active_ability?(:STURDY) + } +) Battle::AI::Handlers::MoveBasePower.add("OHKO", proc { |power, move, user, target, ai, battle| next 999 } -} -Battle::AI::Handlers::MoveEffectScore.add("OHKO", - proc { |score, move, user, target, ai, battle| - next 0 if target.has_active_ability?(:STURDY) - next 0 if target.level > user.level - } ) +Battle::AI::Handlers::MoveFailureCheck.add("OHKOIce", + proc { |move, user, target, ai, battle| + next true if target.level > user.level + next true if target.has_active_ability?(:STURDY) + next true if target.has_type?(:ICE) + } +) +Battle::AI::Handlers::MoveBasePower.copy("OHKO", + "OHKOIce") +Battle::AI::Handlers::MoveEffectScore.copy("OHKO", + "OHKOIce") + Battle::AI::Handlers::MoveBasePower.copy("OHKO", - "OHKOIce", "OHKOHitsUndergroundTarget") Battle::AI::Handlers::MoveEffectScore.copy("OHKO", - "OHKOIce", "OHKOHitsUndergroundTarget") Battle::AI::Handlers::MoveEffectScore.add("DamageTargetAlly", @@ -111,7 +126,7 @@ Battle::AI::Handlers::MoveBasePower.add("PowerHigherWithUserHP", proc { |power, move, user, target, ai, battle| next move.pbBaseDamage(power, user.battler, target.battler) } -} +) Battle::AI::Handlers::MoveBasePower.copy("PowerHigherWithUserHP", "PowerLowerWithUserHP", @@ -130,13 +145,13 @@ Battle::AI::Handlers::MoveBasePower.add("PowerHigherWithLessPP", ppLeft = [move.pp - 1, dmgs.length - 1].min next dmgs[ppLeft] } -} +) Battle::AI::Handlers::MoveBasePower.add("PowerHigherWithTargetWeight", proc { |power, move, user, target, ai, battle| next move.pbBaseDamage(power, user.battler, target.battler) } -} +) Battle::AI::Handlers::MoveBasePower.copy("PowerHigherWithTargetWeight", "PowerHigherWithUserHeavierThanTarget") @@ -145,26 +160,26 @@ Battle::AI::Handlers::MoveBasePower.add("PowerHigherWithConsecutiveUse", proc { |power, move, user, target, ai, battle| next power << user.effects[PBEffects::FuryCutter] } -} +) Battle::AI::Handlers::MoveBasePower.add("PowerHigherWithConsecutiveUseOnUserSide", proc { |power, move, user, target, ai, battle| next power * (user.pbOwnSide.effects[PBEffects::EchoedVoiceCounter] + 1) } -} +) Battle::AI::Handlers::MoveBasePower.add("RandomPowerDoublePowerIfTargetUnderground", proc { |power, move, user, target, ai, battle| power = 71 # Average damage next move.pbModifyDamage(power, user.battler, target.battler) } -} +) Battle::AI::Handlers::MoveBasePower.add("DoublePowerIfTargetHPLessThanHalf", proc { |power, move, user, target, ai, battle| next move.pbBaseDamage(power, user.battler, target.battler) } -} +) Battle::AI::Handlers::MoveBasePower.copy("DoublePowerIfTargetHPLessThanHalf", "DoublePowerIfUserPoisonedBurnedParalyzed") @@ -182,7 +197,7 @@ Battle::AI::Handlers::MoveBasePower.add("DoublePowerIfTargetPoisoned", proc { |power, move, user, target, ai, battle| next move.pbBaseDamage(power, user.battler, target.battler) } -} +) Battle::AI::Handlers::MoveBasePower.copy("DoublePowerIfTargetPoisoned", "DoublePowerIfTargetParalyzedCureTarget") @@ -196,19 +211,19 @@ Battle::AI::Handlers::MoveBasePower.add("DoublePowerIfTargetStatusProblem", proc { |power, move, user, target, ai, battle| next move.pbBaseDamage(power, user.battler, target.battler) } -} +) Battle::AI::Handlers::MoveBasePower.add("DoublePowerIfUserHasNoItem", proc { |power, move, user, target, ai, battle| next power * 2 if !user.item || user.has_active_item?(:FLYINGGEM) } -} +) Battle::AI::Handlers::MoveBasePower.add("DoublePowerIfTargetUnderwater", proc { |power, move, user, target, ai, battle| next move.pbModifyDamage(power, user.battler, target.battler) } -} +) Battle::AI::Handlers::MoveBasePower.copy("DoublePowerIfTargetUnderwater", "DoublePowerIfTargetUnderground") @@ -217,7 +232,7 @@ Battle::AI::Handlers::MoveBasePower.add("DoublePowerIfTargetInSky", proc { |power, move, user, target, ai, battle| next move.pbBaseDamage(power, user.battler, target.battler) } -} +) Battle::AI::Handlers::MoveBasePower.copy("DoublePowerIfTargetInSky", "DoublePowerInElectricTerrain", @@ -265,6 +280,17 @@ Battle::AI::Handlers::MoveEffectScore.add("EnsureNextCriticalHit", } ) +Battle::AI::Handlers::MoveFailureCheck.add("StartPreventCriticalHitsAgainstUserSide", + proc { |move, user, target, ai, battle| + next true if user.pbOwnSide.effects[PBEffects::LuckyChant] > 0 + } +) + +Battle::AI::Handlers::MoveFailureCheck.add("CannotMakeTargetFaint", + proc { |move, user, target, ai, battle| + next true if target.hp == 1 + } +) Battle::AI::Handlers::MoveEffectScore.add("CannotMakeTargetFaint", proc { |score, move, user, target, ai, battle| next 0 if target.hp == 1 @@ -281,8 +307,8 @@ Battle::AI::Handlers::MoveEffectScore.add("UserEnduresFaintingThisTurn", proc { |score, move, user, target, ai, battle| score -= 25 if user.hp > user.totalhp / 2 if ai.trainer.medium_skill? - score -= 90 if user.effects[PBEffects::ProtectRate] > 1 - score -= 90 if target.effects[PBEffects::HyperBeam] > 0 + score -= 50 if user.effects[PBEffects::ProtectRate] > 1 + score -= 50 if target.effects[PBEffects::HyperBeam] > 0 else score -= user.effects[PBEffects::ProtectRate] * 40 end @@ -290,34 +316,56 @@ Battle::AI::Handlers::MoveEffectScore.add("UserEnduresFaintingThisTurn", } ) +Battle::AI::Handlers::MoveFailureCheck.add("StartWeakenElectricMoves", + proc { |move, user, target, ai, battle| + if Settings::MECHANICS_GENERATION >= 6 + next true if battle.field.effects[PBEffects::MudSportField] > 0 + else + next true if battle.allBattlers.any? { |b| b.effects[PBEffects::MudSport] } + end + } +) Battle::AI::Handlers::MoveEffectScore.add("StartWeakenElectricMoves", proc { |score, move, user, target, ai, battle| next 0 if user.effects[PBEffects::MudSport] } ) +Battle::AI::Handlers::MoveFailureCheck.add("StartWeakenFireMoves", + proc { |move, user, target, ai, battle| + if Settings::MECHANICS_GENERATION >= 6 + next true if battle.field.effects[PBEffects::WaterSportField] > 0 + else + next true if battle.allBattlers.any? { |b| b.effects[PBEffects::WaterSport] } + end + } +) Battle::AI::Handlers::MoveEffectScore.add("StartWeakenFireMoves", proc { |score, move, user, target, ai, battle| next 0 if user.effects[PBEffects::WaterSport] } ) -Battle::AI::Handlers::MoveEffectScore.add("StartWeakenPhysicalDamageAgainstUserSide", - proc { |score, move, user, target, ai, battle| - next 0 if user.pbOwnSide.effects[PBEffects::Reflect] > 0 +Battle::AI::Handlers::MoveFailureCheck.add("StartWeakenPhysicalDamageAgainstUserSide", + proc { |move, user, target, ai, battle| + next true if user.pbOwnSide.effects[PBEffects::Reflect] > 0 } ) -Battle::AI::Handlers::MoveEffectScore.add("StartWeakenSpecialDamageAgainstUserSide", - proc { |score, move, user, target, ai, battle| - next 0 if user.pbOwnSide.effects[PBEffects::LightScreen] > 0 +Battle::AI::Handlers::MoveFailureCheck.add("StartWeakenSpecialDamageAgainstUserSide", + proc { |move, user, target, ai, battle| + next true if user.pbOwnSide.effects[PBEffects::LightScreen] > 0 } ) +Battle::AI::Handlers::MoveFailureCheck.add("StartWeakenDamageAgainstUserSideIfHail", + proc { |move, user, target, ai, battle| + next true if user.pbOwnSide.effects[PBEffects::AuroraVeil] > 0 + next true if user.battler.effectiveWeather != :Hail + } +) Battle::AI::Handlers::MoveEffectScore.add("StartWeakenDamageAgainstUserSideIfHail", proc { |score, move, user, target, ai, battle| - next 0 if user.pbOwnSide.effects[PBEffects::AuroraVeil] > 0 || - user.battler.effectiveWeather != :Hail next score + 40 } ) @@ -335,7 +383,7 @@ Battle::AI::Handlers::MoveEffectScore.add("ProtectUser", proc { |score, move, user, target, ai, battle| if user.effects[PBEffects::ProtectRate] > 1 || target.effects[PBEffects::HyperBeam] > 0 - score -= 90 + score -= 50 else if ai.trainer.medium_skill? score -= user.effects[PBEffects::ProtectRate] * 40 @@ -351,7 +399,7 @@ Battle::AI::Handlers::MoveEffectScore.add("ProtectUserBanefulBunker", proc { |score, move, user, target, ai, battle| if user.effects[PBEffects::ProtectRate] > 1 || target.effects[PBEffects::HyperBeam] > 0 - score -= 90 + score -= 50 else if ai.trainer.medium_skill? score -= user.effects[PBEffects::ProtectRate] * 40 @@ -368,7 +416,7 @@ Battle::AI::Handlers::MoveEffectScore.add("ProtectUserFromDamagingMovesKingsShie proc { |score, move, user, target, ai, battle| if user.effects[PBEffects::ProtectRate] > 1 || target.effects[PBEffects::HyperBeam] > 0 - score -= 90 + score -= 50 else if ai.trainer.medium_skill? score -= user.effects[PBEffects::ProtectRate] * 40 @@ -384,7 +432,7 @@ Battle::AI::Handlers::MoveEffectScore.add("ProtectUserFromDamagingMovesObstruct" proc { |score, move, user, target, ai, battle| if user.effects[PBEffects::ProtectRate] > 1 || target.effects[PBEffects::HyperBeam] > 0 - score -= 90 + score -= 50 else if ai.trainer.medium_skill? score -= user.effects[PBEffects::ProtectRate] * 40 @@ -412,14 +460,22 @@ Battle::AI::Handlers::MoveEffectScore.add("ProtectUserFromTargetingMovesSpikyShi } ) +Battle::AI::Handlers::MoveFailureCheck.add("ProtectUserSideFromDamagingMovesIfUserFirstTurn", + proc { |move, user, target, ai, battle| + next true if user.turnCount > 0 + } +) Battle::AI::Handlers::MoveEffectScore.add("ProtectUserSideFromDamagingMovesIfUserFirstTurn", proc { |score, move, user, target, ai, battle| - next 0 if user.turnCount != 0 next score + 30 } ) -# ProtectUserSideFromStatusMoves +Battle::AI::Handlers::MoveFailureCheck.add("ProtectUserSideFromStatusMoves", + proc { |move, user, target, ai, battle| + next true if user.pbOwnSide.effects[PBEffects::CraftyShield] + } +) # ProtectUserSideFromPriorityMoves @@ -429,9 +485,13 @@ Battle::AI::Handlers::MoveEffectScore.add("ProtectUserSideFromDamagingMovesIfUse # RemoveProtectionsBypassSubstitute +Battle::AI::Handlers::MoveFailureCheck.add("HoopaRemoveProtectionsBypassSubstituteLowerUserDef1", + proc { |move, user, target, ai, battle| + next true if !user.battler.isSpecies?(:HOOPA) || user.battler.form != 1 + } +) Battle::AI::Handlers::MoveEffectScore.add("HoopaRemoveProtectionsBypassSubstituteLowerUserDef1", proc { |score, move, user, target, ai, battle| - next 0 if !user.battler.isSpecies?(:HOOPA) || user.battler.form != 1 next score + 20 if target.stages[:DEFENSE] > 0 } ) @@ -495,7 +555,7 @@ Battle::AI::Handlers::MoveBasePower.add("EffectivenessIncludesFlyingType", next (power.to_f * mult / Effectiveness::NORMAL_EFFECTIVE).round end } -} +) Battle::AI::Handlers::MoveEffectScore.add("CategoryDependsOnHigherDamagePoisonTarget", proc { |score, move, user, target, ai, battle| @@ -513,8 +573,7 @@ Battle::AI::Handlers::MoveEffectScore.add("CategoryDependsOnHigherDamagePoisonTa Battle::AI::Handlers::MoveEffectScore.add("EnsureNextMoveAlwaysHits", proc { |score, move, user, target, ai, battle| - next 0 if target.effects[PBEffects::Substitute] > 0 - next 0 if user.effects[PBEffects::LockOn] > 0 + next score - 50 if user.effects[PBEffects::LockOn] > 0 } ) @@ -534,7 +593,7 @@ Battle::AI::Handlers::MoveEffectScore.add("StartNegateTargetEvasionStatStageAndG Battle::AI::Handlers::MoveEffectScore.add("StartNegateTargetEvasionStatStageAndDarkImmunity", proc { |score, move, user, target, ai, battle| if target.effects[PBEffects::MiracleEye] - score -= 90 + score -= 50 elsif target.has_type?(:DARK) score += 70 elsif target.stages[:EVASION] <= 0 @@ -552,19 +611,21 @@ Battle::AI::Handlers::MoveBasePower.add("TypeDependsOnUserIVs", proc { |power, move, user, target, ai, battle| next move.pbBaseDamage(power, user.battler, target.battler) } -} +) +Battle::AI::Handlers::MoveFailureCheck.add("TypeAndPowerDependOnUserBerry", + proc { |move, user, target, ai, battle| + item = user.item + next true if !item || !item.is_berry? || !user.item_active? + next true if item.flags.none? { |f| f[/^NaturalGift_/i] } + } +) Battle::AI::Handlers::MoveBasePower.add("TypeAndPowerDependOnUserBerry", proc { |power, move, user, target, ai, battle| # TODO: Can't this just call move.pbBaseDamage? ret = move.pbNaturalGiftBaseDamage(user.item_id) next (ret == 1) ? 0 : ret } -} -Battle::AI::Handlers::MoveEffectScore.add("TypeAndPowerDependOnUserBerry", - proc { |score, move, user, target, ai, battle| - next 0 if !user.item || !user.item.is_berry? || !user.item_active? - } ) # TypeDependsOnUserPlate @@ -573,6 +634,11 @@ Battle::AI::Handlers::MoveEffectScore.add("TypeAndPowerDependOnUserBerry", # TypeDependsOnUserDrive +Battle::AI::Handlers::MoveFailureCheck.add("TypeDependsOnUserMorpekoFormRaiseUserSpeed1", + proc { |move, user, target, ai, battle| + next true if !user.battler.isSpecies?(:MORPEKO) && user.effects[PBEffects::TransformSpecies] != :MORPEKO + } +) Battle::AI::Handlers::MoveEffectScore.add("TypeDependsOnUserMorpekoFormRaiseUserSpeed1", proc { |score, move, user, target, ai, battle| next score + 20 if user.stages[:SPEED] <= 0 @@ -583,7 +649,7 @@ Battle::AI::Handlers::MoveBasePower.add("TypeAndPowerDependOnWeather", proc { |power, move, user, target, ai, battle| next move.pbBaseDamage(power, user.battler, target.battler) } -} +) Battle::AI::Handlers::MoveBasePower.copy("TypeAndPowerDependOnWeather", "TypeAndPowerDependOnTerrain") diff --git a/Data/Scripts/011_Battle/005_AI/055_AI_MoveHandlers_MultiHit.rb b/Data/Scripts/011_Battle/005_AI/055_AI_MoveHandlers_MultiHit.rb index 45c590d63..7fc2dc3eb 100644 --- a/Data/Scripts/011_Battle/005_AI/055_AI_MoveHandlers_MultiHit.rb +++ b/Data/Scripts/011_Battle/005_AI/055_AI_MoveHandlers_MultiHit.rb @@ -6,7 +6,7 @@ Battle::AI::Handlers::MoveBasePower.add("HitTwoTimes", proc { |power, move, user, target, ai, battle| next power * move.pbNumHits(user.battler, [target.battler]) } -} +) Battle::AI::Handlers::MoveBasePower.copy("HitTwoTimes", "HitTwoTimesPoisonTarget") @@ -40,19 +40,19 @@ Battle::AI::Handlers::MoveBasePower.add("HitTwoTimesTargetThenTargetAlly", proc { |power, move, user, target, ai, battle| next power * 2 } -} +) Battle::AI::Handlers::MoveBasePower.add("HitThreeTimesPowersUpWithEachHit", proc { |power, move, user, target, ai, battle| next power * 6 # Hits do x1, x2, x3 ret in turn, for x6 in total } -} +) Battle::AI::Handlers::MoveBasePower.add("HitThreeTimesAlwaysCriticalHit", proc { |power, move, user, target, ai, battle| next power * move.pbNumHits(user.battler, [target.battler]) } -} +) Battle::AI::Handlers::MoveEffectScore.add("HitThreeTimesAlwaysCriticalHit", proc { |score, move, user, target, ai, battle| if ai.trainer.high_skill? @@ -67,7 +67,7 @@ Battle::AI::Handlers::MoveBasePower.add("HitTwoToFiveTimes", next power * 5 if user.has_active_ability?(:SKILLLINK) next power * 31 / 10 # Average damage dealt } -} +) Battle::AI::Handlers::MoveBasePower.add("HitTwoToFiveTimesOrThreeForAshGreninja", proc { |power, move, user, target, ai, battle| @@ -77,14 +77,14 @@ Battle::AI::Handlers::MoveBasePower.add("HitTwoToFiveTimesOrThreeForAshGreninja" next power * 5 if user.has_active_ability?(:SKILLLINK) next power * 31 / 10 # Average damage dealt } -} +) Battle::AI::Handlers::MoveBasePower.add("HitTwoToFiveTimesRaiseUserSpd1LowerUserDef1", proc { |power, move, user, target, ai, battle| next power * 5 if user.has_active_ability?(:SKILLLINK) next power * 31 / 10 # Average damage dealt } -} +) Battle::AI::Handlers::MoveEffectScore.add("HitTwoToFiveTimesRaiseUserSpd1LowerUserDef1", proc { |score, move, user, target, ai, battle| aspeed = user.rough_stat(:SPEED) @@ -99,7 +99,18 @@ Battle::AI::Handlers::MoveEffectScore.add("HitTwoToFiveTimesRaiseUserSpd1LowerUs } ) -Battle::AI::Handlers::MoveBasePower.add("HitTwoToFiveTimesRaiseUserSpd1LowerUserDef1", +Battle::AI::Handlers::MoveFailureCheck.add("HitOncePerUserTeamMember", + proc { |move, user, target, ai, battle| + will_fail = true + battle.eachInTeamFromBattlerIndex(user.index) do |pkmn, i| + next if !pkmn.able? || pkmn.status != :NONE + will_fail = false + break + end + next will_fail + } +) +Battle::AI::Handlers::MoveBasePower.add("HitOncePerUserTeamMember", proc { |power, move, user, target, ai, battle| ret = 0 ai.battle.eachInTeamFromBattlerIndex(user.index) do |pkmn, _i| @@ -107,7 +118,7 @@ Battle::AI::Handlers::MoveBasePower.add("HitTwoToFiveTimesRaiseUserSpd1LowerUser end next ret } -} +) # AttackAndSkipNextTurn @@ -117,7 +128,7 @@ Battle::AI::Handlers::MoveBasePower.add("TwoTurnAttackOneTurnInSun", proc { |power, move, user, target, ai, battle| next move.pbBaseDamageMultiplier(power, user.battler, target.battler) } -} +) Battle::AI::Handlers::MoveEffectScore.add("TwoTurnAttackParalyzeTarget", proc { |score, move, user, target, ai, battle| @@ -158,6 +169,13 @@ Battle::AI::Handlers::MoveEffectScore.add("TwoTurnAttackFlinchTarget", } ) +Battle::AI::Handlers::MoveFailureCheck.add("TwoTurnAttackRaiseUserSpAtkSpDefSpd2", + proc { |move, user, target, ai, battle| + next true if !user.battler.pbCanRaiseStatStage?(:SPECIAL_ATTACK, user.battler, move.move) && + !user.battler.pbCanRaiseStatStage?(:SPECIAL_DEFENSE, user.battler, move.move) && + !user.battler.pbCanRaiseStatStage?(:SPEED, user.battler, move.move) + } +) Battle::AI::Handlers::MoveEffectScore.add("TwoTurnAttackRaiseUserSpAtkSpDefSpd2", proc { |score, move, user, target, ai, battle| if user.statStageAtMax?(:SPECIAL_ATTACK) && @@ -228,7 +246,14 @@ Battle::AI::Handlers::MoveEffectScore.add("TwoTurnAttackChargeRaiseUserSpAtk1", # TwoTurnAttackInvulnerableInSkyParalyzeTarget -# TwoTurnAttackInvulnerableInSkyTargetCannotAct +Battle::AI::Handlers::MoveFailureCheck.add("TwoTurnAttackInvulnerableInSkyTargetCannotAct", + proc { |move, user, target, ai, battle| + next true if !target.opposes?(user) + next true if target.effects[PBEffects::Substitute] > 0 && !move.move.ignoresSubstitute?(user.battler) + next true if Settings::MECHANICS_GENERATION >= 6 && target.battler.pbWeight >= 2000 # 200.0kg + next true if target.battler.semiInvulnerable? || target.effects[PBEffects::SkyDrop] >= 0 + } +) # TwoTurnAttackInvulnerableRemoveProtections @@ -240,13 +265,13 @@ Battle::AI::Handlers::MoveBasePower.add("MultiTurnAttackPowersUpEachTurn", proc { |power, move, user, target, ai, battle| next power * 2 if user.effects[PBEffects::DefenseCurl] } -} +) Battle::AI::Handlers::MoveBasePower.add("MultiTurnAttackBideThenReturnDoubleDamage", proc { |power, move, user, target, ai, battle| next 40 # Representative value } -} +) Battle::AI::Handlers::MoveEffectScore.add("MultiTurnAttackBideThenReturnDoubleDamage", proc { |score, move, user, target, ai, battle| if user.hp <= user.totalhp / 4 diff --git a/Data/Scripts/011_Battle/005_AI/056_AI_MoveHandlers_Healing.rb b/Data/Scripts/011_Battle/005_AI/056_AI_MoveHandlers_Healing.rb index 61f339514..b81d17c10 100644 --- a/Data/Scripts/011_Battle/005_AI/056_AI_MoveHandlers_Healing.rb +++ b/Data/Scripts/011_Battle/005_AI/056_AI_MoveHandlers_Healing.rb @@ -1,10 +1,15 @@ #=============================================================================== # #=============================================================================== +Battle::AI::Handlers::MoveFailureCheck.add("HealUserFullyAndFallAsleep", + proc { |move, user, target, ai, battle| + next true if !user.battler.canHeal? + next true if user.battler.asleep? + next true if !user.battler.pbCanSleep?(user.battler, false, move.move, true) + } +) Battle::AI::Handlers::MoveEffectScore.add("HealUserFullyAndFallAsleep", proc { |score, move, user, target, ai, battle| - next 0 if user.hp == user.totalhp || - !user.battler.pbCanSleep?(user.battler, false, nil, true) score += 70 score -= user.hp * 140 / user.totalhp score += 30 if user.status != :NONE @@ -12,20 +17,23 @@ Battle::AI::Handlers::MoveEffectScore.add("HealUserFullyAndFallAsleep", } ) +Battle::AI::Handlers::MoveFailureCheck.add("HealUserHalfOfTotalHP", + proc { |move, user, target, ai, battle| + next true if !user.battler.canHeal? + } +) Battle::AI::Handlers::MoveEffectScore.add("HealUserHalfOfTotalHP", proc { |score, move, user, target, ai, battle| - next 0 if user.hp == user.totalhp || - (ai.trainer.medium_skill? && !user.battler.canHeal?) score += 50 score -= user.hp * 100 / user.totalhp next score } ) +Battle::AI::Handlers::MoveFailureCheck.copy("HealUserHalfOfTotalHP", + "HealUserDependingOnWeather") Battle::AI::Handlers::MoveEffectScore.add("HealUserDependingOnWeather", proc { |score, move, user, target, ai, battle| - next 0 if user.hp == user.totalhp || - (ai.trainer.medium_skill? && !user.battler.canHeal?) case user.battler.effectiveWeather when :Sun, :HarshSun score += 30 @@ -39,10 +47,10 @@ Battle::AI::Handlers::MoveEffectScore.add("HealUserDependingOnWeather", } ) +Battle::AI::Handlers::MoveFailureCheck.copy("HealUserHalfOfTotalHP", + "HealUserDependingOnSandstorm") Battle::AI::Handlers::MoveEffectScore.add("HealUserDependingOnSandstorm", proc { |score, move, user, target, ai, battle| - next 0 if user.hp == user.totalhp || - (ai.trainer.medium_skill? && !user.battler.canHeal?) score += 50 score -= user.hp * 100 / user.totalhp score += 30 if user.battler.effectiveWeather == :Sandstorm @@ -50,53 +58,58 @@ Battle::AI::Handlers::MoveEffectScore.add("HealUserDependingOnSandstorm", } ) +Battle::AI::Handlers::MoveFailureCheck.copy("HealUserHalfOfTotalHP", + "HealUserHalfOfTotalHPLoseFlyingTypeThisTurn") Battle::AI::Handlers::MoveEffectScore.add("HealUserHalfOfTotalHPLoseFlyingTypeThisTurn", proc { |score, move, user, target, ai, battle| - next 0 if user.hp == user.totalhp || - (ai.trainer.medium_skill? && !user.battler.canHeal?) score += 50 score -= user.hp * 100 / user.totalhp next score } ) +Battle::AI::Handlers::MoveFailureCheck.add("CureTargetStatusHealUserHalfOfTotalHP", + proc { |move, user, target, ai, battle| + next true if !user.battler.canHeal? + next true if target.status == :NONE + } +) Battle::AI::Handlers::MoveEffectScore.add("CureTargetStatusHealUserHalfOfTotalHP", proc { |score, move, user, target, ai, battle| - if target.status == :NONE - score -= 90 - elsif user.hp == user.totalhp && target.opposes?(user) - score -= 90 - else - score += (user.totalhp - user.hp) * 50 / user.totalhp - score -= 30 if target.opposes?(user) - end + score += (user.totalhp - user.hp) * 50 / user.totalhp + score -= 30 if target.opposes?(user) next score } ) +Battle::AI::Handlers::MoveFailureCheck.add("HealUserByTargetAttackLowerTargetAttack1", + proc { |move, user, target, ai, battle| + if target.has_active_ability?(:CONTRARY) + next true if target.statStageAtMax?(:ATTACK) + else + next true if target.statStageAtMin?(:ATTACK) + end + } +) Battle::AI::Handlers::MoveEffectScore.add("HealUserByTargetAttackLowerTargetAttack1", proc { |score, move, user, target, ai, battle| - if target.statStageAtMin?(:ATTACK) - score -= 90 - else - if target.battler.pbCanLowerStatStage?(:ATTACK, user.battler) - score += target.stages[:ATTACK] * 20 - if ai.trainer.medium_skill? - hasPhysicalAttack = false - target.battler.eachMove do |m| - next if !m.physicalMove?(m.type) - hasPhysicalAttack = true - break - end - if hasPhysicalAttack - score += 20 - elsif ai.trainer.high_skill? - score -= 90 - end + if target.battler.pbCanLowerStatStage?(:ATTACK, user.battler) + score += target.stages[:ATTACK] * 20 + if ai.trainer.medium_skill? + hasPhysicalAttack = false + target.battler.eachMove do |m| + next if !m.physicalMove?(m.type) + hasPhysicalAttack = true + break + end + if hasPhysicalAttack + score += 20 + elsif ai.trainer.high_skill? + score -= 90 end end - score += (user.totalhp - user.hp) * 50 / user.totalhp end + score += (user.totalhp - user.hp) * 50 / user.totalhp next score } ) @@ -112,9 +125,13 @@ Battle::AI::Handlers::MoveEffectScore.add("HealUserByHalfOfDamageDone", } ) +Battle::AI::Handlers::MoveFailureCheck.add("HealUserByHalfOfDamageDoneIfTargetAsleep", + proc { |move, user, target, ai, battle| + next true if !target.battler.asleep? + } +) Battle::AI::Handlers::MoveEffectScore.add("HealUserByHalfOfDamageDoneIfTargetAsleep", proc { |score, move, user, target, ai, battle| - next 0 if !target.battler.asleep? if target.has_active_ability?(:LIQUIDOOZE) score -= 70 elsif user.hp <= user.totalhp / 2 @@ -135,6 +152,11 @@ Battle::AI::Handlers::MoveEffectScore.add("HealUserByThreeQuartersOfDamageDone", } ) +Battle::AI::Handlers::MoveFailureCheck.add("HealUserAndAlliesQuarterOfTotalHP", + proc { |move, user, target, ai, battle| + next true if battle.allSameSideBattlers(user.battler).none? { |b| b.canHeal? } + } +) Battle::AI::Handlers::MoveEffectScore.add("HealUserAndAlliesQuarterOfTotalHP", proc { |score, move, user, target, ai, battle| ally_amt = 30 @@ -149,6 +171,11 @@ Battle::AI::Handlers::MoveEffectScore.add("HealUserAndAlliesQuarterOfTotalHP", } ) +Battle::AI::Handlers::MoveFailureCheck.add("HealUserAndAlliesQuarterOfTotalHPCureStatus", + proc { |move, user, target, ai, battle| + next true if battle.allSameSideBattlers(user.battler).none? { |b| b.canHeal? || b.status != :NONE } + } +) Battle::AI::Handlers::MoveEffectScore.add("HealUserAndAlliesQuarterOfTotalHPCureStatus", proc { |score, move, user, target, ai, battle| ally_amt = 80 / battle.pbSideSize(user.index) @@ -164,6 +191,11 @@ Battle::AI::Handlers::MoveEffectScore.add("HealUserAndAlliesQuarterOfTotalHPCure } ) +Battle::AI::Handlers::MoveFailureCheck.add("HealTargetHalfOfTotalHP", + proc { |move, user, target, ai, battle| + next true if !target.battler.canHeal? + } +) Battle::AI::Handlers::MoveEffectScore.add("HealTargetHalfOfTotalHP", proc { |score, move, user, target, ai, battle| next 0 if user.opposes?(target) @@ -174,6 +206,8 @@ Battle::AI::Handlers::MoveEffectScore.add("HealTargetHalfOfTotalHP", } ) +Battle::AI::Handlers::MoveFailureCheck.copy("HealTargetHalfOfTotalHP", + "HealTargetDependingOnGrassyTerrain") Battle::AI::Handlers::MoveEffectScore.add("HealTargetDependingOnGrassyTerrain", proc { |score, move, user, target, ai, battle| next 0 if user.hp == user.totalhp || @@ -187,30 +221,32 @@ Battle::AI::Handlers::MoveEffectScore.add("HealTargetDependingOnGrassyTerrain", } ) -Battle::AI::Handlers::MoveEffectScore.add("HealUserPositionNextTurn", - proc { |score, move, user, target, ai, battle| - next 0 if battle.positions[user.index].effects[PBEffects::Wish] > 0 +Battle::AI::Handlers::MoveFailureCheck.add("HealUserPositionNextTurn", + proc { |move, user, target, ai, battle| + next true if battle.positions[user.index].effects[PBEffects::Wish] > 0 } ) -Battle::AI::Handlers::MoveEffectScore.add("StartHealUserEachTurn", - proc { |score, move, user, target, ai, battle| - next 0 if user.effects[PBEffects::AquaRing] +Battle::AI::Handlers::MoveFailureCheck.add("StartHealUserEachTurn", + proc { |move, user, target, ai, battle| + next true if user.effects[PBEffects::AquaRing] } ) -Battle::AI::Handlers::MoveEffectScore.add("StartHealUserEachTurnTrapUserInBattle", - proc { |score, move, user, target, ai, battle| - next 0 if user.effects[PBEffects::Ingrain] +Battle::AI::Handlers::MoveFailureCheck.add("StartHealUserEachTurnTrapUserInBattle", + proc { |move, user, target, ai, battle| + next true if user.effects[PBEffects::Ingrain] } ) +Battle::AI::Handlers::MoveFailureCheck.add("StartDamageTargetEachTurnIfTargetAsleep", + proc { |move, user, target, ai, battle| + next true if !target.battler.asleep? || target.effects[PBEffects::Nightmare] + } +) Battle::AI::Handlers::MoveEffectScore.add("StartDamageTargetEachTurnIfTargetAsleep", proc { |score, move, user, target, ai, battle| - if target.effects[PBEffects::Nightmare] || - target.effects[PBEffects::Substitute] > 0 - score -= 90 - elsif !target.battler.asleep? + if target.effects[PBEffects::Substitute] > 0 score -= 90 else score -= 90 if target.statusCount <= 1 @@ -220,6 +256,12 @@ Battle::AI::Handlers::MoveEffectScore.add("StartDamageTargetEachTurnIfTargetAsle } ) +Battle::AI::Handlers::MoveFailureCheck.add("StartLeechSeedTarget", + proc { |move, user, target, ai, battle| + next true if target.effects[PBEffects::LeechSeed] >= 0 + next true if target.has_type?(:GRASS) + } +) Battle::AI::Handlers::MoveEffectScore.add("StartLeechSeedTarget", proc { |score, move, user, target, ai, battle| if target.effects[PBEffects::LeechSeed] >= 0 @@ -239,14 +281,17 @@ Battle::AI::Handlers::MoveEffectScore.add("UserLosesHalfOfTotalHP", } ) +Battle::AI::Handlers::MoveFailureCheck.add("UserLosesHalfOfTotalHPExplosive", + proc { |move, user, target, ai, battle| + next true if battle.pbCheckGlobalAbility(:DAMP) + } +) Battle::AI::Handlers::MoveEffectScore.add("UserLosesHalfOfTotalHPExplosive", proc { |score, move, user, target, ai, battle| reserves = battle.pbAbleNonActiveCount(user.idxOwnSide) foes = battle.pbAbleNonActiveCount(user.idxOpposingSide) - if battle.pbCheckGlobalAbility(:DAMP) - score -= 100 - elsif ai.trainer.medium_skill? && reserves == 0 && foes > 0 - score -= 100 # don't want to lose + if ai.trainer.medium_skill? && reserves == 0 && foes > 0 + score -= 60 # don't want to lose elsif ai.trainer.high_skill? && reserves == 0 && foes == 0 score += 80 # want to draw else @@ -256,14 +301,14 @@ Battle::AI::Handlers::MoveEffectScore.add("UserLosesHalfOfTotalHPExplosive", } ) +Battle::AI::Handlers::MoveFailureCheck.copy("UserLosesHalfOfTotalHPExplosive", + "UserFaintsExplosive") Battle::AI::Handlers::MoveEffectScore.add("UserFaintsExplosive", proc { |score, move, user, target, ai, battle| reserves = battle.pbAbleNonActiveCount(user.idxOwnSide) foes = battle.pbAbleNonActiveCount(user.idxOpposingSide) - if battle.pbCheckGlobalAbility(:DAMP) - score -= 100 - elsif ai.trainer.medium_skill? && reserves == 0 && foes > 0 - score -= 100 # don't want to lose + if ai.trainer.medium_skill? && reserves == 0 && foes > 0 + score -= 60 # don't want to lose elsif ai.trainer.high_skill? && reserves == 0 && foes == 0 score += 80 # want to draw else @@ -273,25 +318,23 @@ Battle::AI::Handlers::MoveEffectScore.add("UserFaintsExplosive", } ) +Battle::AI::Handlers::MoveFailureCheck.copy("UserLosesHalfOfTotalHPExplosive", + "UserFaintsPowersUpInMistyTerrainExplosive") Battle::AI::Handlers::MoveBasePower.add("UserFaintsPowersUpInMistyTerrainExplosive", proc { |power, move, user, target, ai, battle| next power * 3 / 2 if battle.field.terrain == :Misty } -} +) Battle::AI::Handlers::MoveEffectScore.add("UserFaintsPowersUpInMistyTerrainExplosive", proc { |score, move, user, target, ai, battle| reserves = battle.pbAbleNonActiveCount(user.idxOwnSide) foes = battle.pbAbleNonActiveCount(user.idxOpposingSide) - if battle.pbCheckGlobalAbility(:DAMP) - score -= 100 - elsif ai.trainer.medium_skill? && reserves == 0 && foes > 0 - score -= 100 # don't want to lose + if ai.trainer.medium_skill? && reserves == 0 && foes > 0 + score -= 60 # don't want to lose elsif ai.trainer.high_skill? && reserves == 0 && foes == 0 score += 40 # want to draw - score += 40 if battle.field.terrain == :Misty else score -= user.hp * 100 / user.totalhp - score += 20 if battle.field.terrain == :Misty end next score } @@ -301,15 +344,15 @@ Battle::AI::Handlers::MoveBasePower.add("UserFaintsFixedDamageUserHP", proc { |power, move, user, target, ai, battle| next user.hp } -} +) Battle::AI::Handlers::MoveEffectScore.add("UserFaintsLowerTargetAtkSpAtk2", proc { |score, move, user, target, ai, battle| if !target.battler.pbCanLowerStatStage?(:ATTACK, user.battler) && !target.battler.pbCanLowerStatStage?(:SPECIAL_ATTACK, user.battler) - score -= 100 + score -= 60 elsif battle.pbAbleNonActiveCount(user.idxOwnSide) == 0 - score -= 100 + score -= 60 else score += target.stages[:ATTACK] * 10 score += target.stages[:SPECIAL_ATTACK] * 10 @@ -319,26 +362,41 @@ Battle::AI::Handlers::MoveEffectScore.add("UserFaintsLowerTargetAtkSpAtk2", } ) +Battle::AI::Handlers::MoveFailureCheck.add("UserFaintsHealAndCureReplacement", + proc { |move, user, target, ai, battle| + next true if !battle.pbCanChooseNonActive?(user.index) + } +) Battle::AI::Handlers::MoveEffectScore.add("UserFaintsHealAndCureReplacement", proc { |score, move, user, target, ai, battle| next score - 70 } ) +Battle::AI::Handlers::MoveFailureCheck.copy("UserFaintsHealAndCureReplacement", + "UserFaintsHealAndCureReplacementRestorePP") Battle::AI::Handlers::MoveEffectScore.copy("UserFaintsHealAndCureReplacement", "UserFaintsHealAndCureReplacementRestorePP") +Battle::AI::Handlers::MoveFailureCheck.add("StartPerishCountsForAllBattlers", + proc { |move, user, target, ai, battle| + next target.effects[PBEffects::PerishSong] > 0 + } +) Battle::AI::Handlers::MoveEffectScore.add("StartPerishCountsForAllBattlers", proc { |score, move, user, target, ai, battle| if battle.pbAbleNonActiveCount(user.idxOwnSide) == 0 - score -= 90 - elsif target.effects[PBEffects::PerishSong] > 0 - score -= 90 + score -= 60 end next score } ) +Battle::AI::Handlers::MoveFailureCheck.add("AttackerFaintsIfUserFaints", + proc { |move, user, target, ai, battle| + next Settings::MECHANICS_GENERATION >= 7 && user.effects[PBEffects::DestinyBondPrevious] + } +) Battle::AI::Handlers::MoveEffectScore.add("AttackerFaintsIfUserFaints", proc { |score, move, user, target, ai, battle| score += 50 diff --git a/Data/Scripts/011_Battle/005_AI/057_AI_MoveHandlers_Items.rb b/Data/Scripts/011_Battle/005_AI/057_AI_MoveHandlers_Items.rb index ed2955c0d..5f6f69276 100644 --- a/Data/Scripts/011_Battle/005_AI/057_AI_MoveHandlers_Items.rb +++ b/Data/Scripts/011_Battle/005_AI/057_AI_MoveHandlers_Items.rb @@ -16,12 +16,16 @@ Battle::AI::Handlers::MoveEffectScore.add("UserTakesTargetItem", } ) +Battle::AI::Handlers::MoveFailureCheck.add("TargetTakesUserItem", + proc { |move, user, target, ai, battle| + next true if !user.item || user.battler.unlosableItem?(user.item) + next true if target.item || target.battler.unlosableItem?(user.item) + } +) Battle::AI::Handlers::MoveEffectScore.add("TargetTakesUserItem", proc { |score, move, user, target, ai, battle| - if !user.item || target.item - score -= 90 - elsif user.has_active_item?([:FLAMEORB, :TOXICORB, :STICKYBARB, :IRONBALL, - :CHOICEBAND, :CHOICESCARF, :CHOICESPECS]) + if user.has_active_item?([:FLAMEORB, :TOXICORB, :STICKYBARB, :IRONBALL, + :CHOICEBAND, :CHOICESCARF, :CHOICESPECS]) score += 50 else score -= 80 @@ -30,13 +34,18 @@ Battle::AI::Handlers::MoveEffectScore.add("TargetTakesUserItem", } ) +Battle::AI::Handlers::MoveFailureCheck.add("UserTargetSwapItems", + proc { |move, user, target, ai, battle| + next true if user.wild? + next true if !user.item && !target.item + next true if user.battler.unlosableItem?(user.item) || user.battler.unlosableItem?(target.item) + next true if target.battler.unlosableItem?(target.item) || target.battler.unlosableItem?(user.item) + next true if target.has_active_ability?(:STICKYHOLD) + } +) Battle::AI::Handlers::MoveEffectScore.add("UserTargetSwapItems", proc { |score, move, user, target, ai, battle| - if !user.item && !target.item - score -= 90 - elsif target.has_active_ability?(:STICKYHOLD) - score -= 90 - elsif user.has_active_item?([:FLAMEORB, :TOXICORB, :STICKYBARB, :IRONBALL, + if user.has_active_item?([:FLAMEORB, :TOXICORB, :STICKYBARB, :IRONBALL, :CHOICEBAND, :CHOICESCARF, :CHOICESPECS]) score += 50 elsif !user.item && target.item @@ -47,13 +56,14 @@ Battle::AI::Handlers::MoveEffectScore.add("UserTargetSwapItems", } ) +Battle::AI::Handlers::MoveFailureCheck.add("RestoreUserConsumedItem", + proc { |move, user, target, ai, battle| + next true if !user.battler.recycleItem || user.item + } +) Battle::AI::Handlers::MoveEffectScore.add("RestoreUserConsumedItem", proc { |score, move, user, target, ai, battle| - if !user.battler.recycleItem || user.item - score -= 80 - elsif user.battler.recycleItem - score += 30 - end + score += 30 next score } ) @@ -62,7 +72,7 @@ Battle::AI::Handlers::MoveBasePower.add("RemoveTargetItem", proc { |power, move, user, target, ai, battle| next move.pbBaseDamage(power, user.battler, target.battler) } -} +) Battle::AI::Handlers::MoveEffectScore.add("RemoveTargetItem", proc { |score, move, user, target, ai, battle| if ai.trainer.high_skill? @@ -83,15 +93,18 @@ Battle::AI::Handlers::MoveEffectScore.add("DestroyTargetBerryOrGem", } ) +Battle::AI::Handlers::MoveFailureCheck.add("CorrodeTargetItem", + proc { |move, user, target, ai, battle| + next true if !target.item || target.unlosableItem?(target.item) || + target.effects[PBEffects::Substitute] > 0 + next true if target.has_active_ability?(:STICKYHOLD) + next true if battle.corrosiveGas[target.index % 2][target.party_index] + } +) Battle::AI::Handlers::MoveEffectScore.add("CorrodeTargetItem", proc { |score, move, user, target, ai, battle| - if battle.corrosiveGas[target.side][target.party_index] - score -= 100 - elsif !target.item || !target.item_active? || target.battler.unlosableItem?(target.item) || - target.has_active_ability?(:STICKYHOLD) - score -= 90 - elsif target.effects[PBEffects::Substitute] > 0 - score -= 90 + if !target.item_active? + score -= 60 else score += 50 end @@ -99,6 +112,11 @@ Battle::AI::Handlers::MoveEffectScore.add("CorrodeTargetItem", } ) +Battle::AI::Handlers::MoveFailureCheck.add("StartTargetCannotUseItem", + proc { |move, user, target, ai, battle| + next true if target.effects[PBEffects::Embargo] > 0 + } +) Battle::AI::Handlers::MoveEffectScore.add("StartTargetCannotUseItem", proc { |score, move, user, target, ai, battle| next 0 if target.effects[PBEffects::Embargo] > 0 @@ -112,34 +130,41 @@ Battle::AI::Handlers::MoveEffectScore.add("StartNegateHeldItems", } ) +Battle::AI::Handlers::MoveFailureCheck.add("UserConsumeBerryRaiseDefense2", + proc { |move, user, target, ai, battle| + item = user.item + next true if !item || !item.is_berry? || !user.item_active? + } +) Battle::AI::Handlers::MoveEffectScore.add("UserConsumeBerryRaiseDefense2", proc { |score, move, user, target, ai, battle| - if !user.item || !user.item.is_berry? || !user.item_active? - score -= 100 - else - if ai.trainer.high_skill? - useful_berries = [ - :ORANBERRY, :SITRUSBERRY, :AGUAVBERRY, :APICOTBERRY, :CHERIBERRY, - :CHESTOBERRY, :FIGYBERRY, :GANLONBERRY, :IAPAPABERRY, :KEEBERRY, - :LANSATBERRY, :LEPPABERRY, :LIECHIBERRY, :LUMBERRY, :MAGOBERRY, - :MARANGABERRY, :PECHABERRY, :PERSIMBERRY, :PETAYABERRY, :RAWSTBERRY, - :SALACBERRY, :STARFBERRY, :WIKIBERRY - ] - score += 30 if useful_berries.include?(user.item_id) - end - if ai.trainer.medium_skill? - score += 20 if user.battler.canHeal? && user.hp < user.totalhp / 3 && - user.has_active_ability?(:CHEEKPOUCH) - score += 20 if user.has_active_ability?([:HARVEST, :RIPEN]) || - user.battler.pbHasMoveFunction?("RestoreUserConsumedItem") # Recycle - score += 20 if !user.battler.canConsumeBerry? - end - score -= user.stages[:DEFENSE] * 20 + if ai.trainer.high_skill? + useful_berries = [ + :ORANBERRY, :SITRUSBERRY, :AGUAVBERRY, :APICOTBERRY, :CHERIBERRY, + :CHESTOBERRY, :FIGYBERRY, :GANLONBERRY, :IAPAPABERRY, :KEEBERRY, + :LANSATBERRY, :LEPPABERRY, :LIECHIBERRY, :LUMBERRY, :MAGOBERRY, + :MARANGABERRY, :PECHABERRY, :PERSIMBERRY, :PETAYABERRY, :RAWSTBERRY, + :SALACBERRY, :STARFBERRY, :WIKIBERRY + ] + score += 30 if useful_berries.include?(user.item_id) end + if ai.trainer.medium_skill? + score += 20 if user.battler.canHeal? && user.hp < user.totalhp / 3 && + user.has_active_ability?(:CHEEKPOUCH) + score += 20 if user.has_active_ability?([:HARVEST, :RIPEN]) || + user.battler.pbHasMoveFunction?("RestoreUserConsumedItem") # Recycle + score += 20 if !user.battler.canConsumeBerry? + end + score -= user.stages[:DEFENSE] * 20 next score } ) +Battle::AI::Handlers::MoveFailureCheck.add("AllBattlersConsumeBerry", + proc { |move, user, target, ai, battle| + next true if !target.item || !target.item.is_berry? || target.battler.semiInvulnerable? + } +) Battle::AI::Handlers::MoveEffectScore.add("AllBattlersConsumeBerry", proc { |score, move, user, target, ai, battle| useful_berries = [ @@ -150,20 +175,16 @@ Battle::AI::Handlers::MoveEffectScore.add("AllBattlersConsumeBerry", :RAWSTBERRY, :SALACBERRY, :STARFBERRY, :WIKIBERRY ] battle.allSameSideBattlers(user.index).each do |b| - if !b.item || !b.item.is_berry? || !b.itemActive? - score -= 100 / battle.pbSideSize(user.index) - else - if ai.trainer.high_skill? - amt = 30 / battle.pbSideSize(user.index) - score += amt if useful_berries.include?(b.item_id) - end - if ai.trainer.medium_skill? - amt = 20 / battle.pbSideSize(user.index) - score += amt if b.canHeal? && b.hp < b.totalhp / 3 && b.hasActiveAbility?(:CHEEKPOUCH) - score += amt if b.hasActiveAbility?([:HARVEST, :RIPEN]) || - b.pbHasMoveFunction?("RestoreUserConsumedItem") # Recycle - score += amt if !b.canConsumeBerry? - end + if ai.trainer.high_skill? + amt = 30 / battle.pbSideSize(user.index) + score += amt if useful_berries.include?(b.item_id) + end + if ai.trainer.medium_skill? + amt = 20 / battle.pbSideSize(user.index) + score += amt if b.canHeal? && b.hp < b.totalhp / 3 && b.hasActiveAbility?(:CHEEKPOUCH) + score += amt if b.hasActiveAbility?([:HARVEST, :RIPEN]) || + b.pbHasMoveFunction?("RestoreUserConsumedItem") # Recycle + score += amt if !b.canConsumeBerry? end end if ai.trainer.high_skill? @@ -191,14 +212,16 @@ Battle::AI::Handlers::MoveEffectScore.add("UserConsumeTargetBerry", } ) +Battle::AI::Handlers::MoveFailureCheck.add("ThrowUserItemAtTarget", + proc { |move, user, target, ai, battle| + item = user.item + next true if !item || !user.item_active? || user.battler.unlosableItem?(item) + next true if item.is_berry? && !user.battler.canConsumeBerry? + next true if item.flags.none? { |f| f[/^Fling_/i] } + } +) Battle::AI::Handlers::MoveBasePower.add("ThrowUserItemAtTarget", proc { |power, move, user, target, ai, battle| next move.pbBaseDamage(power, user.battler, target.battler) } -} -Battle::AI::Handlers::MoveEffectScore.add("ThrowUserItemAtTarget", - proc { |score, move, user, target, ai, battle| - next 0 if !user.item || !user.item_active? || - user.battler.unlosableItem?(user.item) || user.item.is_poke_ball? - } ) diff --git a/Data/Scripts/011_Battle/005_AI/058_AI_MoveHandlers_ChangeMoveEffect.rb b/Data/Scripts/011_Battle/005_AI/058_AI_MoveHandlers_ChangeMoveEffect.rb index a71494434..ecf3d3c10 100644 --- a/Data/Scripts/011_Battle/005_AI/058_AI_MoveHandlers_ChangeMoveEffect.rb +++ b/Data/Scripts/011_Battle/005_AI/058_AI_MoveHandlers_ChangeMoveEffect.rb @@ -36,28 +36,38 @@ Battle::AI::Handlers::MoveBasePower.add("RandomlyDamageOrHealTarget", proc { |power, move, user, target, ai, battle| next 50 # Average power, ish } -} +) +Battle::AI::Handlers::MoveFailureCheck.add("HealAllyOrDamageFoe", + proc { |move, user, target, ai, battle| + next true if !target.opposes?(user) && target.battler.canHeal? + } +) Battle::AI::Handlers::MoveEffectScore.add("HealAllyOrDamageFoe", proc { |score, move, user, target, ai, battle| if !target.opposes?(user) - if target.hp == target.totalhp || (ai.trainer.medium_skill? && !target.battler.canHeal?) - score -= 90 - else - score += 50 - score -= target.hp * 100 / target.totalhp - end + score += 50 + score -= target.hp * 100 / target.totalhp end next score } ) +Battle::AI::Handlers::MoveFailureCheck.add("CurseTargetOrLowerUserSpd1RaiseUserAtkDef1", + proc { |move, user, target, ai, battle| + if user.has_type?(:GHOST) + next true if target.effects[PBEffects::Curse] + else + next true if !user.battler.pbCanLowerStatStage?(:SPEED, user.battler, move.move) && + !user.battler.pbCanRaiseStatStage?(:ATTACK, user.battler, move.move) && + !user.battler.pbCanRaiseStatStage?(:DEFENSE, user.battler, move.move) + end + } +) Battle::AI::Handlers::MoveEffectScore.add("CurseTargetOrLowerUserSpd1RaiseUserAtkDef1", proc { |score, move, user, target, ai, battle| if user.has_type?(:GHOST) - if target.effects[PBEffects::Curse] - score -= 90 - elsif user.hp <= user.totalhp / 2 + if user.hp <= user.totalhp / 2 if battle.pbAbleNonActiveCount(user.idxOwnSide) == 0 score -= 90 else @@ -81,19 +91,24 @@ Battle::AI::Handlers::MoveBasePower.add("HitsAllFoesAndPowersUpInPsychicTerrain" proc { |power, move, user, target, ai, battle| next move.pbBaseDamage(power, user.battler, target.battler) } -} +) Battle::AI::Handlers::MoveEffectScore.add("HitsAllFoesAndPowersUpInPsychicTerrain", proc { |score, move, user, target, ai, battle| next score + 40 if battle.field.terrain == :Psychic && user.battler.affectedByTerrain? } ) +Battle::AI::Handlers::MoveFailureCheck.add("TargetNextFireMoveDamagesTarget", + proc { |move, user, target, ai, battle| + next true if target.effects[PBEffects::Powder] + } +) Battle::AI::Handlers::MoveEffectScore.add("TargetNextFireMoveDamagesTarget", proc { |score, move, user, target, ai, battle| aspeed = user.rough_stat(:SPEED) ospeed = target.rough_stat(:SPEED) if aspeed > ospeed - score -= 90 + score -= 50 elsif target.battler.pbHasMoveType?(:FIRE) score += 30 end @@ -105,9 +120,14 @@ Battle::AI::Handlers::MoveEffectScore.add("TargetNextFireMoveDamagesTarget", # DoublePowerAfterFusionBolt +Battle::AI::Handlers::MoveFailureCheck.add("PowerUpAllyMove", + proc { |move, user, target, ai, battle| + next true if target.fainted? || target.effects[PBEffects::HelpingHand] + } +) Battle::AI::Handlers::MoveEffectScore.add("PowerUpAllyMove", proc { |score, move, user, target, ai, battle| - next 0 if user.battler.allAllies.empty? + next score - 60 if user.battler.allAllies.empty? next score + 30 } ) @@ -116,7 +136,7 @@ Battle::AI::Handlers::MoveBasePower.add("CounterPhysicalDamage", proc { |power, move, user, target, ai, battle| next 60 # Representative value } -} +) Battle::AI::Handlers::MoveEffectScore.add("CounterPhysicalDamage", proc { |score, move, user, target, ai, battle| if target.effects[PBEffects::HyperBeam] > 0 @@ -139,7 +159,7 @@ Battle::AI::Handlers::MoveBasePower.add("CounterSpecialDamage", proc { |power, move, user, target, ai, battle| next 60 # Representative value } -} +) Battle::AI::Handlers::MoveEffectScore.add("CounterSpecialDamage", proc { |score, move, user, target, ai, battle| if target.effects[PBEffects::HyperBeam] > 0 @@ -162,22 +182,25 @@ Battle::AI::Handlers::MoveBasePower.add("CounterDamagePlusHalf", proc { |power, move, user, target, ai, battle| next 60 # Representative value } -} +) Battle::AI::Handlers::MoveEffectScore.add("CounterDamagePlusHalf", proc { |score, move, user, target, ai, battle| next score - 90 if target.effects[PBEffects::HyperBeam] > 0 } ) +Battle::AI::Handlers::MoveFailureCheck.add("UserAddStockpileRaiseDefSpDef1", + proc { |move, user, target, ai, battle| + next true if user.effects[PBEffects::Stockpile] >= 3 + } +) Battle::AI::Handlers::MoveEffectScore.add("UserAddStockpileRaiseDefSpDef1", proc { |score, move, user, target, ai, battle| avg = 0 avg -= user.stages[:DEFENSE] * 10 avg -= user.stages[:SPECIAL_DEFENSE] * 10 score += avg / 2 - if user.effects[PBEffects::Stockpile] >= 3 - score -= 80 - elsif user.battler.pbHasMoveFunction?("PowerDependsOnUserStockpile", + if user.battler.pbHasMoveFunction?("PowerDependsOnUserStockpile", "HealUserDependingOnUserStockpile") # Spit Up, Swallow score += 20 # More preferable if user also has Spit Up/Swallow end @@ -185,21 +208,27 @@ Battle::AI::Handlers::MoveEffectScore.add("UserAddStockpileRaiseDefSpDef1", } ) +Battle::AI::Handlers::MoveFailureCheck.add("PowerDependsOnUserStockpile", + proc { |move, user, target, ai, battle| + next true if user.effects[PBEffects::Stockpile] == 0 + } +) Battle::AI::Handlers::MoveBasePower.add("PowerDependsOnUserStockpile", proc { |power, move, user, target, ai, battle| next move.pbBaseDamage(power, user.battler, target.battler) } -} -Battle::AI::Handlers::MoveEffectScore.add("PowerDependsOnUserStockpile", - proc { |score, move, user, target, ai, battle| - next 0 if user.effects[PBEffects::Stockpile] == 0 - } ) +Battle::AI::Handlers::MoveFailureCheck.add("HealUserDependingOnUserStockpile", + proc { |move, user, target, ai, battle| + next true if user.effects[PBEffects::Stockpile] == 0 + next true if !user.battler.canHeal? && + user.effects[PBEffects::StockpileDef] == 0 && + user.effects[PBEffects::StockpileSpDef] == 0 + } +) Battle::AI::Handlers::MoveEffectScore.add("HealUserDependingOnUserStockpile", proc { |score, move, user, target, ai, battle| - next 0 if user.effects[PBEffects::Stockpile] == 0 - next 0 if user.hp == user.totalhp mult = [0, 25, 50, 100][user.effects[PBEffects::Stockpile]] score += mult score -= user.hp * mult * 2 / user.totalhp @@ -213,16 +242,22 @@ Battle::AI::Handlers::MoveEffectScore.add("HealUserDependingOnUserStockpile", # WaterPledge -# UseLastMoveUsed +Battle::AI::Handlers::MoveFailureCheck.add("UseLastMoveUsed", + proc { |move, user, target, ai, battle| + next true if !battle.lastMoveUsed + next true if move.move.moveBlacklist.include?(GameData::Move.get(battle.lastMoveUsed).function_code) + } +) +Battle::AI::Handlers::MoveFailureCheck.add("UseLastMoveUsedByTarget", + proc { |move, user, target, ai, battle| + next true if !target.battle.lastRegularMoveUsed + next true if GameData::Move.get(target.battle.lastRegularMoveUsed).flags.none? { |f| f[/^CanMirrorMove$/i] } + } +) Battle::AI::Handlers::MoveEffectScore.add("UseLastMoveUsedByTarget", proc { |score, move, user, target, ai, battle| - score -= 40 - if ai.trainer.high_skill? - score -= 100 if !target.battler.lastRegularMoveUsed || - GameData::Move.get(target.battler.lastRegularMoveUsed).flags.none? { |f| f[/^CanMirrorMove$/i] } - end - next score + next score - 40 } ) @@ -232,16 +267,40 @@ Battle::AI::Handlers::MoveEffectScore.add("UseLastMoveUsedByTarget", # UseRandomMove -# UseRandomMoveFromUserParty +Battle::AI::Handlers::MoveFailureCheck.add("UseRandomMoveFromUserParty", + proc { |move, user, target, ai, battle| + will_fail = true + battle.pbParty(user.index).each_with_index do |pkmn, i| + next if !pkmn || i == user.party_index + next if Settings::MECHANICS_GENERATION >= 6 && pkmn.egg? + pkmn.moves.each do |pkmn_move| + next if move.move.moveBlacklist.include?(pkmn_move.function_code) + next if pkmn_move.type == :SHADOW + will_fail = false + break + end + break if !will_fail + end + next will_fail + } +) +Battle::AI::Handlers::MoveFailureCheck.add("UseRandomUserMoveIfAsleep", + proc { |move, user, target, ai, battle| + next true if !user.battler.asleep? + will_fail = true + user.battler.eachMoveWithIndex do |m, i| + next if move.move.moveBlacklist.include?(m.function) + next if !battle.pbCanChooseMove?(user.index, i, false, true) + will_fail = false + break + end + next will_fail + } +) Battle::AI::Handlers::MoveEffectScore.add("UseRandomUserMoveIfAsleep", proc { |score, move, user, target, ai, battle| - if user.battler.asleep? - score += 100 # Because it can only be used while asleep - else - score -= 90 - end - next score + next score + 50 if user.battler.asleep? # Because it can only be used while asleep } ) @@ -249,52 +308,24 @@ Battle::AI::Handlers::MoveEffectScore.add("UseRandomUserMoveIfAsleep", # StealAndUseBeneficialStatusMove -Battle::AI::Handlers::MoveEffectScore.add("ReplaceMoveThisBattleWithTargetLastMoveUsed", - proc { |score, move, user, target, ai, battle| - moveBlacklist = [ - "Struggle", # Struggle - "ReplaceMoveThisBattleWithTargetLastMoveUsed", # Mimic - "ReplaceMoveWithTargetLastMoveUsed", # Sketch - "UseRandomMove" # Metronome - ] - if user.effects[PBEffects::Transform] || !target.battler.lastRegularMoveUsed - score -= 90 - else - lastMoveData = GameData::Move.get(target.battler.lastRegularMoveUsed) - if moveBlacklist.include?(lastMoveData.function_code) || - lastMoveData.type == :SHADOW - score -= 90 - end - user.battler.eachMove do |m| - next if m != target.battler.lastRegularMoveUsed - score -= 90 - break - end - end - next score +Battle::AI::Handlers::MoveFailureCheck.add("ReplaceMoveThisBattleWithTargetLastMoveUsed", + proc { |move, user, target, ai, battle| + next true if user.effects[PBEffects::Transform] || user.battler.pbHasMove?(move.id) + last_move_data = GameData::Move.try_get(target.battler.lastRegularMoveUsed) + next true if !last_move_data || + user.battler.pbHasMove?(target.battler.lastRegularMoveUsed) || + move.move.moveBlacklist.include?(last_move_data.function_code) || + last_move_data.type == :SHADOW } ) -Battle::AI::Handlers::MoveEffectScore.add("ReplaceMoveWithTargetLastMoveUsed", - proc { |score, move, user, target, ai, battle| - moveBlacklist = [ - "Struggle", # Struggle - "ReplaceMoveWithTargetLastMoveUsed" # Sketch - ] - if user.effects[PBEffects::Transform] || !target.battler.lastRegularMoveUsed - score -= 90 - else - lastMoveData = GameData::Move.get(target.battler.lastRegularMoveUsed) - if moveBlacklist.include?(lastMoveData.function_code) || - lastMoveData.type == :SHADOW - score -= 90 - end - user.battler.eachMove do |m| - next if m != target.battler.lastRegularMoveUsed - score -= 90 # User already knows the move that will be Sketched - break - end - end - next score +Battle::AI::Handlers::MoveFailureCheck.add("ReplaceMoveWithTargetLastMoveUsed", + proc { |move, user, target, ai, battle| + next true if user.effects[PBEffects::Transform] || !user.battler.pbHasMove?(move.id) + last_move_data = GameData::Move.try_get(target.battler.lastRegularMoveUsed) + next true if !last_move_data || + user.battler.pbHasMove?(target.battler.lastRegularMoveUsed) || + move.move.moveBlacklist.include?(last_move_data.function_code) || + last_move_data.type == :SHADOW } ) diff --git a/Data/Scripts/011_Battle/005_AI/059_AI_MoveHandlers_SwitchingActing.rb b/Data/Scripts/011_Battle/005_AI/059_AI_MoveHandlers_SwitchingActing.rb index f86968a72..52eb474f8 100644 --- a/Data/Scripts/011_Battle/005_AI/059_AI_MoveHandlers_SwitchingActing.rb +++ b/Data/Scripts/011_Battle/005_AI/059_AI_MoveHandlers_SwitchingActing.rb @@ -1,17 +1,25 @@ #=============================================================================== # #=============================================================================== -Battle::AI::Handlers::MoveEffectScore.add("FleeFromBattle", - proc { |score, move, user, target, ai, battle| - next 0 if battle.trainerBattle? +Battle::AI::Handlers::MoveFailureCheck.add("FleeFromBattle", + proc { |move, user, target, ai, battle| + next true if battle.pbCanRun?(user.index) } ) +Battle::AI::Handlers::MoveFailureCheck.add("SwitchOutUserStatusMove", + proc { |move, user, target, ai, battle| + if user.wild? + next true if !battle.pbCanRun?(user.index) + else + next true if !battle.pbCanChooseNonActive?(user.index) + end + } +) Battle::AI::Handlers::MoveEffectScore.add("SwitchOutUserStatusMove", proc { |score, move, user, target, ai, battle| - if !battle.pbCanChooseNonActive?(user.index) || - battle.pbTeamAbleNonActiveCount(user.index) > 1 # Don't switch in ace - score -= 100 + if battle.pbTeamAbleNonActiveCount(user.index) > 1 # Don't switch in ace + score -= 60 else score += 40 if user.effects[PBEffects::Confusion] > 0 total = 0 @@ -41,6 +49,17 @@ Battle::AI::Handlers::MoveEffectScore.add("SwitchOutUserDamagingMove", } ) +Battle::AI::Handlers::MoveFailureCheck.add("LowerTargetAtkSpAtk1SwitchOutUser", + proc { |move, user, target, ai, battle| + will_fail = true + (move.move.statDown.length / 2).times do |i| + next if !target.battler.pbCanLowerStatStage?(move.move.statDown[i * 2], user.battler, move.move) + will_fail = false + break + end + next will_fail + } +) Battle::AI::Handlers::MoveEffectScore.add("LowerTargetAtkSpAtk1SwitchOutUser", proc { |score, move, user, target, ai, battle| avg = target.stages[:ATTACK] * 10 @@ -50,6 +69,11 @@ Battle::AI::Handlers::MoveEffectScore.add("LowerTargetAtkSpAtk1SwitchOutUser", } ) +Battle::AI::Handlers::MoveFailureCheck.add("SwitchOutUserPassOnEffects", + proc { |move, user, target, ai, battle| + next true if !battle.pbCanChooseNonActive?(user.index) + } +) Battle::AI::Handlers::MoveEffectScore.add("SwitchOutUserPassOnEffects", proc { |score, move, user, target, ai, battle| if battle.pbCanChooseNonActive?(user.index) @@ -76,23 +100,28 @@ Battle::AI::Handlers::MoveEffectScore.add("SwitchOutUserPassOnEffects", } ) +Battle::AI::Handlers::MoveFailureCheck.add("SwitchOutTargetStatusMove", + proc { |move, user, target, ai, battle| + next true if target.has_active_ability?(:SUCTIONCUPS) || + target.effects[PBEffects::Ingrain] + next true if !battle.canRun + next true if battle.wildBattle? && target.level > user.level + if battle.trainerBattle? + will_fail = true + battle.eachInTeamFromBattlerIndex(target.index) do |_pkmn, i| + next if !battle.pbCanSwitchLax?(target.index, i) + will_fail = false + break + end + next will_fail + end + } +) Battle::AI::Handlers::MoveEffectScore.add("SwitchOutTargetStatusMove", proc { |score, move, user, target, ai, battle| - if target.effects[PBEffects::Ingrain] || - target.has_active_ability?(:SUCTIONCUPS) - score -= 90 - else - ch = 0 - battle.pbParty(target.index).each_with_index do |pkmn, i| - ch += 1 if battle.pbCanSwitchLax?(target.index, i) - end - score -= 90 if ch == 0 - end - if score > 20 - score += 50 if target.pbOwnSide.effects[PBEffects::Spikes] > 0 - score += 50 if target.pbOwnSide.effects[PBEffects::ToxicSpikes] > 0 - score += 50 if target.pbOwnSide.effects[PBEffects::StealthRock] - end + score += 20 if target.pbOwnSide.effects[PBEffects::Spikes] > 0 + score += 20 if target.pbOwnSide.effects[PBEffects::ToxicSpikes] > 0 + score += 20 if target.pbOwnSide.effects[PBEffects::StealthRock] next score } ) @@ -101,9 +130,9 @@ Battle::AI::Handlers::MoveEffectScore.add("SwitchOutTargetDamagingMove", proc { |score, move, user, target, ai, battle| if !target.effects[PBEffects::Ingrain] && !target.has_active_ability?(:SUCTIONCUPS) - score += 40 if target.pbOwnSide.effects[PBEffects::Spikes] > 0 - score += 40 if target.pbOwnSide.effects[PBEffects::ToxicSpikes] > 0 - score += 40 if target.pbOwnSide.effects[PBEffects::StealthRock] + score += 20 if target.pbOwnSide.effects[PBEffects::Spikes] > 0 + score += 20 if target.pbOwnSide.effects[PBEffects::ToxicSpikes] > 0 + score += 20 if target.pbOwnSide.effects[PBEffects::StealthRock] end next score } @@ -119,25 +148,35 @@ Battle::AI::Handlers::MoveBasePower.add("BindTargetDoublePowerIfTargetUnderwater proc { |power, move, user, target, ai, battle| next move.pbModifyDamage(power, user.battler, target.battler) } -} +) Battle::AI::Handlers::MoveEffectScore.add("BindTargetDoublePowerIfTargetUnderwater", proc { |score, move, user, target, ai, battle| next score + 40 if target.effects[PBEffects::Trapping] == 0 } ) -Battle::AI::Handlers::MoveEffectScore.add("TrapTargetInBattle", - proc { |score, move, user, target, ai, battle| - next 0 if target.effects[PBEffects::MeanLook] >= 0 +Battle::AI::Handlers::MoveFailureCheck.add("TrapTargetInBattle", + proc { |move, user, target, ai, battle| + if move.statusMove? + next true if target.effects[PBEffects::MeanLook] >= 0 + next true if Settings::MORE_TYPE_EFFECTS && target.has_type?(:GHOST) + end } ) +Battle::AI::Handlers::MoveFailureCheck.add("TrapTargetInBattle", + proc { |move, user, target, ai, battle| + if move.statusMove? + next true if target.effects[PBEffects::Octolock] >= 0 + next true if Settings::MORE_TYPE_EFFECTS && target.has_type?(:GHOST) + end + } +) Battle::AI::Handlers::MoveEffectScore.add("TrapTargetInBattleLowerTargetDefSpDef1EachTurn", proc { |score, move, user, target, ai, battle| - next 0 if target.effects[PBEffects::Octolock] >= 0 score += 30 if !target.battler.trappedInBattle? - score -= 100 if !target.battler.pbCanLowerStatStage?(:DEFENSE, user.battler, move.move) && - !target.battler.pbCanLowerStatStage?(:SPECIAL_DEFENSE, user.battler, move.move) + score -= 50 if !target.battler.pbCanLowerStatStage?(:DEFENSE, user.battler, move.move) && + !target.battler.pbCanLowerStatStage?(:SPECIAL_DEFENSE, user.battler, move.move) next score } ) @@ -151,7 +190,11 @@ Battle::AI::Handlers::MoveEffectScore.add("TrapUserAndTargetInBattle", } ) -# TrapAllBattlersInBattleForOneTurn +Battle::AI::Handlers::MoveFailureCheck.add("TrapAllBattlersInBattleForOneTurn", + proc { |move, user, target, ai, battle| + next true if battle.field.effects[PBEffects::FairyLock] > 0 + } +) # PursueSwitchingFoe @@ -164,7 +207,7 @@ Battle::AI::Handlers::MoveEffectScore.add("UsedAfterUserTakesPhysicalDamage", hasPhysicalAttack = true break end - score -= 80 if !hasPhysicalAttack + score -= 50 if !hasPhysicalAttack end next score } @@ -186,20 +229,24 @@ Battle::AI::Handlers::MoveEffectScore.add("UsedAfterAllyRoundWithDoublePower", # TargetActsLast +Battle::AI::Handlers::MoveFailureCheck.add("TargetUsesItsLastUsedMoveAgain", + proc { |move, user, target, ai, battle| + next true if !target.battler.lastRegularMoveUsed || + !target.battler.pbHasMove?(target.battler.lastRegularMoveUsed) + next true if target.usingMultiTurnAttack? + next true if move.move.moveBlacklist.include?(GameData::Move.get(target.battler.lastRegularMoveUsed).function_code) + idxMove = -1 + target.battler.eachMoveWithIndex do |m, i| + idxMove = i if m.id == target.battler.lastRegularMoveUsed + end + next true if target.battler.moves[idxMove].pp == 0 && target.battler.moves[idxMove].total_pp > 0 + } +) Battle::AI::Handlers::MoveEffectScore.add("TargetUsesItsLastUsedMoveAgain", proc { |score, move, user, target, ai, battle| - if ai.trainer.medium_skill? - if !target.battler.lastRegularMoveUsed || - !target.battler.pbHasMove?(target.battler.lastRegularMoveUsed) || - target.battler.usingMultiTurnAttack? - score -= 90 - else - # Without lots of code here to determine good/bad moves and relative - # speeds, using this move is likely to just be a waste of a turn - score -= 50 - end - end - next score + # Without lots of code here to determine good/bad moves and relative + # speeds, using this move is likely to just be a waste of a turn + next score - 50 } ) @@ -224,56 +271,91 @@ Battle::AI::Handlers::MoveEffectScore.add("LowerPPOfTargetLastMoveBy3", } ) +Battle::AI::Handlers::MoveFailureCheck.add("LowerPPOfTargetLastMoveBy4", + proc { |move, user, target, ai, battle| + last_move = target.battler.pbGetMoveWithID(target.battler.lastRegularMoveUsed) + next true if !last_move || last_move.pp == 0 || last_move.total_pp <= 0 + } +) Battle::AI::Handlers::MoveEffectScore.add("LowerPPOfTargetLastMoveBy4", proc { |score, move, user, target, ai, battle| next score - 40 } ) -Battle::AI::Handlers::MoveEffectScore.add("DisableTargetLastMoveUsed", - proc { |score, move, user, target, ai, battle| - next 0 if target.effects[PBEffects::Disable] > 0 +Battle::AI::Handlers::MoveFailureCheck.add("DisableTargetLastMoveUsed", + proc { |move, user, target, ai, battle| + next true if target.effects[PBEffects::Disable] > 0 || !target.battler.lastRegularMoveUsed + next true if move.move.pbMoveFailedAromaVeil?(user.battler, target.battler, false) + will_fail = true + target.battler.eachMove do |m| + next if m.id != target.battler.lastRegularMoveUsed + next if m.pp == 0 && m.total_pp > 0 + will_fail = false + break + end + next will_fail } ) +Battle::AI::Handlers::MoveFailureCheck.add("DisableTargetUsingSameMoveConsecutively", + proc { |move, user, target, ai, battle| + next true if target.effects[PBEffects::Torment] + next true if move.move.pbMoveFailedAromaVeil?(user.battler, target.battler, false) + } +) Battle::AI::Handlers::MoveEffectScore.add("DisableTargetUsingSameMoveConsecutively", proc { |score, move, user, target, ai, battle| next 0 if target.effects[PBEffects::Torment] } ) +Battle::AI::Handlers::MoveFailureCheck.add("DisableTargetUsingDifferentMove", + proc { |move, user, target, ai, battle| + next true if target.effects[PBEffects::Encore] > 0 + next true if !target.battler.lastRegularMoveUsed || + move.move.moveBlacklist.include?(GameData::Move.get(target.battler.lastRegularMoveUsed).function_code) + next true if target.effects[PBEffects::ShellTrap] + next true if move.move.pbMoveFailedAromaVeil?(user.battler, target.battler, false) + will_fail = true + target.battler.eachMove do |m| + next if m.id != target.battler.lastRegularMoveUsed + next if m.pp == 0 && m.total_pp > 0 + will_fail = false + break + end + next will_fail + } +) Battle::AI::Handlers::MoveEffectScore.add("DisableTargetUsingDifferentMove", proc { |score, move, user, target, ai, battle| - if target.effects[PBEffects::Encore] > 0 - score -= 90 - elsif user.faster_than?(target) - if target.battler.lastRegularMoveUsed - moveData = GameData::Move.get(target.battler.lastRegularMoveUsed) - if moveData.category == 2 && # Status move - [:User, :BothSides].include?(moveData.target) - score += 60 - elsif moveData.category != 2 && # Damaging move - moveData.target == :NearOther && - Effectiveness.ineffective?(user.effectiveness_of_type_against_battler(moveData.type, target)) - score += 60 - end - else - score -= 90 + if user.faster_than?(target) + moveData = GameData::Move.get(target.battler.lastRegularMoveUsed) + if moveData.category == 2 && # Status move + [:User, :BothSides].include?(moveData.target) + score += 60 + elsif moveData.category != 2 && # Damaging move + moveData.target == :NearOther && + Effectiveness.ineffective?(user.effectiveness_of_type_against_battler(moveData.type, target)) + score += 60 end end next score } ) -Battle::AI::Handlers::MoveEffectScore.add("DisableTargetStatusMoves", - proc { |score, move, user, target, ai, battle| - next 0 if target.effects[PBEffects::Taunt] > 0 +Battle::AI::Handlers::MoveFailureCheck.add("DisableTargetStatusMoves", + proc { |move, user, target, ai, battle| + next true if target.effects[PBEffects::Taunt] > 0 + next true if move.move.pbMoveFailedAromaVeil?(user.battler, target.battler, false) + next true if Settings::MECHANICS_GENERATION >= 6 && target.has_active_ability?(:OBLIVIOUS) } ) -Battle::AI::Handlers::MoveEffectScore.add("DisableTargetHealingMoves", - proc { |score, move, user, target, ai, battle| - next 0 if target.effects[PBEffects::HealBlock] > 0 +Battle::AI::Handlers::MoveFailureCheck.add("DisableTargetHealingMoves", + proc { |move, user, target, ai, battle| + next true if target.effects[PBEffects::HealBlock] > 0 + next true if move.move.pbMoveFailedAromaVeil?(user.battler, target.battler, false) } ) @@ -292,12 +374,17 @@ Battle::AI::Handlers::MoveEffectScore.add("DisableTargetSoundMoves", } ) -Battle::AI::Handlers::MoveEffectScore.add("DisableTargetMovesKnownByUser", - proc { |score, move, user, target, ai, battle| - next 0 if target.effects[PBEffects::Imprison] +Battle::AI::Handlers::MoveFailureCheck.add("DisableTargetMovesKnownByUser", + proc { |move, user, target, ai, battle| + next true if user.effects[PBEffects::Imprison] } ) +Battle::AI::Handlers::MoveFailureCheck.add("AllBattlersLoseHalfHPUserSkipsNextTurn", + proc { |move, user, target, ai, battle| + next true if battle.allBattlers.none? { |b| b.hp > 1 } + } +) Battle::AI::Handlers::MoveEffectScore.add("AllBattlersLoseHalfHPUserSkipsNextTurn", proc { |score, move, user, target, ai, battle| score += 20 # Shadow moves are more preferable @@ -307,7 +394,7 @@ Battle::AI::Handlers::MoveEffectScore.add("AllBattlersLoseHalfHPUserSkipsNextTur } ) -Battle::AI::Handlers::MoveEffectScore.add("AllBattlersLoseHalfHPUserSkipsNextTurn", +Battle::AI::Handlers::MoveEffectScore.add("UserLosesHalfHP", proc { |score, move, user, target, ai, battle| score += 20 # Shadow moves are more preferable score -= 40 @@ -315,33 +402,45 @@ Battle::AI::Handlers::MoveEffectScore.add("AllBattlersLoseHalfHPUserSkipsNextTur } ) +Battle::AI::Handlers::MoveFailureCheck.copy("StartSunWeather", + "StartShadowSkyWeather") Battle::AI::Handlers::MoveEffectScore.add("StartShadowSkyWeather", proc { |score, move, user, target, ai, battle| score += 20 # Shadow moves are more preferable if battle.pbCheckGlobalAbility(:AIRLOCK) || battle.pbCheckGlobalAbility(:CLOUDNINE) - score -= 90 - elsif battle.field.weather == :ShadowSky - score -= 90 + score -= 50 end next score } ) +Battle::AI::Handlers::MoveFailureCheck.add("RemoveAllScreens", + proc { |move, user, target, ai, battle| + will_fail = true + battle.sides.each do |side| + will_fail = false if side.effects[PBEffects::AuroraVeil] > 0 || + side.effects[PBEffects::Reflect] > 0 || + side.effects[PBEffects::LightScreen] > 0 || + side.effects[PBEffects::Safeguard] > 0 + end + next will_fail + } +) Battle::AI::Handlers::MoveEffectScore.add("RemoveAllScreens", proc { |score, move, user, target, ai, battle| score += 20 # Shadow moves are more preferable - if target.pbOwnSide.effects[PBEffects::AuroraVeil] > 0 || - target.pbOwnSide.effects[PBEffects::Reflect] > 0 || - target.pbOwnSide.effects[PBEffects::LightScreen] > 0 || - target.pbOwnSide.effects[PBEffects::Safeguard] > 0 + if user.pbOpposingSide.effects[PBEffects::AuroraVeil] > 0 || + user.pbOpposingSide.effects[PBEffects::Reflect] > 0 || + user.pbOpposingSide.effects[PBEffects::LightScreen] > 0 || + user.pbOpposingSide.effects[PBEffects::Safeguard] > 0 score += 30 - score -= 90 if user.pbOwnSide.effects[PBEffects::AuroraVeil] > 0 || - user.pbOwnSide.effects[PBEffects::Reflect] > 0 || - user.pbOwnSide.effects[PBEffects::LightScreen] > 0 || - user.pbOwnSide.effects[PBEffects::Safeguard] > 0 - else - next 0 + end + if user.pbOwnSide.effects[PBEffects::AuroraVeil] > 0 || + user.pbOwnSide.effects[PBEffects::Reflect] > 0 || + user.pbOwnSide.effects[PBEffects::LightScreen] > 0 || + user.pbOwnSide.effects[PBEffects::Safeguard] > 0 + score -= 70 end next score } diff --git a/Data/Scripts/011_Battle/005_AI/101_AITrainer.rb b/Data/Scripts/011_Battle/005_AI/101_AITrainer.rb index 9b556d6bb..db0deba7a 100644 --- a/Data/Scripts/011_Battle/005_AI/101_AITrainer.rb +++ b/Data/Scripts/011_Battle/005_AI/101_AITrainer.rb @@ -10,6 +10,7 @@ # the trainer's base money value. # # Skill flags: +# PredictMoveFailure #=============================================================================== class Battle::AI::AITrainer attr_reader :side, :trainer_index @@ -27,9 +28,9 @@ class Battle::AI::AITrainer end def set_up_skill - return if !@trainer - @skill = @trainer.skill_level + @skill = @trainer.skill_level if @trainer # TODO: Add skill flags depending on @skill. + @skill_flags.push("PredictMoveFailure") if @skill > 0 end def has_skill_flag?(flag) diff --git a/Data/Scripts/011_Battle/005_AI/103_AIMove.rb b/Data/Scripts/011_Battle/005_AI/103_AIMove.rb index 2c07de438..bf5cb6663 100644 --- a/Data/Scripts/011_Battle/005_AI/103_AIMove.rb +++ b/Data/Scripts/011_Battle/005_AI/103_AIMove.rb @@ -65,6 +65,13 @@ class Battle::AI::AIMove #============================================================================= + def rough_priority(user) + # TODO: More calculations here. + return @move.priority + end + + #============================================================================= + def type; return @move.type; end def rough_type @@ -486,23 +493,23 @@ class Battle::AI::AIMove crit_stage = 0 # Ability effects that alter critical hit rate if user.ability_active? - crit_stage = BattleHandlers.triggerCriticalCalcUserAbility(user_battler.ability, + crit_stage = Battle::AbilityEffects.triggerCriticalCalcFromUser(user_battler.ability, user_battler, target_battler, crit_stage) return -1 if crit_stage < 0 end if !mold_breaker && target.ability_active? - crit_stage = BattleHandlers.triggerCriticalCalcTargetAbility(target_battler.ability, + crit_stage = Battle::AbilityEffects.triggerCriticalCalcFromTarget(target_battler.ability, user_battler, target_battler, crit_stage) return -1 if crit_stage < 0 end # Item effects that alter critical hit rate if user.item_active? - crit_stage = BattleHandlers.triggerCriticalCalcUserItem(user_battler.item, + crit_stage = Battle::ItemEffects.triggerCriticalCalcFromUser(user_battler.item, user_battler, target_battler, crit_stage) return -1 if crit_stage < 0 end if target.item_active? - crit_stage = BattleHandlers.triggerCriticalCalcTargetItem(user_battler.item, + crit_stage = Battle::ItemEffects.triggerCriticalCalcFromTarget(user_battler.item, user_battler, target_battler, crit_stage) return -1 if crit_stage < 0 end diff --git a/Data/Scripts/014_Pokemon/001_Pokemon-related/002_ShadowPokemon_Other.rb b/Data/Scripts/014_Pokemon/001_Pokemon-related/002_ShadowPokemon_Other.rb index 86a96c480..49a2f355a 100644 --- a/Data/Scripts/014_Pokemon/001_Pokemon-related/002_ShadowPokemon_Other.rb +++ b/Data/Scripts/014_Pokemon/001_Pokemon-related/002_ShadowPokemon_Other.rb @@ -399,6 +399,21 @@ end # (Shadow Shed) #=============================================================================== class Battle::Move::RemoveAllScreens < Battle::Move + def pbMoveFailed?(user, targets) + will_fail = true + @battle.sides.each do |side| + will_fail = false if side.effects[PBEffects::AuroraVeil] > 0 || + side.effects[PBEffects::Reflect] > 0 || + side.effects[PBEffects::LightScreen] > 0 || + side.effects[PBEffects::Safeguard] > 0 + end + if will_fail + @battle.pbDisplay(_INTL("But it failed!")) + return true + end + return false + end + def pbEffectGeneral(user) @battle.sides.each do |i| i.effects[PBEffects::AuroraVeil] = 0 diff --git a/PBS/Gen 8/moves.txt b/PBS/Gen 8/moves.txt index 228ed8109..37e566254 100644 --- a/PBS/Gen 8/moves.txt +++ b/PBS/Gen 8/moves.txt @@ -2331,7 +2331,7 @@ Category = Status Accuracy = 0 TotalPP = 10 Target = AllAllies -FunctionCode = RaiseUserAndAlliesAtkDef1 +FunctionCode = RaiseAlliesAtkDef1 Flags = CanMirrorMove Description = The user properly coaches its ally Pokémon, boosting their Attack and Defense stats. #------------------------------- diff --git a/PBS/moves.txt b/PBS/moves.txt index 228ed8109..37e566254 100644 --- a/PBS/moves.txt +++ b/PBS/moves.txt @@ -2331,7 +2331,7 @@ Category = Status Accuracy = 0 TotalPP = 10 Target = AllAllies -FunctionCode = RaiseUserAndAlliesAtkDef1 +FunctionCode = RaiseAlliesAtkDef1 Flags = CanMirrorMove Description = The user properly coaches its ally Pokémon, boosting their Attack and Defense stats. #-------------------------------