Added script to make two random AI trainers battle, tweaked battle messages when logged, fixed typos

This commit is contained in:
Maruno17
2022-09-06 22:57:51 +01:00
parent b8c61a6038
commit eecb7a1453
27 changed files with 335 additions and 154 deletions

View File

@@ -45,7 +45,7 @@ class Battle::AI
@trainer = @trainers[(opposes) ? 1 : 0][trainer_index]
# Find the AI battler for which the action is being chosen
@user = @battlers[idxBattler]
@user.refresh_battler
@battlers.each { |b| b.refresh_battler if b }
end
# Choose an action.

View File

@@ -11,16 +11,18 @@ class Battle::AI
shouldSwitch = forceSwitch
battler = @user.battler
batonPass = -1
foe = nil
moveType = nil
# If Pokémon is within 6 levels of the foe, and foe's last move was
# super-effective and powerful
if !shouldSwitch && battler.turnCount > 0 && @trainer.high_skill?
target = battler.pbDirectOpposing(true)
foe = @battlers[target.index]
if !target.fainted? && target.lastMoveUsed &&
(target.level - battler.level).abs <= 6
moveData = GameData::Move.get(target.lastMoveUsed)
moveType = moveData.type
typeMod = battler.effectiveness_of_type_against_battler(moveType, target)
typeMod = @user.effectiveness_of_type_against_battler(moveType, foe)
if Effectiveness.super_effective?(typeMod) && moveData.base_damage > 50
switchChance = (moveData.base_damage > 70) ? 30 : 20
shouldSwitch = (pbAIRandom(100) < switchChance)
@@ -106,7 +108,7 @@ class Battle::AI
end
end
# moveType is the type of the target's last used move
if moveType && Effectiveness.ineffective?(battler.effectiveness_of_type_against_battler(moveType))
if moveType && Effectiveness.ineffective?(@user.effectiveness_of_type_against_battler(moveType, foe))
weight = 65
typeMod = pbCalcTypeModPokemon(pkmn, battler.pbDirectOpposing(true))
if Effectiveness.super_effective?(typeMod)
@@ -114,7 +116,7 @@ class Battle::AI
weight = 85
end
list.unshift(i) if pbAIRandom(100) < weight # Put this Pokemon first
elsif moveType && Effectiveness.resistant?(battler.effectiveness_of_type_against_battler(moveType))
elsif moveType && Effectiveness.resistant?(@user.effectiveness_of_type_against_battler(moveType, foe))
weight = 40
typeMod = pbCalcTypeModPokemon(pkmn, battler.pbDirectOpposing(true))
if Effectiveness.super_effective?(typeMod)

View File

