Some more rewrites of AI move score calculations (mainly item-related moves)

This commit is contained in:
Maruno17
2022-10-23 18:24:18 +01:00
parent 5a49bbbc94
commit e12fd08eb1
9 changed files with 164 additions and 94 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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
}
)

View File

@@ -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
}
)

View File

@@ -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

View File

@@ -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
}
)

View File

@@ -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.
#===============================================================================