diff --git a/Data/Scripts/011_Battle/002_Battler/006_Battler_AbilityAndItem.rb b/Data/Scripts/011_Battle/002_Battler/006_Battler_AbilityAndItem.rb index 02fa3e9fa..bf40bb061 100644 --- a/Data/Scripts/011_Battle/002_Battler/006_Battler_AbilityAndItem.rb +++ b/Data/Scripts/011_Battle/002_Battler/006_Battler_AbilityAndItem.rb @@ -281,7 +281,8 @@ class Battle::Battler # NOTE: A Pokémon using Bug Bite/Pluck, and a Pokémon having an item thrown at # it via Fling, will gain the effect of the item even if the Pokémon is # affected by item-negating effects. - # item_to_use is an item ID for Bug Bite/Pluck and Fling, and nil otherwise. + # item_to_use is an item ID for Stuff Cheeks, Teatime, Bug Bite/Pluck and + # Fling, and nil otherwise. # fling is for Fling only. def pbHeldItemTriggerCheck(item_to_use = nil, fling = false) return if fainted? diff --git a/Data/Scripts/011_Battle/005_AI/020_AI_Move_EffectScoresGeneric.rb b/Data/Scripts/011_Battle/005_AI/020_AI_Move_EffectScoresGeneric.rb index 1dac1450c..d207c9893 100644 --- a/Data/Scripts/011_Battle/005_AI/020_AI_Move_EffectScoresGeneric.rb +++ b/Data/Scripts/011_Battle/005_AI/020_AI_Move_EffectScoresGeneric.rb @@ -1035,6 +1035,92 @@ class Battle::AI return ret end + #============================================================================= + # Items can be consumed by Stuff Cheeks, Teatime, Bug Bite/Pluck and Fling. + #============================================================================= + def get_score_change_for_consuming_item(battler, item) + ret = 0 + case item + when :ORANBERRY, :BERRYJUICE, :ENIGMABERRY, :SITRUSBERRY + # Healing + ret += (battler.hp > battler.totalhp * 3 / 4) ? -8 : 8 + ret = ret * 3 / 2 if GameData::Item.get(item).is_berry? && battler.has_active_ability?(:RIPEN) + when :AGUAVBERRY, :FIGYBERRY, :IAPAPABERRY, :MAGOBERRY, :WIKIBERRY + # Healing with confusion + fraction_to_heal = 8 # Gens 6 and lower + if Settings::MECHANICS_GENERATION == 7 + fraction_to_heal = 2 + elsif Settings::MECHANICS_GENERATION >= 8 + fraction_to_heal = 3 + end + ret += (battler.hp > battler.totalhp * (1 - (1 / fraction_to_heal))) ? -8 : 8 + ret = ret * 3 / 2 if GameData::Item.get(item).is_berry? && battler.has_active_ability?(:RIPEN) + # TODO: Check whether the item will cause confusion? + when :ASPEARBERRY, :CHERIBERRY, :CHESTOBERRY, :PECHABERRY, :RAWSTBERRY + # Status cure + status = { + :ASPEAR => :FROZEN, + :CHERIBERRY => :PARALYSIS, + :CHESTOBERRY => :SLEEP, + :PECHABERRY => :POISON, + :RAWSTBERRY => :BURN + }[item] + ret += (status && battler.status == status) ? 8 : -8 + when :PERSIMBERRY + # Confusion cure + ret += (battler.effects[PBEffects::Confusion] > 1) ? 8 : -8 + when :LUMBERRY + # Any status/confusion cure + ret += (battler.status != :NONE || battler.effects[PBEffects::Confusion] > 1) ? 8 : -8 + when :MENTALHERB + # Cure mental effects + ret += 8 if battler.effects[PBEffects::Attract] >= 0 || + battler.effects[PBEffects::Taunt] > 1 || + battler.effects[PBEffects::Encore] > 1 || + battler.effects[PBEffects::Torment] || + battler.effects[PBEffects::Disable] > 1 || + battler.effects[PBEffects::HealBlock] > 1 + when :APICOTBERRY, :GANLONBERRY, :LIECHIBERRY, :PETAYABERRY, :SALACBERRY, + :KEEBERRY, :MARANGABERRY + # Stat raise + stat = { + :APICOTBERRY => :SPECIAL_DEFENSE, + :GANLONBERRY => :DEFENSE, + :LIECHIBERRY => :ATTACK, + :PETAYABERRY => :SPECIAL_ATTACK, + :SALACBERRY => :SPEED, + :KEEBERRY => :DEFENSE, + :MARANGABERRY => :SPECIAL_DEFENSE + }[item] + ret += 8 if stat && ai.stat_raise_worthwhile?(battler, stat) + ret = ret * 3 / 2 if GameData::Item.get(item).is_berry? && battler.has_active_ability?(:RIPEN) + when :STARFBERRY + # Random stat raise + ret += 8 + ret = ret * 3 / 2 if GameData::Item.get(item).is_berry? && battler.has_active_ability?(:RIPEN) + when :WHITEHERB + # Resets lowered stats + reduced_stats = false + GameData::Stat.each_battle do |s| + next if battler.stages[s.id] >= 0 + reduced_stats = true + break + end + ret += 8 if reduced_stats + when :MICLEBERRY + # Raises accuracy of next move + ret += 8 + when :LANSATBERRY + # Focus energy + ret += 8 if battler.effects[PBEffects::FocusEnergy] < 2 + when :LEPPABERRY + # Restore PP + ret += 8 + ret = ret * 3 / 2 if GameData::Item.get(item).is_berry? && battler.has_active_ability?(:RIPEN) + end + return ret + end + #============================================================================= # Returns a value indicating how beneficial the given ability will be to the # given battler if it has it. 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 18b002249..79857a780 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 @@ -148,13 +148,21 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("CorrodeTargetItem", ) #=============================================================================== -# TODO: Review score modifiers. +# #=============================================================================== Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("StartTargetCannotUseItem", proc { |move, user, target, ai, battle| next target.effects[PBEffects::Embargo] > 0 } ) +Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("StartTargetCannotUseItem", + proc { |score, move, user, target, ai, battle| + next Battle::AI::MOVE_USELESS_SCORE if !target.item || !target.item_active? + item_score = ai.battler_wants_item?(target, target.item_id) + score += item_score * 5 + next score + } +) #=============================================================================== # TODO: Review score modifiers. @@ -169,7 +177,7 @@ Battle::AI::Handlers::MoveEffectScore.add("StartNegateHeldItems", ) #=============================================================================== -# TODO: Review score modifiers. +# #=============================================================================== Battle::AI::Handlers::MoveFailureCheck.add("UserConsumeBerryRaiseDefense2", proc { |move, user, ai, battle| @@ -179,31 +187,28 @@ Battle::AI::Handlers::MoveFailureCheck.add("UserConsumeBerryRaiseDefense2", ) Battle::AI::Handlers::MoveEffectScore.add("UserConsumeBerryRaiseDefense2", proc { |score, move, user, ai, battle| - 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 + # Score for raising the user's stat + score = Battle::AI::Handlers.apply_move_effect_score("RaiseUserDefense2", + score, move, user, ai, battle) + # Score for the consumed berry's effect + score += ai.get_score_change_for_consuming_item(user, user.item_id) + # Score for other results of consuming the berry 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? + # Prefer if user will heal itself with Cheek Pouch + score += 5 if user.battler.canHeal? && user.hp < user.totalhp / 2 && + user.has_active_ability?(:CHEEKPOUCH) + # Prefer if target can recover the consumed berry + score += 8 if user.has_active_ability?(:HARVEST) || + user.has_move_with_function?("RestoreUserConsumedItem") + # Prefer if user couldn't normally consume the berry + score += 4 if !user.battler.canConsumeBerry? end - score -= user.stages[:DEFENSE] * 20 next score } ) #=============================================================================== -# TODO: Review score modifiers. -# TODO: This code should be for a single battler (each is checked in turn). +# #=============================================================================== Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("AllBattlersConsumeBerry", proc { |move, user, target, ai, battle| @@ -212,36 +217,20 @@ Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("AllBattlersConsumeBerry ) Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("AllBattlersConsumeBerry", proc { |score, move, user, target, ai, battle| - 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 - ] - battle.allSameSideBattlers(user.index).each do |b| - 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? - battle.allOtherSideBattlers(user.index).each do |b| - amt = 10 / battle.pbSideSize(target.index) - score -= amt if b.hasActiveItem?(useful_berries) - 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 + # Score for the consumed berry's effect + score_change = ai.get_score_change_for_consuming_item(target, target.item_id) + # Score for other results of consuming the berry + if ai.trainer.medium_skill? + # Prefer if target will heal itself with Cheek Pouch + score_change += 5 if target.battler.canHeal? && target.hp < target.totalhp / 2 && + target.has_active_ability?(:CHEEKPOUCH) + # Prefer if target can recover the consumed berry + score_change += 8 if target.has_active_ability?(:HARVEST) || + target.has_move_with_function?("RestoreUserConsumedItem") + # Prefer if target couldn't normally consume the berry + score_change += 4 if !target.battler.canConsumeBerry? end + score += (target.opposes?(user)) ? -score_change : score_change next score } ) @@ -255,7 +244,15 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("UserConsumeTargetBerry", 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 + # Score the user gaining the item's effect + score += ai.get_score_change_for_consuming_item(user, target.item_id) + # Score for other results of consuming the berry + if ai.trainer.medium_skill? + # Prefer if user will heal itself with Cheek Pouch + score += 5 if user.battler.canHeal? && user.hp < user.totalhp / 2 && + user.has_active_ability?(:CHEEKPOUCH) + end + # Score the target no longer having the item 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) * 4 @@ -296,16 +293,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("ThrowUserItemAtTarget", score = Battle::AI::Handlers.apply_move_effect_against_target_score("FlinchTarget", score, move, user, target, ai, battle) else - # TODO: Berries/Berry Juice/Mental Herb/White Herb also have Fling - # effects. Should they be accounted for individually, or is it okay - # to consider it bad to Fling these in general? Note that they all - # do minimal damage so this move probably won't be used anyway. - if Battle::ItemEffects::HPHeal[user.item_id] || - Battle::ItemEffects::StatusCure[user.item_id] || - Battle::ItemEffects::OnEndOfUsingMove[user.item_id] || - Battle::ItemEffects::OnEndOfUsingMoveStatRestore[user.item_id] - score -= 8 - end + score -= ai.get_score_change_for_consuming_item(target, user.item_id) end # Prefer if the user doesn't want its held item/don't prefer if it wants to # keep its held item 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 5fb12105d..432cc68d3 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 @@ -439,9 +439,23 @@ Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("UseLastMoveUsedByTarget ) #=============================================================================== -# TODO: Review score modifiers. +# #=============================================================================== -# UseMoveTargetIsAboutToUse +Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("UseMoveTargetIsAboutToUse", + proc { |move, user, target, ai, battle| + next !target.check_for_move { |m| m.damagingMove? && !move.move.moveBlacklist.include?(m.function_code) } + } +) +Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("UseMoveTargetIsAboutToUse", + proc { |score, move, user, target, ai, battle| + next Battle::AI::MOVE_USELESS_SCORE if target.faster_than?(user) + # Don't prefer if target knows any moves that can't be copied + if target.check_for_move { |m| m.statusMove? || move.move.moveBlacklist.include?(m.function_code) } + score -= 8 + end + next score + } +) #=============================================================================== # NOTE: The move that this move will become is determined in def @@ -455,7 +469,7 @@ Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("UseLastMoveUsedByTarget # UseRandomMove #=============================================================================== -# TODO: Review score modifiers. +# #=============================================================================== Battle::AI::Handlers::MoveFailureCheck.add("UseRandomMoveFromUserParty", proc { |move, user, ai, battle| @@ -492,16 +506,47 @@ Battle::AI::Handlers::MoveFailureCheck.add("UseRandomUserMoveIfAsleep", ) #=============================================================================== -# TODO: Review score modifiers. -# TODO: This code shouldn't make use of target. +# #=============================================================================== -# BounceBackProblemCausingStatusMoves +Battle::AI::Handlers::MoveEffectScore.add("BounceBackProblemCausingStatusMoves", + proc { |score, move, user, ai, battle| + next Battle::AI::MOVE_USELESS_SCORE if user.has_active_ability?(:MAGICBOUNCE) + useless = true + ai.each_foe_battler(user.side) do |b, i| + next if !b.can_attack? + next if !b.check_for_move { |m| m.statusMove? && m.canMagicCoat? } + score += 4 + useless = false + end + next Battle::AI::MOVE_USELESS_SCORE if useless + # Don't prefer the lower the user's HP is (better to try something else) + if user.hp < user.totalhp / 2 + score -= 20 * (0.75 - (user.hp.to_f / user.totalhp)) # -5 to -15 + end + next score + } +) #=============================================================================== -# TODO: Review score modifiers. -# TODO: This code shouldn't make use of target. +# #=============================================================================== -# StealAndUseBeneficialStatusMove +Battle::AI::Handlers::MoveEffectScore.add("StealAndUseBeneficialStatusMove", + proc { |score, move, user, ai, battle| + useless = true + ai.each_foe_battler(user.side) do |b, i| + next if !b.can_attack? + next if !b.check_for_move { |m| m.statusMove? && m.canSnatch? } + score += 4 + useless = false + end + next Battle::AI::MOVE_USELESS_SCORE if useless + # Don't prefer the lower the user's HP is (better to try something else) + if user.hp < user.totalhp / 2 + score -= 20 * (0.75 - (user.hp.to_f / user.totalhp)) # -5 to -15 + end + next score + } +) #=============================================================================== # 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 855aeb493..4c9f666e2 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,11 +1,17 @@ #=============================================================================== -# TODO: Review score modifiers. +# #=============================================================================== Battle::AI::Handlers::MoveFailureCheck.add("FleeFromBattle", proc { |move, user, ai, battle| next !battle.pbCanRun?(user.index) } ) +Battle::AI::Handlers::MoveEffectScore.add("FleeFromBattle", + proc { |score, move, user, ai, battle| + # Generally don't prefer (don't want to end the battle too easily) + next score - 15 + } +) #=============================================================================== # TODO: Review score modifiers. @@ -258,32 +264,50 @@ Battle::AI::Handlers::MoveFailureCheck.add("TrapAllBattlersInBattleForOneTurn", # PursueSwitchingFoe #=============================================================================== -# TODO: Review score modifiers. +# #=============================================================================== -Battle::AI::Handlers::MoveEffectScore.add("UsedAfterUserTakesPhysicalDamage", - proc { |score, move, user, ai, battle| +Battle::AI::Handlers::MoveFailureCheck.add("UsedAfterUserTakesPhysicalDamage", + proc { |move, user, ai, battle| found_physical_move = false ai.each_foe_battler(user.side) do |b, i| next if !b.check_for_move { |m| m.physicalMove?(m.type) } found_physical_move = true break end - next Battle::AI::MOVE_USELESS_SCORE if !found_physical_move - next score + next !found_physical_move + } +) +Battle::AI::Handlers::MoveEffectScore.add("UsedAfterUserTakesPhysicalDamage", + proc { |score, move, user, ai, battle| + next Battle::AI::MOVE_USELESS_SCORE if user.effects[PBEffects::Substitute] > 0 + # Prefer if foes don't know any special moves + found_special_move = false + ai.each_foe_battler(user.side) do |b, i| + next if !b.check_for_move { |m| m.specialMove?(m.type) } + found_special_move = true + break + end + score += 10 if !found_special_move + # Generally not worth using + next score - 10 } ) #=============================================================================== -# TODO: Review score modifiers. +# #=============================================================================== Battle::AI::Handlers::MoveEffectScore.add("UsedAfterAllyRoundWithDoublePower", proc { |score, move, user, ai, battle| - if ai.trainer.medium_skill? - user.battler.allAllies.each do |b| - next if !b.pbHasMove?(move.id) - score += 20 - end + # No score change if no allies know this move + ally_has_move = false + ai.each_same_side_battler(user.side) do |b, i| + next if !b.has_move_with_function?(move.function) + ally_has_move = true + break end + next score if !ally_has_move + # Prefer for the sake of doubling in power + score += 5 next score } ) @@ -297,7 +321,7 @@ Battle::AI::Handlers::MoveEffectScore.add("TargetActsNext", next Battle::AI::MOVE_USELESS_SCORE if target.opposes?(user) # Compare the speeds of all battlers speeds = [] - ai.each_battler { |b, i| speeds.push([i, rough_stat(:SPEED)]) } + ai.each_battler { |b, i| speeds.push([i, b.rough_stat(:SPEED)]) } if battle.field.effects[PBEffects::TrickRoom] > 0 speeds.sort! { |a, b| a[1] <=> b[1] } else @@ -332,7 +356,7 @@ Battle::AI::Handlers::MoveEffectScore.add("TargetActsLast", next Battle::AI::MOVE_USELESS_SCORE if !has_ally # Compare the speeds of all battlers speeds = [] - ai.each_battler { |b, i| speeds.push([i, rough_stat(:SPEED)]) } + ai.each_battler { |b, i| speeds.push([i, b.rough_stat(:SPEED)]) } if battle.field.effects[PBEffects::TrickRoom] > 0 speeds.sort! { |a, b| a[1] <=> b[1] } else @@ -354,35 +378,77 @@ Battle::AI::Handlers::MoveEffectScore.add("TargetActsLast", ) #=============================================================================== -# TODO: Review score modifiers. +# #=============================================================================== Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("TargetUsesItsLastUsedMoveAgain", proc { |move, user, target, ai, battle| - next true if !target.battler.lastRegularMoveUsed || - !target.battler.pbHasMove?(target.battler.lastRegularMoveUsed) - next true if target.battler.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 - next false + next target.battler.usingMultiTurnAttack? } ) Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("TargetUsesItsLastUsedMoveAgain", proc { |score, move, user, target, ai, battle| - # 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 Battle::AI::MOVE_USELESS_SCORE + # We don't ever want to make a foe act again + next Battle::AI::MOVE_USELESS_SCORE if target.opposes?(user) + # Useless if target will act before the user, as we don't know what move + # will be instructed + next Battle::AI::MOVE_USELESS_SCORE if target.faster_than?(user) + next Battle::AI::MOVE_USELESS_SCORE if !target.battler.lastRegularMoveUsed + mov = nil + target.battler.eachMove do |m| + mov = m if m.id == target.battler.lastRegularMoveUsed + break if mov + end + next Battle::AI::MOVE_USELESS_SCORE if mov.nil? || (mov.pp == 0 && mov.total_pp > 0) + next Battle::AI::MOVE_USELESS_SCORE if move.move.moveBlacklist.include?(mov.function) + # Without lots of code here to determine good/bad moves, using this move is + # likely to just be a waste of a turn + # NOTE: Because this move can be used against a foe but is being used on an + # ally (since we're here in this code), this move's score will be + # inverted later. A higher score here means this move will be less + # preferred, which is the result we want. + score += 20 + next score } ) #=============================================================================== -# TODO: Review score modifiers. -# TODO: This code shouldn't make use of target. +# #=============================================================================== -# StartSlowerBattlersActFirst +Battle::AI::Handlers::MoveEffectScore.add("StartSlowerBattlersActFirst", + proc { |score, move, user, ai, battle| + # Get the speeds of all battlers + ally_speeds = [] + foe_speeds = [] + ai.each_battler do |b, i| + if b.opposes?(user) + foe_speeds.push(rough_stat(:SPEED)) + foe_speeds.last *= 2 if user.pbOpposingSide.effects[PBEffects::Tailwind] > 1 + foe_speeds.last /= 2 if user.pbOpposingSide.effects[PBEffects::Swamp] > 1 + else + ally_speeds.push(rough_stat(:SPEED)) + ally_speeds.last *= 2 if user.pbOwnSide.effects[PBEffects::Tailwind] > 1 + ally_speeds.last /= 2 if user.pbOwnSide.effects[PBEffects::Swamp] > 1 + end + end + # Just in case a side has no battlers + next Battle::AI::MOVE_USELESS_SCORE if ally_speeds.length == 0 || foe_speeds.length == 0 + # Invert the speeds if Trick Room applies (and will last longer than this round) + if battle.field.effects[PBEffects::TrickRoom] > 1 + foe_speeds.map! { |val| 100_000 - val } # 100_000 is higher than speed can + ally_speeds.map! { |val| 100_000 - val } # possibly be; only order matters + end + # Score based on the relative speeds + next Battle::AI::MOVE_USELESS_SCORE if ally_speeds.min > foe_speeds.max + if foe_speeds.min > ally_speeds.max + score += 20 + elsif ally_speeds.sum / ally_speeds.length < foe_speeds.sum / foe_speeds.length + score += 10 + else + score -= 10 + end + next score + } +) #=============================================================================== #