From 7ace4c528984b9965619463892868c5dd61ab3a6 Mon Sep 17 00:00:00 2001 From: Maruno17 Date: Sat, 10 Dec 2022 21:59:44 +0000 Subject: [PATCH] AI rewrites of ability-changing function codes, OHKO codes and binding codes --- .../005_AI/020_AI_MoveEffectScores_Generic.rb | 301 ++++++++++++++++++ .../053_AI_MoveHandlers_BattlerOther.rb | 107 +++++-- .../054_AI_MoveHandlers_MoveAttributes.rb | 44 ++- .../005_AI/055_AI_MoveHandlers_MultiHit.rb | 2 +- .../059_AI_MoveHandlers_SwitchingActing.rb | 48 ++- .../070_AI_MoveHandlers_GeneralModifiers.rb | 3 + 6 files changed, 471 insertions(+), 34 deletions(-) diff --git a/Data/Scripts/011_Battle/005_AI/020_AI_MoveEffectScores_Generic.rb b/Data/Scripts/011_Battle/005_AI/020_AI_MoveEffectScores_Generic.rb index e3e240d0f..5431e1c98 100644 --- a/Data/Scripts/011_Battle/005_AI/020_AI_MoveEffectScores_Generic.rb +++ b/Data/Scripts/011_Battle/005_AI/020_AI_MoveEffectScores_Generic.rb @@ -292,6 +292,16 @@ class Battle::AI score += 15 * inc_mult break end + # TODO: Prefer if the user is able to cause flinching (moves that flinch, + # or has King's Rock/Stench). + # Prefer if the user has Electro Ball or Power Trip/Stored Power + moves_that_prefer_high_speed = [ + "PowerHigherWithUserFasterThanTarget", + "PowerHigherWithUserPositiveStatStages" + ] + if @user.check_for_move { |m| moves_that_prefer_high_speed.include?(m.function) } + score += 8 * inc_mult + end # Don't prefer if any foe has Gyro Ball each_foe_battler(@user.side) do |b, i| next if !b.check_for_move { |m| m.function == "PowerHigherWithTargetFasterThanUser" } @@ -956,4 +966,295 @@ class Battle::AI end return ret end + + #============================================================================= + # Returns a value indicating how beneficial the given ability will be to the + # given battler if it has it. + # Return values are typically between -10 and +10. 0 is indifferent, positive + # values mean the battler benefits, negative values mean the battler suffers. + #============================================================================= + # These values are taken from the Complete-Fire-Red-Upgrade decomp here: + # https://github.com/Skeli789/Complete-Fire-Red-Upgrade/blob/f7f35becbd111c7e936b126f6328fc52d9af68c8/src/ability_battle_effects.c#L41 + BASE_ABILITY_RATINGS = { + :ADAPTABILITY => 8, + :AERILATE => 8, + :AFTERMATH => 5, + :AIRLOCK => 5, + :ANALYTIC => 5, + :ANGERPOINT => 4, + :ANTICIPATION => 2, + :ARENATRAP => 9, + :AROMAVEIL => 3, +# :ASONECHILLINGNEIGH => 0, +# :ASONEGRIMNEIGH => 0, + :AURABREAK => 3, + :BADDREAMS => 4, +# :BALLFETCH => 0, +# :BATTERY => 0, + :BATTLEARMOR => 2, + :BATTLEBOND => 6, + :BEASTBOOST => 7, + :BERSERK => 5, + :BIGPECKS => 1, + :BLAZE => 5, + :BULLETPROOF => 7, + :CHEEKPOUCH => 4, +# :CHILLINGNEIGH => 0, + :CHLOROPHYLL => 6, + :CLEARBODY => 4, + :CLOUDNINE => 5, + :COLORCHANGE => 2, + :COMATOSE => 6, + :COMPETITIVE => 5, + :COMPOUNDEYES => 7, + :CONTRARY => 8, + :CORROSION => 5, + :COTTONDOWN => 3, +# :CURIOUSMEDICINE => 0, + :CURSEDBODY => 4, + :CUTECHARM => 2, + :DAMP => 2, + :DANCER => 5, + :DARKAURA => 6, + :DAUNTLESSSHIELD => 3, + :DAZZLING => 5, + :DEFEATIST => -1, + :DEFIANT => 5, + :DELTASTREAM => 10, + :DESOLATELAND => 10, + :DISGUISE => 8, + :DOWNLOAD => 7, + :DRAGONSMAW => 8, + :DRIZZLE => 9, + :DROUGHT => 9, + :DRYSKIN => 6, + :EARLYBIRD => 4, + :EFFECTSPORE => 4, + :ELECTRICSURGE => 8, + :EMERGENCYEXIT => 3, + :FAIRYAURA => 6, + :FILTER => 6, + :FLAMEBODY => 4, + :FLAREBOOST => 5, + :FLASHFIRE => 6, + :FLOWERGIFT => 4, +# :FLOWERVEIL => 0, + :FLUFFY => 5, + :FORECAST => 6, + :FOREWARN => 2, +# :FRIENDGUARD => 0, + :FRISK => 3, + :FULLMETALBODY => 4, + :FURCOAT => 7, + :GALEWINGS => 6, + :GALVANIZE => 8, + :GLUTTONY => 3, + :GOOEY => 5, + :GORILLATACTICS => 4, + :GRASSPELT => 2, + :GRASSYSURGE => 8, +# :GRIMNEIGH => 0, + :GULPMISSLE => 3, + :GUTS => 6, + :HARVEST => 5, +# :HEALER => 0, + :HEATPROOF => 5, + :HEAVYMETAL => -1, +# :HONEYGATHER => 0, + :HUGEPOWER => 10, + :HUNGERSWITCH => 2, + :HUSTLE => 7, + :HYDRATION => 4, + :HYPERCUTTER => 3, + :ICEBODY => 3, + :ICEFACE => 4, + :ICESCALES => 7, +# :ILLUMINATE => 0, + :ILLUSION => 8, + :IMMUNITY => 4, + :IMPOSTER => 9, + :INFILTRATOR => 6, + :INNARDSOUT => 5, + :INNERFOCUS => 2, + :INSOMNIA => 4, + :INTIMIDATE => 7, + :INTREPIDSWORD => 3, + :IRONBARBS => 6, + :IRONFIST => 6, + :JUSTIFIED => 4, + :KEENEYE => 1, + :KLUTZ => -1, + :LEAFGUARD => 2, + :LEVITATE => 7, + :LIBERO => 8, + :LIGHTMETAL => 2, + :LIGHTNINGROD => 7, + :LIMBER => 3, + :LIQUIDOOZE => 3, + :LIQUIDVOICE => 5, + :LONGREACH => 3, + :MAGICBOUNCE => 9, + :MAGICGUARD => 9, + :MAGICIAN => 3, + :MAGMAARMOR => 1, + :MAGNETPULL => 9, + :MARVELSCALE => 5, + :MEGALAUNCHER => 7, + :MERCILESS => 4, + :MIMICRY => 2, +# :MINUS => 0, + :MIRRORARMOR => 6, + :MISTYSURGE => 8, + :MOLDBREAKER => 7, + :MOODY => 10, + :MOTORDRIVE => 6, + :MOXIE => 7, + :MULTISCALE => 8, + :MULTITYPE => 8, + :MUMMY => 5, + :NATURALCURE => 7, + :NEUROFORCE => 6, + :NEUTRALIZINGGAS => 5, + :NOGUARD => 8, + :NORMALIZE => -1, + :OBLIVIOUS => 2, + :OVERCOAT => 5, + :OVERGROW => 5, + :OWNTEMPO => 3, + :PARENTALBOND => 10, + :PASTELVEIL => 4, + :PERISHBODY => -1, + :PICKPOCKET => 3, + :PICKUP => 1, + :PIXILATE => 8, +# :PLUS => 0, + :POISONHEAL => 8, + :POISONPOINT => 4, + :POISONTOUCH => 4, + :POWERCONSTRUCT => 10, +# :POWEROFALCHEMY => 0, + :POWERSPOT => 2, + :PRANKSTER => 8, + :PRESSURE => 5, + :PRIMORDIALSEA => 10, + :PRISMARMOR => 6, + :PROPELLORTAIL => 2, + :PROTEAN => 8, + :PSYCHICSURGE => 8, + :PUNKROCK => 2, + :PUREPOWER => 10, + :QUEENLYMAJESTY => 6, +# :QUICKDRAW => 0, + :QUICKFEET => 5, + :RAINDISH => 3, + :RATTLED => 3, +# :RECEIVER => 0, + :RECKLESS => 6, + :REFRIGERATE => 8, + :REGENERATOR => 8, + :RIPEN => 4, + :RIVALRY => 1, + :RKSSYSTEM => 8, + :ROCKHEAD => 5, + :ROUGHSKIN => 6, +# :RUNAWAY => 0, + :SANDFORCE => 4, + :SANDRUSH => 6, + :SANDSPIT => 5, + :SANDSTREAM => 9, + :SANDVEIL => 3, + :SAPSIPPER => 7, + :SCHOOLING => 6, + :SCRAPPY => 6, + :SCREENCLEANER => 3, + :SERENEGRACE => 8, + :SHADOWSHIELD => 8, + :SHADOWTAG => 10, + :SHEDSKIN => 7, + :SHEERFORCE => 8, + :SHELLARMOR => 2, + :SHIELDDUST => 5, + :SHIELDSDOWN => 6, + :SIMPLE => 8, + :SKILLLINK => 7, + :SLOWSTART => -2, + :SLUSHRUSH => 5, + :SNIPER => 3, + :SNOWCLOAK => 3, + :SNOWWARNING => 8, + :SOLARPOWER => 3, + :SOLIDROCK => 6, + :SOULHEART => 7, + :SOUNDPROOF => 4, + :SPEEDBOOST => 9, + :STAKEOUT => 6, + :STALL => -1, + :STALWART => 2, + :STAMINA => 6, + :STANCECHANGE => 10, + :STATIC => 4, + :STEADFAST => 2, + :STEAMENGINE => 3, + :STEELWORKER => 6, + :STEELYSPIRIT => 2, + :STENCH => 1, + :STICKYHOLD => 3, + :STORMDRAIN => 7, + :STRONGJAW => 6, + :STURDY => 6, + :SUCTIONCUPS => 2, + :SUPERLUCK => 3, + :SURGESURFER => 4, + :SWARM => 5, + :SWEETVEIL => 4, + :SWIFTSWIM => 6, +# :SYMBIOSIS => 0, + :SYNCHRONIZE => 4, + :TANGLEDFEET => 2, + :TANGLINGHAIR => 5, + :TECHNICIAN => 8, +# :TELEPATHY => 0, + :TERAVOLT => 7, + :THICKFAT => 7, + :TINTEDLENS => 7, + :TORRENT => 5, + :TOUGHCLAWS => 7, + :TOXICBOOST => 6, + :TRACE => 6, + :TRANSISTOR => 8, + :TRIAGE => 7, + :TRUANT => -2, + :TURBOBLAZE => 7, + :UNAWARE => 6, + :UNBURDEN => 7, + :UNNERVE => 3, +# :UNSEENFIST => 0, + :VICTORYSTAR => 6, + :VITALSPIRIT => 4, + :VOLTABSORB => 7, + :WANDERINGSPIRIT => 2, + :WATERABSORB => 7, + :WATERBUBBLE => 8, + :WATERCOMPACTION => 4, + :WATERVEIL => 4, + :WEAKARMOR => 2, + :WHITESMOKE => 4, + :WIMPOUT => 3, + :WONDERGUARD => 10, + :WONDERSKIN => 4, + :ZENMODE => -1 + } + + # TODO: This method assumes the ability isn't being negated. Should it return + # 0 if it is? The calculations that call this method separately check + # for it being negated, because they need to do something special in + # that case, so I think it's okay for this method to ignore negation. + def battler_wants_ability?(battler, ability = :NONE) + ability = ability.id if !ability.is_a?(Symbol) && ability.respond_to?("id") + # TODO: Ideally replace the above list of ratings with context-sensitive + # calculations. Should they all go in this method, or should there be + # more handlers for each ability? + ret = BASE_ABILITY_RATINGS[ability] || 0 + return ret + end end 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 d9b82fdfc..ec01821e9 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 @@ -916,7 +916,7 @@ Battle::AI::Handlers::MoveFailureCheck.add("UserLosesFireType", ) #=============================================================================== -# TODO: Review score modifiers. +# #=============================================================================== Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("SetTargetAbilityToSimple", proc { |move, user, target, ai, battle| @@ -924,9 +924,23 @@ Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("SetTargetAbilityToSimpl next move.move.pbFailsAgainstTarget?(user.battler, target.battler, false) } ) +Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("SetTargetAbilityToSimple", + proc { |score, move, user, target, ai, battle| + next Battle::AI::MOVE_USELESS_SCORE if !target.ability_active? + old_ability_rating = ai.battler_wants_ability?(target, target.ability_id) + new_ability_rating = ai.battler_wants_ability?(target, :SIMPLE) + side_mult = (target.opposes?(user)) ? 1 : -1 + if old_ability_rating > new_ability_rating + score += 4 * side_mult * [old_ability_rating - new_ability_rating, 3].max + elsif old_ability_rating < new_ability_rating + score -= 4 * side_mult * [new_ability_rating - old_ability_rating, 3].max + end + next score + } +) #=============================================================================== -# TODO: Review score modifiers. +# #=============================================================================== Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("SetTargetAbilityToInsomnia", proc { |move, user, target, ai, battle| @@ -934,9 +948,23 @@ Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("SetTargetAbilityToInsom next move.move.pbFailsAgainstTarget?(user.battler, target.battler, false) } ) +Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("SetTargetAbilityToInsomnia", + proc { |score, move, user, target, ai, battle| + next Battle::AI::MOVE_USELESS_SCORE if !target.ability_active? + old_ability_rating = ai.battler_wants_ability?(target, target.ability_id) + new_ability_rating = ai.battler_wants_ability?(target, :INSOMNIA) + side_mult = (target.opposes?(user)) ? 1 : -1 + if old_ability_rating > new_ability_rating + score += 4 * side_mult * [old_ability_rating - new_ability_rating, 3].max + elsif old_ability_rating < new_ability_rating + score -= 4 * side_mult * [new_ability_rating - old_ability_rating, 3].max + end + next score + } +) #=============================================================================== -# TODO: Review score modifiers. +# #=============================================================================== Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("SetUserAbilityToTargetAbility", proc { |move, user, target, ai, battle| @@ -946,16 +974,20 @@ Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("SetUserAbilityToTargetA ) Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("SetUserAbilityToTargetAbility", proc { |score, move, user, target, ai, battle| - score -= 40 # don't prefer this move - if ai.trainer.medium_skill? && user.opposes?(target) - score -= 50 if [:TRUANT, :SLOWSTART].include?(target.ability_id) + next Battle::AI::MOVE_USELESS_SCORE if !user.ability_active? + old_ability_rating = ai.battler_wants_ability?(user, user.ability_id) + new_ability_rating = ai.battler_wants_ability?(user, target.ability_id) + if old_ability_rating > new_ability_rating + score += 4 * [old_ability_rating - new_ability_rating, 3].max + elsif old_ability_rating < new_ability_rating + score -= 4 * [new_ability_rating - old_ability_rating, 3].max end next score } ) #=============================================================================== -# TODO: Review score modifiers. +# #=============================================================================== Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("SetTargetAbilityToUserAbility", proc { |move, user, target, ai, battle| @@ -967,52 +999,87 @@ Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("SetTargetAbilityToUserA ) Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("SetTargetAbilityToUserAbility", proc { |score, move, user, target, ai, battle| - score -= 40 # don't prefer this move - if ai.trainer.medium_skill? && user.opposes?(target) - score += 90 if [:TRUANT, :SLOWSTART].include?(user.ability_id) + next Battle::AI::MOVE_USELESS_SCORE if !target.ability_active? + old_ability_rating = ai.battler_wants_ability?(target, target.ability_id) + new_ability_rating = ai.battler_wants_ability?(target, user.ability_id) + side_mult = (target.opposes?(user)) ? 1 : -1 + if old_ability_rating > new_ability_rating + score += 4 * side_mult * [old_ability_rating - new_ability_rating, 3].max + elsif old_ability_rating < new_ability_rating + score -= 4 * side_mult * [new_ability_rating - old_ability_rating, 3].max end next score } ) #=============================================================================== -# TODO: Review score modifiers. +# #=============================================================================== Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("UserTargetSwapAbilities", proc { |move, user, target, ai, battle| next true if !user.ability || user.battler.unstoppableAbility? || - user.ability_id == :WONDERGUARD + user.battler.ungainableAbility? || user.ability_id == :WONDERGUARD next move.move.pbFailsAgainstTarget?(user.battler, target.battler, false) } ) Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("UserTargetSwapAbilities", proc { |score, move, user, target, ai, battle| - score -= 40 # don't prefer this move - if ai.trainer.high_skill? && user.opposes?(target) - score -= 90 if [:TRUANT, :SLOWSTART].include?(target.ability_id) + next Battle::AI::MOVE_USELESS_SCORE if !user.ability_active? && !target.ability_active? + old_user_ability_rating = ai.battler_wants_ability?(user, user.ability_id) + new_user_ability_rating = ai.battler_wants_ability?(user, target.ability_id) + user_diff = new_user_ability_rating - old_user_ability_rating + user_diff = 0 if !user.ability_active? + old_target_ability_rating = ai.battler_wants_ability?(target, target.ability_id) + new_target_ability_rating = ai.battler_wants_ability?(target, user.ability_id) + target_diff = new_target_ability_rating - old_target_ability_rating + target_diff = 0 if !target.ability_active? + side_mult = (target.opposes?(user)) ? 1 : -1 + if user_diff > target_diff + score += 4 * side_mult * [user_diff - target_diff, 3].max + elsif target_diff < user_diff + score -= 4 * side_mult * [target_diff - user_diff, 3].max end next score } ) #=============================================================================== -# TODO: Review score modifiers. +# #=============================================================================== Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("NegateTargetAbility", proc { |move, user, target, ai, battle| next move.move.pbFailsAgainstTarget?(user.battler, target.battler, false) } ) +Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("NegateTargetAbility", + proc { |score, move, user, target, ai, battle| + target_ability_rating = ai.battler_wants_ability?(target, target.ability_id) + side_mult = (target.opposes?(user)) ? 1 : -1 + if target_ability_rating > 0 + score += 4 * side_mult * [target_ability_rating, 3].max + elsif target_ability_rating < 0 + score -= 4 * side_mult * [target_ability_rating.abs, 3].max + end + next score + } +) #=============================================================================== -# TODO: Review score modifiers. +# #=============================================================================== Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("NegateTargetAbilityIfTargetActed", proc { |score, move, user, target, ai, battle| next score if target.effects[PBEffects::Substitute] > 0 || target.effects[PBEffects::GastroAcid] next score if target.battler.unstoppableAbility? next score if user.faster_than?(target) - next score + 10 + target_ability_rating = ai.battler_wants_ability?(target, target.ability_id) + side_mult = (target.opposes?(user)) ? 1 : -1 + if target_ability_rating > 0 + score += 4 * side_mult * [target_ability_rating, 3].max + elsif target_ability_rating < 0 + score -= 4 * side_mult * [target_ability_rating.abs, 3].max + end + next score } ) @@ -1134,7 +1201,9 @@ Battle::AI::Handlers::MoveFailureCheck.add("StartGravity", ) Battle::AI::Handlers::MoveEffectScore.add("StartGravity", proc { |score, move, user, ai, battle| - # TODO: Gravity increases accuracy of all moves. Should this be considered? + # TODO: Gravity increases accuracy of all moves. Prefer if user/ally has low + # accuracy moves, don't prefer if foes have them. Should "low + # accuracy" mean anything below 85%? ai.each_battler do |b, i| # Prefer grounding airborne foes, don't prefer grounding airborne allies # Prefer making allies affected by terrain, don't prefer making foes 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 d62b933f6..390d7b07b 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 @@ -58,7 +58,7 @@ Battle::AI::Handlers::MoveBasePower.add("LowerTargetHPToUserHP", ) #=============================================================================== -# TODO: Review score modifiers. +# #=============================================================================== Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("OHKO", proc { |move, user, target, ai, battle| @@ -71,27 +71,44 @@ Battle::AI::Handlers::MoveBasePower.add("OHKO", next target.hp } ) +Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("OHKO", + proc { |score, move, user, target, ai, battle| + # Don't prefer if the target has less HP and user has a non-OHKO damaging move + if user.check_for_move { |m| !m.is_a?(Battle::Move::OHKO) && m.damagingMove? } + score -= 10 if target.hp <= target.totalhp / 2 + score -= 10 if target.hp <= target.totalhp / 4 + end + # TODO: Maybe predict dealt damage of all user's other moves, and score this + # move useless if another one can KO the target. Might also need to + # take into account whether those moves will fail. Might need to do + # this specially after all move scores are determined. + next score + } +) #=============================================================================== -# TODO: Review score modifiers. +# #=============================================================================== Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("OHKOIce", proc { |move, user, target, ai, battle| - next true if target.level > user.level - next true if !battle.moldBreaker && target.has_active_ability?(:STURDY) next true if target.has_type?(:ICE) + next Battle::AI::Handlers.move_will_fail_against_target?("OHKO", move, user, target, ai, battle) } ) Battle::AI::Handlers::MoveBasePower.copy("OHKO", "OHKOIce") +Battle::AI::Handlers::MoveEffectAgainstTargetScore.copy("OHKO", + "OHKOIce") #=============================================================================== -# TODO: Review score modifiers. +# #=============================================================================== Battle::AI::Handlers::MoveFailureAgainstTargetCheck.copy("OHKO", "OHKOHitsUndergroundTarget") Battle::AI::Handlers::MoveBasePower.copy("OHKO", "OHKOHitsUndergroundTarget") +Battle::AI::Handlers::MoveEffectAgainstTargetScore.copy("OHKO", + "OHKOHitsUndergroundTarget") #=============================================================================== # @@ -397,6 +414,8 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("DoublePowerIfTargetNotAc Battle::AI::Handlers::MoveEffectScore.add("EnsureNextCriticalHit", proc { |score, move, user, ai, battle| next Battle::AI::MOVE_USELESS_SCORE if user.effects[PBEffects::LaserFocus] > 0 + # TODO: Useless if user will already always critical hit ("AlwaysCriticalHit" + # or Lucky Chant/crit stage is +3/etc.). next score + 10 } ) @@ -517,6 +536,9 @@ Battle::AI::Handlers::MoveEffectScore.add("StartWeakenPhysicalDamageAgainstUserS # Doesn't stack with Aurora Veil next Battle::AI::MOVE_USELESS_SCORE if user.pbOwnSide.effects[PBEffects::AuroraVeil] > 0 # Don't prefer the lower the user's HP is + # TODO: Should this HP check exist? The effect can still be set up for + # allies. Maybe just don't prefer if there are no replacement mons + # left. if user.hp < user.totalhp / 2 score -= 40 * (0.75 - (user.hp.to_f / user.totalhp)) # -10 to -30 end @@ -543,6 +565,9 @@ Battle::AI::Handlers::MoveEffectScore.add("StartWeakenSpecialDamageAgainstUserSi # Doesn't stack with Aurora Veil next Battle::AI::MOVE_USELESS_SCORE if user.pbOwnSide.effects[PBEffects::AuroraVeil] > 0 # Don't prefer the lower the user's HP is + # TODO: Should this HP check exist? The effect can still be set up for + # allies. Maybe just don't prefer if there are no replacement mons + # left. if user.hp < user.totalhp / 2 score -= 40 * (0.75 - (user.hp.to_f / user.totalhp)) # -10 to -30 end @@ -571,6 +596,9 @@ Battle::AI::Handlers::MoveEffectScore.add("StartWeakenDamageAgainstUserSideIfHai next Battle::AI::MOVE_USELESS_SCORE if user.pbOwnSide.effects[PBEffects::Reflect] > 0 && user.pbOwnSide.effects[PBEffects::LightScreen] > 0 # Don't prefer the lower the user's HP is + # TODO: Should this HP check exist? The effect can still be set up for + # allies. Maybe just don't prefer if there are no replacement mons + # left. if user.hp < user.totalhp / 2 score -= 40 * (0.75 - (user.hp.to_f / user.totalhp)) # -10 to -30 end @@ -893,14 +921,18 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("EnsureNextMoveAlwaysHits next Battle::AI::MOVE_USELESS_SCORE if user.has_active_ability?(:NOGUARD) || target.has_active_ability?(:NOGUARD) next Battle::AI::MOVE_USELESS_SCORE if target.effects[PBEffects::Telekinesis] > 0 # Prefer if the user knows moves with low accuracy + # TODO: This isn't the correct use of check_for_move, since it should just + # loop through them instead. user.check_for_move do |m| next if target.effects[PBEffects::Minimize] && m.tramplesMinimize? && Settings::MECHANICS_GENERATION >= 6 # TODO: There are other effects that make a move certain to hit. Account - # for those as well, or is that too micro-managey? + # for those as well. Score this move useless if no moves would + # benefit from locking on. acc = m.accuracy acc = m.pbBaseAccuracy(user.battler, target.battler) if ai.trainer.medium_skill? score += 4 if acc < 90 && acc != 0 score += 4 if acc <= 50 && acc != 0 + # TODO: Prefer more if m is a OHKO move. end # Not worth it if the user or the target is at low HP score -= 10 if user.hp < user.totalhp / 2 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 98e58c3f5..5a7144186 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 @@ -260,7 +260,7 @@ Battle::AI::Handlers::MoveBasePower.add("TwoTurnAttackOneTurnInSun", ) Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("TwoTurnAttackOneTurnInSun", proc { |score, move, user, target, ai, battle| - # Sunny weather this a 1 turn move, the same as a move with no effect + # In sunny weather this a 1 turn move, the same as a move with no effect next score if [:Sun, :HarshSun].include?(user.battler.effectiveWeather) # Score for being a two turn attack next Battle::AI::Handlers.apply_move_effect_against_target_score("TwoTurnAttack", 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 8ae175be6..9b06b50ec 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 @@ -159,27 +159,59 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("SwitchOutTargetDamagingM ) #=============================================================================== -# TODO: Review score modifiers. +# #=============================================================================== Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("BindTarget", proc { |score, move, user, target, ai, battle| - next score + 40 if target.effects[PBEffects::Trapping] == 0 + next score if target.effects[PBEffects::Trapping] > 0 + next score if target.effects[PBEffects::Substitute] > 0 + # Prefer if the user has a Binding Band or Grip Claw (because why have it if + # you don't want to use it?) + score += 5 if user.has_active_item?([:BINDINGBAND, :GRIPCLAW]) + # Target will take damage at the end of each round from the binding + score += 8 if target.battler.takesIndirectDamage? + # Check whether the target will be trapped in battle by the binding + untrappable = Settings::MORE_TYPE_EFFECTS && target.has_type?(:GHOST) + if !untrappable && target.ability_active? + untrappable = Battle::AbilityEffects.triggerCertainSwitching(target.ability, target.battler, battle) + end + if !untrappable && target.item_active? + untrappable = Battle::ItemEffects.triggerCertainSwitching(target.ability, target.battler, battle) + end + if !untrappable && !target.battler.trappedInBattle? + score += 8 # Prefer if the target will become trapped by this move + eor_damage = target.rough_end_of_round_damage + if eor_damage > 0 + # Prefer if the target will take damage at the end of each round on top + # of binding damage + score += 8 + elsif eor_damage < 0 + # Don't prefer if the target will heal itself at the end of each round + score -= 8 + end + # Prefer if the target has been Perish Songed + score += 10 if target.effects[PBEffects::PerishSong] > 0 + end + # Don't prefer if the target can remove the binding (and the binding has an + # effect) + if (!untrappable && !target.battler.trappedInBattle?) || target.battler.takesIndirectDamage? + if target.check_for_move { |m| m.function == "RemoveUserBindingAndEntryHazards" } + score -= 8 + end + end } ) #=============================================================================== -# TODO: Review score modifiers. +# #=============================================================================== Battle::AI::Handlers::MoveBasePower.add("BindTargetDoublePowerIfTargetUnderwater", proc { |power, move, user, target, ai, battle| next move.move.pbModifyDamage(power, user.battler, target.battler) } ) -Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("BindTargetDoublePowerIfTargetUnderwater", - proc { |score, move, user, target, ai, battle| - next score + 40 if target.effects[PBEffects::Trapping] == 0 - } -) +Battle::AI::Handlers::MoveEffectAgainstTargetScore.copy("BindTarget", + "BindTargetDoublePowerIfTargetUnderwater") #=============================================================================== # TODO: Review score modifiers. diff --git a/Data/Scripts/011_Battle/005_AI/070_AI_MoveHandlers_GeneralModifiers.rb b/Data/Scripts/011_Battle/005_AI/070_AI_MoveHandlers_GeneralModifiers.rb index 98c577df5..174c06318 100644 --- a/Data/Scripts/011_Battle/005_AI/070_AI_MoveHandlers_GeneralModifiers.rb +++ b/Data/Scripts/011_Battle/005_AI/070_AI_MoveHandlers_GeneralModifiers.rb @@ -1,3 +1,6 @@ +# TODO: Check all lingering effects to see if the AI needs to adjust itself +# because of them. + #=============================================================================== # TODO: Review score modifier. #===============================================================================