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?
end
def damaging?
return @category != 2
end
def status?
return @category == 2
end
def hidden_move?
GameData::Item.each do |i|
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
# by 1 stage and decreases the user's Defense by 1 stage. (Scale Shot)
#===============================================================================
class Battle::Move::HitTwoToFiveTimesRaiseUserSpd1LowerUserDef1 < Battle::Move
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
class Battle::Move::HitTwoToFiveTimesRaiseUserSpd1LowerUserDef1 < Battle::Move::HitTwoToFiveTimes
def pbEffectAfterAllHits(user, target)
return if target.damageState.unaffected
if user.pbCanLowerStatStage?(:DEFENSE, user, self)

View File

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

View File

@@ -442,7 +442,7 @@ class Battle::Scene
moveType = moveData.type
moveKind = moveData.category
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,
# multiple targets physical, multiple targets special, non-user status]
typeDefaultAnim = {

View File

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

View File

@@ -29,11 +29,11 @@ class Battle::AI
end
next
end
PBDebug.log_ai("#{@user.name} is considering using #{move.name}...")
# Set up move in class variables
set_up_move_check(move)
# Predict whether the move will fail (generally)
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")
add_move_to_choices(choices, idxMove, MOVE_FAIL_SCORE)
next
@@ -43,6 +43,7 @@ class Battle::AI
case target_data.num_targets
when 0 # No targets, affects the user or a side or the whole field
# Includes: BothSides, FoeSide, None, User, UserSide
PBDebug.log_ai("#{@user.name} is considering using #{move.name}...")
score = MOVE_BASE_SCORE
PBDebug.logonerr { score = pbGetMoveScore }
add_move_to_choices(choices, idxMove, score)
@@ -57,6 +58,7 @@ class Battle::AI
# TODO: Should this sometimes consider targeting an ally? See def
# pbGetMoveScoreAgainstTarget for more information.
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
PBDebug.logonerr { score = pbGetMoveScore([b]) }
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)
targets.push(b)
end
PBDebug.log_ai("#{@user.name} is considering using #{move.name}...")
score = MOVE_BASE_SCORE
PBDebug.logonerr { score = pbGetMoveScore(targets) }
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 = Battle::Move.from_pokemon_move(@battle, Pokemon::Move.new(move.npMove))
end
@move.set_up(move, @user)
@move.set_up(move)
@battle.moldBreaker = @user.has_mold_breaker?
end
@@ -130,7 +133,9 @@ class Battle::AI
# User is awake and can't use moves that are only usable when asleep
return true if !@user.battler.asleep? && @move.move.usableWhenAsleep?
# 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
return true if @battle.pbWeather == :HeavyRain && @move.rough_type == :FIRE
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
if @trainer.high_skill? && @user.can_switch_lax?
badMoves = false
if (max_score <= MOVE_FAIL_SCORE && user_battler.turnCount > 2) ||
(max_score <= MOVE_USELESS_SCORE && user_battler.turnCount > 4)
if max_score <= MOVE_USELESS_SCORE
badMoves = true
elsif max_score < MOVE_BASE_SCORE * move_score_threshold && user_battler.turnCount > 2
badMoves = true if pbAIRandom(100) < 80
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
PBDebug.log_ai("#{@user.name} wants to switch due to terrible moves")
return if pbEnemyShouldWithdrawEx?(true)

View File

