diff --git a/Data/Scripts/011_Battle/003_Move/007_MoveEffects_BattlerOther.rb b/Data/Scripts/011_Battle/003_Move/007_MoveEffects_BattlerOther.rb index 748d14c52..ff8d13e69 100644 --- a/Data/Scripts/011_Battle/003_Move/007_MoveEffects_BattlerOther.rb +++ b/Data/Scripts/011_Battle/003_Move/007_MoveEffects_BattlerOther.rb @@ -872,7 +872,7 @@ class Battle::Move::AddGhostTypeToTarget < Battle::Move def canMagicCoat?; return true; end def pbFailsAgainstTarget?(user, target, show_message) - if !GameData::Type.exists?(:GHOST) || target.pbHasType?(:GHOST) || !target.canChangeType? + if !target.canChangeType? || !GameData::Type.exists?(:GHOST) || target.pbHasType?(:GHOST) @battle.pbDisplay(_INTL("But it failed!")) if show_message return true end @@ -893,7 +893,7 @@ class Battle::Move::AddGrassTypeToTarget < Battle::Move def canMagicCoat?; return true; end def pbFailsAgainstTarget?(user, target, show_message) - if !GameData::Type.exists?(:GRASS) || target.pbHasType?(:GRASS) || !target.canChangeType? + if !target.canChangeType? || !GameData::Type.exists?(:GRASS) || target.pbHasType?(:GRASS) @battle.pbDisplay(_INTL("But it failed!")) if show_message return true end diff --git a/Data/Scripts/011_Battle/005_AI/020_AI_MoveEffectScores_Generic.rb b/Data/Scripts/011_Battle/005_AI/020_AI_MoveEffectScores_Generic.rb index f83dc2847..11dc4b3f5 100644 --- a/Data/Scripts/011_Battle/005_AI/020_AI_MoveEffectScores_Generic.rb +++ b/Data/Scripts/011_Battle/005_AI/020_AI_MoveEffectScores_Generic.rb @@ -7,6 +7,10 @@ class Battle::AI if !@battle.moldBreaker && @user.has_active_ability?(:CONTRARY) return (@move.statusMove?) ? MOVE_USELESS_SCORE : score - 20 end + # Don't make score changes if user will faint from EOR damage + if @user.rough_end_of_round_damage > @user.hp + return (@move.statusMove?) ? MOVE_USELESS_SCORE : score + 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 { |m| m.function == "PowerHigherWithUserPositiveStatStages" } @@ -14,7 +18,9 @@ class Battle::AI each_foe_battler(@user.side) do |b, i| foe_is_aware = true if !b.has_active_ability?(:UNAWARE) end - return score if !foe_is_aware + if !foe_is_aware + return (@move.statusMove?) ? MOVE_USELESS_SCORE : score + end end # Figure out which stat raises can happen @@ -124,9 +130,6 @@ class Battle::AI score += total_increment * ((100 * @user.hp / @user.totalhp) - 50) / 4 # +5 to -12 per stage end - # Don't prefer if user is about to faint due to EOR damage - score -= 30 if @user.rough_end_of_round_damage > @user.hp - # TODO: Look at abilities that trigger upon stat raise. There are none. return score @@ -239,45 +242,45 @@ class Battle::AI when :ATTACK # Modify score depending on current stat stage # More strongly prefer if the user has no special moves - if old_stage >= 3 + if old_stage >= 2 score -= 20 else has_special_moves = @user.check_for_move { |m| m.specialMove?(m.type) } inc = (has_special_moves) ? 5 : 10 - score += inc * (3 - old_stage) * inc_mult - score += 5 * inc_mult if @user.hp == @user.totalhp + score += inc * (2 - old_stage) * inc_mult + score += 4 * inc_mult if @user.hp == @user.totalhp end when :DEFENSE # Modify score depending on current stat stage - if old_stage >= 3 + if old_stage >= 2 score -= 20 else - score += 5 * (3 - old_stage) * inc_mult - score += 5 * inc_mult if @user.hp == @user.totalhp + score += 5 * (2 - old_stage) * inc_mult + score += 4 * inc_mult if @user.hp == @user.totalhp end when :SPECIAL_ATTACK # Modify score depending on current stat stage # More strongly prefer if the user has no physical moves - if old_stage >= 3 + if old_stage >= 2 score -= 20 else has_physical_moves = @user.check_for_move { |m| m.physicalMove?(m.type) && m.function != "UseUserDefenseInsteadOfUserAttack" && m.function != "UseTargetAttackInsteadOfUserAttack" } inc = (has_physical_moves) ? 5 : 10 - score += inc * (3 - old_stage) * inc_mult - score += 5 * inc_mult if @user.hp == @user.totalhp + score += inc * (2 - old_stage) * inc_mult + score += 4 * inc_mult if @user.hp == @user.totalhp end when :SPECIAL_DEFENSE # Modify score depending on current stat stage - if old_stage >= 3 + if old_stage >= 2 score -= 20 else - score += 5 * (3 - old_stage) * inc_mult - score += 5 * inc_mult if @user.hp == @user.totalhp + score += 5 * (2 - old_stage) * inc_mult + score += 4 * inc_mult if @user.hp == @user.totalhp end when :SPEED @@ -299,7 +302,7 @@ class Battle::AI when :ACCURACY # Modify score depending on current stat stage - if old_stage >= 3 + if old_stage >= 2 score -= 20 else min_accuracy = 100 @@ -309,8 +312,8 @@ class Battle::AI end min_accuracy = min_accuracy * stage_mul[old_stage] / stage_div[old_stage] if min_accuracy < 90 - score += 5 * (3 - old_stage) * inc_mult - score += 5 * inc_mult if @user.hp == @user.totalhp + score += 5 * (2 - old_stage) * inc_mult + score += 4 * inc_mult if @user.hp == @user.totalhp end end @@ -324,11 +327,11 @@ class Battle::AI score += 60 * eor_damage / b.totalhp if eor_damage > 0 end # Modify score depending on current stat stage - if old_stage >= 3 + if old_stage >= 2 score -= 20 else - score += 5 * (3 - old_stage) * inc_mult - score += 5 * inc_mult if @user.hp == @user.totalhp + score += 5 * (2 - old_stage) * inc_mult + score += 4 * inc_mult if @user.hp == @user.totalhp end end @@ -563,13 +566,19 @@ class Battle::AI if !@battle.moldBreaker && @target.has_active_ability?(:CONTRARY) return (@move.statusMove?) ? MOVE_USELESS_SCORE : score - 20 end - # Don't make score changes if foes have Unaware and user can't make use of - # extra stat stages + # Don't make score changes if target will faint from EOR damage + if @target.rough_end_of_round_damage > @target.hp + return (@move.statusMove?) ? MOVE_USELESS_SCORE : score + end + # Don't make score changes if allies have Unaware and can't make use of + # target's lowered stat stages ally_is_aware = false each_foe_battler(@target.side) do |b, i| ally_is_aware = true if !b.has_active_ability?(:UNAWARE) end - return score if !ally_is_aware + if !ally_is_aware + return (@move.statusMove?) ? MOVE_USELESS_SCORE : score + end # Figure out which stat raises can happen stat_changes = [] @@ -663,19 +672,22 @@ class Battle::AI # TODO: Don't prefer if target is semi-invulnerable and user is faster. # Prefer if move is a status move and it's the user's first/second turn -# if @user.turnCount < 2 && @move.statusMove? -# score += total_decrement * 4 -# end + if @user.turnCount < 2 && @move.statusMove? + score += total_decrement * 4 + end # Prefer if user is at high HP, don't prefer if user is at low HP -# if @user.hp >= @user.totalhp * 0.7 -# score += 4 * total_decrement -# else -# score += total_decrement * ((100 * @user.hp / @user.totalhp) - 50) / 4 # +5 to -12 per stage -# end - - # Don't prefer if user is about to faint due to EOR damage -# score -= 30 if @user.rough_end_of_round_damage > @user.hp + if @user.hp >= @user.totalhp * 0.7 + score += 3 * total_decrement + else + score += total_decrement * ((100 * @user.hp / @user.totalhp) - 50) / 6 # +3 to -8 per stage + end + # Prefer if target is at high HP, don't prefer if target is at low HP + if @target.hp >= @target.totalhp * 0.7 + score += 3 * total_decrement + else + score += total_decrement * ((100 * @target.hp / @target.totalhp) - 50) / 6 # +3 to -8 per stage + end # TODO: Look at abilities that trigger upon stat lowering. @@ -703,45 +715,45 @@ class Battle::AI when :ATTACK # Modify score depending on current stat stage # More strongly prefer if the target has no special moves - if old_stage <= -3 + if old_stage <= -2 score -= 20 else has_special_moves = @target.check_for_move { |m| m.specialMove?(m.type) } dec = (has_special_moves) ? 5 : 10 - score += dec * (3 + old_stage) * dec_mult - score += 5 * dec_mult if @target.hp == @target.totalhp + score += dec * (2 + old_stage) * dec_mult + score += 4 * dec_mult if @user.hp == @user.totalhp end when :DEFENSE # Modify score depending on current stat stage - if old_stage <= -3 + if old_stage <= -2 score -= 20 else - score += 5 * (3 + old_stage) * dec_mult - score += 5 * dec_mult if @target.hp == @target.totalhp + score += 5 * (2 + old_stage) * dec_mult + score += 4 * dec_mult if @user.hp == @user.totalhp end when :SPECIAL_ATTACK # Modify score depending on current stat stage # More strongly prefer if the target has no physical moves - if old_stage <= -3 + if old_stage <= -2 score -= 20 else has_physical_moves = @target.check_for_move { |m| m.physicalMove?(m.type) && m.function != "UseUserDefenseInsteadOfUserAttack" && m.function != "UseTargetAttackInsteadOfUserAttack" } dec = (has_physical_moves) ? 5 : 10 - score += dec * (3 + old_stage) * dec_mult - score += 5 * dec_mult if @target.hp == @target.totalhp + score += dec * (2 + old_stage) * dec_mult + score += 4 * dec_mult if @user.hp == @user.totalhp end when :SPECIAL_DEFENSE # Modify score depending on current stat stage - if old_stage <= -3 + if old_stage <= -2 score -= 20 else - score += 5 * (3 + old_stage) * dec_mult - score += 5 * dec_mult if @target.hp == @target.totalhp + score += 5 * (2 + old_stage) * dec_mult + score += 4 * dec_mult if @user.hp == @user.totalhp end when :SPEED @@ -763,20 +775,21 @@ class Battle::AI when :ACCURACY # Modify score depending on current stat stage - if old_stage <= -3 + if old_stage <= -2 score -= 20 else - score += 5 * (3 + old_stage) * dec_mult - score += 5 * dec_mult if @target.hp == @target.totalhp + score += 5 * (2 + old_stage) * dec_mult + score += 4 * dec_mult if @user.hp == @user.totalhp end + # TODO: Prefer if target is poisoned/toxiced/Leech Seeded/cursed. when :EVASION # Modify score depending on current stat stage - if old_stage <= -3 + if old_stage <= -2 score -= 20 else - score += 5 * (3 + old_stage) * dec_mult - score += 5 * dec_mult if @target.hp == @target.totalhp + score += 5 * (2 + old_stage) * dec_mult + score += 4 * dec_mult if @user.hp == @user.totalhp end end 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 ee24f203e..a42443300 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 @@ -538,7 +538,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("CureTargetBurn", ) #=============================================================================== -# TODO: Review score modifiers. +# #=============================================================================== Battle::AI::Handlers::MoveFailureCheck.add("StartUserSideImmunityToInflictedStatus", proc { |move, user, ai, battle| @@ -547,11 +547,19 @@ Battle::AI::Handlers::MoveFailureCheck.add("StartUserSideImmunityToInflictedStat ) Battle::AI::Handlers::MoveEffectScore.add("StartUserSideImmunityToInflictedStatus", proc { |score, move, user, ai, battle| - if user.status != :NONE - score -= 20 - else - score += 10 + # Not worth it if Misty Terrain is already safeguarding all user side battlers + if battle.field.terrain == :Misty && + (battle.field.terrainDuration > 1 || battle.field.terrainDuration < 0) + already_immune = true + ai.each_same_side_battler(user.side) do |b| + already_immune = false if !b.battler.affectedByTerrain? + end + next Battle::AI::MOVE_USELESS_SCORE if already_immune end + # Tends to be wasteful if the foe just has one Pokémon left + next score - 20 if battle.pbAbleNonActiveCount(user.idxOpposingSide) == 0 + # Prefer for each user side battler + ai.each_same_side_battler(user.side) { |b| score += 10 } next score } ) @@ -705,7 +713,7 @@ Battle::AI::Handlers::MoveFailureCheck.add("SetUserTypesBasedOnEnvironment", ) #=============================================================================== -# TODO: Review score modifiers. +# #=============================================================================== Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("SetUserTypesToResistLastAttack", proc { |move, user, target, ai, battle| @@ -722,9 +730,24 @@ Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("SetUserTypesToResistLas next !has_possible_type } ) +Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("SetUserTypesToResistLastAttack", + proc { |score, move, user, target, ai, battle| + effectiveness = user.effectiveness_of_type_against_battler(target.battler.lastMoveUsedType, target) + if Effectiveness.ineffective?(effectiveness) + next Battle::AI::MOVE_USELESS_SCORE + elsif Effectiveness.super_effective?(effectiveness) + score += 12 + elsif Effectiveness.normal?(effectiveness) + score += 8 + else # Not very effective + score += 4 + end + next score + } +) #=============================================================================== -# TODO: Review score modifiers. +# #=============================================================================== Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("SetUserTypesToTargetTypes", proc { |move, user, target, ai, battle| @@ -736,7 +759,7 @@ Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("SetUserTypesToTargetTyp ) #=============================================================================== -# TODO: Review score modifiers. +# #=============================================================================== Battle::AI::Handlers::MoveFailureCheck.add("SetUserTypesToUserMoveType", proc { |move, user, ai, battle| @@ -752,36 +775,131 @@ Battle::AI::Handlers::MoveFailureCheck.add("SetUserTypesToUserMoveType", next !has_possible_type } ) +Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("SetUserTypesToUserMoveType", + proc { |score, move, user, target, ai, battle| + possible_types = [] + user.battler.eachMoveWithIndex do |m, i| + break if Settings::MECHANICS_GENERATION >= 6 && i > 0 + next if GameData::Type.get(m.type).pseudo_type + next if user.has_type?(m.type) + possible_types.push(m.type) + end + # Check if any user's moves will get STAB because of the type change + possible_types.each do |type| + if user.check_for_move { |m| m.damagingMove? } + score += 10 + break + end + end + # NOTE: Other things could be considered, like the foes' moves' + # effectivenesses against the current and new user's type(s), and + # whether any of the user's moves will lose STAB because of the type + # change (and if so, which set of STAB is more beneficial). However, + # I'm keeping this simple because, if you know this move, you probably + # want to use it just because. + next score + } +) #=============================================================================== -# TODO: Review score modifiers. +# #=============================================================================== Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("SetTargetTypesToPsychic", proc { |move, user, target, ai, battle| next move.move.pbFailsAgainstTarget?(user.battler, target.battler, false) } ) +Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("SetTargetTypesToPsychic", + proc { |score, move, user, target, ai, battle| + # Prefer if user knows damaging moves that are super-effective against + # Psychic, and don't prefer if they know damaging moves that are ineffective + # against Psychic + user.battler.eachMoveWithIndex do |m, i| + next if !m.damagingMove? + effectiveness = Effectiveness.calculate(m.pbCalcType(user.battler), :PSYCHIC) + if Effectiveness.super_effective?(effectiveness) + score += 8 + elsif Effectiveness.ineffective?(effectiveness) + score -= 10 + end + end + next score + } +) #=============================================================================== -# TODO: Review score modifiers. +# #=============================================================================== Battle::AI::Handlers::MoveFailureAgainstTargetCheck.copy("SetTargetTypesToPsychic", "SetTargetTypesToWater") +Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("SetTargetTypesToWater", + proc { |score, move, user, target, ai, battle| + # Prefer if user knows damaging moves that are super-effective against + # Water, and don't prefer if they know damaging moves that are ineffective + # against Water + user.battler.eachMoveWithIndex do |m, i| + next if !m.damagingMove? + effectiveness = Effectiveness.calculate(m.pbCalcType(user.battler), :WATER) + if Effectiveness.super_effective?(effectiveness) + score += 8 + elsif Effectiveness.ineffective?(effectiveness) + score -= 10 + end + end + next score + } +) #=============================================================================== -# TODO: Review score modifiers. +# #=============================================================================== Battle::AI::Handlers::MoveFailureAgainstTargetCheck.copy("SetTargetTypesToWater", "AddGhostTypeToTarget") +Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("AddGhostTypeToTarget", + proc { |score, move, user, target, ai, battle| + # Prefer/don't prefer depending on the effectiveness of the user's damaging + # moves against the added type + user.battler.eachMoveWithIndex do |m, i| + next if !m.damagingMove? + effectiveness = Effectiveness.calculate(m.pbCalcType(user.battler), :GHOST) + if Effectiveness.super_effective?(effectiveness) + score += 8 + elsif Effectiveness.not_very_effective?(effectiveness) + score -= 5 + elsif Effectiveness.ineffective?(effectiveness) + score -= 10 + end + end + next score + } +) #=============================================================================== -# TODO: Review score modifiers. +# #=============================================================================== Battle::AI::Handlers::MoveFailureAgainstTargetCheck.copy("AddGhostTypeToTarget", "AddGrassTypeToTarget") +Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("AddGrassTypeToTarget", + proc { |score, move, user, target, ai, battle| + # Prefer/don't prefer depending on the effectiveness of the user's damaging + # moves against the added type + user.battler.eachMoveWithIndex do |m, i| + next if !m.damagingMove? + effectiveness = Effectiveness.calculate(m.pbCalcType(user.battler), :GRASS) + if Effectiveness.super_effective?(effectiveness) + score += 8 + elsif Effectiveness.not_very_effective?(effectiveness) + score -= 5 + elsif Effectiveness.ineffective?(effectiveness) + score -= 10 + end + end + next score + } +) #=============================================================================== -# TODO: Review score modifiers. +# #=============================================================================== Battle::AI::Handlers::MoveFailureCheck.add("UserLosesFireType", proc { |move, user, ai, battle| 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 0c200952a..5ee35886e 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 @@ -44,7 +44,7 @@ Battle::AI::Handlers::GeneralMoveAgainstTargetScore.add(:add_predicted_damage, 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 + score += 15 if dmg > target.hp * 1.1 # Predicted to KO the target next score.to_i end }