Rewrites of disabling move AI function codes, fixed various AI errors

This commit is contained in:
Maruno17
2023-01-19 22:30:55 +00:00
parent 0c9df4627e
commit f7578002ea
16 changed files with 359 additions and 217 deletions

View File

@@ -84,6 +84,14 @@ module GameData
return GameData::Type.get(@type).special? return GameData::Type.get(@type).special?
end end
def damaging?
return @category != 2
end
def status?
return @category == 2
end
def hidden_move? def hidden_move?
GameData::Item.each do |i| GameData::Item.each do |i|
return true if i.is_HM? && i.move == @id return true if i.is_HM? && i.move == @id

View File

@@ -134,21 +134,7 @@ end
# Hits 2-5 times in a row. If the move does not fail, increases the user's Speed # Hits 2-5 times in a row. If the move does not fail, increases the user's Speed
# by 1 stage and decreases the user's Defense by 1 stage. (Scale Shot) # by 1 stage and decreases the user's Defense by 1 stage. (Scale Shot)
#=============================================================================== #===============================================================================
class Battle::Move::HitTwoToFiveTimesRaiseUserSpd1LowerUserDef1 < Battle::Move class Battle::Move::HitTwoToFiveTimesRaiseUserSpd1LowerUserDef1 < Battle::Move::HitTwoToFiveTimes
def multiHitMove?; return true; end
def pbNumHits(user, targets)
hitChances = [
2, 2, 2, 2, 2, 2, 2,
3, 3, 3, 3, 3, 3, 3,
4, 4, 4,
5, 5, 5
]
r = @battle.pbRandom(hitChances.length)
r = hitChances.length - 1 if user.hasActiveAbility?(:SKILLLINK)
return hitChances[r]
end
def pbEffectAfterAllHits(user, target) def pbEffectAfterAllHits(user, target)
return if target.damageState.unaffected return if target.damageState.unaffected
if user.pbCanLowerStatStage?(:DEFENSE, user, self) if user.pbCanLowerStatStage?(:DEFENSE, user, self)

View File

@@ -767,26 +767,26 @@ class Battle::Move::DisableTargetUsingDifferentMove < Battle::Move
def initialize(battle, move) def initialize(battle, move)
super super
@moveBlacklist = [ @moveBlacklist = [
"DisableTargetUsingDifferentMove", # Encore "DisableTargetUsingDifferentMove", # Encore
# Struggle # Struggle
"Struggle", # Struggle "Struggle", # Struggle
# Moves that affect the moveset # Moves that affect the moveset
"ReplaceMoveThisBattleWithTargetLastMoveUsed", # Mimic "ReplaceMoveThisBattleWithTargetLastMoveUsed", # Mimic
"ReplaceMoveWithTargetLastMoveUsed", # Sketch "ReplaceMoveWithTargetLastMoveUsed", # Sketch
"TransformUserIntoTarget", # Transform "TransformUserIntoTarget", # Transform
# Moves that call other moves (see also below) # Moves that call other moves (see also below)
"UseLastMoveUsedByTarget" # Mirror Move "UseLastMoveUsedByTarget" # Mirror Move
] ]
if Settings::MECHANICS_GENERATION >= 7 if Settings::MECHANICS_GENERATION >= 7
@moveBlacklist += [ @moveBlacklist += [
# Moves that call other moves # Moves that call other moves
# "UseLastMoveUsedByTarget", # Mirror Move # See above # "UseLastMoveUsedByTarget", # Mirror Move # See above
"UseLastMoveUsed", # Copycat "UseLastMoveUsed", # Copycat
"UseMoveTargetIsAboutToUse", # Me First "UseMoveTargetIsAboutToUse", # Me First
"UseMoveDependingOnEnvironment", # Nature Power "UseMoveDependingOnEnvironment", # Nature Power
"UseRandomUserMoveIfAsleep", # Sleep Talk "UseRandomUserMoveIfAsleep", # Sleep Talk
"UseRandomMoveFromUserParty", # Assist "UseRandomMoveFromUserParty", # Assist
"UseRandomMove" # Metronome "UseRandomMove" # Metronome
] ]
end end
end end

View File