@@ -11,19 +11,16 @@ class Battle::AI
# (which are based on the predicted damages). Multi-target moves could
# be fiddly since damages should be calculated for each target but
# they're all related.
battler.eachMoveWithIndex do |_m, i|
next if !@battle.pbCanChooseMove?(battler.index, i, false) # Unchoosable moves aren't considered
pbAddMoveWithScoreToChoices(i, choices)
end
# Log the available choices
if $INTERNAL
logMsg = "[AI] Move choices for #{battler.pbThis(true)} (#{battler.index}): "
choices.each_with_index do |c, i|
logMsg += "#{battler.moves[c[0]].name}=#{c[1]}"
logMsg += " (target #{c[2]})" if c[2] >= 0
logMsg += ", " if i < choices.length - 1
battler.eachMoveWithIndex do |m, i|
if !@battle.pbCanChooseMove?(battler.index, i, false) # Unchoosable moves aren't considered
if m.pp == 0 && m.total_pp > 0
PBDebug.log("[AI] #{battler.pbThis} (#{battler.index}) cannot use move #{m.name} as it has no PP left")
else
PBDebug.log("[AI] #{battler.pbThis} (#{battler.index}) cannot choose to use #{m.name}")
end
next
end
PBDebug.log(logMsg)
pbAddMoveWithScoreToChoices(i, choices)
end
@battle.moldBreaker = false
return choices
@@ -159,7 +156,7 @@ class Battle::AI
target_battler = @target.battler
# Predict whether the move will fail
return 50 if pbPredictMoveFailure
return 25 if pbPredictMoveFailure
# Get the base score for the move
if @move.damagingMove?
@@ -188,20 +185,11 @@ class Battle::AI
def pbChooseMove(choices)
user_battler = @user.battler
# If there are no calculated choices, pick one at random
# If no moves can be chosen, auto-choose a move or Struggle
if choices.length == 0
# NOTE: Can only get here if no moves can be chosen, i.e. will auto-use a
# move or struggle.
user_battler.eachMoveWithIndex do |_m, i|
next if !@battle.pbCanChooseMove?(user_battler.index, i, false)
choices.push([i, 100, -1]) # Move index, score, target
end
if choices.length == 0 # No moves are physically possible to use; use Struggle
@battle.pbAutoChooseMove(user_battler.index)
PBDebug.log("[AI] #{user_battler.pbThis} (#{user_battler.index}) will auto-use a move or Struggle")
return
end
PBDebug.log("[AI] #{user_battler.pbThis} (#{user_battler.index}) doesn't want to use any moves; picking one at random")
@battle.pbAutoChooseMove(user_battler.index)
PBDebug.log("[AI] #{user_battler.pbThis} (#{user_battler.index}) will auto-use a move or Struggle")
return
end
# Figure out useful information about the choices
@@ -211,31 +199,45 @@ 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 <= 20 && user_battler.turnCount > 2) ||
(max_score <= 40 && user_battler.turnCount > 5)
if (max_score <= 25 && user_battler.turnCount > 2) ||
(max_score <= 50 && user_battler.turnCount > 5)
badMoves = true if pbAIRandom(100) < 80
end
if !badMoves && max_score < 60 && user_battler.turnCount > 1
if !badMoves && max_score < 50 && user_battler.turnCount >= 1
badMoves = choices.none? { |c| user_battler.moves[c[0]].damagingMove? }
badMoves = false if badMoves && pbAIRandom(100) < 10
end
if badMoves && pbEnemyShouldWithdrawEx?(true)
if $INTERNAL
PBDebug.log("[AI] #{user_battler.pbThis} (#{user_battler.index}) will switch due to terrible moves")
end
PBDebug.log("[AI] #{user_battler.pbThis} (#{user_battler.index}) will switch due to terrible moves")
return
end
end
# Calculate a minimum score threshold and reduce all move scores by it
threshold = (max_score * 0.85).floor
choices.each { |c| c[1] = [c[1] - threshold, 0].max }
total_score = choices.sum { |c| c[1] }
choices.each { |c| c[3] = [c[1] - threshold, 0].max }
total_score = choices.sum { |c| c[3] }
# Log the available choices
if $INTERNAL
PBDebug.log("[AI] Move choices for #{user_battler.pbThis(true)} (#{user_battler.index}):")
choices.each_with_index do |c, i|
chance = "0"
chance = sprintf("%.1f", 100.0 * c[3] / total_score) if c[3] > 0
while chance.length < 5
chance = " " + chance
end
log_msg = " * #{chance}% chance: #{user_battler.moves[c[0]].name}"
log_msg += " (against target #{c[2]})" if c[2] >= 0
log_msg += " = score #{c[1]}"
PBDebug.log(log_msg)
end
end
# Pick a move randomly from choices weighted by their scores
randNum = pbAIRandom(total_score)
choices.each do |c|
randNum -= c[1]
randNum -= c[3]
next if randNum >= 0
@battle.pbRegisterMove(user_battler.index, c[0], false)
@battle.pbRegisterTarget(user_battler.index, c[2]) if c[2] >= 0
@@ -244,7 +246,7 @@ class Battle::AI
# Log the result
if @battle.choices[user_battler.index][2]
PBDebug.log("[AI] #{user_battler.pbThis} (#{user_battler.index}) will use #{@battle.choices[user_battler.index][2].name}")
PBDebug.log(" => will use #{@battle.choices[user_battler.index][2].name}")
end
end
end

