From c53a52564b947d756da373d10ffbe5583907beb3 Mon Sep 17 00:00:00 2001 From: Maruno17 Date: Sat, 26 Nov 2022 22:31:28 +0000 Subject: [PATCH] More AI rewrites of various function codes, made move score threshold multiplier depend on trainer skill --- .../011_Battle/005_AI/004_AI_ChooseMove.rb | 19 ++- .../052_AI_MoveHandlers_BattlerStats.rb | 2 +- .../053_AI_MoveHandlers_BattlerOther.rb | 7 +- .../054_AI_MoveHandlers_MoveAttributes.rb | 150 +++++++++++++++--- .../058_AI_MoveHandlers_ChangeMoveEffect.rb | 32 ++-- .../059_AI_MoveHandlers_SwitchingActing.rb | 4 +- .../070_AI_MoveHandlers_GeneralModifiers.rb | 8 + 7 files changed, 174 insertions(+), 48 deletions(-) diff --git a/Data/Scripts/011_Battle/005_AI/004_AI_ChooseMove.rb b/Data/Scripts/011_Battle/005_AI/004_AI_ChooseMove.rb index f746b3148..aa0014949 100644 --- a/Data/Scripts/011_Battle/005_AI/004_AI_ChooseMove.rb +++ b/Data/Scripts/011_Battle/005_AI/004_AI_ChooseMove.rb @@ -3,6 +3,12 @@ class Battle::AI MOVE_USELESS_SCORE = 60 # Move predicted to do nothing or just be detrimental MOVE_BASE_SCORE = 100 + # Returns a value between 0.0 and 1.0. All move scores are lowered by this + # value multiplied by the highest-scoring move's score. + def move_score_threshold + return 0.6 + 0.35 * (([@trainer.skill, 100].min / 100.0) ** 0.5) # 0.6 to 0.95 + end + #============================================================================= # Get scores for the user's moves (done before any action is assessed). #============================================================================= @@ -105,6 +111,9 @@ class Battle::AI @user.statusCount > 1 && !@move.move.usableWhenAsleep? # User will be truanting return true if @user.has_active_ability?(:TRUANT) && @user.effects[PBEffects::Truant] + # Primal weather + return true if @battle.pbWeather == :HeavyRain && @move.rough_type == :FIRE + return true if @battle.pbWeather == :HarshSun && @move.rough_type == :WATER # Move effect-specific checks return true if Battle::AI::Handlers.move_will_fail?(@move.function, @move, @user, self, @battle) return false @@ -116,12 +125,18 @@ class Battle::AI # Immunity to priority moves because of Psychic Terrain return true if @battle.field.terrain == :Psychic && @target.battler.affectedByTerrain? && @target.opposes?(@user) && @move.rough_priority(@user) > 0 - # Immunity because of ability (intentionally before type immunity check) + # Immunity because of ability # TODO: Check for target-redirecting abilities that also provide immunity. # If an ally has such an ability, may want to just not prefer the move # instead of predicting its failure, as might want to hit the ally # after all. return true if @move.move.pbImmunityByAbility(@user.battler, @target.battler, false) + # Immunity because of Dazzling/Queenly Majesty + if @move.rough_priority(@user) > 0 && @target.opposes?(@user) + each_same_side_battler(@target.side) do |b, i| + return true if b.has_active_ability?([:DAZZLING, :QUEENLYMAJESTY]) + end + end # Type immunity calc_type = @move.rough_type typeMod = @move.move.pbCalcTypeMod(calc_type, @user.battler, @target.battler) @@ -237,7 +252,7 @@ class Battle::AI end end # Calculate a minimum score threshold and reduce all move scores by it - threshold = (max_score * 0.85).floor + threshold = (max_score * move_score_threshold.to_f).floor choices.each { |c| c[3] = [c[1] - threshold, 0].max } total_score = choices.sum { |c| c[3] } # Log the available choices diff --git a/Data/Scripts/011_Battle/005_AI/052_AI_MoveHandlers_BattlerStats.rb b/Data/Scripts/011_Battle/005_AI/052_AI_MoveHandlers_BattlerStats.rb index ca6f409f2..a1390450f 100644 --- a/Data/Scripts/011_Battle/005_AI/052_AI_MoveHandlers_BattlerStats.rb +++ b/Data/Scripts/011_Battle/005_AI/052_AI_MoveHandlers_BattlerStats.rb @@ -823,7 +823,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.copy("LowerTargetAttack1", "LowerTargetSpAtk1") #=============================================================================== -# TODO: Review score modifiers. +# #=============================================================================== Battle::AI::Handlers::MoveFailureAgainstTargetCheck.copy("LowerTargetSpAtk1", "LowerTargetSpAtk2") diff --git a/Data/Scripts/011_Battle/005_AI/053_AI_MoveHandlers_BattlerOther.rb b/Data/Scripts/011_Battle/005_AI/053_AI_MoveHandlers_BattlerOther.rb index 608d67d32..d9b82fdfc 100644 --- a/Data/Scripts/011_Battle/005_AI/053_AI_MoveHandlers_BattlerOther.rb +++ b/Data/Scripts/011_Battle/005_AI/053_AI_MoveHandlers_BattlerOther.rb @@ -814,8 +814,8 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("SetTargetTypesToPsychic" # Prefer if target's foes know damaging moves that are super-effective # against Psychic, and don't prefer if they know damaging moves that are # ineffective against Psychic - ai.each_foe_battler(target.side) do |b, b| - b.battler.eachMove do |m,| + ai.each_foe_battler(target.side) do |b, i| + b.battler.eachMove do |m| next if !m.damagingMove? effectiveness = Effectiveness.calculate(m.pbCalcType(b.battler), :PSYCHIC) if Effectiveness.super_effective?(effectiveness) @@ -824,6 +824,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("SetTargetTypesToPsychic" score -= 10 end end + end next score } ) @@ -1144,7 +1145,7 @@ Battle::AI::Handlers::MoveEffectScore.add("StartGravity", score += (user.opposes?(b)) ? score_change : -score_change # Prefer if allies have any damaging Ground moves they'll be able to use # on a grounded foe, and vice versa - ai.each_foe_battler(b.side) do |b2| + ai.each_foe_battler(b.side) do |b2, j| if b2.check_for_move { |m| m.damagingMove? && m.pbCalcType(b2.battler) == :GROUND } score += (user.opposes?(b2)) ? -5 : 5 end diff --git a/Data/Scripts/011_Battle/005_AI/054_AI_MoveHandlers_MoveAttributes.rb b/Data/Scripts/011_Battle/005_AI/054_AI_MoveHandlers_MoveAttributes.rb index 21b31bca5..d62b933f6 100644 --- a/Data/Scripts/011_Battle/005_AI/054_AI_MoveHandlers_MoveAttributes.rb +++ b/Data/Scripts/011_Battle/005_AI/054_AI_MoveHandlers_MoveAttributes.rb @@ -192,22 +192,40 @@ Battle::AI::Handlers::MoveBasePower.copy("PowerHigherWithTargetWeight", "PowerHigherWithUserHeavierThanTarget") #=============================================================================== -# TODO: Review score modifiers. +# #=============================================================================== Battle::AI::Handlers::MoveBasePower.add("PowerHigherWithConsecutiveUse", proc { |power, move, user, target, ai, battle| next power << user.effects[PBEffects::FuryCutter] } ) +Battle::AI::Handlers::MoveEffectScore.add("PowerHigherWithConsecutiveUse", + proc { |score, move, user, ai, battle| + # Prefer continuing to use this move + score += 10 if user.effects[PBEffects::FuryCutter] > 0 + # Prefer if holding the Metronome + score += 5 if user.has_active_item?(:METRONOME) + next score + } +) #=============================================================================== -# TODO: Review score modifiers. +# #=============================================================================== Battle::AI::Handlers::MoveBasePower.add("PowerHigherWithConsecutiveUseOnUserSide", proc { |power, move, user, target, ai, battle| next power * (user.pbOwnSide.effects[PBEffects::EchoedVoiceCounter] + 1) } ) +Battle::AI::Handlers::MoveEffectScore.add("PowerHigherWithConsecutiveUse", + proc { |score, move, user, ai, battle| + # Prefer continuing to use this move + score += 10 if user.pbOwnSide.effects[PBEffects::EchoedVoiceCounter] > 0 + # Prefer if holding the Metronome + score += 5 if user.has_active_item?(:METRONOME) + next score + } +) #=============================================================================== # @@ -351,7 +369,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("DoublePowerIfTargetLostH # DoublePowerIfUserStatsLoweredThisTurn #=============================================================================== -# TODO: Review score modifiers. +# #=============================================================================== Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("DoublePowerIfTargetActed", proc { |score, move, user, target, ai, battle| @@ -360,7 +378,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("DoublePowerIfTargetActed ) #=============================================================================== -# TODO: Review score modifiers. +# #=============================================================================== Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("DoublePowerIfTargetNotActed", proc { |score, move, user, target, ai, battle| @@ -369,7 +387,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("DoublePowerIfTargetNotAc ) #=============================================================================== -# TODO: Review score modifiers. +# #=============================================================================== # AlwaysCriticalHit @@ -378,12 +396,8 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("DoublePowerIfTargetNotAc #=============================================================================== Battle::AI::Handlers::MoveEffectScore.add("EnsureNextCriticalHit", proc { |score, move, user, ai, battle| - if user.effects[PBEffects::LaserFocus] > 0 - score -= 90 - else - score += 40 - end - next score + next Battle::AI::MOVE_USELESS_SCORE if user.effects[PBEffects::LaserFocus] > 0 + next score + 10 } ) @@ -423,7 +437,7 @@ Battle::AI::Handlers::MoveEffectScore.add("UserEnduresFaintingThisTurn", ) #=============================================================================== -# TODO: Review score modifiers. +# #=============================================================================== Battle::AI::Handlers::MoveFailureCheck.add("StartWeakenElectricMoves", proc { |move, user, ai, battle| @@ -434,9 +448,30 @@ Battle::AI::Handlers::MoveFailureCheck.add("StartWeakenElectricMoves", end } ) +Battle::AI::Handlers::MoveEffectScore.add("StartWeakenElectricMoves", + proc { |score, move, user, ai, battle| + # Don't prefer the lower the user's HP is + if user.hp < user.totalhp / 2 + score -= 40 * (0.75 - (user.hp.to_f / user.totalhp)) # -10 to -30 + end + # Prefer if foes have Electric moves + ai.each_foe_battler(user.side) do |b, i| + next if !b.check_for_move { |m| m.damagingMove? && m.pbCalcType(b.battler) == :ELECTRIC } + score += 10 + score += 5 if !b.check_for_move { |m| m.damagingMove? && m.pbCalcType(b.battler) != :ELECTRIC } + end + # Don't prefer if any allies have Electric moves + ai.each_same_side_battler(user.side) do |b, i| + next if !b.check_for_move { |m| m.damagingMove? && m.pbCalcType(b.battler) == :ELECTRIC } + score -= 8 + score -= 4 if !b.check_for_move { |m| m.damagingMove? && m.pbCalcType(b.battler) != :ELECTRIC } + end + next score + } +) #=============================================================================== -# TODO: Review score modifiers. +# #=============================================================================== Battle::AI::Handlers::MoveFailureCheck.add("StartWeakenFireMoves", proc { |move, user, ai, battle| @@ -447,27 +482,82 @@ Battle::AI::Handlers::MoveFailureCheck.add("StartWeakenFireMoves", end } ) +Battle::AI::Handlers::MoveEffectScore.add("StartWeakenElectricMoves", + proc { |score, move, user, ai, battle| + # Don't prefer the lower the user's HP is + if user.hp < user.totalhp / 2 + score -= 40 * (0.75 - (user.hp.to_f / user.totalhp)) # -10 to -30 + end + # Prefer if foes have Fire moves + ai.each_foe_battler(user.side) do |b, i| + next if !b.check_for_move { |m| m.damagingMove? && m.pbCalcType(b.battler) == :FIRE } + score += 10 + score += 5 if !b.check_for_move { |m| m.damagingMove? && m.pbCalcType(b.battler) != :FIRE } + end + # Don't prefer if any allies have Fire moves + ai.each_same_side_battler(user.side) do |b, i| + next if !b.check_for_move { |m| m.damagingMove? && m.pbCalcType(b.battler) == :FIRE } + score -= 8 + score -= 4 if !b.check_for_move { |m| m.damagingMove? && m.pbCalcType(b.battler) != :FIRE } + end + next score + } +) #=============================================================================== -# TODO: Review score modifiers. +# #=============================================================================== Battle::AI::Handlers::MoveFailureCheck.add("StartWeakenPhysicalDamageAgainstUserSide", proc { |move, user, ai, battle| next true if user.pbOwnSide.effects[PBEffects::Reflect] > 0 } ) +Battle::AI::Handlers::MoveEffectScore.add("StartWeakenPhysicalDamageAgainstUserSide", + proc { |score, move, user, ai, battle| + # 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 + if user.hp < user.totalhp / 2 + score -= 40 * (0.75 - (user.hp.to_f / user.totalhp)) # -10 to -30 + end + # Prefer if foes have physical moves (moreso if they don't have special moves) + ai.each_foe_battler(user.side) do |b, i| + next if !b.check_for_move { |m| m.physicalMove?(m.type) } + score += 8 + score += 5 if !b.check_for_move { |m| m.specialMove?(m.type) } + end + next score + } +) #=============================================================================== -# TODO: Review score modifiers. +# #=============================================================================== Battle::AI::Handlers::MoveFailureCheck.add("StartWeakenSpecialDamageAgainstUserSide", proc { |move, user, ai, battle| next true if user.pbOwnSide.effects[PBEffects::LightScreen] > 0 } ) +Battle::AI::Handlers::MoveEffectScore.add("StartWeakenSpecialDamageAgainstUserSide", + proc { |score, move, user, ai, battle| + # 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 + if user.hp < user.totalhp / 2 + score -= 40 * (0.75 - (user.hp.to_f / user.totalhp)) # -10 to -30 + end + # Prefer if foes have special moves (moreso if they don't have physical moves) + ai.each_foe_battler(user.side) do |b, i| + next if !b.check_for_move { |m| m.specialMove?(m.type) } + score += 8 + score += 5 if !b.check_for_move { |m| m.physicalMove?(m.type) } + end + next score + } +) #=============================================================================== -# TODO: Review score modifiers. +# #=============================================================================== Battle::AI::Handlers::MoveFailureCheck.add("StartWeakenDamageAgainstUserSideIfHail", proc { |move, user, ai, battle| @@ -477,18 +567,36 @@ Battle::AI::Handlers::MoveFailureCheck.add("StartWeakenDamageAgainstUserSideIfHa ) Battle::AI::Handlers::MoveEffectScore.add("StartWeakenDamageAgainstUserSideIfHail", proc { |score, move, user, ai, battle| - next score + 40 + # Doesn't stack with Reflect/Light Screen + 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 + if user.hp < user.totalhp / 2 + score -= 40 * (0.75 - (user.hp.to_f / user.totalhp)) # -10 to -30 + end + next score + 15 } ) #=============================================================================== -# TODO: Review score modifiers. +# #=============================================================================== Battle::AI::Handlers::MoveEffectScore.add("RemoveScreens", proc { |score, move, user, ai, battle| - score += 10 if user.pbOpposingSide.effects[PBEffects::AuroraVeil] > 0 - score += 10 if user.pbOpposingSide.effects[PBEffects::Reflect] > 0 - score += 10 if user.pbOpposingSide.effects[PBEffects::LightScreen] > 0 + # Prefer if allies have physical moves that are being weakened + if user.pbOpposingSide.effects[PBEffects::Reflect] > 0 || + user.pbOpposingSide.effects[PBEffects::AuroraVeil] > 0 + ai.each_same_side_battler(user.side) do |b, i| + score += 10 if b.check_for_move { |m| m.physicalMove?(m.type) } + end + end + # Prefer if allies have special moves that are being weakened + if user.pbOpposingSide.effects[PBEffects::LightScreen] > 0 || + user.pbOpposingSide.effects[PBEffects::AuroraVeil] > 0 + ai.each_same_side_battler(user.side) do |b, i| + score += 10 if b.check_for_move { |m| m.specialMove?(m.type) } + end + end next score } ) 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 3de26dbae..eaa51c68f 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 @@ -3,7 +3,7 @@ #=============================================================================== Battle::AI::Handlers::MoveEffectScore.add("RedirectAllMovesToUser", proc { |score, move, user, ai, battle| - next 0 if user.battler.allAllies.length == 0 + next Battle::AI::MOVE_USELESS_SCORE if user.battler.allAllies.length == 0 } ) @@ -12,7 +12,7 @@ Battle::AI::Handlers::MoveEffectScore.add("RedirectAllMovesToUser", #=============================================================================== Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("RedirectAllMovesToTarget", proc { |score, move, user, target, ai, battle| - next 0 if user.battler.allAllies.length == 0 + next Battle::AI::MOVE_USELESS_SCORE if user.battler.allAllies.length == 0 } ) @@ -21,6 +21,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("RedirectAllMovesToTarget #=============================================================================== Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("CannotBeRedirected", proc { |score, move, user, target, ai, battle| + next score if target.battler.allAllies.length == 0 redirection = false user.battler.allOpposing.each do |b| next if b.index == target.index @@ -113,22 +114,16 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("CurseTargetOrLowerUserSp # EffectDependsOnEnvironment #=============================================================================== -# TODO: Review score modifiers. +# #=============================================================================== Battle::AI::Handlers::MoveBasePower.add("HitsAllFoesAndPowersUpInPsychicTerrain", proc { |power, move, user, target, ai, battle| next move.move.pbBaseDamage(power, user.battler, target.battler) } ) -Battle::AI::Handlers::MoveEffectScore.add("HitsAllFoesAndPowersUpInPsychicTerrain", - proc { |score, move, user, ai, battle| - next score + 20 if battle.field.terrain == :Psychic && user.battler.affectedByTerrain? && - battle.allOtherSideBattlers(user.index).length > 1 - } -) #=============================================================================== -# TODO: Review score modifiers. +# #=============================================================================== Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("TargetNextFireMoveDamagesTarget", proc { |move, user, target, ai, battle| @@ -137,12 +132,12 @@ Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("TargetNextFireMoveDamag ) Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("TargetNextFireMoveDamagesTarget", proc { |score, move, user, target, ai, battle| - aspeed = user.rough_stat(:SPEED) - ospeed = target.rough_stat(:SPEED) - if aspeed > ospeed - score -= 50 - elsif target.battler.pbHasMoveType?(:FIRE) - score += 30 + # Effect wears off at the end of the round + next Battle::AI::MOVE_USELESS_SCORE if target.faster_than?(user) + # Prefer if target knows any Fire moves (moreso if that's the only type they know) + if target.check_for_move { |m| m.pbCalcType(b.battler) == :FIRE } + score += 10 + score += 10 if !target.check_for_move { |m| m.pbCalcType(b.battler) != :FIRE } end next score } @@ -168,7 +163,7 @@ Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("PowerUpAllyMove", ) Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("PowerUpAllyMove", proc { |score, move, user, target, ai, battle| - next score + 30 + next score + 15 } ) @@ -342,8 +337,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("UseLastMoveUsedByTarget" # UseMoveDependingOnEnvironment #=============================================================================== -# TODO: Review score modifiers. -# TODO: This code shouldn't make use of target. +# #=============================================================================== # UseRandomMove 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 510b20b67..30e8bd331 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 @@ -22,7 +22,7 @@ Battle::AI::Handlers::MoveFailureCheck.add("SwitchOutUserStatusMove", Battle::AI::Handlers::MoveEffectScore.add("SwitchOutUserStatusMove", proc { |score, move, user, ai, battle| next score + 10 if user.wild? - if battle.pbTeamAbleNonActiveCount(user.index) > 1 # Don't switch in ace + if battle.pbTeamAbleNonActiveCount(user.index) == 1 # Don't switch in ace score -= 60 else score += 40 if user.effects[PBEffects::Confusion] > 0 @@ -52,7 +52,7 @@ Battle::AI::Handlers::MoveEffectScore.add("SwitchOutUserStatusMove", Battle::AI::Handlers::MoveEffectScore.add("SwitchOutUserDamagingMove", proc { |score, move, user, ai, battle| next 0 if !battle.pbCanChooseNonActive?(user.index) || - battle.pbTeamAbleNonActiveCount(user.index) > 1 # Don't switch in ace + battle.pbTeamAbleNonActiveCount(user.index) == 1 # Don't switch in ace } ) 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 5ee35886e..b2de360e4 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 @@ -157,6 +157,14 @@ Battle::AI::Handlers::GeneralMoveAgainstTargetScore.add(:dance_move_against_danc } ) +#=============================================================================== +# TODO: Review score modifier. +#=============================================================================== +# TODO: Prefer a higher priority move if the user is slower than the foe(s) and +# the user is at risk of being knocked out. Consider whether the foe(s) +# have priority moves of their own? Limit this to prefer priority damaging +# moves? + #=============================================================================== # TODO: Review score modifier. #===============================================================================