@@ -442,7 +442,7 @@ class Battle::Scene
moveType = moveData.type moveType = moveData.type
moveKind = moveData.category moveKind = moveData.category
moveKind += 3 if target_data.num_targets > 1 || target_data.affects_foe_side moveKind += 3 if target_data.num_targets > 1 || target_data.affects_foe_side
moveKind += 3 if moveKind == 2 && target_data.num_targets > 0 moveKind += 3 if moveData.status? && target_data.num_targets > 0
# [one target physical, one target special, user status, # [one target physical, one target special, user status,
# multiple targets physical, multiple targets special, non-user status] # multiple targets physical, multiple targets special, non-user status]
typeDefaultAnim = { typeDefaultAnim = {

View File

@@ -107,7 +107,7 @@ class Battle::AI
if spikes > 0 if spikes > 0
spikesDmg = [8, 6, 4][spikes - 1] spikesDmg = [8, 6, 4][spikes - 1]
next if pkmn.hp <= pkmn.totalhp / spikesDmg && next if pkmn.hp <= pkmn.totalhp / spikesDmg &&
!pkmn.hasType?(:FLYING) && !pkmn.hasActiveAbility?(:LEVITATE) !pkmn.hasType?(:FLYING) && !pkmn.hasAbility?(:LEVITATE)
end end
end end
# moveType is the type of the target's last used move # moveType is the type of the target's last used move

View File

@@ -29,11 +29,11 @@ class Battle::AI
end end
next next
end end
PBDebug.log_ai("#{@user.name} is considering using #{move.name}...")
# Set up move in class variables # Set up move in class variables
set_up_move_check(move) set_up_move_check(move)
# Predict whether the move will fail (generally) # Predict whether the move will fail (generally)
if @trainer.has_skill_flag?("PredictMoveFailure") && pbPredictMoveFailure if @trainer.has_skill_flag?("PredictMoveFailure") && pbPredictMoveFailure
PBDebug.log_ai("#{@user.name} is considering using #{move.name}...")
PBDebug.log_score_change(MOVE_FAIL_SCORE - MOVE_BASE_SCORE, "move will fail") PBDebug.log_score_change(MOVE_FAIL_SCORE - MOVE_BASE_SCORE, "move will fail")
add_move_to_choices(choices, idxMove, MOVE_FAIL_SCORE) add_move_to_choices(choices, idxMove, MOVE_FAIL_SCORE)
next next
@@ -43,6 +43,7 @@ class Battle::AI
case target_data.num_targets case target_data.num_targets
when 0 # No targets, affects the user or a side or the whole field when 0 # No targets, affects the user or a side or the whole field
# Includes: BothSides, FoeSide, None, User, UserSide # Includes: BothSides, FoeSide, None, User, UserSide
PBDebug.log_ai("#{@user.name} is considering using #{move.name}...")
score = MOVE_BASE_SCORE score = MOVE_BASE_SCORE
PBDebug.logonerr { score = pbGetMoveScore } PBDebug.logonerr { score = pbGetMoveScore }
add_move_to_choices(choices, idxMove, score) add_move_to_choices(choices, idxMove, score)
@@ -57,6 +58,7 @@ class Battle::AI
# TODO: Should this sometimes consider targeting an ally? See def # TODO: Should this sometimes consider targeting an ally? See def
# pbGetMoveScoreAgainstTarget for more information. # pbGetMoveScoreAgainstTarget for more information.
next if target_data.targets_foe && !@user.battler.opposes?(b) next if target_data.targets_foe && !@user.battler.opposes?(b)
PBDebug.log_ai("#{@user.name} is considering using #{move.name} against #{b.name} (#{b.index})...")
score = MOVE_BASE_SCORE score = MOVE_BASE_SCORE
PBDebug.logonerr { score = pbGetMoveScore([b]) } PBDebug.logonerr { score = pbGetMoveScore([b]) }
add_move_to_choices(choices, idxMove, score, b.index) add_move_to_choices(choices, idxMove, score, b.index)
@@ -70,6 +72,7 @@ class Battle::AI
next if !@battle.pbMoveCanTarget?(@user.battler.index, b.index, target_data) next if !@battle.pbMoveCanTarget?(@user.battler.index, b.index, target_data)
targets.push(b) targets.push(b)
end end
PBDebug.log_ai("#{@user.name} is considering using #{move.name}...")
score = MOVE_BASE_SCORE score = MOVE_BASE_SCORE
PBDebug.logonerr { score = pbGetMoveScore(targets) } PBDebug.logonerr { score = pbGetMoveScore(targets) }
add_move_to_choices(choices, idxMove, score) add_move_to_choices(choices, idxMove, score)
@@ -108,7 +111,7 @@ class Battle::AI
move.pbOnStartUse(@user.battler, []) # Determine which move is used instead move.pbOnStartUse(@user.battler, []) # Determine which move is used instead
move = Battle::Move.from_pokemon_move(@battle, Pokemon::Move.new(move.npMove)) move = Battle::Move.from_pokemon_move(@battle, Pokemon::Move.new(move.npMove))
end end
@move.set_up(move, @user) @move.set_up(move)
@battle.moldBreaker = @user.has_mold_breaker? @battle.moldBreaker = @user.has_mold_breaker?
end end
@@ -130,7 +133,9 @@ class Battle::AI
# User is awake and can't use moves that are only usable when asleep # User is awake and can't use moves that are only usable when asleep
return true if !@user.battler.asleep? && @move.move.usableWhenAsleep? return true if !@user.battler.asleep? && @move.move.usableWhenAsleep?
# User will be truanting # User will be truanting
return true if @user.has_active_ability?(:TRUANT) && @user.effects[PBEffects::Truant] # TODO: Should Truanting treat all moves as failing? If it does, it will
# trigger switching due to terrible moves.
# return true if @user.has_active_ability?(:TRUANT) && @user.effects[PBEffects::Truant]
# Primal weather # Primal weather
return true if @battle.pbWeather == :HeavyRain && @move.rough_type == :FIRE return true if @battle.pbWeather == :HeavyRain && @move.rough_type == :FIRE
return true if @battle.pbWeather == :HarshSun && @move.rough_type == :WATER return true if @battle.pbWeather == :HarshSun && @move.rough_type == :WATER
@@ -301,14 +306,11 @@ class Battle::AI
# Decide whether all choices are bad, and if so, try switching instead # Decide whether all choices are bad, and if so, try switching instead
if @trainer.high_skill? && @user.can_switch_lax? if @trainer.high_skill? && @user.can_switch_lax?
badMoves = false badMoves = false
if (max_score <= MOVE_FAIL_SCORE && user_battler.turnCount > 2) || if max_score <= MOVE_USELESS_SCORE
(max_score <= MOVE_USELESS_SCORE && user_battler.turnCount > 4) badMoves = true
elsif max_score < MOVE_BASE_SCORE * move_score_threshold && user_battler.turnCount > 2
badMoves = true if pbAIRandom(100) < 80 badMoves = true if pbAIRandom(100) < 80
end end
if !badMoves && max_score <= MOVE_USELESS_SCORE && user_battler.turnCount >= 1
badMoves = choices.none? { |c| user_battler.moves[c[0]].damagingMove? }
badMoves = false if badMoves && pbAIRandom(100) < 10
end
if badMoves if badMoves
PBDebug.log_ai("#{@user.name} wants to switch due to terrible moves") PBDebug.log_ai("#{@user.name} wants to switch due to terrible moves")
return if pbEnemyShouldWithdrawEx?(true) return if pbEnemyShouldWithdrawEx?(true)

View File

@@ -31,7 +31,7 @@ class Battle::AI
end end
# Don't make score changes if foes have Unaware and target can't make use of # Don't make score changes if foes have Unaware and target can't make use of
# extra stat stages # extra stat stages
if !target.check_for_move { |m| m.function == "PowerHigherWithUserPositiveStatStages" } if !target.has_move_with_function?("PowerHigherWithUserPositiveStatStages")
foe_is_aware = false foe_is_aware = false
each_foe_battler(target.side) do |b, i| each_foe_battler(target.side) do |b, i|
foe_is_aware = true if !b.has_active_ability?(:UNAWARE) foe_is_aware = true if !b.has_active_ability?(:UNAWARE)
@@ -121,7 +121,7 @@ class Battle::AI
"PowerHigherWithUserFasterThanTarget", "PowerHigherWithUserFasterThanTarget",
"PowerHigherWithUserPositiveStatStages" "PowerHigherWithUserPositiveStatStages"
] ]
if !target.check_for_move { |m| moves_that_prefer_high_speed.include?(m.function) } if !target.has_move_with_function?(*moves_that_prefer_high_speed)
each_foe_battler(target.side) do |b, i| each_foe_battler(target.side) do |b, i|
return true if b.faster_than?(target) return true if b.faster_than?(target)
end end
@@ -272,7 +272,7 @@ class Battle::AI
end end
old_stage = target.stages[stat] old_stage = target.stages[stat]
new_stage = old_stage + increment new_stage = old_stage + increment
inc_mult = (stage_mul[new_stage].to_f * stage_div[old_stage]) / (stage_div[new_stage] * stage_mul[old_stage]) inc_mult = (stage_mul[new_stage + 6].to_f * stage_div[old_stage + 6]) / (stage_div[new_stage + 6] * stage_mul[old_stage + 6])
inc_mult -= 1 inc_mult -= 1
inc_mult *= desire_mult inc_mult *= desire_mult
# Stat-based score changes # Stat-based score changes
@@ -280,8 +280,8 @@ class Battle::AI
when :ATTACK when :ATTACK
# Modify score depending on current stat stage # Modify score depending on current stat stage
# More strongly prefer if the target has no special moves # More strongly prefer if the target has no special moves
if old_stage >= 2 if old_stage >= 2 && increment == 1
score -= 20 * ((target.opposes?(@user)) ? 1 : desire_mult) score -= 15 * ((target.opposes?(@user)) ? 1 : desire_mult)
else else
has_special_moves = target.check_for_move { |m| m.specialMove?(m.type) } has_special_moves = target.check_for_move { |m| m.specialMove?(m.type) }
inc = (has_special_moves) ? 10 : 20 inc = (has_special_moves) ? 10 : 20
@@ -290,8 +290,8 @@ class Battle::AI
when :DEFENSE when :DEFENSE
# Modify score depending on current stat stage # Modify score depending on current stat stage
if old_stage >= 2 if old_stage >= 2 && increment == 1
score -= 20 * ((target.opposes?(@user)) ? 1 : desire_mult) score -= 15 * ((target.opposes?(@user)) ? 1 : desire_mult)
else else
score += 10 * inc_mult score += 10 * inc_mult
end end
@@ -299,8 +299,8 @@ class Battle::AI
when :SPECIAL_ATTACK when :SPECIAL_ATTACK
# Modify score depending on current stat stage # Modify score depending on current stat stage
# More strongly prefer if the target has no physical moves # More strongly prefer if the target has no physical moves
if old_stage >= 2 if old_stage >= 2 && increment == 1
score -= 20 * ((target.opposes?(@user)) ? 1 : desire_mult) score -= 15 * ((target.opposes?(@user)) ? 1 : desire_mult)
else else
has_physical_moves = target.check_for_move { |m| m.physicalMove?(m.type) && has_physical_moves = target.check_for_move { |m| m.physicalMove?(m.type) &&
m.function != "UseUserDefenseInsteadOfUserAttack" && m.function != "UseUserDefenseInsteadOfUserAttack" &&
@@ -311,8 +311,8 @@ class Battle::AI
when :SPECIAL_DEFENSE when :SPECIAL_DEFENSE
# Modify score depending on current stat stage # Modify score depending on current stat stage
if old_stage >= 2 if old_stage >= 2 && increment == 1
score -= 20 * ((target.opposes?(@user)) ? 1 : desire_mult) score -= 15 * ((target.opposes?(@user)) ? 1 : desire_mult)
else else
score += 10 * inc_mult score += 10 * inc_mult
end end
@@ -333,12 +333,12 @@ class Battle::AI
"PowerHigherWithUserFasterThanTarget", "PowerHigherWithUserFasterThanTarget",
"PowerHigherWithUserPositiveStatStages" "PowerHigherWithUserPositiveStatStages"
] ]
if target.check_for_move { |m| moves_that_prefer_high_speed.include?(m.function) } if target.has_move_with_function?(*moves_that_prefer_high_speed)
score += 8 * inc_mult score += 8 * inc_mult
end end
# Don't prefer if any foe has Gyro Ball # Don't prefer if any foe has Gyro Ball
each_foe_battler(target.side) do |b, i| each_foe_battler(target.side) do |b, i|
next if !b.check_for_move { |m| m.function == "PowerHigherWithTargetFasterThanUser" } next if !b.has_move_with_function?("PowerHigherWithTargetFasterThanUser")
score -= 8 * inc_mult score -= 8 * inc_mult
end end
# Don't prefer if target has Speed Boost (will be gaining Speed anyway) # Don't prefer if target has Speed Boost (will be gaining Speed anyway)
@@ -348,8 +348,8 @@ class Battle::AI
when :ACCURACY when :ACCURACY
# Modify score depending on current stat stage # Modify score depending on current stat stage
if old_stage >= 2 if old_stage >= 2 && increment == 1
score -= 20 * ((target.opposes?(@user)) ? 1 : desire_mult) score -= 15 * ((target.opposes?(@user)) ? 1 : desire_mult)
else else
min_accuracy = 100 min_accuracy = 100
target.battler.moves.each do |m| target.battler.moves.each do |m|
@@ -372,8 +372,8 @@ class Battle::AI
next if eor_damage <= 0 next if eor_damage <= 0
end end
# Modify score depending on current stat stage # Modify score depending on current stat stage
if old_stage >= 2 if old_stage >= 2 && increment == 1
score -= 20 * ((target.opposes?(@user)) ? 1 : desire_mult) score -= 15 * ((target.opposes?(@user)) ? 1 : desire_mult)
else else
score += 10 * inc_mult score += 10 * inc_mult
end end
@@ -381,12 +381,12 @@ class Battle::AI
end end
# Prefer if target has Stored Power # Prefer if target has Stored Power
if target.check_for_move { |m| m.function == "PowerHigherWithUserPositiveStatStages" } if target.has_move_with_function?("PowerHigherWithUserPositiveStatStages")
score += 5 * increment * desire_mult score += 5 * increment * desire_mult
end end
# Don't prefer if any foe has Punishment # Don't prefer if any foe has Punishment
each_foe_battler(target.side) do |b, i| each_foe_battler(target.side) do |b, i|
next if !b.check_for_move { |m| m.function == "PowerHigherWithTargetPositiveStatStages" } next if !b.has_move_with_function?("PowerHigherWithTargetPositiveStatStages")
score -= 5 * increment * desire_mult score -= 5 * increment * desire_mult
end end
@@ -611,7 +611,7 @@ class Battle::AI
#============================================================================= #=============================================================================
def get_score_for_target_stat_drop(score, target, stat_changes, whole_effect = true, fixed_change = false) def get_score_for_target_stat_drop(score, target, stat_changes, whole_effect = true, fixed_change = false)
whole_effect = false if @move.damagingMove? whole_effect = false if @move.damagingMove?
# Decide whether the target raising its stat(s) is a good thing # Decide whether the target lowering its stat(s) is a good thing
desire_mult = -1 desire_mult = -1
if target.opposes?(@user) || if target.opposes?(@user) ||
(@move.pbTarget(@user.battler).targets_foe && target.index != @user.index) (@move.pbTarget(@user.battler).targets_foe && target.index != @user.index)
@@ -619,7 +619,7 @@ class Battle::AI
end end
# Discard status move/don't prefer damaging move if target has Contrary # Discard status move/don't prefer damaging move if target has Contrary
# TODO: Maybe this should return get_score_for_target_stat_raise if Contrary # TODO: Maybe this should return get_score_for_target_stat_raise if Contrary
# applies and desire_mult < 1. # applies and desire_mult < 0.
if !fixed_change && !@battle.moldBreaker && target.has_active_ability?(:CONTRARY) && desire_mult > 0 if !fixed_change && !@battle.moldBreaker && target.has_active_ability?(:CONTRARY) && desire_mult > 0
ret = (whole_effect) ? MOVE_USELESS_SCORE : score - 20 ret = (whole_effect) ? MOVE_USELESS_SCORE : score - 20
PBDebug.log_score_change(ret - score, "don't prefer lowering target's stats (it has Contrary)") PBDebug.log_score_change(ret - score, "don't prefer lowering target's stats (it has Contrary)")
@@ -643,7 +643,7 @@ class Battle::AI
return ret return ret
end end
# Figure out which stat raises can happen # Figure out which stat drops can happen
real_stat_changes = [] real_stat_changes = []
stat_changes.each_with_index do |stat, idx| stat_changes.each_with_index do |stat, idx|
next if idx.odd? next if idx.odd?
@@ -655,7 +655,7 @@ class Battle::AI
end end
next next
end end
# Calculate amount that stat will be raised by # Calculate amount that stat will be lowered by
decrement = stat_changes[idx + 1] decrement = stat_changes[idx + 1]
decrement *= 2 if !fixed_change && !@battle.moldBreaker && @user.has_active_ability?(:SIMPLE) decrement *= 2 if !fixed_change && !@battle.moldBreaker && @user.has_active_ability?(:SIMPLE)
decrement = [decrement, 6 + target.stages[stat]].min # The actual stages lost decrement = [decrement, 6 + target.stages[stat]].min # The actual stages lost
@@ -721,7 +721,7 @@ class Battle::AI
"PowerHigherWithUserFasterThanTarget", "PowerHigherWithUserFasterThanTarget",
"PowerHigherWithUserPositiveStatStages" "PowerHigherWithUserPositiveStatStages"
] ]
if !target.check_for_move { |m| moves_that_prefer_high_speed.include?(m.function) } if !target.has_move_with_function?(*moves_that_prefer_high_speed)
each_foe_battler(target.side) do |b, i| each_foe_battler(target.side) do |b, i|
return true if !b.faster_than?(target) return true if !b.faster_than?(target)
end end
@@ -786,7 +786,7 @@ class Battle::AI
end end
old_stage = target.stages[stat] old_stage = target.stages[stat]
new_stage = old_stage - decrement new_stage = old_stage - decrement
dec_mult = (stage_mul[old_stage].to_f * stage_div[new_stage]) / (stage_div[old_stage] * stage_mul[new_stage]) dec_mult = (stage_mul[old_stage + 6].to_f * stage_div[new_stage + 6]) / (stage_div[old_stage + 6] * stage_mul[new_stage + 6])
dec_mult -= 1 dec_mult -= 1
dec_mult *= desire_mult dec_mult *= desire_mult
# Stat-based score changes # Stat-based score changes
@@ -794,8 +794,8 @@ class Battle::AI
when :ATTACK when :ATTACK
# Modify score depending on current stat stage # Modify score depending on current stat stage
# More strongly prefer if the target has no special moves # More strongly prefer if the target has no special moves
if old_stage <= -2 if old_stage <= -2 && decrement == 1
score -= 20 * ((target.opposes?(@user)) ? 1 : desire_mult) score -= 15 * ((target.opposes?(@user)) ? 1 : desire_mult)
else else
has_special_moves = target.check_for_move { |m| m.specialMove?(m.type) } has_special_moves = target.check_for_move { |m| m.specialMove?(m.type) }
dec = (has_special_moves) ? 5 : 10 dec = (has_special_moves) ? 5 : 10
@@ -804,8 +804,8 @@ class Battle::AI
when :DEFENSE when :DEFENSE
# Modify score depending on current stat stage # Modify score depending on current stat stage
if old_stage <= -2 if old_stage <= -2 && decrement == 1
score -= 20 * ((target.opposes?(@user)) ? 1 : desire_mult) score -= 15 * ((target.opposes?(@user)) ? 1 : desire_mult)
else else
score += 5 * dec_mult score += 5 * dec_mult
end end
@@ -813,8 +813,8 @@ class Battle::AI
when :SPECIAL_ATTACK when :SPECIAL_ATTACK
# Modify score depending on current stat stage # Modify score depending on current stat stage
# More strongly prefer if the target has no physical moves # More strongly prefer if the target has no physical moves
if old_stage <= -2 if old_stage <= -2 && decrement == 1
score -= 20 * ((target.opposes?(@user)) ? 1 : desire_mult) score -= 15 * ((target.opposes?(@user)) ? 1 : desire_mult)
else else
has_physical_moves = target.check_for_move { |m| m.physicalMove?(m.type) && has_physical_moves = target.check_for_move { |m| m.physicalMove?(m.type) &&
m.function != "UseUserDefenseInsteadOfUserAttack" && m.function != "UseUserDefenseInsteadOfUserAttack" &&
@@ -825,8 +825,8 @@ class Battle::AI
when :SPECIAL_DEFENSE when :SPECIAL_DEFENSE
# Modify score depending on current stat stage # Modify score depending on current stat stage
if old_stage <= -2 if old_stage <= -2 && decrement == 1
score -= 20 * ((target.opposes?(@user)) ? 1 : desire_mult) score -= 15 * ((target.opposes?(@user)) ? 1 : desire_mult)
else else
score += 5 * dec_mult score += 5 * dec_mult
end end
@@ -842,7 +842,7 @@ class Battle::AI
end end
# Prefer if any ally has Electro Ball # Prefer if any ally has Electro Ball
each_foe_battler(target.side) do |b, i| each_foe_battler(target.side) do |b, i|
next if !b.check_for_move { |m| m.function == "PowerHigherWithUserFasterThanTarget" } next if !b.has_move_with_function?("PowerHigherWithUserFasterThanTarget")
score += 8 * dec_mult score += 8 * dec_mult
end end
# Don't prefer if target has Speed Boost (will be gaining Speed anyway) # Don't prefer if target has Speed Boost (will be gaining Speed anyway)
@@ -852,8 +852,8 @@ class Battle::AI
when :ACCURACY when :ACCURACY
# Modify score depending on current stat stage # Modify score depending on current stat stage
if old_stage <= -2 if old_stage <= -2 && decrement == 1
score -= 20 * ((target.opposes?(@user)) ? 1 : desire_mult) score -= 15 * ((target.opposes?(@user)) ? 1 : desire_mult)
else else
score += 5 * dec_mult score += 5 * dec_mult
end end
@@ -861,8 +861,8 @@ class Battle::AI
when :EVASION when :EVASION
# Modify score depending on current stat stage # Modify score depending on current stat stage
if old_stage <= -2 if old_stage <= -2 && decrement == 1
score -= 20 * ((target.opposes?(@user)) ? 1 : desire_mult) score -= 15 * ((target.opposes?(@user)) ? 1 : desire_mult)
else else
score += 5 * dec_mult score += 5 * dec_mult
end end
@@ -870,12 +870,12 @@ class Battle::AI
end end
# Prefer if target has Stored Power # Prefer if target has Stored Power
if target.check_for_move { |m| m.function == "PowerHigherWithUserPositiveStatStages" } if target.has_move_with_function?("PowerHigherWithUserPositiveStatStages")
score += 5 * decrement * desire_mult score += 5 * decrement * desire_mult
end end
# Don't prefer if any foe has Punishment # Don't prefer if any foe has Punishment
each_foe_battler(target.side) do |b, i| each_foe_battler(target.side) do |b, i|
next if !b.check_for_move { |m| m.function == "PowerHigherWithTargetPositiveStatStages" } next if !b.has_move_with_function?("PowerHigherWithTargetPositiveStatStages")
score -= 5 * decrement * desire_mult score -= 5 * decrement * desire_mult
end end
@@ -901,14 +901,14 @@ class Battle::AI
ret += (b.opposes?(move_user)) ? -10 : 10 ret += (b.opposes?(move_user)) ? -10 : 10
end end
# Check for Electric moves # Check for Electric moves
if b.check_for_move { |m| m.type == :ELECTRIC && m.damagingMove? } if b.has_damaging_move_of_type?(:ELECTRIC)
ret += (b.opposes?(move_user)) ? -15 : 15 ret += (b.opposes?(move_user)) ? -15 : 15
end end
when :Grassy when :Grassy
# End of round healing # End of round healing
ret += (b.opposes?(move_user)) ? -10 : 10 ret += (b.opposes?(move_user)) ? -10 : 10
# Check for Grass moves # Check for Grass moves
if b.check_for_move { |m| m.type == :GRASS && m.damagingMove? } if b.has_damaging_move_of_type?(:GRASS)
ret += (b.opposes?(move_user)) ? -15 : 15 ret += (b.opposes?(move_user)) ? -15 : 15
end end
when :Misty when :Misty
@@ -919,7 +919,7 @@ class Battle::AI
ret += (b.opposes?(move_user)) ? -5 : 5 ret += (b.opposes?(move_user)) ? -5 : 5
end end
# Check for Dragon moves # Check for Dragon moves
if b.check_for_move { |m| m.type == :DRAGON && m.damagingMove? } if b.has_damaging_move_of_type?(:DRAGON)
ret += (b.opposes?(move_user)) ? 15 : -15 ret += (b.opposes?(move_user)) ? 15 : -15
end end
when :Psychic when :Psychic
@@ -928,7 +928,7 @@ class Battle::AI
ret += (b.opposes?(move_user)) ? 10 : -10 ret += (b.opposes?(move_user)) ? 10 : -10
end end
# Check for Psychic moves # Check for Psychic moves
if b.check_for_move { |m| m.type == :PSYCHIC && m.damagingMove? } if b.has_damaging_move_of_type?(:PSYCHIC)
ret += (b.opposes?(move_user)) ? -15 : 15 ret += (b.opposes?(move_user)) ? -15 : 15
end end
end end
@@ -980,16 +980,16 @@ class Battle::AI
ret += (b.opposes?(move_user)) ? -15 : 15 ret += (b.opposes?(move_user)) ? -15 : 15
end end
# Moves # Moves
if b.check_for_move { |m| ["EffectDependsOnEnvironment", if b.has_move_with_function?("EffectDependsOnEnvironment",
"SetUserTypesBasedOnEnvironment", "SetUserTypesBasedOnEnvironment",
"TypeAndPowerDependOnTerrain", "TypeAndPowerDependOnTerrain",
"UseMoveDependingOnEnvironment"].include?(m.function) } "UseMoveDependingOnEnvironment")
ret += (b.opposes?(move_user)) ? -10 : 10 ret += (b.opposes?(move_user)) ? -10 : 10
end end
if good_moves && b.check_for_move { |m| good_moves.include?(m.function) } if good_moves && b.has_move_with_function?(*good_moves)
ret += (b.opposes?(move_user)) ? -10 : 10 ret += (b.opposes?(move_user)) ? -10 : 10
end end
if bad_moves && b.check_for_move { |m| bad_moves.include?(m.function) } if bad_moves && b.has_move_with_function?(*bad_moves)
ret += (b.opposes?(move_user)) ? 10 : -10 ret += (b.opposes?(move_user)) ? 10 : -10
end end
end end
@@ -1011,7 +1011,7 @@ class Battle::AI
:LEFTOVERS :LEFTOVERS
] ]
preferred_items.push(:BLACKSLUDGE) if battler.has_type?(:POISON) 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(:IRONBALL) if battler.has_move_with_function?("ThrowUserItemAtTarget")
preferred_items.push(:CHOICEBAND) if battler.check_for_move { |m| m.physicalMove?(m.type) } 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) } preferred_items.push(:CHOICESPECS) if battler.check_for_move { |m| m.specialMove?(m.type) }
unpreferred_items = [ unpreferred_items = [
@@ -1029,7 +1029,7 @@ class Battle::AI
ret = -2 ret = -2
end end
# Don't prefer if the battler knows Acrobatics # Don't prefer if the battler knows Acrobatics
if battler.check_for_move { |m| m.function == "DoublePowerIfUserHasNoItem" } if battler.has_move_with_function?("DoublePowerIfUserHasNoItem")
ret += (item == :NONE) ? 1 : -1 ret += (item == :NONE) ? 1 : -1
end end
return ret return ret
@@ -1050,7 +1050,7 @@ class Battle::AI
:AIRLOCK => 5, :AIRLOCK => 5,
:ANALYTIC => 5, :ANALYTIC => 5,
:ANGERPOINT => 4, :ANGERPOINT => 4,
:ANTICIPATION => 2, :ANTICIPATION => 0,
:ARENATRAP => 9, :ARENATRAP => 9,
:AROMAVEIL => 3, :AROMAVEIL => 3,
# :ASONECHILLINGNEIGH => 0, # :ASONECHILLINGNEIGH => 0,
@@ -1109,9 +1109,9 @@ class Battle::AI
# :FLOWERVEIL => 0, # :FLOWERVEIL => 0,
:FLUFFY => 5, :FLUFFY => 5,
:FORECAST => 6, :FORECAST => 6,
:FOREWARN => 2, :FOREWARN => 0,
# :FRIENDGUARD => 0, # :FRIENDGUARD => 0,
:FRISK => 3, :FRISK => 0,
:FULLMETALBODY => 4, :FULLMETALBODY => 4,
:FURCOAT => 7, :FURCOAT => 7,
:GALEWINGS => 6, :GALEWINGS => 6,
@@ -1322,6 +1322,52 @@ class Battle::AI
# TODO: Ideally replace the above list of ratings with context-sensitive # TODO: Ideally replace the above list of ratings with context-sensitive
# calculations. Should they all go in this method, or should there be # calculations. Should they all go in this method, or should there be
# more handlers for each ability? # more handlers for each ability?
case ability
when :BLAZE
return 0 if !battler.has_damaging_move_of_type?(:FIRE)
when :CUTECHARM, :RIVALRY
return 0 if battler.gender == 2
when :FRIENDGUARD, :HEALER, :SYMBOISIS, :TELEPATHY
has_ally = false
each_ally(battler.side) { |b, i| has_ally = true }
return 0 if !has_ally
when :GALEWINGS
return 0 if !battler.check_for_move { |m| m.type == :FLYING }
when :HUGEPOWER, :PUREPOWER
return 0 if !battler.check_for_move { |m| m.physicalMove?(m.type) &&
m.function != "UseUserDefenseInsteadOfUserAttack" &&
m.function != "UseTargetAttackInsteadOfUserAttack" }
when :IRONFIST
return 0 if !battler.check_for_move { |m| m.punchingMove? }
when :LIQUIDVOICE
return 0 if !battler.check_for_move { |m| m.soundMove? }
when :MEGALAUNCHER
return 0 if !battler.check_for_move { |m| m.pulseMove? }
when :OVERGROW
return 0 if !battler.has_damaging_move_of_type?(:GRASS)
when :PRANKSTER
return 0 if !battler.check_for_move { |m| m.statusMove? }
when :PUNKROCK
return 1 if !battler.check_for_move { |m| m.damagingMove? && m.soundMove? }
when :RECKLESS
return 0 if !battler.check_for_move { |m| m.recoilMove? }
when :ROCKHEAD
return 0 if !battler.check_for_move { |m| m.recoilMove? && !m.is_a?(Battle::Move::CrashDamageIfFailsUnusableInGravity) }
when :RUNAWAY
return 0 if battler.wild?
when :SANDFORCE
return 2 if !battler.has_damaging_move_of_type?(:GROUND, :ROCK, :STEEL)
when :SKILLLINK
return 0 if !battler.check_for_move { |m| m.is_a?(Battle::Move::HitTwoToFiveTimes) }
when :STEELWORKER
return 0 if !battler.has_damaging_move_of_type?(:GRASS)
when :SWARM
return 0 if !battler.has_damaging_move_of_type?(:BUG)
when :TORRENT
return 0 if !battler.has_damaging_move_of_type?(:WATER)
when :TRIAGE
return 0 if !battler.check_for_move { |m| m.healingMove? }
end
ret = BASE_ABILITY_RATINGS[ability] || 0 ret = BASE_ABILITY_RATINGS[ability] || 0
return ret return ret
end end

View File

@@ -185,10 +185,10 @@ Battle::AI::Handlers::MoveEffectScore.add("StartSunWeather",
# Check for Fire/Water moves # Check for Fire/Water moves
ai.battlers.each do |b| ai.battlers.each do |b|
next if !b || b.battler.fainted? next if !b || b.battler.fainted?
if b.check_for_move { |m| m.type == :FIRE && m.damagingMove? } if b.has_damaging_move_of_type?(:FIRE)
score += (b.opposes?(user)) ? -15 : 15 score += (b.opposes?(user)) ? -15 : 15
end end
if b.check_for_move { |m| m.type == :WATER && m.damagingMove? } if b.has_damaging_move_of_type?(:WATER)
score += (b.opposes?(user)) ? 15 : -15 score += (b.opposes?(user)) ? 15 : -15
end end
end end
@@ -201,14 +201,14 @@ Battle::AI::Handlers::MoveEffectScore.add("StartSunWeather",
elsif user.has_active_ability?(:DRYSKIN) elsif user.has_active_ability?(:DRYSKIN)
score -= 10 score -= 10
end end
if user.check_for_move { |m| ["HealUserDependingOnWeather", if user.has_move_with_function?("HealUserDependingOnWeather",
"RaiseUserAtkSpAtk1Or2InSun", "RaiseUserAtkSpAtk1Or2InSun",
"TwoTurnAttackOneTurnInSun", "TwoTurnAttackOneTurnInSun",
"TypeAndPowerDependOnWeather"].include?(m.function) } "TypeAndPowerDependOnWeather")
score += 10 score += 10
end end
if user.check_for_move { |m| ["ConfuseTargetAlwaysHitsInRainHitsTargetInSky", if user.has_move_with_function?("ConfuseTargetAlwaysHitsInRainHitsTargetInSky",
"ParalyzeTargetAlwaysHitsInRainHitsTargetInSky"].include?(m.function) } "ParalyzeTargetAlwaysHitsInRainHitsTargetInSky")
score -= 10 score -= 10
end end
end end
@@ -231,10 +231,10 @@ Battle::AI::Handlers::MoveEffectScore.add("StartRainWeather",
# Check for Fire/Water moves # Check for Fire/Water moves
ai.battlers.each do |b| ai.battlers.each do |b|
next if !b || b.battler.fainted? next if !b || b.battler.fainted?
if b.check_for_move { |m| m.type == :WATER && m.damagingMove? } if b.has_damaging_move_of_type?(:WATER)
score += (b.opposes?(user)) ? -15 : 15 score += (b.opposes?(user)) ? -15 : 15
end end
if b.check_for_move { |m| m.type == :FIRE && m.damagingMove? } if b.has_damaging_move_of_type?(:FIRE)
score += (b.opposes?(user)) ? 15 : -15 score += (b.opposes?(user)) ? 15 : -15
end end
end end
@@ -244,13 +244,13 @@ Battle::AI::Handlers::MoveEffectScore.add("StartRainWeather",
if user.has_active_ability?([:DRYSKIN, :FORECAST, :HYDRATION, :RAINDISH, :SWIFTSWIM]) if user.has_active_ability?([:DRYSKIN, :FORECAST, :HYDRATION, :RAINDISH, :SWIFTSWIM])
score += 15 score += 15
end end
if user.check_for_move { |m| ["ConfuseTargetAlwaysHitsInRainHitsTargetInSky", if user.has_move_with_function?("ConfuseTargetAlwaysHitsInRainHitsTargetInSky",
"ParalyzeTargetAlwaysHitsInRainHitsTargetInSky", "ParalyzeTargetAlwaysHitsInRainHitsTargetInSky",
"TypeAndPowerDependOnWeather"].include?(m.function) } "TypeAndPowerDependOnWeather")
score += 10 score += 10
end end
if user.check_for_move { |m| ["HealUserDependingOnWeather", if user.has_move_with_function?("HealUserDependingOnWeather",
"TwoTurnAttackOneTurnInSun"].include?(m.function) } "TwoTurnAttackOneTurnInSun")
score -= 10 score -= 10
end end
end end
@@ -286,12 +286,12 @@ Battle::AI::Handlers::MoveEffectScore.add("StartSandstormWeather",
if user.has_active_ability?([:SANDFORCE, :SANDRUSH, :SANDVEIL]) if user.has_active_ability?([:SANDFORCE, :SANDRUSH, :SANDVEIL])
score += 15 score += 15
end end
if user.check_for_move { |m| ["HealUserDependingOnSandstorm", if user.has_move_with_function?("HealUserDependingOnSandstorm",
"TypeAndPowerDependOnWeather"].include?(m.function) } "TypeAndPowerDependOnWeather")
score += 10 score += 10
end end
if user.check_for_move { |m| ["HealUserDependingOnWeather", if user.has_move_with_function?("HealUserDependingOnWeather",
"TwoTurnAttackOneTurnInSun"].include?(m.function) } "TwoTurnAttackOneTurnInSun")
score -= 10 score -= 10
end end
end end
@@ -326,13 +326,13 @@ Battle::AI::Handlers::MoveEffectScore.add("StartHailWeather",
elsif user.ability == :ICEFACE elsif user.ability == :ICEFACE
score += 15 score += 15
end end
if user.check_for_move { |m| ["FreezeTargetAlwaysHitsInHail", if user.has_move_with_function?("FreezeTargetAlwaysHitsInHail",
"StartWeakenDamageAgainstUserSideIfHail", "StartWeakenDamageAgainstUserSideIfHail",
"TypeAndPowerDependOnWeather"].include?(m.function) } "TypeAndPowerDependOnWeather")
score += 10 score += 10
end end
if user.check_for_move { |m| ["HealUserDependingOnWeather", if user.has_move_with_function?("HealUserDependingOnWeather",
"TwoTurnAttackOneTurnInSun"].include?(m.function) } "TwoTurnAttackOneTurnInSun")
score -= 10 score -= 10
end end
end end

View File

@@ -84,7 +84,7 @@ Battle::AI::Handlers::MoveEffectScore.add("RaiseUserDefense1CurlUpUser",
proc { |score, move, user, ai, battle| proc { |score, move, user, ai, battle|
score = ai.get_score_for_target_stat_raise(score, user, move.move.statUp) score = ai.get_score_for_target_stat_raise(score, user, move.move.statUp)
if !user.effects[PBEffects::DefenseCurl] && if !user.effects[PBEffects::DefenseCurl] &&
user.check_for_move { |m| m.function == "MultiTurnAttackPowersUpEachTurn" } user.has_move_with_function?("MultiTurnAttackPowersUpEachTurn")
score += 10 score += 10
end end
next score next score
@@ -148,7 +148,7 @@ Battle::AI::Handlers::MoveFailureCheck.copy("RaiseUserSpDef1",
Battle::AI::Handlers::MoveEffectScore.add("RaiseUserSpDef1PowerUpElectricMove", Battle::AI::Handlers::MoveEffectScore.add("RaiseUserSpDef1PowerUpElectricMove",
proc { |score, move, user, ai, battle| proc { |score, move, user, ai, battle|
score = ai.get_score_for_target_stat_raise(score, user, move.move.statUp) score = ai.get_score_for_target_stat_raise(score, user, move.move.statUp)
if user.check_for_move { |m| m.damagingMove? && m.type == :ELECTRIC } if user.has_damaging_move_of_type?(:ELECTRIC)
score += 10 score += 10
end end
next score next score
@@ -201,14 +201,14 @@ Battle::AI::Handlers::MoveEffectScore.add("RaiseUserSpeed2LowerUserWeight",
# because of those modifiers, and the score changes may need to be # because of those modifiers, and the score changes may need to be
# different accordingly. # different accordingly.
if user.battler.pokemon.weight - user.effects[PBEffects::WeightChange] > 1 if user.battler.pokemon.weight - user.effects[PBEffects::WeightChange] > 1
if user.check_for_move { |m| m.function == "PowerHigherWithUserHeavierThanTarget" } if user.has_move_with_function?("PowerHigherWithUserHeavierThanTarget")
score -= 10 score -= 10
end end
ai.each_foe_battler(user.side) do |b, i| ai.each_foe_battler(user.side) do |b, i|
if b.check_for_move { |m| m.function == "PowerHigherWithUserHeavierThanTarget" } if b.has_move_with_function?("PowerHigherWithUserHeavierThanTarget")
score -= 10 score -= 10
end end
if b.check_for_move { |m| m.function == "PowerHigherWithTargetWeight" } if b.has_move_with_function?("PowerHigherWithTargetWeight")
score += 10 score += 10
end end
# TODO: Check foes for Sky Drop and whether the user is too heavy for it # TODO: Check foes for Sky Drop and whether the user is too heavy for it
@@ -528,7 +528,7 @@ Battle::AI::Handlers::MoveEffectScore.add("StartRaiseUserAtk1WhenDamaged",
m.function != "UseUserDefenseInsteadOfUserAttack" && m.function != "UseUserDefenseInsteadOfUserAttack" &&
m.function != "UseTargetAttackInsteadOfUserAttack" } m.function != "UseTargetAttackInsteadOfUserAttack" }
score += 8 score += 8
elsif user.check_for_move { |m| m.function == "PowerHigherWithUserPositiveStatStages" } elsif user.has_move_with_function?("PowerHigherWithUserPositiveStatStages")
score += 4 score += 4
end end
next score next score
@@ -715,12 +715,12 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("RaiseTargetRandomStat2",
score += ((100 * target.hp / target.totalhp) - 50) / 4 # +5 to -12 score += ((100 * target.hp / target.totalhp) - 50) / 4 # +5 to -12
end end
# Prefer if target has Stored Power # Prefer if target has Stored Power
if target.check_for_move { |m| m.function == "PowerHigherWithUserPositiveStatStages" } if target.has_move_with_function?("PowerHigherWithUserPositiveStatStages")
score += 8 score += 8
end end
# Don't prefer if any foe has Punishment # Don't prefer if any foe has Punishment
ai.each_foe_battler(target.side) do |b, i| ai.each_foe_battler(target.side) do |b, i|
next if !b.check_for_move { |m| m.function == "PowerHigherWithTargetPositiveStatStages" } next if !b.has_move_with_function?("PowerHigherWithTargetPositiveStatStages")
score -= 5 score -= 5
end end
next score next score
@@ -921,7 +921,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("LowerTargetSpeed1MakeTar
if !target.effects[PBEffects::TarShot] if !target.effects[PBEffects::TarShot]
eff = target.effectiveness_of_type_against_battler(:FIRE) eff = target.effectiveness_of_type_against_battler(:FIRE)
if !Effectiveness.ineffective?(eff) if !Effectiveness.ineffective?(eff)
score += 8 * eff if user.check_for_move { |m| m.damagingMove? && m.pbCalcType(user.battler) == :FIRE } score += 8 * eff if user.has_damaging_move_of_type?(:FIRE)
end end
end end
next score next score
@@ -1119,7 +1119,7 @@ Battle::AI::Handlers::MoveFailureCheck.add("RaisePlusMinusUserAndAlliesAtkSpAtk1
) )
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("RaisePlusMinusUserAndAlliesAtkSpAtk1", Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("RaisePlusMinusUserAndAlliesAtkSpAtk1",
proc { |move, user, target, ai, battle| proc { |move, user, target, ai, battle|
next true if !target.hasActiveAbility?([:MINUS, :PLUS]) next true if !target.has_active_ability?([:MINUS, :PLUS])
next !target.battler.pbCanRaiseStatStage?(:ATTACK, user.battler, move.move) && next !target.battler.pbCanRaiseStatStage?(:ATTACK, user.battler, move.move) &&
!target.battler.pbCanRaiseStatStage?(:SPECIAL_ATTACK, user.battler, move.move) !target.battler.pbCanRaiseStatStage?(:SPECIAL_ATTACK, user.battler, move.move)
} }
@@ -1157,7 +1157,7 @@ Battle::AI::Handlers::MoveFailureCheck.add("RaisePlusMinusUserAndAlliesDefSpDef1
) )
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("RaisePlusMinusUserAndAlliesDefSpDef1", Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("RaisePlusMinusUserAndAlliesDefSpDef1",
proc { |move, user, target, ai, battle| proc { |move, user, target, ai, battle|
next true if !target.hasActiveAbility?([:MINUS, :PLUS]) next true if !target.has_active_ability?([:MINUS, :PLUS])
next !target.battler.pbCanRaiseStatStage?(:DEFENSE, user.battler, move.move) && next !target.battler.pbCanRaiseStatStage?(:DEFENSE, user.battler, move.move) &&
!target.battler.pbCanRaiseStatStage?(:SPECIAL_DEFENSE, user.battler, move.move) !target.battler.pbCanRaiseStatStage?(:SPECIAL_DEFENSE, user.battler, move.move)
} }

View File

@@ -25,10 +25,10 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("SleepTarget",
score += 15 score += 15
# Prefer if the user or an ally has a move/ability that is better if the target is asleep # Prefer if the user or an ally has a move/ability that is better if the target is asleep
ai.each_same_side_battler(user.side) do |b, i| ai.each_same_side_battler(user.side) do |b, i|
score += 5 if b.check_for_move { |m| ["DoublePowerIfTargetAsleepCureTarget", score += 5 if b.has_move_with_function?("DoublePowerIfTargetAsleepCureTarget",
"DoublePowerIfTargetStatusProblem", "DoublePowerIfTargetStatusProblem",
"HealUserByHalfOfDamageDoneIfTargetAsleep", "HealUserByHalfOfDamageDoneIfTargetAsleep",
"StartDamageTargetEachTurnIfTargetAsleep"].include?(m.function) } "StartDamageTargetEachTurnIfTargetAsleep")
score += 10 if b.has_active_ability?(:BADDREAMS) score += 10 if b.has_active_ability?(:BADDREAMS)
end end
# Don't prefer if target benefits from having the sleep status problem # Don't prefer if target benefits from having the sleep status problem
@@ -119,8 +119,8 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("PoisonTarget",
score += 10 * target.hp / target.totalhp score += 10 * target.hp / target.totalhp
# Prefer if the user or an ally has a move/ability that is better if the target is poisoned # Prefer if the user or an ally has a move/ability that is better if the target is poisoned
ai.each_same_side_battler(user.side) do |b, i| ai.each_same_side_battler(user.side) do |b, i|
score += 5 if b.check_for_move { |m| ["DoublePowerIfTargetPoisoned", score += 5 if b.has_move_with_function?("DoublePowerIfTargetPoisoned",
"DoublePowerIfTargetStatusProblem"].include?(m.function) } "DoublePowerIfTargetStatusProblem")
score += 10 if b.has_active_ability?(:MERCILESS) score += 10 if b.has_active_ability?(:MERCILESS)
end end
# Don't prefer if target benefits from having the poison status problem # Don't prefer if target benefits from having the poison status problem
@@ -128,8 +128,8 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("PoisonTarget",
score -= 25 if target.has_active_ability?(:POISONHEAL) score -= 25 if target.has_active_ability?(:POISONHEAL)
score -= 15 if target.has_active_ability?(:SYNCHRONIZE) && score -= 15 if target.has_active_ability?(:SYNCHRONIZE) &&
user.battler.pbCanPoisonSynchronize?(target.battler) user.battler.pbCanPoisonSynchronize?(target.battler)
score -= 5 if target.check_for_move { |m| ["DoublePowerIfUserPoisonedBurnedParalyzed", score -= 5 if target.has_move_with_function?("DoublePowerIfUserPoisonedBurnedParalyzed",
"CureUserBurnPoisonParalysis"].include?(m.function) } "CureUserBurnPoisonParalysis")
score -= 10 if target.check_for_move { |m| score -= 10 if target.check_for_move { |m|
m.function == "GiveUserStatusToTarget" && user.battler.pbCanPoison?(target.battler, false, m) m.function == "GiveUserStatusToTarget" && user.battler.pbCanPoison?(target.battler, false, m)
} }
@@ -214,15 +214,15 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("ParalyzeTarget",
score += 5 if target.effects[PBEffects::Attract] >= 0 score += 5 if target.effects[PBEffects::Attract] >= 0
# Prefer if the user or an ally has a move/ability that is better if the target is paralysed # Prefer if the user or an ally has a move/ability that is better if the target is paralysed
ai.each_same_side_battler(user.side) do |b, i| ai.each_same_side_battler(user.side) do |b, i|
score += 5 if b.check_for_move { |m| ["DoublePowerIfTargetParalyzedCureTarget", score += 5 if b.has_move_with_function?("DoublePowerIfTargetParalyzedCureTarget",
"DoublePowerIfTargetStatusProblem"].include?(m.function) } "DoublePowerIfTargetStatusProblem")
end end
# Don't prefer if target benefits from having the paralysis status problem # Don't prefer if target benefits from having the paralysis status problem
score -= 8 if target.has_active_ability?([:GUTS, :MARVELSCALE, :QUICKFEET]) score -= 8 if target.has_active_ability?([:GUTS, :MARVELSCALE, :QUICKFEET])
score -= 15 if target.has_active_ability?(:SYNCHRONIZE) && score -= 15 if target.has_active_ability?(:SYNCHRONIZE) &&
user.battler.pbCanParalyzeSynchronize?(target.battler) user.battler.pbCanParalyzeSynchronize?(target.battler)
score -= 5 if target.check_for_move { |m| ["DoublePowerIfUserPoisonedBurnedParalyzed", score -= 5 if target.has_move_with_function?("DoublePowerIfUserPoisonedBurnedParalyzed",
"CureUserBurnPoisonParalysis"].include?(m.function) } "CureUserBurnPoisonParalysis")
score -= 10 if target.check_for_move { |m| score -= 10 if target.check_for_move { |m|
m.function == "GiveUserStatusToTarget" && user.battler.pbCanParalyze?(target.battler, false, m) m.function == "GiveUserStatusToTarget" && user.battler.pbCanParalyze?(target.battler, false, m)
} }
@@ -306,15 +306,15 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("BurnTarget",
end end
# Prefer if the user or an ally has a move/ability that is better if the target is burned # Prefer if the user or an ally has a move/ability that is better if the target is burned
ai.each_same_side_battler(user.side) do |b, i| ai.each_same_side_battler(user.side) do |b, i|
score += 5 if b.check_for_move { |m| m.function == "DoublePowerIfTargetStatusProblem" } score += 5 if b.has_move_with_function?("DoublePowerIfTargetStatusProblem")
end end
# Don't prefer if target benefits from having the burn status problem # Don't prefer if target benefits from having the burn status problem
score -= 8 if target.has_active_ability?([:FLAREBOOST, :GUTS, :MARVELSCALE, :QUICKFEET]) score -= 8 if target.has_active_ability?([:FLAREBOOST, :GUTS, :MARVELSCALE, :QUICKFEET])
score -= 5 if target.has_active_ability?(:HEATPROOF) score -= 5 if target.has_active_ability?(:HEATPROOF)
score -= 15 if target.has_active_ability?(:SYNCHRONIZE) && score -= 15 if target.has_active_ability?(:SYNCHRONIZE) &&
user.battler.pbCanBurnSynchronize?(target.battler) user.battler.pbCanBurnSynchronize?(target.battler)
score -= 5 if target.check_for_move { |m| ["DoublePowerIfUserPoisonedBurnedParalyzed", score -= 5 if target.has_move_with_function?("DoublePowerIfUserPoisonedBurnedParalyzed",
"CureUserBurnPoisonParalysis"].include?(m.function) } "CureUserBurnPoisonParalysis")
score -= 10 if target.check_for_move { |m| score -= 10 if target.check_for_move { |m|
m.function == "GiveUserStatusToTarget" && user.battler.pbCanBurn?(target.battler, false, m) m.function == "GiveUserStatusToTarget" && user.battler.pbCanBurn?(target.battler, false, m)
} }
@@ -380,7 +380,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("FreezeTarget",
score += 15 score += 15
# Prefer if the user or an ally has a move/ability that is better if the target is frozen # Prefer if the user or an ally has a move/ability that is better if the target is frozen
ai.each_same_side_battler(user.side) do |b, i| ai.each_same_side_battler(user.side) do |b, i|
score += 5 if b.check_for_move { |m| m.function == "DoublePowerIfTargetStatusProblem" } score += 5 if b.has_move_with_function?("DoublePowerIfTargetStatusProblem")
end end
# Don't prefer if target benefits from having the frozen status problem # Don't prefer if target benefits from having the frozen status problem
# NOTE: The target's Guts/Quick Feet will benefit from the target being # NOTE: The target's Guts/Quick Feet will benefit from the target being
@@ -722,15 +722,11 @@ Battle::AI::Handlers::MoveEffectScore.add("SetUserTypesBasedOnEnvironment",
new_type = :NORMAL if !GameData::Type.exists?(new_type) new_type = :NORMAL if !GameData::Type.exists?(new_type)
end end
# Check if any user's moves will get STAB because of the type change # Check if any user's moves will get STAB because of the type change
if user.check_for_move { |m| m.damagingMove? && m.pbCalcType(user.battler) == new_type } score += 8 if user.has_damaging_move_of_type?(new_type)
score += 8
end
# Check if any user's moves will lose STAB because of the type change # Check if any user's moves will lose STAB because of the type change
user.battler.pbTypes(true).each do |type| user.battler.pbTypes(true).each do |type|
next if type == new_type next if type == new_type
if user.check_for_move { |m| m.damagingMove? && m.pbCalcType(user.battler) == type } score -= 8 if user.has_damaging_move_of_type?(type)
score -= 8
end
end end
# NOTE: Other things could be considered, like the foes' moves' # NOTE: Other things could be considered, like the foes' moves'
# effectivenesses against the current and new user's type(s), and # effectivenesses against the current and new user's type(s), and
@@ -816,10 +812,9 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("SetUserTypesToUserMoveTy
end end
# Check if any user's moves will get STAB because of the type change # Check if any user's moves will get STAB because of the type change
possible_types.each do |type| possible_types.each do |type|
if user.check_for_move { |m| m.damagingMove? && m.pbCalcType(user.battler) == type } next if !user.has_damaging_move_of_type?(type)
score += 10 score += 10
break break
end
end end
# NOTE: Other things could be considered, like the foes' moves' # NOTE: Other things could be considered, like the foes' moves'
# effectivenesses against the current and new user's type(s), and # effectivenesses against the current and new user's type(s), and
@@ -1142,7 +1137,7 @@ Battle::AI::Handlers::MoveEffectScore.add("StartUserAirborne",
# Prefer if any foes have damaging Ground-type moves that do 1x or more # Prefer if any foes have damaging Ground-type moves that do 1x or more
# damage to the user # damage to the user
ai.each_foe_battler(user.side) do |b, i| ai.each_foe_battler(user.side) do |b, i|
next if !b.check_for_move { |m| m.damagingMove? && m.pbCalcType(b.battler) == :GROUND } next if !b.has_damaging_move_of_type?(:GROUND)
next if Effectiveness.resistant?(user.effectiveness_of_type_against_battler(:GROUND, b)) next if Effectiveness.resistant?(user.effectiveness_of_type_against_battler(:GROUND, b))
score += 5 score += 5
end end
@@ -1181,7 +1176,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("StartUserAirborne",
score += 4 if acc < 90 && acc != 0 score += 4 if acc < 90 && acc != 0
score += 4 if acc <= 50 && acc != 0 score += 4 if acc <= 50 && acc != 0
end end
next if !b.check_for_move { |m| m.damagingMove? && m.pbCalcType(b.battler) == :GROUND } next if !b.has_damaging_move_of_type?(:GROUND)
next if Effectiveness.resistant?(target.effectiveness_of_type_against_battler(:GROUND, b)) next if Effectiveness.resistant?(target.effectiveness_of_type_against_battler(:GROUND, b))
score -= 5 score -= 5
end end
@@ -1213,7 +1208,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("HitsTargetInSkyGroundsTa
score += 10 score += 10
# Prefer if any allies have damaging Ground-type moves # Prefer if any allies have damaging Ground-type moves
ai.each_foe_battler(target.side) do |b, i| ai.each_foe_battler(target.side) do |b, i|
score += 5 if b.check_for_move { |m| m.damagingMove? && m.pbCalcType(b.battler) == :GROUND } score += 5 if b.has_damaging_move_of_type?(:GROUND)
end end
# Don't prefer if terrain exists (which the target will become affected by) # Don't prefer if terrain exists (which the target will become affected by)
if ai.trainer.medium_skill? if ai.trainer.medium_skill?
@@ -1247,7 +1242,7 @@ Battle::AI::Handlers::MoveEffectScore.add("StartGravity",
# Prefer if allies have any damaging Ground moves they'll be able to use # Prefer if allies have any damaging Ground moves they'll be able to use
# on a grounded foe, and vice versa # on a grounded foe, and vice versa
ai.each_foe_battler(b.side) do |b2, j| ai.each_foe_battler(b.side) do |b2, j|
if b2.check_for_move { |m| m.damagingMove? && m.pbCalcType(b2.battler) == :GROUND } if b2.has_damaging_move_of_type?(:GROUND)
score += (user.opposes?(b2)) ? -5 : 5 score += (user.opposes?(b2)) ? -5 : 5
end end
end end

View File

@@ -504,13 +504,13 @@ Battle::AI::Handlers::MoveEffectScore.add("StartWeakenElectricMoves",
end end
# Prefer if foes have Electric moves # Prefer if foes have Electric moves
ai.each_foe_battler(user.side) do |b, i| ai.each_foe_battler(user.side) do |b, i|
next if !b.check_for_move { |m| m.damagingMove? && m.pbCalcType(b.battler) == :ELECTRIC } next if !b.has_damaging_move_of_type?(:ELECTRIC)
score += 10 score += 10
score += 5 if !b.check_for_move { |m| m.damagingMove? && m.pbCalcType(b.battler) != :ELECTRIC } score += 5 if !b.check_for_move { |m| m.damagingMove? && m.pbCalcType(b.battler) != :ELECTRIC }
end end
# Don't prefer if any allies have Electric moves # Don't prefer if any allies have Electric moves
ai.each_same_side_battler(user.side) do |b, i| ai.each_same_side_battler(user.side) do |b, i|
next if !b.check_for_move { |m| m.damagingMove? && m.pbCalcType(b.battler) == :ELECTRIC } next if !b.has_damaging_move_of_type?(:ELECTRIC)
score -= 8 score -= 8
score -= 4 if !b.check_for_move { |m| m.damagingMove? && m.pbCalcType(b.battler) != :ELECTRIC } score -= 4 if !b.check_for_move { |m| m.damagingMove? && m.pbCalcType(b.battler) != :ELECTRIC }
end end
@@ -535,13 +535,13 @@ Battle::AI::Handlers::MoveEffectScore.add("StartWeakenFireMoves",
end end
# Prefer if foes have Fire moves # Prefer if foes have Fire moves
ai.each_foe_battler(user.side) do |b, i| ai.each_foe_battler(user.side) do |b, i|
next if !b.check_for_move { |m| m.damagingMove? && m.pbCalcType(b.battler) == :FIRE } next if !b.has_damaging_move_of_type?(:FIRE)
score += 10 score += 10
score += 5 if !b.check_for_move { |m| m.damagingMove? && m.pbCalcType(b.battler) != :FIRE } score += 5 if !b.check_for_move { |m| m.damagingMove? && m.pbCalcType(b.battler) != :FIRE }
end end
# Don't prefer if any allies have Fire moves # Don't prefer if any allies have Fire moves
ai.each_same_side_battler(user.side) do |b, i| ai.each_same_side_battler(user.side) do |b, i|
next if !b.check_for_move { |m| m.damagingMove? && m.pbCalcType(b.battler) == :FIRE } next if !b.has_damaging_move_of_type?(:FIRE)
score -= 8 score -= 8
score -= 4 if !b.check_for_move { |m| m.damagingMove? && m.pbCalcType(b.battler) != :FIRE } score -= 4 if !b.check_for_move { |m| m.damagingMove? && m.pbCalcType(b.battler) != :FIRE }
end end
@@ -949,9 +949,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("EnsureNextMoveAlwaysHits
next Battle::AI::MOVE_USELESS_SCORE if user.has_active_ability?(:NOGUARD) || target.has_active_ability?(:NOGUARD) next Battle::AI::MOVE_USELESS_SCORE if user.has_active_ability?(:NOGUARD) || target.has_active_ability?(:NOGUARD)
next Battle::AI::MOVE_USELESS_SCORE if target.effects[PBEffects::Telekinesis] > 0 next Battle::AI::MOVE_USELESS_SCORE if target.effects[PBEffects::Telekinesis] > 0
# Prefer if the user knows moves with low accuracy # Prefer if the user knows moves with low accuracy
# TODO: This isn't the correct use of check_for_move, since it should just user.battler.eachMove do |m|
# loop through them instead.
user.check_for_move do |m|
next if target.effects[PBEffects::Minimize] && m.tramplesMinimize? && Settings::MECHANICS_GENERATION >= 6 next if target.effects[PBEffects::Minimize] && m.tramplesMinimize? && Settings::MECHANICS_GENERATION >= 6
# TODO: There are other effects that make a move certain to hit. Account # TODO: There are other effects that make a move certain to hit. Account
# for those as well. Score this move useless if no moves would # for those as well. Score this move useless if no moves would
@@ -978,7 +976,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("StartNegateTargetEvasion
# Check if the user knows any moves that would benefit from negating the # Check if the user knows any moves that would benefit from negating the
# target's Ghost type immunity # target's Ghost type immunity
if target.has_type?(:GHOST) if target.has_type?(:GHOST)
user.check_for_move do |m| user.battler.eachMove do |m|
next if !m.damagingMove? next if !m.damagingMove?
score += 10 if Effectiveness.ineffective_type?(m.pbCalcType(user.battler), :GHOST) score += 10 if Effectiveness.ineffective_type?(m.pbCalcType(user.battler), :GHOST)
end end
@@ -998,7 +996,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("StartNegateTargetEvasion
# Check if the user knows any moves that would benefit from negating the # Check if the user knows any moves that would benefit from negating the
# target's Dark type immunity # target's Dark type immunity
if target.has_type?(:DARK) if target.has_type?(:DARK)
user.check_for_move do |m| user.battler.eachMove do |m|
next if !m.damagingMove? next if !m.damagingMove?
score += 10 if Effectiveness.ineffective_type?(m.pbCalcType(user.battler), :DARK) score += 10 if Effectiveness.ineffective_type?(m.pbCalcType(user.battler), :DARK)
end end

View File

@@ -215,27 +215,27 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("TwoTurnAttack",
has_protect_move = false has_protect_move = false
if move.move.pbTarget(user).num_targets > 1 && if move.move.pbTarget(user).num_targets > 1 &&
(Settings::MECHANICS_GENERATION >= 7 || move.damagingMove?) (Settings::MECHANICS_GENERATION >= 7 || move.damagingMove?)
if target.check_for_move { |m| m.function == "ProtectUserSideFromMultiTargetDamagingMoves" } if target.has_move_with_function?("ProtectUserSideFromMultiTargetDamagingMoves")
has_protect_move = true has_protect_move = true
end end
end end
if move.move.canProtectAgainst? if move.move.canProtectAgainst?
if target.check_for_move { |m| ["ProtectUser", if target.has_move_with_function?("ProtectUser",
"ProtectUserFromTargetingMovesSpikyShield", "ProtectUserFromTargetingMovesSpikyShield",
"ProtectUserBanefulBunker"].include?(m.function) } "ProtectUserBanefulBunker")
has_protect_move = true has_protect_move = true
end end
if move.damagingMove? if move.damagingMove?
# NOTE: Doesn't check for Mat Block because it only works on its # NOTE: Doesn't check for Mat Block because it only works on its
# user's first turn in battle, so it can't be used in response # user's first turn in battle, so it can't be used in response
# to this move charging up. # to this move charging up.
if target.check_for_move { |m| ["ProtectUserFromDamagingMovesKingsShield", if target.has_move_with_function?("ProtectUserFromDamagingMovesKingsShield",
"ProtectUserFromDamagingMovesObstruct"].include?(m.function) } "ProtectUserFromDamagingMovesObstruct")
has_protect_move = true has_protect_move = true
end end
end end
if move.rough_priority(user) > 0 if move.rough_priority(user) > 0
if target.check_for_move { |m| m.function == "ProtectUserSideFromPriorityMoves" } if target.has_move_with_function?("ProtectUserSideFromPriorityMoves")
has_protect_move = true has_protect_move = true
end end
end end

View File

@@ -206,7 +206,7 @@ Battle::AI::Handlers::MoveEffectScore.add("DoublePowerAfterFusionFlare",
proc { |score, move, user, ai, battle| proc { |score, move, user, ai, battle|
# Prefer if an ally knows Fusion Flare # Prefer if an ally knows Fusion Flare
ai.each_ally(user.index) do |b, i| ai.each_ally(user.index) do |b, i|
score += 10 if b.check_for_move { |m| m.function == "DoublePowerAfterFusionBolt" } score += 10 if b.has_move_with_function?("DoublePowerAfterFusionBolt")
end end
next score next score
} }
@@ -219,7 +219,7 @@ Battle::AI::Handlers::MoveEffectScore.add("DoublePowerAfterFusionBolt",
proc { |score, move, user, ai, battle| proc { |score, move, user, ai, battle|
# Prefer if an ally knows Fusion Bolt # Prefer if an ally knows Fusion Bolt
ai.each_ally(user.index) do |b, i| ai.each_ally(user.index) do |b, i|
score += 10 if b.check_for_move { |m| m.function == "DoublePowerAfterFusionFlare" } score += 10 if b.has_move_with_function?("DoublePowerAfterFusionFlare")
end end
next score next score
} }
@@ -380,7 +380,7 @@ Battle::AI::Handlers::MoveEffectScore.add("GrassPledge",
proc { |score, move, user, ai, battle| proc { |score, move, user, ai, battle|
# Prefer if an ally knows a different Pledge move # Prefer if an ally knows a different Pledge move
ai.each_ally(user.index) do |b, i| ai.each_ally(user.index) do |b, i|
score += 10 if b.check_for_move { |m| ["FirePledge", "WaterPledge"].include?(m.function) } score += 10 if b.has_move_with_function?("FirePledge", "WaterPledge")
end end
next score next score
} }
@@ -393,7 +393,7 @@ Battle::AI::Handlers::MoveEffectScore.add("FirePledge",
proc { |score, move, user, ai, battle| proc { |score, move, user, ai, battle|
# Prefer if an ally knows a different Pledge move # Prefer if an ally knows a different Pledge move
ai.each_ally(user.index) do |b, i| ai.each_ally(user.index) do |b, i|
score += 10 if b.check_for_move { |m| ["GrassPledge", "WaterPledge"].include?(m.function) } score += 10 if b.has_move_with_function?("GrassPledge", "WaterPledge")
end end
next score next score
} }
@@ -406,7 +406,7 @@ Battle::AI::Handlers::MoveEffectScore.add("WaterPledge",
proc { |score, move, user, ai, battle| proc { |score, move, user, ai, battle|
# Prefer if an ally knows a different Pledge move # Prefer if an ally knows a different Pledge move
ai.each_ally(user.index) do |b, i| ai.each_ally(user.index) do |b, i|
score += 10 if b.check_for_move { |m| ["GrassPledge", "FirePledge"].include?(m.function) } score += 10 if b.has_move_with_function?("GrassPledge", "FirePledge")
end end
next score next score
} }

View File

@@ -30,13 +30,7 @@ Battle::AI::Handlers::MoveEffectScore.add("SwitchOutUserStatusMove",
else else
score -= total * 10 score -= total * 10
# special case: user has no damaging moves # special case: user has no damaging moves
hasDamagingMove = false score += 75 if !user.check_for_move { |m| m.damagingMove? }
user.battler.eachMove do |m|
next if !m.damagingMove?
hasDamagingMove = true
break
end
score += 75 if !hasDamagingMove
end end
end end
next score next score
@@ -95,13 +89,7 @@ Battle::AI::Handlers::MoveEffectScore.add("SwitchOutUserPassOnEffects",
else else
score += total * 10 score += total * 10
# special case: user has no damaging moves # special case: user has no damaging moves
hasDamagingMove = false score += 75 if !user.check_for_move { |m| m.damagingMove? }
user.battler.eachMove do |m|
next if !m.damagingMove?
hasDamagingMove = true
break
end
score += 75 if !hasDamagingMove
end end
else else
score -= 100 score -= 100
@@ -192,7 +180,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("BindTarget",
# Don't prefer if the target can remove the binding (and the binding has an # Don't prefer if the target can remove the binding (and the binding has an
# effect) # effect)
if (!untrappable && !target.battler.trappedInBattle?) || target.battler.takesIndirectDamage? if (!untrappable && !target.battler.trappedInBattle?) || target.battler.takesIndirectDamage?
if target.check_for_move { |m| m.function == "RemoveUserBindingAndEntryHazards" } if target.has_move_with_function?("RemoveUserBindingAndEntryHazards")
score -= 8 score -= 8
end end
end end
@@ -440,7 +428,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("LowerPPOfTargetLastMoveB
) )
#=============================================================================== #===============================================================================
# TODO: Review score modifiers. #
#=============================================================================== #===============================================================================
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("DisableTargetLastMoveUsed", Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("DisableTargetLastMoveUsed",
proc { |move, user, target, ai, battle| proc { |move, user, target, ai, battle|
@@ -456,9 +444,25 @@ Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("DisableTargetLastMoveUs
next will_fail next will_fail
} }
) )
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("DisableTargetUsingSameMoveConsecutively",
proc { |score, move, user, target, ai, battle|
next Battle::AI::MOVE_USELESS_SCORE if target.has_active_item?(:MENTALHERB)
# Prefer if the target is locked into using a single move, or will be
if target.effects[PBEffects::ChoiceBand] ||
target.has_active_item?([:CHOICEBAND, :CHOICESPECS, :CHOICESCARF]) ||
target.has_active_ability?(:GORILLATACTICS)
score += 8
end
# PRefer disabling a damaging move
score += 5 if GameData::Move.try_get(target.battler.lastRegularMoveUsed)&.damaging?
# Inherent preference
score += 8
next score
}
)
#=============================================================================== #===============================================================================
# TODO: Review score modifiers. #
#=============================================================================== #===============================================================================
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("DisableTargetUsingSameMoveConsecutively", Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("DisableTargetUsingSameMoveConsecutively",
proc { |move, user, target, ai, battle| proc { |move, user, target, ai, battle|
@@ -469,13 +473,21 @@ Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("DisableTargetUsingSameM
) )
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("DisableTargetUsingSameMoveConsecutively", Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("DisableTargetUsingSameMoveConsecutively",
proc { |score, move, user, target, ai, battle| proc { |score, move, user, target, ai, battle|
next 0 if target.effects[PBEffects::Torment] next Battle::AI::MOVE_USELESS_SCORE if target.has_active_item?(:MENTALHERB)
# Prefer if the target is locked into using a single move, or will be
if target.effects[PBEffects::ChoiceBand] ||
target.has_active_item?([:CHOICEBAND, :CHOICESPECS, :CHOICESCARF]) ||
target.has_active_ability?(:GORILLATACTICS)
score += 8
end
# Inherent preference
score += 8
next score next score
} }
) )
#=============================================================================== #===============================================================================
# TODO: Review score modifiers. #
#=============================================================================== #===============================================================================
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("DisableTargetUsingDifferentMove", Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("DisableTargetUsingDifferentMove",
proc { |move, user, target, ai, battle| proc { |move, user, target, ai, battle|
@@ -496,23 +508,44 @@ Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("DisableTargetUsingDiffe
) )
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("DisableTargetUsingDifferentMove", Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("DisableTargetUsingDifferentMove",
proc { |score, move, user, target, ai, battle| proc { |score, move, user, target, ai, battle|
next Battle::AI::MOVE_USELESS_SCORE if target.has_active_item?(:MENTALHERB)
if user.faster_than?(target) if user.faster_than?(target)
moveData = GameData::Move.get(target.battler.lastRegularMoveUsed) # We know which move is going to be encored (assuming the target doesn't
if moveData.category == 2 && # Status move # use a high priority move)
[:User, :BothSides].include?(moveData.target) move_data = GameData::Move.get(target.battler.lastRegularMoveUsed)
score += 60 if move_data.status?
elsif moveData.category != 2 && # Damaging move # Prefer encoring status moves
moveData.target == :NearOther && if [:User, :BothSides].include?(move_data.target)
Effectiveness.ineffective?(user.effectiveness_of_type_against_battler(moveData.type, target)) # TODO: This target distinction was in the old code. Is it appropriate?
score += 60 score += 10
else
score += 8
end
elsif move_data.damaging? && move_data.target == :NearOther
# Prefer encoring damaging moves depending on their type effectiveness
# against the user
eff = user.effectiveness_of_type_against_battler(move_data.type, target)
if Effectiveness.ineffective?(eff)
score += 15
elsif Effectiveness.not_very_effective?(eff)
score += 10
elsif Effectiveness.super_effective?(eff)
score -= 5
else
score += 5
end
end end
else
# We don't know which move is going to be encored; just prefer limiting
# the target's options
score += 8
end end
next score next score
} }
) )
#=============================================================================== #===============================================================================
# TODO: Review score modifiers. #
#=============================================================================== #===============================================================================
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("DisableTargetStatusMoves", Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("DisableTargetStatusMoves",
proc { |move, user, target, ai, battle| proc { |move, user, target, ai, battle|
@@ -526,12 +559,45 @@ Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("DisableTargetStatusMove
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("DisableTargetStatusMoves", Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("DisableTargetStatusMoves",
proc { |score, move, user, target, ai, battle| proc { |score, move, user, target, ai, battle|
next Battle::AI::MOVE_USELESS_SCORE if !target.check_for_move { |m| m.statusMove? } next Battle::AI::MOVE_USELESS_SCORE if !target.check_for_move { |m| m.statusMove? }
# Not worth using on a sleeping target that won't imminently wake up
if target.status == :SLEEP && target.statusCount > ((target.faster_than?(user)) ? 2 : 1)
if !target.check_for_move { |m| m.statusMove? && m.usableWhenAsleep? && (m.pp > 0 || m.total_pp == 0) }
next Battle::AI::MOVE_USELESS_SCORE
end
end
# Move is likely useless if the target will lock themselves into a move,
# because they'll likely lock themselves into a damaging move anyway
if !target.effects[PBEffects::ChoiceBand]
if target.has_active_item?([:CHOICEBAND, :CHOICESPECS, :CHOICESCARF]) ||
target.has_active_ability?(:GORILLATACTICS)
next Battle::AI::MOVE_USELESS_SCORE
end
end
# Prefer if the target has a protection move
protection_moves = [
"ProtectUser", # Detect, Protect
"ProtectUserSideFromPriorityMoves", # Quick Guard
"ProtectUserSideFromMultiTargetDamagingMoves", # Wide Guard
"UserEnduresFaintingThisTurn", # Endure
"ProtectUserSideFromDamagingMovesIfUserFirstTurn", # Mat Block
"ProtectUserSideFromStatusMoves", # Crafty Shield
"ProtectUserFromDamagingMovesKingsShield", # King's Shield
"ProtectUserFromDamagingMovesObstruct", # Obstruct
"ProtectUserFromTargetingMovesSpikyShield", # Spiky Shield
"ProtectUserBanefulBunker" # Baneful Bunker
]
if target.check_for_move { |m| m.statusMove? && protection_moves.include?(m.function) &&
(m.pp > 0 || m.total_pp == 0) }
score += 6
end
# Inherent preference
score += 8
next score next score
} }
) )
#=============================================================================== #===============================================================================
# TODO: Review score modifiers. #
#=============================================================================== #===============================================================================
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("DisableTargetHealingMoves", Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("DisableTargetHealingMoves",
proc { |move, user, target, ai, battle| proc { |move, user, target, ai, battle|
@@ -542,28 +608,57 @@ Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("DisableTargetHealingMov
) )
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("DisableTargetHealingMoves", Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("DisableTargetHealingMoves",
proc { |score, move, user, target, ai, battle| proc { |score, move, user, target, ai, battle|
next Battle::AI::MOVE_USELESS_SCORE if !target.check_for_move { |m| m.healingMove? } # Useless if the foe can't heal themselves with a move or some held items
if !target.check_for_move { |m| m.healingMove? && (m.pp > 0 || m.total_pp == 0) }
if !target.has_active_item?(:LEFTOVERS) &&
!(target.has_active_item?(:BLACKSLUDGE) && target.has_type?(:POISON))
next Battle::AI::MOVE_USELESS_SCORE
end
end
# Inherent preference
score += 8
next score next score
} }
) )
#=============================================================================== #===============================================================================
# TODO: Review score modifiers. #.
#=============================================================================== #===============================================================================
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("DisableTargetSoundMoves", Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("DisableTargetSoundMoves",
proc { |score, move, user, target, ai, battle| proc { |score, move, user, target, ai, battle|
if target.effects[PBEffects::ThroatChop] == 0 next score if target.effects[PBEffects::ThroatChop] > 1
score += 10 if target.check_for_move { |m| m.soundMove? } next score if !target.check_for_move { |m| m.soundMove? && (m.pp > 0 || m.total_pp == 0) }
end # Inherent preference
score += 8
next score next score
} }
) )
#=============================================================================== #===============================================================================
# TODO: Review score modifiers. #
#=============================================================================== #===============================================================================
Battle::AI::Handlers::MoveFailureCheck.add("DisableTargetMovesKnownByUser", Battle::AI::Handlers::MoveFailureCheck.add("DisableTargetMovesKnownByUser",
proc { |move, user, ai, battle| proc { |move, user, ai, battle|
next user.effects[PBEffects::Imprison] next user.effects[PBEffects::Imprison]
} }
) )
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("DisableTargetMovesKnownByUser",
proc { |score, move, user, target, ai, battle|
# Useless if the foes have no moves that the user also knows
shared_move = false
user_moves = user.battler.moves.map { |m| m.id }
ai.each_foe_battler(user.side) do |b, i|
b.battler.eachMove do |m|
next if !user_moves.include?(m.id)
next if m.pp == 0 && m.total_pp > 0
shared_move = true
break
end
break if shared_move
end
next Battle::AI::MOVE_USELESS_SCORE if !shared_move
# Inherent preference
score += 6
next score
}
)

View File

@@ -267,6 +267,18 @@ class Battle::AI::AIBattler
return ret return ret
end end
def has_damaging_move_of_type?(*types)
check_for_move do |m|
return true if m.damagingMove? && types.include?(m.pbCalcType(@battler))
end
return false
end
def has_move_with_function?(*functions)
check_for_move { |m| return true if functions.include?(m.function) }
return false
end
#============================================================================= #=============================================================================
def can_switch_lax? def can_switch_lax?

View File

@@ -8,9 +8,9 @@ class Battle::AI::AIMove
@ai = ai @ai = ai
end end
def set_up(move, ai_battler) def set_up(move)
@move = move @move = move
@ai_battler = ai_battler @move.calcType = rough_type
end end
#============================================================================= #=============================================================================
@@ -46,7 +46,7 @@ class Battle::AI::AIMove
# Returns whether this move targets multiple battlers. # Returns whether this move targets multiple battlers.
def targets_multiple_battlers? def targets_multiple_battlers?
user_battler = @ai_battler.battler user_battler = @ai.user.battler
target_data = @move.pbTarget(user_battler) target_data = @move.pbTarget(user_battler)
return false if target_data.num_targets <= 1 return false if target_data.num_targets <= 1
num_targets = 0 num_targets = 0