From e12fd08eb13a19e6319fe2a8f77c43b786de665a Mon Sep 17 00:00:00 2001 From: Maruno17 Date: Sun, 23 Oct 2022 18:24:18 +0100 Subject: [PATCH] Some more rewrites of AI move score calculations (mainly item-related moves) --- .../003_Move/011_MoveEffects_Items.rb | 4 +- .../011_Battle/005_AI/004_AI_ChooseMove.rb | 3 + .../005_AI/020_AI_MoveEffectScores_Generic.rb | 39 ++++++- .../005_AI/051_AI_MoveHandlers_Misc.rb | 50 ++++---- .../052_AI_MoveHandlers_BattlerStats.rb | 8 +- .../005_AI/055_AI_MoveHandlers_MultiHit.rb | 27 +++-- .../005_AI/056_AI_MoveHandlers_Healing.rb | 10 +- .../005_AI/057_AI_MoveHandlers_Items.rb | 109 ++++++++++-------- .../070_AI_MoveHandlers_GeneralModifiers.rb | 8 ++ 9 files changed, 164 insertions(+), 94 deletions(-) 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 a0a08642b..d5f66f6f7 100644 --- a/Data/Scripts/011_Battle/003_Move/011_MoveEffects_Items.rb +++ b/Data/Scripts/011_Battle/003_Move/011_MoveEffects_Items.rb @@ -196,6 +196,8 @@ class Battle::Move::DestroyTargetBerryOrGem < Battle::Move return if target.damageState.substitute || target.damageState.berryWeakened return if !target.item || (!target.item.is_berry? && !(Settings::MECHANICS_GENERATION >= 6 && target.item.is_gem?)) + return if target.unlosableItem?(target.item) + return if target.hasActiveAbility?(:STICKYHOLD) && !@battle.moldBreaker item_name = target.itemName target.pbRemoveItem @battle.pbDisplay(_INTL("{1}'s {2} was incinerated!", target.pbThis, item_name)) @@ -379,7 +381,7 @@ class Battle::Move::UserConsumeTargetBerry < Battle::Move def pbEffectAfterAllHits(user, target) return if user.fainted? || target.fainted? return if target.damageState.unaffected || target.damageState.substitute - return if !target.item || !target.item.is_berry? + return if !target.item || !target.item.is_berry? || target.unlosableItem?(target.item) return if target.hasActiveAbility?(:STICKYHOLD) && !@battle.moldBreaker item = target.item itemName = target.itemName diff --git a/Data/Scripts/011_Battle/005_AI/004_AI_ChooseMove.rb b/Data/Scripts/011_Battle/005_AI/004_AI_ChooseMove.rb index 3ba761c26..5639eb4bd 100644 --- a/Data/Scripts/011_Battle/005_AI/004_AI_ChooseMove.rb +++ b/Data/Scripts/011_Battle/005_AI/004_AI_ChooseMove.rb @@ -76,6 +76,9 @@ class Battle::AI else # Includes: Foe, NearAlly, NearFoe, NearOther, Other, RandomNearFoe, UserOrNearAlly # If move affects one battler and you have to choose which one + # TODO: Figure out first which targets are valid. Includes the call to + # pbMoveCanTarget?, but also includes move-redirecting effects like + # Lightning Rod. Skip any battlers that can't be targeted. @battle.allBattlers.each do |b| next if !@battle.pbMoveCanTarget?(battler.index, b.index, target_data) # TODO: This should consider targeting an ally if possible. Scores will 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 7a45e5f0f..d139f2431 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 @@ -9,7 +9,7 @@ class Battle::AI end # Don't make score changes if foes have Unaware and user can't make use of # extra stat stages - if !@user.check_for_move { |move| move.function == "PowerHigherWithUserPositiveStatStages" } + if !@user.check_for_move { |m| m.function == "PowerHigherWithUserPositiveStatStages" } foe_is_aware = false each_foe_battler(@user.side) do |b, i| foe_is_aware = true if !b.has_active_ability?(:UNAWARE) @@ -64,7 +64,7 @@ class Battle::AI # TODO: Exception if user knows Baton Pass/Stored Power? case stat when :ATTACK - return false if !@user.check_for_move { |m| m.physicalMove?(move.type) && + return false if !@user.check_for_move { |m| m.physicalMove?(m.type) && m.function != "UseUserDefenseInsteadOfUserAttack" && m.function != "UseTargetAttackInsteadOfUserAttack" } when :DEFENSE @@ -683,4 +683,39 @@ class Battle::AI end return ret end + + #============================================================================= + # Returns a value indicating how beneficial the given item will be to the + # given battler if it is holding it. + # Return values are typically -2, -1, 0, 1 or 2. 0 is indifferent, positive + # values mean the battler benefits, negative values mean the battler suffers. + #============================================================================= + def battler_wants_item?(battler, item = :NONE) + item == :NONE if item.nil? + # TODO: Add more items. + preferred_items = [ + :CHOICESCARF, + :LEFTOVERS + ] + preferred_items.push(:BLACKSLUDGE) if battler.has_type?(:POISON) + preferred_items.push(:IRONBALL) if battler.check_for_move { |m| m.function = "ThrowUserItemAtTarget" } + preferred_items.push(:CHOICEBAND) if battler.check_for_move { |m| m.physicalMove?(m.type) } + preferred_items.push(:CHOICESPECS) if battler.check_for_move { |m| m.specialMove?(m.type) } + unpreferred_items = [ + :BLACKSLUDGE, + :FLAMEORB, + :IRONBALL, + :LAGGINGTAIL, + :STICKYBARB, + :TOXICORB + ] + ret = 0 + ret = 2 if preferred_items.include?(item) + ret = -2 if unpreferred_items.include?(item) + # Don't prefer if the battler knows Acrobatics + if battler.check_for_move { |m| m.function == "DoublePowerIfUserHasNoItem" } + ret += (item == :NONE) ? 1 : -1 + end + return ret + 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 7116fea28..7b88050be 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 @@ -190,10 +190,10 @@ Battle::AI::Handlers::MoveEffectScore.add("StartSunWeather", # Check for Fire/Water moves ai.battlers.each do |b| next if !b || b.battler.fainted? - if b.check_for_move { |move| move.type == :FIRE && move.damagingMove? } + if b.check_for_move { |m| m.type == :FIRE && m.damagingMove? } score += (b.opposes?(user)) ? -15 : 15 end - if b.check_for_move { |move| move.type == :WATER && move.damagingMove? } + if b.check_for_move { |m| m.type == :WATER && m.damagingMove? } score += (b.opposes?(user)) ? 15 : -15 end end @@ -206,14 +206,14 @@ Battle::AI::Handlers::MoveEffectScore.add("StartSunWeather", elsif user.has_active_ability?(:DRYSKIN) score -= 10 end - if user.check_for_move { |move| ["HealUserDependingOnWeather", - "RaiseUserAtkSpAtk1Or2InSun", - "TwoTurnAttackOneTurnInSun", - "TypeAndPowerDependOnWeather"].include?(move.function) } + if user.check_for_move { |m| ["HealUserDependingOnWeather", + "RaiseUserAtkSpAtk1Or2InSun", + "TwoTurnAttackOneTurnInSun", + "TypeAndPowerDependOnWeather"].include?(m.function) } score += 10 end - if user.check_for_move { |move| ["ConfuseTargetAlwaysHitsInRainHitsTargetInSky", - "ParalyzeTargetAlwaysHitsInRainHitsTargetInSky"].include?(move.function) } + if user.check_for_move { |m| ["ConfuseTargetAlwaysHitsInRainHitsTargetInSky", + "ParalyzeTargetAlwaysHitsInRainHitsTargetInSky"].include?(m.function) } score -= 10 end end @@ -236,10 +236,10 @@ Battle::AI::Handlers::MoveEffectScore.add("StartRainWeather", # Check for Fire/Water moves ai.battlers.each do |b| next if !b || b.battler.fainted? - if b.check_for_move { |move| move.type == :WATER && move.damagingMove? } + if b.check_for_move { |m| m.type == :WATER && m.damagingMove? } score += (b.opposes?(user)) ? -15 : 15 end - if b.check_for_move { |move| move.type == :FIRE && move.damagingMove? } + if b.check_for_move { |m| m.type == :FIRE && m.damagingMove? } score += (b.opposes?(user)) ? 15 : -15 end end @@ -249,13 +249,13 @@ Battle::AI::Handlers::MoveEffectScore.add("StartRainWeather", if user.has_active_ability?([:DRYSKIN, :FORECAST, :HYDRATION, :RAINDISH, :SWIFTSWIM]) score += 15 end - if user.check_for_move { |move| ["ConfuseTargetAlwaysHitsInRainHitsTargetInSky", - "ParalyzeTargetAlwaysHitsInRainHitsTargetInSky", - "TypeAndPowerDependOnWeather"].include?(move.function) } + if user.check_for_move { |m| ["ConfuseTargetAlwaysHitsInRainHitsTargetInSky", + "ParalyzeTargetAlwaysHitsInRainHitsTargetInSky", + "TypeAndPowerDependOnWeather"].include?(m.function) } score += 10 end - if user.check_for_move { |move| ["HealUserDependingOnWeather", - "TwoTurnAttackOneTurnInSun"].include?(move.function) } + if user.check_for_move { |m| ["HealUserDependingOnWeather", + "TwoTurnAttackOneTurnInSun"].include?(m.function) } score -= 10 end end @@ -291,12 +291,12 @@ Battle::AI::Handlers::MoveEffectScore.add("StartSandstormWeather", if user.has_active_ability?([:SANDFORCE, :SANDRUSH, :SANDVEIL]) score += 15 end - if user.check_for_move { |move| ["HealUserDependingOnSandstorm", - "TypeAndPowerDependOnWeather"].include?(move.function) } + if user.check_for_move { |m| ["HealUserDependingOnSandstorm", + "TypeAndPowerDependOnWeather"].include?(m.function) } score += 10 end - if user.check_for_move { |move| ["HealUserDependingOnWeather", - "TwoTurnAttackOneTurnInSun"].include?(move.function) } + if user.check_for_move { |m| ["HealUserDependingOnWeather", + "TwoTurnAttackOneTurnInSun"].include?(m.function) } score -= 10 end end @@ -331,13 +331,13 @@ Battle::AI::Handlers::MoveEffectScore.add("StartHailWeather", elsif user.ability == :ICEFACE score += 15 end - if user.check_for_move { |move| ["FreezeTargetAlwaysHitsInHail", - "StartWeakenDamageAgainstUserSideIfHail", - "TypeAndPowerDependOnWeather"].include?(move.function) } + if user.check_for_move { |m| ["FreezeTargetAlwaysHitsInHail", + "StartWeakenDamageAgainstUserSideIfHail", + "TypeAndPowerDependOnWeather"].include?(m.function) } score += 10 end - if user.check_for_move { |move| ["HealUserDependingOnWeather", - "TwoTurnAttackOneTurnInSun"].include?(move.function) } + if user.check_for_move { |m| ["HealUserDependingOnWeather", + "TwoTurnAttackOneTurnInSun"].include?(m.function) } score -= 10 end end @@ -686,7 +686,7 @@ Battle::AI::Handlers::MoveEffectScore.add("BurnAttackerBeforeUserActs", next if !b.battler.affectedByContactEffect? next if !b.battler.pbCanBurn?(user.battler, false, move.move) if ai.trainer.high_skill? - next if !b.check_for_move { |move| move.pbContactMove?(b.battler) } + next if !b.check_for_move { |m| m.pbContactMove?(b.battler) } end score += 10 # Possible to burn end 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 4130086e1..6bfb2e596 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 @@ -81,7 +81,7 @@ Battle::AI::Handlers::MoveEffectScore.add("RaiseUserDefense1CurlUpUser", proc { |score, move, user, target, ai, battle| score = ai.get_score_for_user_stat_raise(score) if !user.effects[PBEffects::DefenseCurl] && - user.check_for_move { |move| move.function == "MultiTurnAttackPowersUpEachTurn" } + user.check_for_move { |m| m.function == "MultiTurnAttackPowersUpEachTurn" } score += 10 end next score @@ -144,7 +144,7 @@ Battle::AI::Handlers::MoveFailureCheck.copy("RaiseUserSpDef1", Battle::AI::Handlers::MoveEffectScore.add("RaiseUserSpDef1PowerUpElectricMove", proc { |score, move, user, target, ai, battle| score = ai.get_score_for_user_stat_raise(score) - if user.check_for_move { |move| move.damagingMove? && move.type == :ELECTRIC } + if user.check_for_move { |m| m.damagingMove? && m.type == :ELECTRIC } score += 10 end next score @@ -658,7 +658,7 @@ Battle::AI::Handlers::MoveFailureCheck.add("RaiseTargetAttack2ConfuseTarget", ) Battle::AI::Handlers::MoveEffectScore.add("RaiseTargetAttack2ConfuseTarget", proc { |score, move, user, target, ai, battle| - next score - 90 if !target.battler.pbCanConfuse?(user.battler, false) + next score - 60 if !target.battler.pbCanConfuse?(user.battler, false) next score + 30 if target.stages[:ATTACK] < 0 } ) @@ -674,7 +674,7 @@ Battle::AI::Handlers::MoveFailureCheck.add("RaiseTargetSpAtk1ConfuseTarget", ) Battle::AI::Handlers::MoveEffectScore.add("RaiseTargetSpAtk1ConfuseTarget", proc { |score, move, user, target, ai, battle| - next score - 90 if !target.battler.pbCanConfuse?(user.battler, false) + next score - 60 if !target.battler.pbCanConfuse?(user.battler, false) next score + 30 if target.stages[:SPECIAL_ATTACK] < 0 } ) 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 271520500..5f1864ec6 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 @@ -209,7 +209,7 @@ Battle::AI::Handlers::MoveEffectScore.add("TwoTurnAttack", # Power Herb makes this a 1 turn move, the same as a move with no effect next score if user.has_active_item?(:POWERHERB) # Treat as a failure if user has Truant (the charging turn has no effect) - next 25 if user.has_active_ability?(:TRUANT) + next score - 60 if user.has_active_ability?(:TRUANT) # Don't prefer because it uses up two turns score -= 15 # Don't prefer if user is at a low HP (time is better spent on quicker moves) @@ -330,28 +330,31 @@ Battle::AI::Handlers::MoveEffectScore.add("TwoTurnAttackRaiseUserSpAtkSpDefSpd2" ) #=============================================================================== -# TODO: Review score modifiers. +# #=============================================================================== Battle::AI::Handlers::MoveEffectScore.add("TwoTurnAttackChargeRaiseUserDefense1", proc { |score, move, user, target, ai, battle| - score += 20 if user.stages[:DEFENSE] < 0 + # Score for being a two turn attack + score = Battle::AI::Handlers.apply_move_effect_score("TwoTurnAttack", + score, move, user, target, ai, battle) + # Score for raising the user's stat + score = Battle::AI::Handlers.apply_move_effect_score("RaiseUserDefense1", + score, move, user, target, ai, battle) next score } ) #=============================================================================== -# TODO: Review score modifiers. +# #=============================================================================== Battle::AI::Handlers::MoveEffectScore.add("TwoTurnAttackChargeRaiseUserSpAtk1", proc { |score, move, user, target, ai, battle| - aspeed = user.rough_stat(:SPEED) - ospeed = target.rough_stat(:SPEED) - if (aspeed > ospeed && user.hp > user.totalhp / 3) || user.hp > user.totalhp / 2 - score += 60 - else - score -= 90 - end - score += user.stages[:SPECIAL_ATTACK] * 20 + # Score for being a two turn attack + score = Battle::AI::Handlers.apply_move_effect_score("TwoTurnAttack", + score, move, user, target, ai, battle) + # Score for raising the user's stat + score = Battle::AI::Handlers.apply_move_effect_score("RaiseUserSpAtk1", + score, move, user, target, ai, battle) next score } ) 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 91c490f4b..bc68ffbbd 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 @@ -20,7 +20,7 @@ Battle::AI::Handlers::MoveEffectScore.add("HealUserFullyAndFallAsleep", score += 10 if user.status != :NONE # Check if user will be able to act while asleep if ai.trainer.medium_skill? - if user.check_for_move { |move| move.usableWhenAsleep? } + if user.check_for_move { |m| m.usableWhenAsleep? } score += 10 else score -= 10 @@ -159,7 +159,7 @@ Battle::AI::Handlers::MoveEffectScore.add("HealUserByTargetAttackLowerTargetAtta # Check whether lowering the target's Attack will have any impact if ai.trainer.medium_skill? if target.battler.pbCanLowerStatStage?(:ATTACK, user.battler, move.move) && - target.check_for_move { |move| move.physicalMove?(move.type) } + target.check_for_move { |m| m.physicalMove?(m.type) } score += target.stages[:ATTACK] * 10 end end @@ -419,16 +419,16 @@ Battle::AI::Handlers::MoveEffectScore.add("StartLeechSeedTarget", proc { |score, move, user, target, ai, battle| score += 10 if user.turnCount < 2 if ai.trainer.medium_skill? - if !user.check_for_move { |move| move.damagingMove? } + if !user.check_for_move { |m| m.damagingMove? } score += 20 end score -= 20 if target.has_active_ability?([:LIQUIDOOZE]) || !target.battler.takesIndirectDamage? end if ai.trainer.high_skill? - if user.check_for_move { |move| move.is_a?(Battle::Move::ProtectMove) } + if user.check_for_move { |m| m.is_a?(Battle::Move::ProtectMove) } score += 15 end - if target.check_for_move { |move| move.is_a?(Battle::Move::RemoveUserBindingAndEntryHazards) } + if target.check_for_move { |m| m.is_a?(Battle::Move::RemoveUserBindingAndEntryHazards) } score -= 15 end end 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 28432b41d..6f0b8baf0 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 @@ -1,23 +1,26 @@ #=============================================================================== -# TODO: Review score modifiers. +# #=============================================================================== Battle::AI::Handlers::MoveEffectScore.add("UserTakesTargetItem", proc { |score, move, user, target, ai, battle| - if ai.trainer.high_skill? - if !user.item && target.item - score += 40 - else - score -= 90 - end - else - score -= 80 - end + next score if user.wild? || user.item + next score if !target.item || target.battler.unlosableItem?(target.item) + next score if user.battler.unlosableItem?(target.item) + next score if target.effects[PBEffects::Substitute] > 0 + next score if target.has_active_ability?(:STICKYHOLD) && !battle.moldBreaker + # User can steal the target's item; score it + user_item_preference = ai.battler_wants_item?(user, target.item_id) + user_no_item_preference = ai.battler_wants_item?(user, :NONE) + target_item_preference = ai.battler_wants_item?(target, target.item_id) + target_no_item_preference = ai.battler_wants_item?(target, :NONE) + score += (user_item_preference - user_no_item_preference) * 5 + score += (target_item_preference - target_no_item_preference) * 5 next score } ) #=============================================================================== -# TODO: Review score modifiers. +# #=============================================================================== Battle::AI::Handlers::MoveFailureCheck.add("TargetTakesUserItem", proc { |move, user, target, ai, battle| @@ -27,18 +30,18 @@ Battle::AI::Handlers::MoveFailureCheck.add("TargetTakesUserItem", ) Battle::AI::Handlers::MoveEffectScore.add("TargetTakesUserItem", proc { |score, move, user, target, ai, battle| - if user.has_active_item?([:FLAMEORB, :TOXICORB, :STICKYBARB, :IRONBALL, - :CHOICEBAND, :CHOICESCARF, :CHOICESPECS]) - score += 50 - else - score -= 80 - end + user_item_preference = ai.battler_wants_item?(user, user.item_id) + user_no_item_preference = ai.battler_wants_item?(user, :NONE) + target_item_preference = ai.battler_wants_item?(target, user.item_id) + target_no_item_preference = ai.battler_wants_item?(target, :NONE) + score -= (user_item_preference - user_no_item_preference) * 5 + score -= (target_item_preference - target_no_item_preference) * 5 next score } ) #=============================================================================== -# TODO: Review score modifiers. +# #=============================================================================== Battle::AI::Handlers::MoveFailureCheck.add("UserTargetSwapItems", proc { |move, user, target, ai, battle| @@ -46,24 +49,26 @@ Battle::AI::Handlers::MoveFailureCheck.add("UserTargetSwapItems", 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 !battle.moldBreaker && target.has_active_ability?(:STICKYHOLD) + next true if target.has_active_ability?(:STICKYHOLD) && !battle.moldBreaker } ) Battle::AI::Handlers::MoveEffectScore.add("UserTargetSwapItems", proc { |score, move, user, target, ai, battle| - if user.has_active_item?([:FLAMEORB, :TOXICORB, :STICKYBARB, :IRONBALL, - :CHOICEBAND, :CHOICESCARF, :CHOICESPECS]) - score += 50 - elsif !user.item && target.item - score -= 30 if user.battler.lastMoveUsed && - GameData::Move.get(user.battler.lastMoveUsed).function_code == "UserTargetSwapItems" - end + user_new_item_preference = ai.battler_wants_item?(user, target.item_id) + user_old_item_preference = ai.battler_wants_item?(user, user.item_id) + target_new_item_preference = ai.battler_wants_item?(target, user.item_id) + target_old_item_preference = ai.battler_wants_item?(target, target.item_id) + score += (user_new_item_preference - user_old_item_preference) * 5 + score -= (target_new_item_preference - target_old_item_preference) * 5 + # Don't prefer if user used this move in the last round + score -= 15 if user.battler.lastMoveUsed && + GameData::Move.get(user.battler.lastMoveUsed).function_code == "UserTargetSwapItems" next score } ) #=============================================================================== -# TODO: Review score modifiers. +# #=============================================================================== Battle::AI::Handlers::MoveFailureCheck.add("RestoreUserConsumedItem", proc { |move, user, target, ai, battle| @@ -72,13 +77,15 @@ Battle::AI::Handlers::MoveFailureCheck.add("RestoreUserConsumedItem", ) Battle::AI::Handlers::MoveEffectScore.add("RestoreUserConsumedItem", proc { |score, move, user, target, ai, battle| - score += 30 + user_new_item_preference = ai.battler_wants_item?(user, user.battler.recycleItem) + user_old_item_preference = ai.battler_wants_item?(user, user.item_id) + score += (user_new_item_preference - user_old_item_preference) * 8 next score } ) #=============================================================================== -# TODO: Review score modifiers. +# #=============================================================================== Battle::AI::Handlers::MoveBasePower.add("RemoveTargetItem", proc { |power, move, user, target, ai, battle| @@ -87,23 +94,32 @@ Battle::AI::Handlers::MoveBasePower.add("RemoveTargetItem", ) Battle::AI::Handlers::MoveEffectScore.add("RemoveTargetItem", proc { |score, move, user, target, ai, battle| - if ai.trainer.high_skill? - score += 20 if target.item - end + next score if user.wild? + next score if !target.item || target.battler.unlosableItem?(target.item) + next score if target.effects[PBEffects::Substitute] > 0 + next score if target.has_active_ability?(:STICKYHOLD) && !battle.moldBreaker + # User can knock off the target's item; score it + target_item_preference = ai.battler_wants_item?(target, target.item_id) + target_no_item_preference = ai.battler_wants_item?(target, :NONE) + score += (target_item_preference - target_no_item_preference) * 5 next score } ) #=============================================================================== -# TODO: Review score modifiers. +# #=============================================================================== Battle::AI::Handlers::MoveEffectScore.add("DestroyTargetBerryOrGem", proc { |score, move, user, target, ai, battle| - if ai.trainer.high_skill? - if target.item && target.item.is_berry? && target.effects[PBEffects::Substitute] == 0 - score += 30 - end - end + next score if !target.item || (!target.item.is_berry? && + !(Settings::MECHANICS_GENERATION >= 6 && target.item.is_gem?)) + next score if user.battler.unlosableItem?(target.item) + next score if target.effects[PBEffects::Substitute] > 0 + next score if target.has_active_ability?(:STICKYHOLD) && !battle.moldBreaker + # User can incinerate the target's item; score it + target_item_preference = ai.battler_wants_item?(target, target.item_id) + target_no_item_preference = ai.battler_wants_item?(target, :NONE) + score += (target_item_preference - target_no_item_preference) * 8 next score } ) @@ -150,7 +166,7 @@ Battle::AI::Handlers::MoveEffectScore.add("StartTargetCannotUseItem", #=============================================================================== Battle::AI::Handlers::MoveEffectScore.add("StartNegateHeldItems", proc { |score, move, user, target, ai, battle| - next 0 if battle.field.effects[PBEffects::MagicRoom] > 0 + next score - 40 if battle.field.effects[PBEffects::MagicRoom] > 0 next score + 30 if !user.item && target.item } ) @@ -234,15 +250,18 @@ Battle::AI::Handlers::MoveEffectScore.add("AllBattlersConsumeBerry", ) #=============================================================================== -# TODO: Review score modifiers. +# #=============================================================================== Battle::AI::Handlers::MoveEffectScore.add("UserConsumeTargetBerry", proc { |score, move, user, target, ai, battle| - if target.effects[PBEffects::Substitute] == 0 - if ai.trainer.high_skill? && target.item && target.item.is_berry? - score += 30 - end - end + next score if !target.item || !target.item.is_berry? + next score if user.battler.unlosableItem?(target.item) + next score if target.effects[PBEffects::Substitute] > 0 + next score if target.has_active_ability?(:STICKYHOLD) && !battle.moldBreaker + # User can consume the target's berry; score it + target_item_preference = ai.battler_wants_item?(target, target.item_id) + target_no_item_preference = ai.battler_wants_item?(target, :NONE) + score += (target_item_preference - target_no_item_preference) * 8 next score } ) 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 6c8b602fc..919aa2fa0 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 @@ -48,6 +48,14 @@ Battle::AI::Handlers::GeneralMoveScore.add(:dance_move_against_dancer, # TODO: Don't prefer sound move if user hasn't been Throat Chopped but # target has previously used Throat Chop. +#=============================================================================== +# TODO: Review score modifier. +#=============================================================================== +# TODO: Don't prefer damaging moves if the target is Biding, unless the move +# will deal enough damage to KO the target before it retaliates (assuming +# the move is used repeatedly until the target retaliates). Don't worry +# about the target's Bide if the user will be immune to it. + #=============================================================================== # TODO: Review score modifier. #===============================================================================