More work on the AI, refactored stat stage multipliers

This commit is contained in:
Maruno17
2023-04-09 22:26:48 +01:00
parent 5d9cc71a99
commit a22c5ea89c
21 changed files with 618 additions and 651 deletions

View File

@@ -562,8 +562,9 @@ Battle::AI::Handlers::MoveEffectScore.add("UserMakeSubstitute",
ai.each_foe_battler(user.side) do |b, i|
score += 5 if !b.check_for_move { |m| m.ignoresSubstitute?(b.battler) }
end
# TODO: Predict incoming damage, and prefer if it's greater than
# user.totalhp / 4?
# Prefer if the user lost more than a Substitute's worth of HP from the last
# attack against it
score += 7 if user.battler.lastHPLost >= user.totalhp / 4
next score
}
)

View File

@@ -518,8 +518,6 @@ Battle::AI::Handlers::MoveEffectScore.add("StartRaiseUserAtk1WhenDamaged",
if ai.trainer.has_skill_flag?("HPAware")
next score if user.hp <= user.totalhp / 3
end
# TODO: Check whether any foe has damaging moves that will trigger the stat
# raise?
# Prefer if user benefits from a raised Attack stat
score += 10 if ai.stat_raise_worthwhile?(user, :ATTACK)
score += 7 if user.has_move_with_function?("PowerHigherWithUserPositiveStatStages")

View File

@@ -1,6 +1,5 @@
#===============================================================================
# TODO: Should there be all the "next score" for status moves? Remember that
# other function codes can call this code as part of their scoring.
#
#===============================================================================
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("SleepTarget",
proc { |move, user, target, ai, battle|
@@ -9,15 +8,16 @@ Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("SleepTarget",
)
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("SleepTarget",
proc { |score, move, user, target, ai, battle|
next score if target.effects[PBEffects::Yawn] > 0 # Target is going to fall asleep anyway
useless_score = (move.statusMove?) ? Battle::AI::MOVE_USELESS_SCORE : score
next useless_score if target.effects[PBEffects::Yawn] > 0 # Target is going to fall asleep anyway
# No score modifier if the sleep will be removed immediately
next score if target.has_active_item?([:CHESTOBERRY, :LUMBERRY])
next score if target.faster_than?(user) &&
target.has_active_ability?(:HYDRATION) &&
[:Rain, :HeavyRain].include?(target.battler.effectiveWeather)
next useless_score if target.has_active_item?([:CHESTOBERRY, :LUMBERRY])
next useless_score if target.faster_than?(user) &&
target.has_active_ability?(:HYDRATION) &&
[:Rain, :HeavyRain].include?(target.battler.effectiveWeather)
if target.battler.pbCanSleep?(user.battler, false, move.move)
add_effect = move.get_score_change_for_additional_effect(user, target)
next score if add_effect == -999 # Additional effect will be negated
next useless_score if add_effect == -999 # Additional effect will be negated
score += add_effect
# Inherent preference
score += 15
@@ -88,8 +88,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.copy("SleepTarget",
"SleepTargetNextTurn")
#===============================================================================
# TODO: Should there be all the "next score" for status moves? Remember that
# other function codes can call this code as part of their scoring.
#
#===============================================================================
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("PoisonTarget",
proc { |move, user, target, ai, battle|
@@ -98,16 +97,16 @@ Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("PoisonTarget",
)
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("PoisonTarget",
proc { |score, move, user, target, ai, battle|
next score if target.effects[PBEffects::Yawn] > 0 # Target is going to fall asleep
next Battle::AI::MOVE_USELESS_SCORE if move.statusMove? && target.has_active_ability?(:POISONHEAL)
useless_score = (move.statusMove?) ? Battle::AI::MOVE_USELESS_SCORE : score
next useless_score if target.has_active_ability?(:POISONHEAL)
# No score modifier if the poisoning will be removed immediately
next score if target.has_active_item?([:PECHABERRY, :LUMBERRY])
next score if target.faster_than?(user) &&
target.has_active_ability?(:HYDRATION) &&
[:Rain, :HeavyRain].include?(target.battler.effectiveWeather)
next useless_score if target.has_active_item?([:PECHABERRY, :LUMBERRY])
next useless_score if target.faster_than?(user) &&
target.has_active_ability?(:HYDRATION) &&
[:Rain, :HeavyRain].include?(target.battler.effectiveWeather)
if target.battler.pbCanPoison?(user.battler, false, move.move)
add_effect = move.get_score_change_for_additional_effect(user, target)
next score if add_effect == -999 # Additional effect will be negated
next useless_score if add_effect == -999 # Additional effect will be negated
score += add_effect
# Inherent preference
score += 15
@@ -159,10 +158,10 @@ Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("PoisonTargetLowerTarget
)
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("PoisonTargetLowerTargetSpeed1",
proc { |score, move, user, target, ai, battle|
score = Battle::AI::Handlers.apply_move_effect_against_target_score("PoisonTarget",
score, move, user, target, ai, battle)
score = Battle::AI::Handlers.apply_move_effect_against_target_score("LowerTargetSpeed1",
score, move, user, target, ai, battle)
poison_score = Battle::AI::Handlers.apply_move_effect_against_target_score("PoisonTarget",
0, move, user, target, ai, battle)
score += poison_score if poison_score != Battle::AI::MOVE_USELESS_SCORE
score = ai.get_score_for_target_stat_drop(score, target, move.move.statDown, false)
next score
}
)
@@ -176,8 +175,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.copy("PoisonTarget",
"BadPoisonTarget")
#===============================================================================
# TODO: Should there be all the "next score" for status moves? Remember that
# other function codes can call this code as part of their scoring.
#
#===============================================================================
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("ParalyzeTarget",
proc { |move, user, target, ai, battle|
@@ -186,15 +184,15 @@ Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("ParalyzeTarget",
)
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("ParalyzeTarget",
proc { |score, move, user, target, ai, battle|
next score if target.effects[PBEffects::Yawn] > 0 # Target is going to fall asleep
useless_score = (move.statusMove?) ? Battle::AI::MOVE_USELESS_SCORE : score
# No score modifier if the paralysis will be removed immediately
next score if target.has_active_item?([:CHERIBERRY, :LUMBERRY])
next score if target.faster_than?(user) &&
target.has_active_ability?(:HYDRATION) &&
[:Rain, :HeavyRain].include?(target.battler.effectiveWeather)
next useless_score if target.has_active_item?([:CHERIBERRY, :LUMBERRY])
next useless_score if target.faster_than?(user) &&
target.has_active_ability?(:HYDRATION) &&
[:Rain, :HeavyRain].include?(target.battler.effectiveWeather)
if target.battler.pbCanParalyze?(user.battler, false, move.move)
add_effect = move.get_score_change_for_additional_effect(user, target)
next score if add_effect == -999 # Additional effect will be negated
next useless_score if add_effect == -999 # Additional effect will be negated
score += add_effect
# Inherent preference (because of the chance of full paralysis)
score += 10
@@ -262,17 +260,22 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.copy("ParalyzeTarget",
#===============================================================================
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("ParalyzeFlinchTarget",
proc { |score, move, user, target, ai, battle|
score = Battle::AI::Handlers.apply_move_effect_against_target_score("ParalyzeTarget",
score, move, user, target, ai, battle)
score = Battle::AI::Handlers.apply_move_effect_against_target_score("FlinchTarget",
score, move, user, target, ai, battle)
paralyze_score = Battle::AI::Handlers.apply_move_effect_against_target_score("ParalyzeTarget",
0, move, user, target, ai, battle)
flinch_score = Battle::AI::Handlers.apply_move_effect_against_target_score("FlinchTarget",
0, move, user, target, ai, battle)
if paralyze_score == Battle::AI::MOVE_USELESS_SCORE &&
flinch_score == Battle::AI::MOVE_USELESS_SCORE
next Battle::AI::MOVE_USELESS_SCORE
end
score += paralyze_score if paralyze_score != Battle::AI::MOVE_USELESS_SCORE
score += flinch_score if flinch_score != Battle::AI::MOVE_USELESS_SCORE
next score
}
)
#===============================================================================
# TODO: Should there be all the "next score" for status moves? Remember that
# other function codes can call this code as part of their scoring.
#
#===============================================================================
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("BurnTarget",
proc { |move, user, target, ai, battle|
@@ -281,15 +284,15 @@ Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("BurnTarget",
)
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("BurnTarget",
proc { |score, move, user, target, ai, battle|
next score if target.effects[PBEffects::Yawn] > 0 # Target is going to fall asleep
useless_score = (move.statusMove?) ? Battle::AI::MOVE_USELESS_SCORE : score
# No score modifier if the burn will be removed immediately
next score if target.has_active_item?([:RAWSTBERRY, :LUMBERRY])
next score if target.faster_than?(user) &&
target.has_active_ability?(:HYDRATION) &&
[:Rain, :HeavyRain].include?(target.battler.effectiveWeather)
next useless_score if target.has_active_item?([:RAWSTBERRY, :LUMBERRY])
next useless_score if target.faster_than?(user) &&
target.has_active_ability?(:HYDRATION) &&
[:Rain, :HeavyRain].include?(target.battler.effectiveWeather)
if target.battler.pbCanBurn?(user.battler, false, move.move)
add_effect = move.get_score_change_for_additional_effect(user, target)
next score if add_effect == -999 # Additional effect will be negated
next useless_score if add_effect == -999 # Additional effect will be negated
score += add_effect
# Inherent preference
score += 15
@@ -339,17 +342,22 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("BurnTarget",
#===============================================================================
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("BurnFlinchTarget",
proc { |score, move, user, target, ai, battle|
score = Battle::AI::Handlers.apply_move_effect_against_target_score("BurnTarget",
score, move, user, target, ai, battle)
score = Battle::AI::Handlers.apply_move_effect_against_target_score("FlinchTarget",
score, move, user, target, ai, battle)
burn_score = Battle::AI::Handlers.apply_move_effect_against_target_score("BurnTarget",
0, move, user, target, ai, battle)
flinch_score = Battle::AI::Handlers.apply_move_effect_against_target_score("FlinchTarget",
0, move, user, target, ai, battle)
if burn_score == Battle::AI::MOVE_USELESS_SCORE &&
flinch_score == Battle::AI::MOVE_USELESS_SCORE
next Battle::AI::MOVE_USELESS_SCORE
end
score += burn_score if burn_score != Battle::AI::MOVE_USELESS_SCORE
score += flinch_score if flinch_score != Battle::AI::MOVE_USELESS_SCORE
next score
}
)
#===============================================================================
# TODO: Should there be all the "next score" for status moves? Remember that
# other function codes can call this code as part of their scoring.
#
#===============================================================================
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("FreezeTarget",
proc { |move, user, target, ai, battle|
@@ -358,15 +366,15 @@ Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("FreezeTarget",
)
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("FreezeTarget",
proc { |score, move, user, target, ai, battle|
next score if target.effects[PBEffects::Yawn] > 0 # Target is going to fall asleep
useless_score = (move.statusMove?) ? Battle::AI::MOVE_USELESS_SCORE : score
# No score modifier if the freeze will be removed immediately
next score if target.has_active_item?([:ASPEARBERRY, :LUMBERRY])
next score if target.faster_than?(user) &&
target.has_active_ability?(:HYDRATION) &&
[:Rain, :HeavyRain].include?(target.battler.effectiveWeather)
next useless_score if target.has_active_item?([:ASPEARBERRY, :LUMBERRY])
next useless_score if target.faster_than?(user) &&
target.has_active_ability?(:HYDRATION) &&
[:Rain, :HeavyRain].include?(target.battler.effectiveWeather)
if target.battler.pbCanFreeze?(user.battler, false, move.move)
add_effect = move.get_score_change_for_additional_effect(user, target)
next score if add_effect == -999 # Additional effect will be negated
next useless_score if add_effect == -999 # Additional effect will be negated
score += add_effect
# Inherent preference
score += 15
@@ -413,10 +421,16 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.copy("FreezeTarget",
#===============================================================================
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("FreezeFlinchTarget",
proc { |score, move, user, target, ai, battle|
score = Battle::AI::Handlers.apply_move_effect_against_target_score("FreezeTarget",
score, move, user, target, ai, battle)
score = Battle::AI::Handlers.apply_move_effect_against_target_score("FlinchTarget",
score, move, user, target, ai, battle)
freeze_score = Battle::AI::Handlers.apply_move_effect_against_target_score("FreezeTarget",
0, move, user, target, ai, battle)
flinch_score = Battle::AI::Handlers.apply_move_effect_against_target_score("FlinchTarget",
0, move, user, target, ai, battle)
if freeze_score == Battle::AI::MOVE_USELESS_SCORE &&
flinch_score == Battle::AI::MOVE_USELESS_SCORE
next Battle::AI::MOVE_USELESS_SCORE
end
score += freeze_score if freeze_score != Battle::AI::MOVE_USELESS_SCORE
score += flinch_score if flinch_score != Battle::AI::MOVE_USELESS_SCORE
next score
}
)
@@ -426,19 +440,17 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("FreezeFlinchTarget",
#===============================================================================
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("ParalyzeBurnOrFreezeTarget",
proc { |score, move, user, target, ai, battle|
next score if target.effects[PBEffects::Yawn] > 0 # Target is going to fall asleep
# No score modifier if the status problem will be removed immediately
next score if target.has_active_item?(:LUMBERRY)
next score if target.faster_than?(user) &&
target.has_active_ability?(:HYDRATION) &&
[:Rain, :HeavyRain].include?(target.battler.effectiveWeather)
# Scores for the possible effects
score += (Battle::AI::Handlers.apply_move_effect_against_target_score("ParalyzeTarget",
Battle::AI::MOVE_BASE_SCORE, move, user, target, ai, battle) - Battle::AI::MOVE_BASE_SCORE) / 3
score += (Battle::AI::Handlers.apply_move_effect_against_target_score("BurnTarget",
Battle::AI::MOVE_BASE_SCORE, move, user, target, ai, battle) - Battle::AI::MOVE_BASE_SCORE) / 3
score += (Battle::AI::Handlers.apply_move_effect_against_target_score("FreezeTarget",
Battle::AI::MOVE_BASE_SCORE, move, user, target, ai, battle) - Battle::AI::MOVE_BASE_SCORE) / 3
["ParalyzeTarget", "BurnTarget", "FreezeTarget"].each do |function_code|
effect_score = Battle::AI::Handlers.apply_move_effect_against_target_score(function_code,
0, move, user, target, ai, battle)
score += effect_score / 3 if effect_score != Battle::AI::MOVE_USELESS_SCORE
end
next score
}
)
@@ -461,22 +473,17 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("GiveUserStatusToTarget",
# Curing the user's status problem
score += 15 if !user.wants_status_problem?(user.status)
# Giving the target a status problem
case user.status
when :SLEEP
next Battle::AI::Handlers.apply_move_effect_against_target_score("SleepTarget",
score, move, user, target, ai, battle)
when :PARALYSIS
next Battle::AI::Handlers.apply_move_effect_against_target_score("ParalyzeTarget",
score, move, user, target, ai, battle)
when :POISON
next Battle::AI::Handlers.apply_move_effect_against_target_score("PoisonTarget",
score, move, user, target, ai, battle)
when :BURN
next Battle::AI::Handlers.apply_move_effect_against_target_score("BurnTarget",
score, move, user, target, ai, battle)
when :FROZEN
next Battle::AI::Handlers.apply_move_effect_against_target_score("FreezeTarget",
function_code = {
:SLEEP => "SleepTarget",
:PARALYSIS => "ParalyzeTarget",
:POISON => "PoisonTarget",
:BURN => "BurnTarget",
:FROZEN => "FreezeTarget"
}[user.status]
if function_code
new_score = Battle::AI::Handlers.apply_move_effect_against_target_score(function_code,
score, move, user, target, ai, battle)
next new_score if new_score != Battle::AI::MOVE_USELESS_SCORE
end
next score
}
@@ -633,7 +640,6 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("ConfuseTarget",
score += 20 * target.hp / target.totalhp
end
# Prefer if the target is paralysed or infatuated, to compound the turn skipping
# TODO: Also prefer if the target is trapped in battle or can't switch out?
score += 8 if target.status == :PARALYSIS || target.effects[PBEffects::Attract] >= 0
# Don't prefer if target benefits from being confused
score -= 15 if target.has_active_ability?(:TANGLEDFEET)
@@ -665,7 +671,6 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("AttractTarget",
# Inherent preference
score += 15
# Prefer if the target is paralysed or confused, to compound the turn skipping
# TODO: Also prefer if the target is trapped in battle or can't switch out?
score += 8 if target.status == :PARALYSIS || target.effects[PBEffects::Confusion] > 1
# Don't prefer if the target can infatuate the user because of this move
score -= 15 if target.has_active_item?(:DESTINYKNOT) &&

View File

@@ -464,9 +464,6 @@ Battle::AI::Handlers::MoveEffectScore.add("EnsureNextCriticalHit",
end
# Prefer if user knows a damaging move which won't definitely critical hit
if user.check_for_move { |m| m.damagingMove? && m.function != "AlwaysCriticalHit"}
# TODO: Change the score depending on how much of an effect a critical hit
# will have? Critical hits ignore the user's offensive stat drops
# and the target's defensive stat raises, and multiply the damage.
score += 15
end
next score
@@ -521,9 +518,6 @@ Battle::AI::Handlers::MoveEffectScore.add("StartPreventCriticalHitsAgainstUserSi
crit_stage = 99 if b.check_for_move { |m| m.pbCritialOverride(b.battler, user.battler) > 0 }
crit_stage = [crit_stage, Battle::Move::CRITICAL_HIT_RATIOS.length - 1].min
end
# TODO: Change the score depending on how much of an effect a critical hit
# will have? Critical hits ignore the user's offensive stat drops
# and the target's defensive stat raises, and multiply the damage.
score += 8 * crit_stage if crit_stage > 0
score += 10 if b.effects[PBEffects::LaserFocus] > 0
end
@@ -655,10 +649,7 @@ 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 ai.trainer.has_skill_flag?("HPAware")
if ai.trainer.has_skill_flag?("HPAware") && battle.pbAbleNonActiveCount(user.idxOwnSide) == 0
if user.hp <= user.totalhp / 2
score -= (20 * (0.75 - (user.hp.to_f / user.totalhp))).to_i # -5 to -15
end
@@ -686,10 +677,7 @@ 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 ai.trainer.has_skill_flag?("HPAware")
if ai.trainer.has_skill_flag?("HPAware") && battle.pbAbleNonActiveCount(user.idxOwnSide) == 0
if user.hp <= user.totalhp / 2
score -= (20 * (0.75 - (user.hp.to_f / user.totalhp))).to_i # -5 to -15
end
@@ -720,10 +708,7 @@ 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 ai.trainer.has_skill_flag?("HPAware")
if ai.trainer.has_skill_flag?("HPAware") && battle.pbAbleNonActiveCount(user.idxOwnSide) == 0
if user.hp <= user.totalhp / 2
score -= (20 * (0.75 - (user.hp.to_f / user.totalhp))).to_i # -5 to -15
end
@@ -767,8 +752,7 @@ Battle::AI::Handlers::MoveEffectScore.add("ProtectUser",
ai.each_foe_battler(user.side) do |b, i|
next if !b.can_attack?
next if !b.check_for_move { |m| m.canProtectAgainst? }
# TODO: Include b's Unseen Fist somehow? We don't know which move b will
# be using, so we don't know if Unseen Fist will apply.
next if b.has_active_ability?(:UNSEENFIST) && b.check_for_move { |m| m.contactMove? }
useless = false
# General preference
score += 7
@@ -812,8 +796,7 @@ Battle::AI::Handlers::MoveEffectScore.add("ProtectUserBanefulBunker",
ai.each_foe_battler(user.side) do |b, i|
next if !b.can_attack?
next if !b.check_for_move { |m| m.canProtectAgainst? }
# TODO: Include b's Unseen Fist somehow? We don't know which move b will
# be using, so we don't know if Unseen Fist will apply.
next if b.has_active_ability?(:UNSEENFIST) && b.check_for_move { |m| m.contactMove? }
useless = false
# General preference
score += 7
@@ -821,7 +804,9 @@ Battle::AI::Handlers::MoveEffectScore.add("ProtectUserBanefulBunker",
if b.check_for_move { |m| m.contactMove? }
poison_score = Battle::AI::Handlers.apply_move_effect_against_target_score("PoisonTarget",
0, move, user, b, ai, battle)
score += poison_score / 2 # Halved because we don't know what move b will use
if poison_score != Battle::AI::MOVE_USELESS_SCORE
score += poison_score / 2 # Halved because we don't know what move b will use
end
end
# Prefer if the foe is in the middle of using a two turn attack
score += 15 if b.effects[PBEffects::TwoTurnAttack] &&
@@ -852,7 +837,7 @@ Battle::AI::Handlers::MoveEffectScore.add("ProtectUserBanefulBunker",
)
#===============================================================================
# TODO: Special scoring for Aegislash.
#
#===============================================================================
Battle::AI::Handlers::MoveEffectScore.add("ProtectUserFromDamagingMovesKingsShield",
proc { |score, move, user, ai, battle|
@@ -863,8 +848,7 @@ Battle::AI::Handlers::MoveEffectScore.add("ProtectUserFromDamagingMovesKingsShie
ai.each_foe_battler(user.side) do |b, i|
next if !b.can_attack?
next if !b.check_for_move { |m| m.damagingMove? && m.canProtectAgainst? }
# TODO: Include b's Unseen Fist somehow? We don't know which move b will
# be using, so we don't know if Unseen Fist will apply.
next if b.has_active_ability?(:UNSEENFIST) && b.check_for_move { |m| m.contactMove? }
useless = false
# General preference
score += 7
@@ -898,6 +882,9 @@ Battle::AI::Handlers::MoveEffectScore.add("ProtectUserFromDamagingMovesKingsShie
# Don't prefer if the user used a protection move last turn, making this one
# less likely to work
score -= (user.effects[PBEffects::ProtectRate] - 1) * ((Settings::MECHANICS_GENERATION >= 6) ? 15 : 10)
# Aegislash
score += 10 if user.battler.isSpecies?(:AEGISLASH) && user.form == 1 &&
user.ability == :STANCECHANGE
next score
}
)
@@ -914,8 +901,7 @@ Battle::AI::Handlers::MoveEffectScore.add("ProtectUserFromDamagingMovesObstruct"
ai.each_foe_battler(user.side) do |b, i|
next if !b.can_attack?
next if !b.check_for_move { |m| m.damagingMove? && m.canProtectAgainst? }
# TODO: Include b's Unseen Fist somehow? We don't know which move b will
# be using, so we don't know if Unseen Fist will apply.
next if b.has_active_ability?(:UNSEENFIST) && b.check_for_move { |m| m.contactMove? }
useless = false
# General preference
score += 7
@@ -964,8 +950,7 @@ Battle::AI::Handlers::MoveEffectScore.add("ProtectUserFromTargetingMovesSpikyShi
ai.each_foe_battler(user.side) do |b, i|
next if !b.can_attack?
next if !b.check_for_move { |m| m.canProtectAgainst? }
# TODO: Include b's Unseen Fist somehow? We don't know which move b will
# be using, so we don't know if Unseen Fist will apply.
next if b.has_active_ability?(:UNSEENFIST) && b.check_for_move { |m| m.contactMove? }
useless = false
# General preference
score += 7
@@ -1016,8 +1001,7 @@ Battle::AI::Handlers::MoveEffectScore.add("ProtectUserSideFromDamagingMovesIfUse
ai.each_foe_battler(user.side) do |b, i|
next if !b.can_attack?
next if !b.check_for_move { |m| m.damagingMove? && m.canProtectAgainst? }
# TODO: Include b's Unseen Fist somehow? We don't know which move b will
# be using, so we don't know if Unseen Fist will apply.
next if b.has_active_ability?(:UNSEENFIST) && b.check_for_move { |m| m.contactMove? }
useless = false
# General preference
score += 7
@@ -1252,8 +1236,9 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("RecoilThirdOfDamageDealt
score -= 25 * [dmg, user.hp].min / user.hp
end
# Score for paralysing
score = Battle::AI::Handlers.apply_move_effect_against_target_score("ParalyzeTarget",
score, move, user, target, ai, battle)
paralyze_score = Battle::AI::Handlers.apply_move_effect_against_target_score("ParalyzeTarget",
0, move, user, target, ai, battle)
score += paralyze_score if paralyze_score != Battle::AI::MOVE_USELESS_SCORE
next score
}
)
@@ -1274,8 +1259,9 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("RecoilThirdOfDamageDealt
score -= 25 * [dmg, user.hp].min / user.hp
end
# Score for burning
score = Battle::AI::Handlers.apply_move_effect_against_target_score("BurnTarget",
score, move, user, target, ai, battle)
burn_score = Battle::AI::Handlers.apply_move_effect_against_target_score("BurnTarget",
0, move, user, target, ai, battle)
score += burn_score if burn_score != Battle::AI::MOVE_USELESS_SCORE
next score
}
)
@@ -1359,7 +1345,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("EnsureNextMoveAlwaysHits
acc = m.pbBaseAccuracy(user.battler, target.battler) if ai.trainer.medium_skill?
score += 5 if acc < 90 && acc != 0
score += 8 if acc <= 50 && acc != 0
# TODO: Prefer more if m is a OHKO move.
score += 8 if m.is_a?(Battle::Move::OHKO)
end
# TODO: Prefer if target has increased evasion.
# Not worth it if the user or the target is at low HP
@@ -1535,10 +1521,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("TargetMovesBecomeElectri
)
#===============================================================================
# TODO: This could check all other battlers, not just foes. It could check the
# effectivenesses of their Normal and Electric moves on all their foes,
# not just on the user. I think this is overkill, particularly as the
# effect only lasts for one round.
#
#===============================================================================
Battle::AI::Handlers::MoveEffectScore.add("NormalMovesBecomeElectric",
proc { |score, move, user, ai, battle|

View File

@@ -31,8 +31,9 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("HitTwoTimesPoisonTarget"
score = Battle::AI::Handlers.apply_move_effect_against_target_score("HitTwoTimes",
score, move, user, target, ai, battle)
# Score for poisoning
score = Battle::AI::Handlers.apply_move_effect_against_target_score("PoisonTarget",
score, move, user, target, ai, battle)
poison_score = Battle::AI::Handlers.apply_move_effect_against_target_score("PoisonTarget",
0, move, user, target, ai, battle)
score += poison_score if poison_score != Battle::AI::MOVE_USELESS_SCORE
next score
}
)
@@ -279,6 +280,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("TwoTurnAttackParalyzeTar
# Score for being a two turn attack
score = Battle::AI::Handlers.apply_move_effect_against_target_score("TwoTurnAttack",
score, move, user, target, ai, battle)
next score if score == Battle::AI::MOVE_USELESS_SCORE
# Score for paralysing
score = Battle::AI::Handlers.apply_move_effect_against_target_score("ParalyzeTarget",
score, move, user, target, ai, battle)
@@ -294,6 +296,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("TwoTurnAttackBurnTarget"
# Score for being a two turn attack
score = Battle::AI::Handlers.apply_move_effect_against_target_score("TwoTurnAttack",
score, move, user, target, ai, battle)
next score if score == Battle::AI::MOVE_USELESS_SCORE
# Score for burning
score = Battle::AI::Handlers.apply_move_effect_against_target_score("BurnTarget",
score, move, user, target, ai, battle)
@@ -309,6 +312,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("TwoTurnAttackFlinchTarge
# Score for being a two turn attack
score = Battle::AI::Handlers.apply_move_effect_against_target_score("TwoTurnAttack",
score, move, user, target, ai, battle)
next score if score == Battle::AI::MOVE_USELESS_SCORE
# Score for flinching
score = Battle::AI::Handlers.apply_move_effect_against_target_score("FlinchTarget",
score, move, user, target, ai, battle)
@@ -323,11 +327,12 @@ Battle::AI::Handlers::MoveFailureCheck.copy("RaiseUserAtkDef1",
"TwoTurnAttackRaiseUserSpAtkSpDefSpd2")
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("TwoTurnAttackRaiseUserSpAtkSpDefSpd2",
proc { |score, move, user, target, ai, battle|
# Score for raising user's stats
score = ai.get_score_for_target_stat_raise(score, user, move.move.statUp)
# Score for being a two turn attack
score = Battle::AI::Handlers.apply_move_effect_against_target_score("TwoTurnAttack",
score, move, user, target, ai, battle)
next score if score == Battle::AI::MOVE_USELESS_SCORE
# Score for raising user's stats
score = ai.get_score_for_target_stat_raise(score, user, move.move.statUp)
next score
}
)
@@ -340,6 +345,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("TwoTurnAttackChargeRaise
# Score for being a two turn attack
score = Battle::AI::Handlers.apply_move_effect_against_target_score("TwoTurnAttack",
score, move, user, target, ai, battle)
next score if score == Battle::AI::MOVE_USELESS_SCORE
# Score for raising the user's stat
score = Battle::AI::Handlers.apply_move_effect_score("RaiseUserDefense1",
score, move, user, ai, battle)
@@ -355,6 +361,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("TwoTurnAttackChargeRaise
# Score for being a two turn attack
score = Battle::AI::Handlers.apply_move_effect_against_target_score("TwoTurnAttack",
score, move, user, target, ai, battle)
next score if score == Battle::AI::MOVE_USELESS_SCORE
# Score for raising the user's stat
score = Battle::AI::Handlers.apply_move_effect_score("RaiseUserSpAtk1",
score, move, user, ai, battle)
@@ -370,6 +377,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("TwoTurnAttackInvulnerabl
# Score for being a two turn attack
score = Battle::AI::Handlers.apply_move_effect_against_target_score("TwoTurnAttack",
score, move, user, target, ai, battle)
next score if score == Battle::AI::MOVE_USELESS_SCORE
# Score for being semi-invulnerable underground
ai.each_foe_battler(user.side) do |b, i|
if b.check_for_move { |m| m.hitsDiggingTargets? }
@@ -390,6 +398,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("TwoTurnAttackInvulnerabl
# Score for being a two turn attack
score = Battle::AI::Handlers.apply_move_effect_against_target_score("TwoTurnAttack",
score, move, user, target, ai, battle)
next score if score == Battle::AI::MOVE_USELESS_SCORE
# Score for being semi-invulnerable underwater
ai.each_foe_battler(user.side) do |b, i|
if b.check_for_move { |m| m.hitsDivingTargets? }
@@ -410,6 +419,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("TwoTurnAttackInvulnerabl
# Score for being a two turn attack
score = Battle::AI::Handlers.apply_move_effect_against_target_score("TwoTurnAttack",
score, move, user, target, ai, battle)
next score if score == Battle::AI::MOVE_USELESS_SCORE
# Score for being semi-invulnerable in the sky
ai.each_foe_battler(user.side) do |b, i|
if b.check_for_move { |m| m.hitsFlyingTargets? }
@@ -430,6 +440,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("TwoTurnAttackInvulnerabl
# Score for being a two turn attack and semi-invulnerable in the sky
score = Battle::AI::Handlers.apply_move_effect_against_target_score("TwoTurnAttackInvulnerableInSky",
score, move, user, target, ai, battle)
next score if score == Battle::AI::MOVE_USELESS_SCORE
# Score for paralyzing the target
score = Battle::AI::Handlers.apply_move_effect_against_target_score("ParalyzeTarget",
score, move, user, target, ai, battle)
@@ -460,6 +471,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("TwoTurnAttackInvulnerabl
# Score for being a two turn attack
score = Battle::AI::Handlers.apply_move_effect_against_target_score("TwoTurnAttack",
score, move, user, target, ai, battle)
next score if score == Battle::AI::MOVE_USELESS_SCORE
# Score for being invulnerable
score += 8
# Score for removing protections

View File

@@ -97,11 +97,7 @@ Battle::AI::Handlers::MoveEffectScore.add("HealUserHalfOfTotalHPLoseFlyingTypeTh
score = Battle::AI::Handlers.apply_move_effect_score("HealUserHalfOfTotalHP",
score, move, user, ai, battle)
# User loses the Flying type this round
if user.has_type?(:FLYING)
# TODO: Decide whether losing the Flying type is good or bad. Look at
# type effectiveness changes against the user, and for foes' Ground
# moves (foe foes slower than the user). Anything else?
end
# NOTE: Not worth considering and scoring for.
next score
}
)
@@ -118,7 +114,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("CureTargetStatusHealUser
proc { |score, move, user, target, ai, battle|
# Consider how much HP will be restored
score = Battle::AI::Handlers.apply_move_effect_score("HealUserHalfOfTotalHP",
score, move, user, ai, battle)
score, move, user, ai, battle)
# Will cure target's status
score += (target.wants_status_problem?(target.status)) ? 10 : -8
next score

View File

@@ -217,8 +217,9 @@ Battle::AI::Handlers::MoveFailureCheck.add("UserConsumeBerryRaiseDefense2",
Battle::AI::Handlers::MoveEffectScore.add("UserConsumeBerryRaiseDefense2",
proc { |score, move, user, ai, battle|
# Score for raising the user's stat
score = Battle::AI::Handlers.apply_move_effect_score("RaiseUserDefense2",
score, move, user, ai, battle)
stat_raise_score = Battle::AI::Handlers.apply_move_effect_score("RaiseUserDefense2",
0, move, user, ai, battle)
score += stat_raise_score if stat_raise_score != Battle::AI::MOVE_USELESS_SCORE
# Score for the consumed berry's effect
score += user.get_score_change_for_consuming_item(user.item_id, true)
# Score for other results of consuming the berry