View File

@@ -62,22 +62,22 @@ class Battle::AI
# TODO: Exception if user knows Baton Pass/Stored Power?
case stat
when :ATTACK
return false if !@user.check_for_move { |move| move.physicalMove?(move.type) &&
move.function != "UseUserBaseDefenseInsteadOfUserBaseAttack" &&
move.function != "UseTargetAttackInsteadOfUserAttack" }
return false if !@user.check_for_move { |m| m.physicalMove?(move.type) &&
m.function != "UseUserBaseDefenseInsteadOfUserBaseAttack" &&
m.function != "UseTargetAttackInsteadOfUserAttack" }
when :DEFENSE
each_foe_battler(@user.side) do |b, i|
next if !b.check_for_move { |move| move.physicalMove?(move.type) ||
move.function == "UseTargetDefenseInsteadOfTargetSpDef" }
next if !b.check_for_move { |m| m.physicalMove?(m.type) ||
m.function == "UseTargetDefenseInsteadOfTargetSpDef" }
return true
end
return false
when :SPECIAL_ATTACK
return false if !@user.check_for_move { |move| move.specialMove?(move.rough_type) }
return false if !@user.check_for_move { |m| m.specialMove?(m.type) }
when :SPECIAL_DEFENSE
each_foe_battler(@user.side) do |b, i|
next if !b.check_for_move { |move| move.specialMove?(move.type) &&
move.function != "UseTargetDefenseInsteadOfTargetSpDef" }
next if !b.check_for_move { |m| m.specialMove?(m.type) &&
m.function != "UseTargetDefenseInsteadOfTargetSpDef" }
return true
end
return false
@@ -86,7 +86,7 @@ class Battle::AI
"PowerHigherWithUserFasterThanTarget",
"PowerHigherWithUserPositiveStatStages"
]
if !@user.check_for_move { |move| moves_that_prefer_high_speed.include?(move.function) }
if !@user.check_for_move { |m| moves_that_prefer_high_speed.include?(m.function) }
each_foe_battler(@user.side) do |b, i|
return true if b.faster_than?(@user)
end
@@ -241,7 +241,7 @@ class Battle::AI
if @user.stages[stat] >= 3
score -= 20
else
has_special_moves = @user.check_for_move { |move| move.specialMove?(move.rough_type) }
has_special_moves = @user.check_for_move { |m| m.specialMove?(m.type) }
inc = (has_special_moves) ? 5 : 10
score += inc * (3 - @user.stages[stat]) * increment # 5 to 45
score += 5 * increment if @user.hp == @user.totalhp
@@ -262,9 +262,9 @@ class Battle::AI
if @user.stages[stat] >= 3
score -= 20
else
has_physical_moves = @user.check_for_move { |move| move.physicalMove?(move.type) &&
move.function != "UseUserBaseDefenseInsteadOfUserBaseAttack" &&
move.function != "UseTargetAttackInsteadOfUserAttack" }
has_physical_moves = @user.check_for_move { |m| m.physicalMove?(m.type) &&
m.function != "UseUserBaseDefenseInsteadOfUserBaseAttack" &&
m.function != "UseTargetAttackInsteadOfUserAttack" }
inc = (has_physical_moves) ? 5 : 10
score += inc * (3 - @user.stages[stat]) * increment # 5 to 45
score += 5 * increment if @user.hp == @user.totalhp
@@ -288,7 +288,7 @@ class Battle::AI
end
# Don't prefer if any foe has Gyro Ball
each_foe_battler(@user.side) do |b, i|
next if !b.check_for_move { |move| move.function == "PowerHigherWithTargetFasterThanUser" }
next if !b.check_for_move { |m| m.function == "PowerHigherWithTargetFasterThanUser" }
score -= 10 * increment
end
# Don't prefer if user has Speed Boost (will be gaining Speed anyway)
@@ -336,12 +336,12 @@ class Battle::AI
pos_change = [@user.stages[stat] + increment, increment].min
if pos_change > 0
# Prefer if user has Stored Power
if @user.check_for_move { |move| move.function == "PowerHigherWithUserPositiveStatStages" }
if @user.check_for_move { |m| m.function == "PowerHigherWithUserPositiveStatStages" }
score += 10 * pos_change
end
# Don't prefer if any foe has Punishment
each_foe_battler(@user.side) do |b, i|
next if !b.check_for_move { |move| move.function == "PowerHigherWithTargetPositiveStatStages" }
next if !b.check_for_move { |m| m.function == "PowerHigherWithTargetPositiveStatStages" }
score -= 10 * pos_change
end
end
@@ -355,7 +355,7 @@ class Battle::AI
when :ATTACK
# TODO: Don't prefer if target has previously used a move that benefits
# from user's Attack being boosted.
# mini_score *= 0.3 if @target.check_for_move { |move| move.function == "UseTargetAttackInsteadOfUserAttack" } # Foul Play
# mini_score *= 0.3 if @target.check_for_move { |m| m.function == "UseTargetAttackInsteadOfUserAttack" } # Foul Play
# Prefer if user can definitely survive a hit no matter how powerful, and
# it won't be hurt by weather
# if @user.hp == @user.totalhp &&
@@ -393,7 +393,7 @@ class Battle::AI
# (@user.hasActiveItem?(:BLACKSLUDGE) && @user.pbHasType?(:POISON))
# Prefer if user knows any healing moves
# # TODO: Is 1.2x for RaiseUserAtkDefAcc1 Coil (+Atk, +Def, +acc).
# mini_score *= 1.3 if check_for_move(@user) { |move| move.healingMove? }
# mini_score *= 1.3 if check_for_move(@user) { |m| m.healingMove? }
# Prefer if user knows Pain Split or Leech Seed
# # TODO: Leech Seed is 1.2x for RaiseUserAtkDefAcc1 Coil (+Atk, +Def, +acc).
# mini_score *= 1.2 if @user.pbHasMoveFunction?("UserTargetAverageHP") # Pain Split
@@ -483,7 +483,7 @@ class Battle::AI
# mini_score *= 1.2 if @user.hasActiveItem?(:LEFTOVERS) ||
# (@user.hasActiveItem?(:BLACKSLUDGE) && @user.pbHasType?(:POISON))
# Prefer if user knows any healing moves
# mini_score *= 1.3 if check_for_move(@user) { |move| move.healingMove? }
# mini_score *= 1.3 if check_for_move(@user) { |m| m.healingMove? }
# Prefer if user knows Pain Split or Leech Seed
# mini_score *= 1.2 if @user.pbHasMoveFunction?("UserTargetAverageHP") # Pain Split
# mini_score *= 1.3 if @user.pbHasMoveFunction?("StartLeechSeedTarget") # Leech Seed
@@ -495,7 +495,7 @@ class Battle::AI
when :ACCURACY
# Prefer if user knows any weaker moves
mini_score *= 1.1 if check_for_move(@user) { |move| move.damagingMove? && move.basedamage < 95 }
mini_score *= 1.1 if check_for_move(@user) { |m| m.damagingMove? && m.basedamage < 95 }
# Prefer if target has a raised evasion
sum_stages = @target.stages[:EVASION]
mini_score *= 1 + sum_stages * 0.05 if sum_stages > 0
@@ -521,7 +521,7 @@ class Battle::AI
mini_score *= 1.3
end
# Prefer if user knows any healing moves
mini_score *= 1.3 if check_for_move(@user) { |move| move.healingMove? }
mini_score *= 1.3 if check_for_move(@user) { |m| move.healingMove? }
# Prefer if user knows Pain Split or Leech Seed
mini_score *= 1.2 if @user.pbHasMoveFunction?("UserTargetAverageHP") # Pain Split
mini_score *= 1.3 if @user.pbHasMoveFunction?("StartLeechSeedTarget") # Leech Seed
@@ -537,8 +537,8 @@ class Battle::AI
# TODO: Don't prefer if any foe has previously used a stat stage-clearing
# move (Clear Smog/Haze).
mini_score *= 0.3 if check_for_move(@target) { |move|
["ResetTargetStatStages", "ResetAllBattlersStatStages"].include?(move.function)
mini_score *= 0.3 if check_for_move(@target) { |m|
["ResetTargetStatStages", "ResetAllBattlersStatStages"].include?(m.function)
} # Clear Smog, Haze
# TODO: Prefer if user is faster than the target.
@@ -561,8 +561,8 @@ class Battle::AI
def get_score_for_terrain(terrain, move_user)
ret = 0
# Inherent effects of terrain
@battlers.each do |b|
next if !b || b.battler.fainted? || !b.battler.affectedByTerrain?
each_battler do |b, i|
next if !b.battler.affectedByTerrain?
case terrain
when :Electric
# Immunity to sleep
@@ -574,14 +574,14 @@ class Battle::AI
ret += (b.opposes?(move_user)) ? -10 : 10
end
# Check for Electric moves
if b.check_for_move { |move| move.type == :ELECTRIC && move.damagingMove? }
if b.check_for_move { |m| m.type == :ELECTRIC && m.damagingMove? }
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 { |move| move.type == :GRASS && move.damagingMove? }
if b.check_for_move { |m| m.type == :GRASS && m.damagingMove? }
ret += (b.opposes?(move_user)) ? -15 : 15
end
when :Misty
@@ -592,16 +592,16 @@ class Battle::AI
ret += (b.opposes?(move_user)) ? -5 : 5
end
# Check for Dragon moves
if b.check_for_move { |move| move.type == :DRAGON && move.damagingMove? }
if b.check_for_move { |m| m.type == :DRAGON && m.damagingMove? }
ret += (b.opposes?(move_user)) ? 15 : -15
end
when :Psychic
# Check for priority moves
if b.check_for_move { |move| move.priority > 0 && move.pbTarget&.can_target_one_foe? }
if b.check_for_move { |m| m.priority > 0 && m.pbTarget&.can_target_one_foe? }
ret += (b.opposes?(move_user)) ? 10 : -10
end
# Check for Psychic moves
if b.check_for_move { |move| move.type == :PSYCHIC && move.damagingMove? }
if b.check_for_move { |m| m.type == :PSYCHIC && m.damagingMove? }
ret += (b.opposes?(move_user)) ? -15 : 15
end
end
@@ -613,8 +613,7 @@ class Battle::AI
:Misty => :MISTYSEED,
:Psychic => :PSYCHICSEED
}[terrain]
ai.battlers.each do |b|
next if !b || b.battler.fainted?
each_battler do |b, i|
if b.has_active_item?(:TERRAINEXTENDER)
ret += (b.opposes?(move_user)) ? -15 : 15
elsif seed && b.has_active_item?(seed)
@@ -622,7 +621,7 @@ class Battle::AI
end
end
# Check for abilities/moves affected by the terrain
if ai.trainer.medium_skill?
if @trainer.medium_skill?
abils = {
:Electric => :SURGESURFER,
:Grassy => :GRASSPELT,
@@ -644,8 +643,8 @@ class Battle::AI
:Misty => nil,
:Psychic => nil
}[terrain]
ai.battlers.each do |b|
next if !b || b.battler.fainted? || !b.battler.affectedByTerrain?
each_battler do |b, i|
next if !b.battler.affectedByTerrain?
# Abilities
if b.has_active_ability?(:MIMICRY)
ret += (b.opposes?(move_user)) ? -5 : 5
@@ -654,16 +653,16 @@ class Battle::AI
ret += (b.opposes?(move_user)) ? -15 : 15
end
# Moves
if b.check_for_move { |move| ["EffectDependsOnEnvironment",
"SetUserTypesBasedOnEnvironment",
"TypeAndPowerDependOnTerrain",
"UseMoveDependingOnEnvironment"].include?(move.function) }
if b.check_for_move { |m| ["EffectDependsOnEnvironment",
"SetUserTypesBasedOnEnvironment",
"TypeAndPowerDependOnTerrain",
"UseMoveDependingOnEnvironment"].include?(m.function) }
ret += (b.opposes?(move_user)) ? -10 : 10
end
if good_moves && b.check_for_move { |move| good_moves.include?(move.function) }
if good_moves && b.check_for_move { |m| good_moves.include?(m.function) }
ret += (b.opposes?(move_user)) ? -10 : 10
end
if bad_moves && b.check_for_move { |move| bad_moves.include?(move.function) }
if bad_moves && b.check_for_move { |m| bad_moves.include?(m.function) }
ret += (b.opposes?(move_user)) ? 10 : -10
end
end

