From 92c0fe5c90140a0f3ca3e0bf45fe0636630d432f Mon Sep 17 00:00:00 2001 From: Maruno17 Date: Tue, 30 Aug 2022 22:13:23 +0100 Subject: [PATCH] Rewrote AI calculations for move effects relating to healing the user, added calculation to add predicted damage to a move's score --- .../005_AI/056_AI_MoveHandlers_Healing.rb | 187 ++++++++++++------ .../070_AI_MoveHandlers_GeneralModifiers.rb | 27 +-- .../011_Battle/005_AI/102_AIBattler.rb | 12 ++ 3 files changed, 153 insertions(+), 73 deletions(-) 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 676bcaaaf..393a943c3 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 @@ -1,5 +1,5 @@ #=============================================================================== -# TODO: Review score modifiers. +# #=============================================================================== Battle::AI::Handlers::MoveFailureCheck.add("HealUserFullyAndFallAsleep", proc { |move, user, target, ai, battle| @@ -10,15 +10,28 @@ Battle::AI::Handlers::MoveFailureCheck.add("HealUserFullyAndFallAsleep", ) Battle::AI::Handlers::MoveEffectScore.add("HealUserFullyAndFallAsleep", proc { |score, move, user, target, ai, battle| - score += 70 - score -= user.hp * 140 / user.totalhp - score += 30 if user.status != :NONE + # Consider how much HP will be restored + if user.hp >= user.totalhp * 0.5 + score -= 10 + else + score += 20 * (user.totalhp - user.hp) / user.totalhp + end + # Check whether an existing status problem will be removed + 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? } + score += 10 + else + score -= 10 + end + end next score } ) #=============================================================================== -# TODO: Review score modifiers. +# #=============================================================================== Battle::AI::Handlers::MoveFailureCheck.add("HealUserHalfOfTotalHP", proc { |move, user, target, ai, battle| @@ -27,61 +40,82 @@ Battle::AI::Handlers::MoveFailureCheck.add("HealUserHalfOfTotalHP", ) Battle::AI::Handlers::MoveEffectScore.add("HealUserHalfOfTotalHP", proc { |score, move, user, target, ai, battle| - score += 50 - score -= user.hp * 100 / user.totalhp + # Consider how much HP will be restored + if user.hp >= user.totalhp * 0.5 + score -= 10 + else + score += 20 * (user.totalhp - user.hp) / user.totalhp + end next score } ) #=============================================================================== -# TODO: Review score modifiers. +# #=============================================================================== Battle::AI::Handlers::MoveFailureCheck.copy("HealUserHalfOfTotalHP", "HealUserDependingOnWeather") Battle::AI::Handlers::MoveEffectScore.add("HealUserDependingOnWeather", proc { |score, move, user, target, ai, battle| - case user.battler.effectiveWeather - when :Sun, :HarshSun - score += 30 - when :None + # Consider how much HP will be restored + if user.hp >= user.totalhp * 0.5 + score -= 10 else - score -= 30 + case user.battler.effectiveWeather + when :Sun, :HarshSun + score += 5 + when :None, :StrongWinds + else + score -= 10 + end + score += 20 * (user.totalhp - user.hp) / user.totalhp end - score += 50 - score -= user.hp * 100 / user.totalhp next score } ) #=============================================================================== -# TODO: Review score modifiers. +# #=============================================================================== Battle::AI::Handlers::MoveFailureCheck.copy("HealUserHalfOfTotalHP", "HealUserDependingOnSandstorm") Battle::AI::Handlers::MoveEffectScore.add("HealUserDependingOnSandstorm", proc { |score, move, user, target, ai, battle| - score += 50 - score -= user.hp * 100 / user.totalhp - score += 30 if user.battler.effectiveWeather == :Sandstorm + # Consider how much HP will be restored + if user.hp >= user.totalhp * 0.5 + score -= 10 + else + score += 5 if user.battler.effectiveWeather == :Sandstorm + score += 20 * (user.totalhp - user.hp) / user.totalhp + end next score } ) #=============================================================================== -# TODO: Review score modifiers. +# #=============================================================================== Battle::AI::Handlers::MoveFailureCheck.copy("HealUserHalfOfTotalHP", "HealUserHalfOfTotalHPLoseFlyingTypeThisTurn") Battle::AI::Handlers::MoveEffectScore.add("HealUserHalfOfTotalHPLoseFlyingTypeThisTurn", proc { |score, move, user, target, ai, battle| - score += 50 - score -= user.hp * 100 / user.totalhp + # Consider how much HP will be restored + if user.hp >= user.totalhp * 0.5 + score -= 10 + else + score += 20 * (user.totalhp - user.hp) / user.totalhp + end + 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. Anything else? + end next score } ) #=============================================================================== -# TODO: Review score modifiers. +# #=============================================================================== Battle::AI::Handlers::MoveFailureCheck.add("CureTargetStatusHealUserHalfOfTotalHP", proc { |move, user, target, ai, battle| @@ -91,14 +125,25 @@ Battle::AI::Handlers::MoveFailureCheck.add("CureTargetStatusHealUserHalfOfTotalH ) Battle::AI::Handlers::MoveEffectScore.add("CureTargetStatusHealUserHalfOfTotalHP", proc { |score, move, user, target, ai, battle| - score += (user.totalhp - user.hp) * 50 / user.totalhp - score -= 30 if target.opposes?(user) + # TODO: Add high level checks for whether the target wants to lose their + # status problem, and change the score accordingly. + if target.opposes?(user) + score -= 10 + else + score += 15 + end + # Consider how much HP will be restored + if user.hp >= user.totalhp * 0.5 + score -= 10 + else + score += 20 * (user.totalhp - user.hp) / user.totalhp + end next score } ) #=============================================================================== -# TODO: Review score modifiers. +# #=============================================================================== Battle::AI::Handlers::MoveFailureCheck.add("HealUserByTargetAttackLowerTargetAttack1", proc { |move, user, target, ai, battle| @@ -111,69 +156,87 @@ Battle::AI::Handlers::MoveFailureCheck.add("HealUserByTargetAttackLowerTargetAtt ) Battle::AI::Handlers::MoveEffectScore.add("HealUserByTargetAttackLowerTargetAttack1", proc { |score, move, user, target, ai, battle| - if target.battler.pbCanLowerStatStage?(:ATTACK, user.battler) - score += target.stages[:ATTACK] * 20 - if ai.trainer.medium_skill? - hasPhysicalAttack = false - target.battler.eachMove do |m| - next if !m.physicalMove?(m.type) - hasPhysicalAttack = true - break - end - if hasPhysicalAttack - score += 20 - elsif ai.trainer.high_skill? - score -= 90 - end + # 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) } + score += target.stages[:ATTACK] * 10 end end - score += (user.totalhp - user.hp) * 50 / user.totalhp + # Consider how much HP will be restored + heal_amt = target.rough_stat(:ATTACK) + if heal_amt > user.totalhp * 0.3 # Only modify the score if it'll heal a decent amount + # Things that affect healing caused by draining + if target.has_active_ability?(:LIQUIDOOZE) + score -= 20 + elsif user.battler.canHeal? + if user.hp >= user.totalhp * 0.5 + score -= 10 + else + heal_amt *= 1.3 if user.has_active_item?(:BIGROOT) + heal_fraction = [user.totalhp - user.hp, heal_amt].min.to_f / user.totalhp + score += 40 * heal_fraction * (user.totalhp - user.hp) / user.totalhp + end + end + else + score -= 10 if target.has_active_ability?(:LIQUIDOOZE) + end next score } ) #=============================================================================== -# TODO: Review score modifiers. +# #=============================================================================== Battle::AI::Handlers::MoveEffectScore.add("HealUserByHalfOfDamageDone", proc { |score, move, user, target, ai, battle| - if target.has_active_ability?(:LIQUIDOOZE) - score -= 70 - elsif user.hp <= user.totalhp / 2 - score += 20 + # Consider how much HP will be restored + heal_amt = move.rough_damage / 2 + if heal_amt > user.totalhp * 0.3 # Only modify the score if it'll heal a decent amount + # Things that affect healing caused by draining + if target.has_active_ability?(:LIQUIDOOZE) + score -= 20 + elsif user.battler.canHeal? + heal_amt *= 1.3 if user.has_active_item?(:BIGROOT) + heal_fraction = [user.totalhp - user.hp, heal_amt].min.to_f / user.totalhp + score += 40 * heal_fraction * (user.totalhp - user.hp) / user.totalhp + end + else + score -= 10 if target.has_active_ability?(:LIQUIDOOZE) end next score } ) #=============================================================================== -# TODO: Review score modifiers. +# #=============================================================================== Battle::AI::Handlers::MoveFailureCheck.add("HealUserByHalfOfDamageDoneIfTargetAsleep", proc { |move, user, target, ai, battle| next true if !target.battler.asleep? } ) -Battle::AI::Handlers::MoveEffectScore.add("HealUserByHalfOfDamageDoneIfTargetAsleep", - proc { |score, move, user, target, ai, battle| - if target.has_active_ability?(:LIQUIDOOZE) - score -= 70 - elsif user.hp <= user.totalhp / 2 - score += 20 - end - next score - } -) +Battle::AI::Handlers::MoveEffectScore.copy("HealUserByHalfOfDamageDone", + "HealUserByHalfOfDamageDoneIfTargetAsleep") #=============================================================================== -# TODO: Review score modifiers. +# #=============================================================================== Battle::AI::Handlers::MoveEffectScore.add("HealUserByThreeQuartersOfDamageDone", proc { |score, move, user, target, ai, battle| - if target.has_active_ability?(:LIQUIDOOZE) - score -= 80 - elsif user.hp <= user.totalhp / 2 - score += 40 + # Consider how much HP will be restored + heal_amt = move.rough_damage * 0.75 + if heal_amt > user.totalhp * 0.3 # Only modify the score if it'll heal a decent amount + # Things that affect healing caused by draining + if target.has_active_ability?(:LIQUIDOOZE) + score -= 20 + elsif user.battler.canHeal? + heal_amt *= 1.3 if user.has_active_item?(:BIGROOT) + heal_fraction = [user.totalhp - user.hp, heal_amt].min.to_f / user.totalhp + score += 40 * heal_fraction * (user.totalhp - user.hp) / user.totalhp + end + else + score -= 10 if target.has_active_ability?(:LIQUIDOOZE) end 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 1cf99bad5..5fdbd6efc 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 @@ -258,14 +258,19 @@ Battle::AI::Handlers::GeneralMoveScore.add(:flinching_effects, # Adjust score based on how much damage it can deal. # TODO: Review score modifier. #=============================================================================== -# Battle::AI::Handlers::GeneralMoveScore.add(:add_predicted_damage, -# proc { |score, move, user, target, ai, battle| -# if move.damagingMove? -# dmg = move.rough_damage -# next score + [30.0 * dmg / target.hp, 40].min -# else # Status moves -# # Don't prefer attacks which don't deal damage -# next score - 10 -# end -# } -# ) +Battle::AI::Handlers::GeneralMoveScore.add(:add_predicted_damage, + proc { |score, move, user, target, ai, battle| + if move.damagingMove? + dmg = move.rough_damage + score += [15.0 * dmg / target.hp, 20].min + score += 10 if dmg > target.hp * 1.1 # Predicted to KO the target + next score + end + } +) + +#=============================================================================== +# TODO: Review score modifier. +#=============================================================================== +# TODO: Prefer a damaging move if it's predicted to KO the target. Maybe include +# EOR damage in the prediction? diff --git a/Data/Scripts/011_Battle/005_AI/102_AIBattler.rb b/Data/Scripts/011_Battle/005_AI/102_AIBattler.rb index d375932f6..03e98e425 100644 --- a/Data/Scripts/011_Battle/005_AI/102_AIBattler.rb +++ b/Data/Scripts/011_Battle/005_AI/102_AIBattler.rb @@ -57,6 +57,18 @@ class Battle::AI::AIBattler #============================================================================= + def check_for_move + ret = false + @battler.eachMove do |move| + next unless yield move + ret = true + break + end + return ret + end + + #============================================================================= + def speed; return @battler.speed; end # TODO: Cache calculated rough stats? Forget them in def refresh_battler.