@@ -31,7 +31,7 @@ class Battle::AI
end
# Don't make score changes if foes have Unaware and target can't make use of
# extra stat stages
if !target.check_for_move { |m| m.function == "PowerHigherWithUserPositiveStatStages" }
if !target.has_move_with_function?("PowerHigherWithUserPositiveStatStages")
foe_is_aware = false
each_foe_battler(target.side) do |b, i|
foe_is_aware = true if !b.has_active_ability?(:UNAWARE)
@@ -121,7 +121,7 @@ class Battle::AI
"PowerHigherWithUserFasterThanTarget",
"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|
return true if b.faster_than?(target)
end
@@ -272,7 +272,7 @@ class Battle::AI
end
old_stage = target.stages[stat]
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 *= desire_mult
# Stat-based score changes
@@ -280,8 +280,8 @@ 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 >= 2
score -= 20 * ((target.opposes?(@user)) ? 1 : desire_mult)
if old_stage >= 2 && increment == 1
score -= 15 * ((target.opposes?(@user)) ? 1 : desire_mult)
else
has_special_moves = target.check_for_move { |m| m.specialMove?(m.type) }
inc = (has_special_moves) ? 10 : 20
@@ -290,8 +290,8 @@ class Battle::AI
when :DEFENSE
# Modify score depending on current stat stage
if old_stage >= 2
score -= 20 * ((target.opposes?(@user)) ? 1 : desire_mult)
if old_stage >= 2 && increment == 1
score -= 15 * ((target.opposes?(@user)) ? 1 : desire_mult)
else
score += 10 * inc_mult
end
@@ -299,8 +299,8 @@ class Battle::AI
when :SPECIAL_ATTACK
# Modify score depending on current stat stage
# More strongly prefer if the target has no physical moves
if old_stage >= 2
score -= 20 * ((target.opposes?(@user)) ? 1 : desire_mult)
if old_stage >= 2 && increment == 1
score -= 15 * ((target.opposes?(@user)) ? 1 : desire_mult)
else
has_physical_moves = target.check_for_move { |m| m.physicalMove?(m.type) &&
m.function != "UseUserDefenseInsteadOfUserAttack" &&
@@ -311,8 +311,8 @@ class Battle::AI
when :SPECIAL_DEFENSE
# Modify score depending on current stat stage
if old_stage >= 2
score -= 20 * ((target.opposes?(@user)) ? 1 : desire_mult)
if old_stage >= 2 && increment == 1
score -= 15 * ((target.opposes?(@user)) ? 1 : desire_mult)
else
score += 10 * inc_mult
end
@@ -333,12 +333,12 @@ class Battle::AI
"PowerHigherWithUserFasterThanTarget",
"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
end
# Don't prefer if any foe has Gyro Ball
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
end
# Don't prefer if target has Speed Boost (will be gaining Speed anyway)
@@ -348,8 +348,8 @@ class Battle::AI
when :ACCURACY
# Modify score depending on current stat stage
if old_stage >= 2
score -= 20 * ((target.opposes?(@user)) ? 1 : desire_mult)
if old_stage >= 2 && increment == 1
score -= 15 * ((target.opposes?(@user)) ? 1 : desire_mult)
else
min_accuracy = 100
target.battler.moves.each do |m|
@@ -372,8 +372,8 @@ class Battle::AI
next if eor_damage <= 0
end
# Modify score depending on current stat stage
if old_stage >= 2
score -= 20 * ((target.opposes?(@user)) ? 1 : desire_mult)
if old_stage >= 2 && increment == 1
score -= 15 * ((target.opposes?(@user)) ? 1 : desire_mult)
else
score += 10 * inc_mult
end
@@ -381,12 +381,12 @@ class Battle::AI
end
# 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
end
# Don't prefer if any foe has Punishment
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
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)
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
if target.opposes?(@user) ||
(@move.pbTarget(@user.battler).targets_foe && target.index != @user.index)
@@ -619,7 +619,7 @@ class Battle::AI
end
# 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
# applies and desire_mult < 1.
# applies and desire_mult < 0.
if !fixed_change && !@battle.moldBreaker && target.has_active_ability?(:CONTRARY) && desire_mult > 0
ret = (whole_effect) ? MOVE_USELESS_SCORE : score - 20
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
end
# Figure out which stat raises can happen
# Figure out which stat drops can happen
real_stat_changes = []
stat_changes.each_with_index do |stat, idx|
next if idx.odd?
@@ -655,7 +655,7 @@ class Battle::AI
end
next
end
# Calculate amount that stat will be raised by
# Calculate amount that stat will be lowered by
decrement = stat_changes[idx + 1]
decrement *= 2 if !fixed_change && !@battle.moldBreaker && @user.has_active_ability?(:SIMPLE)
decrement = [decrement, 6 + target.stages[stat]].min # The actual stages lost
@@ -721,7 +721,7 @@ class Battle::AI
"PowerHigherWithUserFasterThanTarget",
"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|
return true if !b.faster_than?(target)
end
@@ -786,7 +786,7 @@ class Battle::AI
end
old_stage = target.stages[stat]
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 *= desire_mult
# Stat-based score changes
@@ -794,8 +794,8 @@ 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 <= -2
score -= 20 * ((target.opposes?(@user)) ? 1 : desire_mult)
if old_stage <= -2 && decrement == 1
score -= 15 * ((target.opposes?(@user)) ? 1 : desire_mult)
else
has_special_moves = target.check_for_move { |m| m.specialMove?(m.type) }
dec = (has_special_moves) ? 5 : 10
@@ -804,8 +804,8 @@ class Battle::AI
when :DEFENSE
# Modify score depending on current stat stage
if old_stage <= -2
score -= 20 * ((target.opposes?(@user)) ? 1 : desire_mult)
if old_stage <= -2 && decrement == 1
score -= 15 * ((target.opposes?(@user)) ? 1 : desire_mult)
else
score += 5 * dec_mult
end
@@ -813,8 +813,8 @@ class Battle::AI
when :SPECIAL_ATTACK
# Modify score depending on current stat stage
# More strongly prefer if the target has no physical moves
if old_stage <= -2
score -= 20 * ((target.opposes?(@user)) ? 1 : desire_mult)
if old_stage <= -2 && decrement == 1
score -= 15 * ((target.opposes?(@user)) ? 1 : desire_mult)
else
has_physical_moves = target.check_for_move { |m| m.physicalMove?(m.type) &&
m.function != "UseUserDefenseInsteadOfUserAttack" &&
@@ -825,8 +825,8 @@ class Battle::AI
when :SPECIAL_DEFENSE
# Modify score depending on current stat stage
if old_stage <= -2
score -= 20 * ((target.opposes?(@user)) ? 1 : desire_mult)
if old_stage <= -2 && decrement == 1
score -= 15 * ((target.opposes?(@user)) ? 1 : desire_mult)
else
score += 5 * dec_mult
end
@@ -842,7 +842,7 @@ class Battle::AI
end
# Prefer if any ally has Electro Ball
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
end
# Don't prefer if target has Speed Boost (will be gaining Speed anyway)
@@ -852,8 +852,8 @@ class Battle::AI
when :ACCURACY
# Modify score depending on current stat stage
if old_stage <= -2
score -= 20 * ((target.opposes?(@user)) ? 1 : desire_mult)
if old_stage <= -2 && decrement == 1
score -= 15 * ((target.opposes?(@user)) ? 1 : desire_mult)
else
score += 5 * dec_mult
end
@@ -861,8 +861,8 @@ class Battle::AI
when :EVASION
# Modify score depending on current stat stage
if old_stage <= -2
score -= 20 * ((target.opposes?(@user)) ? 1 : desire_mult)
if old_stage <= -2 && decrement == 1
score -= 15 * ((target.opposes?(@user)) ? 1 : desire_mult)
else
score += 5 * dec_mult
end
@@ -870,12 +870,12 @@ class Battle::AI
end
# 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
end
# Don't prefer if any foe has Punishment
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
end
@@ -901,14 +901,14 @@ class Battle::AI
ret += (b.opposes?(move_user)) ? -10 : 10
end
# 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
end
when :Grassy
# End of round healing
ret += (b.opposes?(move_user)) ? -10 : 10
# 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
end
when :Misty
@@ -919,7 +919,7 @@ class Battle::AI
ret += (b.opposes?(move_user)) ? -5 : 5
end
# 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
end
when :Psychic
@@ -928,7 +928,7 @@ class Battle::AI
ret += (b.opposes?(move_user)) ? 10 : -10
end
# 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
end
end
@@ -980,16 +980,16 @@ class Battle::AI
ret += (b.opposes?(move_user)) ? -15 : 15
end
# Moves
if b.check_for_move { |m| ["EffectDependsOnEnvironment",
"SetUserTypesBasedOnEnvironment",
"TypeAndPowerDependOnTerrain",
"UseMoveDependingOnEnvironment"].include?(m.function) }
if b.has_move_with_function?("EffectDependsOnEnvironment",
"SetUserTypesBasedOnEnvironment",
"TypeAndPowerDependOnTerrain",
"UseMoveDependingOnEnvironment")
ret += (b.opposes?(move_user)) ? -10 : 10
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
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
end
end
@@ -1011,7 +1011,7 @@ class Battle::AI
:LEFTOVERS
]
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(:CHOICESPECS) if battler.check_for_move { |m| m.specialMove?(m.type) }
unpreferred_items = [
@@ -1029,7 +1029,7 @@ class Battle::AI
ret = -2
end
# 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
end
return ret
@@ -1050,7 +1050,7 @@ class Battle::AI
:AIRLOCK => 5,
:ANALYTIC => 5,
:ANGERPOINT => 4,
:ANTICIPATION => 2,
:ANTICIPATION => 0,
:ARENATRAP => 9,
:AROMAVEIL => 3,
# :ASONECHILLINGNEIGH => 0,
@@ -1109,9 +1109,9 @@ class Battle::AI
# :FLOWERVEIL => 0,
:FLUFFY => 5,
:FORECAST => 6,
:FOREWARN => 2,
:FOREWARN => 0,
# :FRIENDGUARD => 0,
:FRISK => 3,
:FRISK => 0,
:FULLMETALBODY => 4,
:FURCOAT => 7,
:GALEWINGS => 6,
@@ -1322,6 +1322,52 @@ class Battle::AI
# TODO: Ideally replace the above list of ratings with context-sensitive
# calculations. Should they all go in this method, or should there be
# 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
return ret
end

View File

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

View File

@@ -84,7 +84,7 @@ Battle::AI::Handlers::MoveEffectScore.add("RaiseUserDefense1CurlUpUser",
proc { |score, move, user, ai, battle|
score = ai.get_score_for_target_stat_raise(score, user, move.move.statUp)
if !user.effects[PBEffects::DefenseCurl] &&
user.check_for_move { |m| m.function == "MultiTurnAttackPowersUpEachTurn" }
user.has_move_with_function?("MultiTurnAttackPowersUpEachTurn")
score += 10
end
next score
@@ -148,7 +148,7 @@ Battle::AI::Handlers::MoveFailureCheck.copy("RaiseUserSpDef1",
Battle::AI::Handlers::MoveEffectScore.add("RaiseUserSpDef1PowerUpElectricMove",
proc { |score, move, user, ai, battle|
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
end
next score
@@ -201,14 +201,14 @@ Battle::AI::Handlers::MoveEffectScore.add("RaiseUserSpeed2LowerUserWeight",
# because of those modifiers, and the score changes may need to be
# different accordingly.
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
end
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
end
if b.check_for_move { |m| m.function == "PowerHigherWithTargetWeight" }
if b.has_move_with_function?("PowerHigherWithTargetWeight")
score += 10
end
# 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 != "UseTargetAttackInsteadOfUserAttack" }
score += 8
elsif user.check_for_move { |m| m.function == "PowerHigherWithUserPositiveStatStages" }
elsif user.has_move_with_function?("PowerHigherWithUserPositiveStatStages")
score += 4
end
next score
@@ -715,12 +715,12 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("RaiseTargetRandomStat2",
score += ((100 * target.hp / target.totalhp) - 50) / 4 # +5 to -12
end
# Prefer if target has Stored Power
if target.check_for_move { |m| m.function == "PowerHigherWithUserPositiveStatStages" }
if target.has_move_with_function?("PowerHigherWithUserPositiveStatStages")
score += 8
end
# Don't prefer if any foe has Punishment
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
end
next score
@@ -921,7 +921,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("LowerTargetSpeed1MakeTar
if !target.effects[PBEffects::TarShot]
eff = target.effectiveness_of_type_against_battler(:FIRE)
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
next score
@@ -1119,7 +1119,7 @@ Battle::AI::Handlers::MoveFailureCheck.add("RaisePlusMinusUserAndAlliesAtkSpAtk1
)
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("RaisePlusMinusUserAndAlliesAtkSpAtk1",
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) &&
!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",
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) &&
!target.battler.pbCanRaiseStatStage?(:SPECIAL_DEFENSE, user.battler, move.move)
}

View File

@@ -25,10 +25,10 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("SleepTarget",
score += 15
# 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|
score += 5 if b.check_for_move { |m| ["DoublePowerIfTargetAsleepCureTarget",
"DoublePowerIfTargetStatusProblem",
"HealUserByHalfOfDamageDoneIfTargetAsleep",
"StartDamageTargetEachTurnIfTargetAsleep"].include?(m.function) }
score += 5 if b.has_move_with_function?("DoublePowerIfTargetAsleepCureTarget",
"DoublePowerIfTargetStatusProblem",
"HealUserByHalfOfDamageDoneIfTargetAsleep",
"StartDamageTargetEachTurnIfTargetAsleep")
score += 10 if b.has_active_ability?(:BADDREAMS)
end
# 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
# 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|
score += 5 if b.check_for_move { |m| ["DoublePowerIfTargetPoisoned",
"DoublePowerIfTargetStatusProblem"].include?(m.function) }
score += 5 if b.has_move_with_function?("DoublePowerIfTargetPoisoned",
"DoublePowerIfTargetStatusProblem")
score += 10 if b.has_active_ability?(:MERCILESS)
end
# 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 -= 15 if target.has_active_ability?(:SYNCHRONIZE) &&
user.battler.pbCanPoisonSynchronize?(target.battler)
score -= 5 if target.check_for_move { |m| ["DoublePowerIfUserPoisonedBurnedParalyzed",
"CureUserBurnPoisonParalysis"].include?(m.function) }
score -= 5 if target.has_move_with_function?("DoublePowerIfUserPoisonedBurnedParalyzed",
"CureUserBurnPoisonParalysis")
score -= 10 if target.check_for_move { |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
# 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|
score += 5 if b.check_for_move { |m| ["DoublePowerIfTargetParalyzedCureTarget",
"DoublePowerIfTargetStatusProblem"].include?(m.function) }
score += 5 if b.has_move_with_function?("DoublePowerIfTargetParalyzedCureTarget",
"DoublePowerIfTargetStatusProblem")
end
# Don't prefer if target benefits from having the paralysis status problem
score -= 8 if target.has_active_ability?([:GUTS, :MARVELSCALE, :QUICKFEET])
score -= 15 if target.has_active_ability?(:SYNCHRONIZE) &&
user.battler.pbCanParalyzeSynchronize?(target.battler)
score -= 5 if target.check_for_move { |m| ["DoublePowerIfUserPoisonedBurnedParalyzed",
"CureUserBurnPoisonParalysis"].include?(m.function) }
score -= 5 if target.has_move_with_function?("DoublePowerIfUserPoisonedBurnedParalyzed",
"CureUserBurnPoisonParalysis")
score -= 10 if target.check_for_move { |m|
m.function == "GiveUserStatusToTarget" && user.battler.pbCanParalyze?(target.battler, false, m)
}
@@ -306,15 +306,15 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("BurnTarget",
end
# 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|
score += 5 if b.check_for_move { |m| m.function == "DoublePowerIfTargetStatusProblem" }
score += 5 if b.has_move_with_function?("DoublePowerIfTargetStatusProblem")
end
# Don't prefer if target benefits from having the burn status problem
score -= 8 if target.has_active_ability?([:FLAREBOOST, :GUTS, :MARVELSCALE, :QUICKFEET])
score -= 5 if target.has_active_ability?(:HEATPROOF)
score -= 15 if target.has_active_ability?(:SYNCHRONIZE) &&
user.battler.pbCanBurnSynchronize?(target.battler)
score -= 5 if target.check_for_move { |m| ["DoublePowerIfUserPoisonedBurnedParalyzed",
"CureUserBurnPoisonParalysis"].include?(m.function) }
score -= 5 if target.has_move_with_function?("DoublePowerIfUserPoisonedBurnedParalyzed",
"CureUserBurnPoisonParalysis")
score -= 10 if target.check_for_move { |m|
m.function == "GiveUserStatusToTarget" && user.battler.pbCanBurn?(target.battler, false, m)
}
@@ -380,7 +380,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("FreezeTarget",
score += 15
# 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|
score += 5 if b.check_for_move { |m| m.function == "DoublePowerIfTargetStatusProblem" }
score += 5 if b.has_move_with_function?("DoublePowerIfTargetStatusProblem")
end
# 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
@@ -722,15 +722,11 @@ Battle::AI::Handlers::MoveEffectScore.add("SetUserTypesBasedOnEnvironment",
new_type = :NORMAL if !GameData::Type.exists?(new_type)
end
# 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
end
score += 8 if user.has_damaging_move_of_type?(new_type)
# Check if any user's moves will lose STAB because of the type change
user.battler.pbTypes(true).each do |type|
next if type == new_type
if user.check_for_move { |m| m.damagingMove? && m.pbCalcType(user.battler) == type }
score -= 8
end
score -= 8 if user.has_damaging_move_of_type?(type)
end
# NOTE: Other things could be considered, like the foes' moves'
# effectivenesses against the current and new user's type(s), and
@@ -816,10 +812,9 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("SetUserTypesToUserMoveTy
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? && m.pbCalcType(user.battler) == type }
score += 10
break
end
next if !user.has_damaging_move_of_type?(type)
score += 10
break
end
# NOTE: Other things could be considered, like the foes' moves'
# 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
# damage to the user
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))
score += 5
end
@@ -1181,7 +1176,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("StartUserAirborne",
score += 4 if acc < 90 && acc != 0
score += 4 if acc <= 50 && acc != 0
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))
score -= 5
end
@@ -1213,7 +1208,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("HitsTargetInSkyGroundsTa
score += 10
# Prefer if any allies have damaging Ground-type moves
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
# Don't prefer if terrain exists (which the target will become affected by)
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
# on a grounded foe, and vice versa
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
end
end

View File

@@ -504,13 +504,13 @@ Battle::AI::Handlers::MoveEffectScore.add("StartWeakenElectricMoves",
end
# Prefer if foes have Electric moves
ai.each_foe_battler(user.side) do |b, i|
next if !b.check_for_move { |m| m.damagingMove? && m.pbCalcType(b.battler) == :ELECTRIC }
next if !b.has_damaging_move_of_type?(:ELECTRIC)
score += 10
score += 5 if !b.check_for_move { |m| m.damagingMove? && m.pbCalcType(b.battler) != :ELECTRIC }
end
# Don't prefer if any allies have Electric moves
ai.each_same_side_battler(user.side) do |b, i|
next if !b.check_for_move { |m| m.damagingMove? && m.pbCalcType(b.battler) == :ELECTRIC }
next if !b.has_damaging_move_of_type?(:ELECTRIC)
score -= 8
score -= 4 if !b.check_for_move { |m| m.damagingMove? && m.pbCalcType(b.battler) != :ELECTRIC }
end
@@ -535,13 +535,13 @@ Battle::AI::Handlers::MoveEffectScore.add("StartWeakenFireMoves",
end
# Prefer if foes have Fire moves
ai.each_foe_battler(user.side) do |b, i|
next if !b.check_for_move { |m| m.damagingMove? && m.pbCalcType(b.battler) == :FIRE }
next if !b.has_damaging_move_of_type?(:FIRE)
score += 10
score += 5 if !b.check_for_move { |m| m.damagingMove? && m.pbCalcType(b.battler) != :FIRE }
end
# Don't prefer if any allies have Fire moves
ai.each_same_side_battler(user.side) do |b, i|
next if !b.check_for_move { |m| m.damagingMove? && m.pbCalcType(b.battler) == :FIRE }
next if !b.has_damaging_move_of_type?(:FIRE)
score -= 8
score -= 4 if !b.check_for_move { |m| m.damagingMove? && m.pbCalcType(b.battler) != :FIRE }
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 target.effects[PBEffects::Telekinesis] > 0
# Prefer if the user knows moves with low accuracy
# TODO: This isn't the correct use of check_for_move, since it should just
# loop through them instead.
user.check_for_move do |m|
user.battler.eachMove do |m|
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
# 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
# target's Ghost type immunity
if target.has_type?(:GHOST)
user.check_for_move do |m|
user.battler.eachMove do |m|
next if !m.damagingMove?
score += 10 if Effectiveness.ineffective_type?(m.pbCalcType(user.battler), :GHOST)
end
@@ -998,7 +996,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("StartNegateTargetEvasion
# Check if the user knows any moves that would benefit from negating the
# target's Dark type immunity
if target.has_type?(:DARK)
user.check_for_move do |m|
user.battler.eachMove do |m|
next if !m.damagingMove?
score += 10 if Effectiveness.ineffective_type?(m.pbCalcType(user.battler), :DARK)
end

View File

@@ -215,27 +215,27 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("TwoTurnAttack",
has_protect_move = false
if move.move.pbTarget(user).num_targets > 1 &&
(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
end
end
if move.move.canProtectAgainst?
if target.check_for_move { |m| ["ProtectUser",
"ProtectUserFromTargetingMovesSpikyShield",
"ProtectUserBanefulBunker"].include?(m.function) }
if target.has_move_with_function?("ProtectUser",
"ProtectUserFromTargetingMovesSpikyShield",
"ProtectUserBanefulBunker")
has_protect_move = true
end
if move.damagingMove?
# 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
# to this move charging up.
if target.check_for_move { |m| ["ProtectUserFromDamagingMovesKingsShield",
"ProtectUserFromDamagingMovesObstruct"].include?(m.function) }
if target.has_move_with_function?("ProtectUserFromDamagingMovesKingsShield",
"ProtectUserFromDamagingMovesObstruct")
has_protect_move = true
end
end
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
end
end

View File

@@ -206,7 +206,7 @@ Battle::AI::Handlers::MoveEffectScore.add("DoublePowerAfterFusionFlare",
proc { |score, move, user, ai, battle|
# Prefer if an ally knows Fusion Flare
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
next score
}
@@ -219,7 +219,7 @@ Battle::AI::Handlers::MoveEffectScore.add("DoublePowerAfterFusionBolt",
proc { |score, move, user, ai, battle|
# Prefer if an ally knows Fusion Bolt
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
next score
}
@@ -380,7 +380,7 @@ Battle::AI::Handlers::MoveEffectScore.add("GrassPledge",
proc { |score, move, user, ai, battle|
# Prefer if an ally knows a different Pledge move
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
next score
}
@@ -393,7 +393,7 @@ Battle::AI::Handlers::MoveEffectScore.add("FirePledge",
proc { |score, move, user, ai, battle|
# Prefer if an ally knows a different Pledge move
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
next score
}
@@ -406,7 +406,7 @@ Battle::AI::Handlers::MoveEffectScore.add("WaterPledge",
proc { |score, move, user, ai, battle|
# Prefer if an ally knows a different Pledge move
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
next score
}

View File

@@ -30,13 +30,7 @@ Battle::AI::Handlers::MoveEffectScore.add("SwitchOutUserStatusMove",
else
score -= total * 10
# special case: user has no damaging moves
hasDamagingMove = false
user.battler.eachMove do |m|
next if !m.damagingMove?
hasDamagingMove = true
break
end
score += 75 if !hasDamagingMove
score += 75 if !user.check_for_move { |m| m.damagingMove? }
end
end
next score
@@ -95,13 +89,7 @@ Battle::AI::Handlers::MoveEffectScore.add("SwitchOutUserPassOnEffects",
else
score += total * 10
# special case: user has no damaging moves
hasDamagingMove = false
user.battler.eachMove do |m|
next if !m.damagingMove?
hasDamagingMove = true
break
end
score += 75 if !hasDamagingMove
score += 75 if !user.check_for_move { |m| m.damagingMove? }
end
else
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
# effect)
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
end
end
@@ -440,7 +428,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("LowerPPOfTargetLastMoveB
)
#===============================================================================
# TODO: Review score modifiers.
#
#===============================================================================
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("DisableTargetLastMoveUsed",
proc { |move, user, target, ai, battle|
@@ -456,9 +444,25 @@ Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("DisableTargetLastMoveUs
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",
proc { |move, user, target, ai, battle|
@@ -469,13 +473,21 @@ Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("DisableTargetUsingSameM
)
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("DisableTargetUsingSameMoveConsecutively",
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
}
)
#===============================================================================
# TODO: Review score modifiers.
#
#===============================================================================
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("DisableTargetUsingDifferentMove",
proc { |move, user, target, ai, battle|
@@ -496,23 +508,44 @@ Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("DisableTargetUsingDiffe
)
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("DisableTargetUsingDifferentMove",
proc { |score, move, user, target, ai, battle|
next Battle::AI::MOVE_USELESS_SCORE if target.has_active_item?(:MENTALHERB)
if user.faster_than?(target)
moveData = GameData::Move.get(target.battler.lastRegularMoveUsed)
if moveData.category == 2 && # Status move
[:User, :BothSides].include?(moveData.target)
score += 60
elsif moveData.category != 2 && # Damaging move
moveData.target == :NearOther &&
Effectiveness.ineffective?(user.effectiveness_of_type_against_battler(moveData.type, target))
score += 60
# We know which move is going to be encored (assuming the target doesn't
# use a high priority move)
move_data = GameData::Move.get(target.battler.lastRegularMoveUsed)
if move_data.status?
# Prefer encoring status moves
if [:User, :BothSides].include?(move_data.target)
# TODO: This target distinction was in the old code. Is it appropriate?
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
else
# We don't know which move is going to be encored; just prefer limiting
# the target's options
score += 8
end
next score
}
)
#===============================================================================
# TODO: Review score modifiers.
#
#===============================================================================
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("DisableTargetStatusMoves",
proc { |move, user, target, ai, battle|
@@ -526,12 +559,45 @@ Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("DisableTargetStatusMove
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("DisableTargetStatusMoves",
proc { |score, move, user, target, ai, battle|
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
}
)
#===============================================================================
# TODO: Review score modifiers.
#
#===============================================================================
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("DisableTargetHealingMoves",
proc { |move, user, target, ai, battle|
@@ -542,28 +608,57 @@ Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("DisableTargetHealingMov
)
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("DisableTargetHealingMoves",
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
}
)
#===============================================================================
# TODO: Review score modifiers.
#.
#===============================================================================
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("DisableTargetSoundMoves",
proc { |score, move, user, target, ai, battle|
if target.effects[PBEffects::ThroatChop] == 0
score += 10 if target.check_for_move { |m| m.soundMove? }
end
next score if target.effects[PBEffects::ThroatChop] > 1
next score if !target.check_for_move { |m| m.soundMove? && (m.pp > 0 || m.total_pp == 0) }
# Inherent preference
score += 8
next score
}
)
#===============================================================================
# TODO: Review score modifiers.
#
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.add("DisableTargetMovesKnownByUser",
proc { |move, user, ai, battle|
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
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?

View File

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