View File

@@ -129,12 +129,12 @@ Battle::AI::Handlers::MoveEffectScore.add("FailsIfUserDamagedThisTurn",
if target.effects[PBEffects::HyperBeam] > 0 ||
target.effects[PBEffects::Truant] ||
(target.battler.asleep? && target.statusCount > 1) ||
target.frozen?
target.battler.frozen?
score += 20
elsif target.effects[PBEffects::Confusion] > 1 ||
target.effects[PBEffects::Attract] == user.index
score += 10
elsif target.paralyzed?
elsif target.battler.paralyzed?
score += 5
end
end
@@ -167,7 +167,7 @@ Battle::AI::Handlers::MoveEffectScore.add("FailsIfTargetActed",
#===============================================================================
Battle::AI::Handlers::MoveEffectScore.add("CrashDamageIfFailsUnusableInGravity",
proc { |score, move, user, target, ai, battle|
next score - (100 - move.rough_accuracy) if user.takesIndirectDamage?
next score - (100 - move.rough_accuracy) if user.battler.takesIndirectDamage?
}
)
@@ -448,7 +448,7 @@ Battle::AI::Handlers::MoveEffectScore.add("AddSpikesToFoeSide",
inBattleIndices = battle.allSameSideBattlers(user.idxOpposingSide).map { |b| b.pokemonIndex }
foe_reserves = []
battle.pbParty(user.idxOpposingSide).each_with_index do |pkmn, idxParty|
next if !pkmn || !pkmn.able? || inBattleIndices.include(idxParty)
next if !pkmn || !pkmn.able? || inBattleIndices.include?(idxParty)
if ai.trainer.medium_skill?
# Check affected by entry hazard
next if pkmn.hasItem?(:HEAVYDUTYBOOTS)
@@ -484,7 +484,7 @@ Battle::AI::Handlers::MoveEffectScore.add("AddToxicSpikesToFoeSide",
inBattleIndices = battle.allSameSideBattlers(user.idxOpposingSide).map { |b| b.pokemonIndex }
foe_reserves = []
battle.pbParty(user.idxOpposingSide).each_with_index do |pkmn, idxParty|
next if !pkmn || !pkmn.able? || inBattleIndices.include(idxParty)
next if !pkmn || !pkmn.able? || inBattleIndices.include?(idxParty)
if ai.trainer.medium_skill?
# Check affected by entry hazard
next if pkmn.hasItem?(:HEAVYDUTYBOOTS)
@@ -522,7 +522,7 @@ Battle::AI::Handlers::MoveEffectScore.add("AddStealthRocksToFoeSide",
inBattleIndices = battle.allSameSideBattlers(user.idxOpposingSide).map { |b| b.pokemonIndex }
foe_reserves = []
battle.pbParty(user.idxOpposingSide).each_with_index do |pkmn, idxParty|
next if !pkmn || !pkmn.able? || inBattleIndices.include(idxParty)
next if !pkmn || !pkmn.able? || inBattleIndices.include?(idxParty)
if ai.trainer.medium_skill?
# Check affected by entry hazard
next if pkmn.hasItem?(:HEAVYDUTYBOOTS)
@@ -549,7 +549,7 @@ Battle::AI::Handlers::MoveEffectScore.add("AddStickyWebToFoeSide",
inBattleIndices = battle.allSameSideBattlers(user.idxOpposingSide).map { |b| b.pokemonIndex }
foe_reserves = []
battle.pbParty(user.idxOpposingSide).each_with_index do |pkmn, idxParty|
next if !pkmn || !pkmn.able? || inBattleIndices.include(idxParty)
next if !pkmn || !pkmn.able? || inBattleIndices.include?(idxParty)
if ai.trainer.medium_skill?
# Check affected by entry hazard
next if pkmn.hasItem?(:HEAVYDUTYBOOTS)

View File

@@ -393,7 +393,7 @@ Battle::AI::Handlers::MoveEffectScore.add("FlinchTarget",
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.add("FlinchTargetFailsIfUserNotAsleep",
proc { |move, user, target, ai, battle|
next true if !user.asleep?
next true if !user.battler.asleep?
}
)
Battle::AI::Handlers::MoveEffectScore.add("FlinchTargetFailsIfUserNotAsleep",
@@ -649,7 +649,7 @@ Battle::AI::Handlers::MoveFailureCheck.add("SetTargetAbilityToInsomnia",
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.add("SetUserAbilityToTargetAbility",
proc { |move, user, target, ai, battle|
next true if user.battle.unstoppableAbility?
next true if user.battler.unstoppableAbility?
next true if !target.ability || user.ability_id == target.ability_id
next true if target.battler.ungainableAbility? ||
[:POWEROFALCHEMY, :RECEIVER, :TRACE, :WONDERGUARD].include?(target.ability_id)
@@ -673,7 +673,7 @@ Battle::AI::Handlers::MoveFailureCheck.add("SetTargetAbilityToUserAbility",
next true if !user.ability || user.ability_id == target.ability_id
next true if user.battler.ungainableAbility? ||
[:POWEROFALCHEMY, :RECEIVER, :TRACE].include?(user.ability_id)
next true if target.battle.unstoppableAbility? || target.ability_id == :TRUANT
next true if target.battler.unstoppableAbility? || target.ability_id == :TRUANT
}
)
Battle::AI::Handlers::MoveEffectScore.add("SetTargetAbilityToUserAbility",
@@ -693,9 +693,9 @@ Battle::AI::Handlers::MoveFailureCheck.add("UserTargetSwapAbilities",
proc { |move, user, target, ai, battle|
next true if !user.ability || !target.ability
next true if Settings::MECHANICS_GENERATION <= 5 && user.ability_id == target.ability_id
next true if user.battle.unstoppableAbility? || user.battler.ungainableAbility? ||
next true if user.battler.unstoppableAbility? || user.battler.ungainableAbility? ||
user.ability_id == :WONDERGUARD
next true if target.battle.unstoppableAbility? || target.battler.ungainableAbility? ||
next true if target.battler.unstoppableAbility? || target.battler.ungainableAbility? ||
target.ability_id == :WONDERGUARD
}
)
@@ -714,7 +714,7 @@ Battle::AI::Handlers::MoveEffectScore.add("UserTargetSwapAbilities",
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.add("NegateTargetAbility",
proc { |move, user, target, ai, battle|
next true if target.unstoppableAbility? ||
next true if target.battler.unstoppableAbility? ||
target.effects[PBEffects::GastroAcid]
}
)

View File

@@ -422,7 +422,7 @@ Battle::AI::Handlers::MoveEffectScore.add("StartLeechSeedTarget",
if !user.check_for_move { |move| move.damagingMove? }
score += 20
end
score -= 20 if target.has_active_ability?([:LIQUIDOOZE]) || !target.takesIndirectDamage?
score -= 20 if target.has_active_ability?([:LIQUIDOOZE]) || !target.battler.takesIndirectDamage?
end
if ai.trainer.high_skill?
if user.check_for_move { |move| move.is_a?(Battle::Move::ProtectMove) }

View File

@@ -315,8 +315,8 @@ Battle::AI::Handlers::MoveFailureCheck.add("UseLastMoveUsed",
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.add("UseLastMoveUsedByTarget",
proc { |move, user, target, ai, battle|
next true if !target.battle.lastRegularMoveUsed
next true if GameData::Move.get(target.battle.lastRegularMoveUsed).flags.none? { |f| f[/^CanMirrorMove$/i] }
next true if !target.battler.lastRegularMoveUsed
next true if GameData::Move.get(target.battler.lastRegularMoveUsed).flags.none? { |f| f[/^CanMirrorMove$/i] }
}
)
Battle::AI::Handlers::MoveEffectScore.add("UseLastMoveUsedByTarget",

View File

@@ -104,7 +104,7 @@ Battle::AI::Handlers::GeneralMoveScore.add(:damaging_moves_if_last_pokemon,
if ai.trainer.medium_skill? && battle.pbAbleNonActiveCount(user.idxOwnSide) == 0 &&
!(ai.trainer.high_skill? && target && battle.pbAbleNonActiveCount(target.idxOwnSide) > 0)
next score * 0.9 if move.statusMove?
next score * 1.1 if target_battler.hp <= target_battler.totalhp / 2
next score * 1.1 if target && target.battler.hp <= target.battler.totalhp / 2
end
}
)
@@ -213,7 +213,7 @@ Battle::AI::Handlers::GeneralMoveScore.add(:thawing_move_against_frozen_target,
#===============================================================================
Battle::AI::Handlers::GeneralMoveScore.add(:shiny_target,
proc { |score, move, user, target, ai, battle|
next score - 40 if target&.wild? && target&.battler.shiny?
next score - 40 if target && target.wild? && target.battler.shiny?
}
)
@@ -260,7 +260,7 @@ Battle::AI::Handlers::GeneralMoveScore.add(:flinching_effects,
#===============================================================================
Battle::AI::Handlers::GeneralMoveScore.add(:add_predicted_damage,
proc { |score, move, user, target, ai, battle|
if move.damagingMove?
if move.damagingMove? && target
dmg = move.rough_damage
score += [15.0 * dmg / target.hp, 20].min
score += 10 if dmg > target.hp * 1.1 # Predicted to KO the target

View File

@@ -138,7 +138,7 @@ class Battle::AI::AIBattler
# Trapping damage
if self.effects[PBEffects::Trapping] > 1 && @battler.takesIndirectDamage?
amt = (Settings::MECHANICS_GENERATION >= 6) ? self.totalhp / 8 : self.totalhp / 16
if @battlers[self.effects[PBEffects::TrappingUser]].has_active_item?(:BINDINGBAND)
if @ai.battlers[self.effects[PBEffects::TrappingUser]].has_active_item?(:BINDINGBAND)
amt = (Settings::MECHANICS_GENERATION >= 6) ? self.totalhp / 6 : self.totalhp / 8
end
ret += [amt, 1].max

View File

@@ -371,17 +371,17 @@ class Battle::AI::AIMove
end
def rough_accuracy
# Determine user and target
user = @ai.user
user_battler = user.battler
target = @ai.target
target_battler = target.battler
# "Always hit" effects and "always hit" accuracy
if @ai.trainer.medium_skill?
return 100 if target.effects[PBEffects::Telekinesis] > 0
return 100 if target.effects[PBEffects::Minimize] && @move.tramplesMinimize? &&
Settings::MECHANICS_GENERATION >= 6
end
# Determine user and target
user = @ai.user
user_battler = user.battler
target = @ai.target
target_battler = target.battler
# Get base accuracy
baseAcc = self.accuracy
return 100 if baseAcc == 0
@@ -486,7 +486,7 @@ class Battle::AI::AIMove
case function
when "BadPoisonTarget"
modifiers[:base_accuracy] = 0 if Settings::MORE_TYPE_EFFECTS &&
@move.statusMove? && @user.has_type?(:POISON)
@move.statusMove? && user.has_type?(:POISON)
end
end
end