mirror of
https://github.com/infinitefusion/infinitefusion-e18.git
synced 2025-12-06 06:01:46 +00:00
More AI checks and fixes
This commit is contained in:
@@ -71,15 +71,22 @@ end
|
||||
# (Belly Drum)
|
||||
#===============================================================================
|
||||
class Battle::Move::MaxUserAttackLoseHalfOfTotalHP < Battle::Move
|
||||
attr_reader :statUp
|
||||
|
||||
def canSnatch?; return true; end
|
||||
|
||||
def initialize(battle, move)
|
||||
super
|
||||
@statUp = [:ATTACK, 12]
|
||||
end
|
||||
|
||||
def pbMoveFailed?(user, targets)
|
||||
hpLoss = [user.totalhp / 2, 1].max
|
||||
if user.hp <= hpLoss
|
||||
@battle.pbDisplay(_INTL("But it failed!"))
|
||||
return true
|
||||
end
|
||||
return true if !user.pbCanRaiseStatStage?(:ATTACK, user, self, true)
|
||||
return true if !user.pbCanRaiseStatStage?(@statUp[0], user, self, true)
|
||||
return false
|
||||
end
|
||||
|
||||
@@ -87,16 +94,18 @@ class Battle::Move::MaxUserAttackLoseHalfOfTotalHP < Battle::Move
|
||||
hpLoss = [user.totalhp / 2, 1].max
|
||||
user.pbReduceHP(hpLoss, false, false)
|
||||
if user.hasActiveAbility?(:CONTRARY)
|
||||
user.stages[:ATTACK] = -6
|
||||
user.stages[@statUp[0]] = -6
|
||||
user.statsLoweredThisRound = true
|
||||
user.statsDropped = true
|
||||
@battle.pbCommonAnimation("StatDown", user)
|
||||
@battle.pbDisplay(_INTL("{1} cut its own HP and minimized its Attack!", user.pbThis))
|
||||
@battle.pbDisplay(_INTL("{1} cut its own HP and minimized its {2}!",
|
||||
user.pbThis, GameData::Stat.get(@statUp[0]).name))
|
||||
else
|
||||
user.stages[:ATTACK] = 6
|
||||
user.stages[@statUp[0]] = 6
|
||||
user.statsRaisedThisRound = true
|
||||
@battle.pbCommonAnimation("StatUp", user)
|
||||
@battle.pbDisplay(_INTL("{1} cut its own HP and maximized its Attack!", user.pbThis))
|
||||
@battle.pbDisplay(_INTL("{1} cut its own HP and maximized its {2}!",
|
||||
user.pbThis, GameData::Stat.get(@statUp[0]).name))
|
||||
end
|
||||
user.pbItemHPHealCheck
|
||||
end
|
||||
|
||||
@@ -99,9 +99,6 @@ class Battle::AI
|
||||
@target = (target) ? @battlers[target.index] : @user
|
||||
@target&.refresh_battler
|
||||
@battle.moldBreaker = @user.has_mold_breaker?
|
||||
# Determine whether user or target is faster, and store that result so it
|
||||
# doesn't need recalculating
|
||||
@user_faster = @user.faster_than?(@target)
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
@@ -110,7 +107,6 @@ class Battle::AI
|
||||
# TODO: Add skill checks in here for particular calculations?
|
||||
#=============================================================================
|
||||
def pbPredictMoveFailure
|
||||
return false if !@trainer.has_skill_flag?("PredictMoveFailure")
|
||||
# TODO: Something involving user.usingMultiTurnAttack? (perhaps earlier than
|
||||
# this?).
|
||||
# User is asleep and will not wake up
|
||||
@@ -152,20 +148,22 @@ class Battle::AI
|
||||
#=============================================================================
|
||||
def pbGetMoveScore(move, target = nil)
|
||||
set_up_move_check(move, target)
|
||||
user_battler = @user.battler
|
||||
target_battler = @target.battler
|
||||
|
||||
# Predict whether the move will fail
|
||||
return 25 if pbPredictMoveFailure
|
||||
if @trainer.has_skill_flag?("PredictMoveFailure")
|
||||
return 25 if pbPredictMoveFailure
|
||||
end
|
||||
|
||||
# Get the base score for the move
|
||||
if @move.damagingMove?
|
||||
# Is also the predicted damage amount as a percentage of target's current HP
|
||||
score = pbGetDamagingMoveBaseScore
|
||||
else # Status moves
|
||||
# Depends on the move's effect
|
||||
score = pbGetStatusMoveBaseScore
|
||||
end
|
||||
score = 100
|
||||
# if @move.damagingMove?
|
||||
# # Is also the predicted damage amount as a percentage of target's current HP
|
||||
# score = pbGetDamagingMoveBaseScore
|
||||
# else # Status moves
|
||||
# # Depends on the move's effect
|
||||
# score = pbGetStatusMoveBaseScore
|
||||
# end
|
||||
|
||||
# Modify the score according to the move's effect
|
||||
score = Battle::AI::Handlers.apply_move_effect_score(@move.function,
|
||||
score, @move, @user, @target, self, @battle)
|
||||
@@ -200,10 +198,10 @@ class Battle::AI
|
||||
if @trainer.high_skill? && @user.can_switch_lax?
|
||||
badMoves = false
|
||||
if (max_score <= 25 && user_battler.turnCount > 2) ||
|
||||
(max_score <= 50 && user_battler.turnCount > 5)
|
||||
(max_score <= 60 && user_battler.turnCount > 4)
|
||||
badMoves = true if pbAIRandom(100) < 80
|
||||
end
|
||||
if !badMoves && max_score < 50 && user_battler.turnCount >= 1
|
||||
if !badMoves && max_score <= 60 && user_battler.turnCount >= 1
|
||||
badMoves = choices.none? { |c| user_battler.moves[c[0]].damagingMove? }
|
||||
badMoves = false if badMoves && pbAIRandom(100) < 10
|
||||
end
|
||||
@@ -222,11 +220,7 @@ class Battle::AI
|
||||
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
|
||||
chance = sprintf("%5.1f", (c[3] > 0) ? 100.0 * c[3] / total_score : 0)
|
||||
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]}"
|
||||
@@ -31,7 +31,7 @@ class Battle::AI
|
||||
mod2 = Effectiveness::NORMAL_EFFECTIVE
|
||||
if pkmn.types.length > 1
|
||||
mod2 = Effectiveness.calculate(pkmn.types[1], target_battler.types[0], target_battler.types[1])
|
||||
mod2 = mod2.to_f / Effectivenesss::NORMAL_EFFECTIVE
|
||||
mod2 = mod2.to_f / Effectiveness::NORMAL_EFFECTIVE
|
||||
end
|
||||
return mod1 * mod2
|
||||
end
|
||||
|
||||
@@ -120,14 +120,14 @@ class Battle::AI
|
||||
|
||||
# Prefer if move is a status move and it's the user's first/second turn
|
||||
if @user.turnCount < 2 && @move.statusMove?
|
||||
score += total_increment * 5
|
||||
score += total_increment * 4
|
||||
end
|
||||
|
||||
# Prefer if user is at high HP, don't prefer if user is at low HP
|
||||
if @user.hp >= @user.totalhp * 0.7
|
||||
score += 10 * total_increment
|
||||
score += 4 * total_increment
|
||||
else
|
||||
score += total_increment * ((100 * @user.hp / @user.totalhp) - 50) / 2 # +10 to -25 per stage
|
||||
score += total_increment * ((100 * @user.hp / @user.totalhp) - 50) / 4 # +5 to -12 per stage
|
||||
end
|
||||
|
||||
# Don't prefer if user is about to faint due to EOR damage
|
||||
@@ -234,69 +234,81 @@ class Battle::AI
|
||||
# Make score changes based on the raising of a specific stat.
|
||||
#=============================================================================
|
||||
def get_user_stat_raise_score_one(score, stat, increment)
|
||||
# Figure out how much the stat will actually change by
|
||||
stage_mul = [2, 2, 2, 2, 2, 2, 2, 3, 4, 5, 6, 7, 8]
|
||||
stage_div = [8, 7, 6, 5, 4, 3, 2, 2, 2, 2, 2, 2, 2]
|
||||
if [:ACCURACY, :EVASION].include?(stat)
|
||||
stage_mul = [3, 3, 3, 3, 3, 3, 3, 4, 5, 6, 7, 8, 9]
|
||||
stage_div = [9, 8, 7, 6, 5, 4, 3, 3, 3, 3, 3, 3, 3]
|
||||
end
|
||||
old_stage = @user.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 -= 1
|
||||
# Stat-based score changes
|
||||
case stat
|
||||
when :ATTACK
|
||||
# Modify score depending on current stat stage
|
||||
# More strongly prefer if the user has no special moves
|
||||
if @user.stages[stat] >= 3
|
||||
if old_stage >= 3
|
||||
score -= 20
|
||||
else
|
||||
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
|
||||
score += inc * (3 - old_stage) * inc_mult
|
||||
score += 5 * inc_mult if @user.hp == @user.totalhp
|
||||
end
|
||||
|
||||
when :DEFENSE
|
||||
# Modify score depending on current stat stage
|
||||
if @user.stages[stat] >= 3
|
||||
if old_stage >= 3
|
||||
score -= 20
|
||||
else
|
||||
score += 5 * (3 - @user.stages[stat]) * increment # 5 to 45
|
||||
score += 5 * increment if @user.hp == @user.totalhp
|
||||
score += 5 * (3 - old_stage) * inc_mult
|
||||
score += 5 * inc_mult if @user.hp == @user.totalhp
|
||||
end
|
||||
|
||||
when :SPECIAL_ATTACK
|
||||
# Modify score depending on current stat stage
|
||||
# More strongly prefer if the user has no physical moves
|
||||
if @user.stages[stat] >= 3
|
||||
if old_stage >= 3
|
||||
score -= 20
|
||||
else
|
||||
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
|
||||
score += inc * (3 - old_stage) * inc_mult
|
||||
score += 5 * inc_mult if @user.hp == @user.totalhp
|
||||
end
|
||||
|
||||
when :SPECIAL_DEFENSE
|
||||
# Modify score depending on current stat stage
|
||||
if @user.stages[stat] >= 3
|
||||
if old_stage >= 3
|
||||
score -= 20
|
||||
else
|
||||
score += 5 * (3 - @user.stages[stat]) * increment # 5 to 45
|
||||
score += 5 * increment if @user.hp == @user.totalhp
|
||||
score += 5 * (3 - old_stage) * inc_mult
|
||||
score += 5 * inc_mult if @user.hp == @user.totalhp
|
||||
end
|
||||
|
||||
when :SPEED
|
||||
# Prefer if user is slower than a foe
|
||||
each_foe_battler(@user.side) do |b, i|
|
||||
next if @user.faster_than?(b)
|
||||
score += 15 * increment
|
||||
score += 15 * inc_mult
|
||||
break
|
||||
end
|
||||
# Don't prefer if any foe has Gyro Ball
|
||||
each_foe_battler(@user.side) do |b, i|
|
||||
next if !b.check_for_move { |m| m.function == "PowerHigherWithTargetFasterThanUser" }
|
||||
score -= 10 * increment
|
||||
score -= 8 * inc_mult
|
||||
end
|
||||
# Don't prefer if user has Speed Boost (will be gaining Speed anyway)
|
||||
score -= 20 if @user.has_active_ability?(:SPEEDBOOST)
|
||||
|
||||
when :ACCURACY
|
||||
# Modify score depending on current stat stage
|
||||
if @user.stages[stat] >= 3
|
||||
if old_stage >= 3
|
||||
score -= 20
|
||||
else
|
||||
min_accuracy = 100
|
||||
@@ -304,12 +316,10 @@ class Battle::AI
|
||||
next if m.accuracy == 0 || m.is_a?(Battle::Move::OHKO)
|
||||
min_accuracy = m.accuracy if m.accuracy < min_accuracy
|
||||
end
|
||||
stageMul = [3, 3, 3, 3, 3, 3, 3, 4, 5, 6, 7, 8, 9]
|
||||
stageDiv = [9, 8, 7, 6, 5, 4, 3, 3, 3, 3, 3, 3, 3]
|
||||
min_accuracy *= stageMul[@user.stages[stat]] / stageDiv[@user.stages[stat]]
|
||||
min_accuracy *= stage_mul[old_stage] / stage_div[old_stage]
|
||||
if min_accuracy < 90
|
||||
score += 5 * (3 - @user.stages[stat]) * increment # 5 to 45
|
||||
score += 5 * increment if @user.hp == @user.totalhp
|
||||
score += 5 * (3 - old_stage) * inc_mult
|
||||
score += 5 * inc_mult if @user.hp == @user.totalhp
|
||||
end
|
||||
end
|
||||
|
||||
@@ -323,26 +333,26 @@ class Battle::AI
|
||||
score += 60 * eor_damage / b.totalhp if eor_damage > 0
|
||||
end
|
||||
# Modify score depending on current stat stage
|
||||
if @user.stages[stat] >= 3
|
||||
if old_stage >= 3
|
||||
score -= 20
|
||||
else
|
||||
score += 5 * (3 - @user.stages[stat]) * increment # 5 to 45
|
||||
score += 5 * increment if @user.hp == @user.totalhp
|
||||
score += 5 * (3 - old_stage) * inc_mult
|
||||
score += 5 * inc_mult if @user.hp == @user.totalhp
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# Check impact on moves of gaining stat stages
|
||||
pos_change = [@user.stages[stat] + increment, increment].min
|
||||
pos_change = [old_stage + increment, increment].min
|
||||
if pos_change > 0
|
||||
# Prefer if user has Stored Power
|
||||
if @user.check_for_move { |m| m.function == "PowerHigherWithUserPositiveStatStages" }
|
||||
score += 10 * pos_change
|
||||
score += 5 * 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 { |m| m.function == "PowerHigherWithTargetPositiveStatStages" }
|
||||
score -= 10 * pos_change
|
||||
score -= 5 * pos_change
|
||||
end
|
||||
end
|
||||
|
||||
@@ -543,7 +553,7 @@ class Battle::AI
|
||||
|
||||
# TODO: Prefer if user is faster than the target.
|
||||
# TODO: Is 1.3x for RaiseUserAtkDefAcc1 Coil (+Atk, +Def, +acc).
|
||||
mini_score *= 1.5 if @user_faster
|
||||
mini_score *= 1.5 if @user.faster_than?(@target)
|
||||
# TODO: Don't prefer if target is a higher level than the user
|
||||
if @target.level > @user.level + 5
|
||||
mini_score *= 0.6
|
||||
|
||||
@@ -22,10 +22,15 @@ Battle::AI::Handlers::MoveEffectScore.copy("RaiseUserAttack1",
|
||||
"RaiseUserAttack2")
|
||||
|
||||
#===============================================================================
|
||||
# TODO: Review score modifiers.
|
||||
#
|
||||
#===============================================================================
|
||||
Battle::AI::Handlers::MoveEffectScore.copy("RaiseUserAttack2",
|
||||
"RaiseUserAttack2IfTargetFaints")
|
||||
Battle::AI::Handlers::MoveEffectScore.add("RaiseUserAttack2IfTargetFaints",
|
||||
proc { |score, move, user, target, ai, battle|
|
||||
if move.rough_damage >= target.hp * 0.9
|
||||
next ai.get_score_for_user_stat_raise(score)
|
||||
end
|
||||
}
|
||||
)
|
||||
|
||||
#===============================================================================
|
||||
#
|
||||
@@ -36,13 +41,13 @@ Battle::AI::Handlers::MoveEffectScore.copy("RaiseUserAttack2",
|
||||
"RaiseUserAttack3")
|
||||
|
||||
#===============================================================================
|
||||
# TODO: Review score modifiers.
|
||||
#
|
||||
#===============================================================================
|
||||
Battle::AI::Handlers::MoveEffectScore.copy("RaiseUserAttack2IfTargetFaints",
|
||||
"RaiseUserAttack3IfTargetFaints")
|
||||
|
||||
#===============================================================================
|
||||
# TODO: Review score modifiers.
|
||||
#
|
||||
#===============================================================================
|
||||
Battle::AI::Handlers::MoveFailureCheck.add("MaxUserAttackLoseHalfOfTotalHP",
|
||||
proc { |move, user, target, ai, battle|
|
||||
@@ -52,20 +57,9 @@ Battle::AI::Handlers::MoveFailureCheck.add("MaxUserAttackLoseHalfOfTotalHP",
|
||||
)
|
||||
Battle::AI::Handlers::MoveEffectScore.add("MaxUserAttackLoseHalfOfTotalHP",
|
||||
proc { |score, move, user, target, ai, battle|
|
||||
score += (6 - user.stages[:ATTACK]) * 10
|
||||
if ai.trainer.medium_skill?
|
||||
hasPhysicalAttack = false
|
||||
user.battler.eachMove do |m|
|
||||
next if !m.physicalMove?(m.type)
|
||||
hasPhysicalAttack = true
|
||||
break
|
||||
end
|
||||
if hasPhysicalAttack
|
||||
score += 40
|
||||
elsif ai.trainer.high_skill?
|
||||
score -= 90
|
||||
end
|
||||
end
|
||||
score = ai.get_score_for_user_stat_raise(score)
|
||||
# Don't prefer the lower the user's HP is
|
||||
score -= 80 * (1 - (@user.hp.to_f / @user.totalhp)) # 0 to -40
|
||||
next score
|
||||
}
|
||||
)
|
||||
@@ -190,12 +184,37 @@ Battle::AI::Handlers::MoveEffectScore.copy("RaiseUserSpeed1",
|
||||
"RaiseUserSpeed2")
|
||||
|
||||
#===============================================================================
|
||||
# TODO: Review score modifiers.
|
||||
#
|
||||
#===============================================================================
|
||||
Battle::AI::Handlers::MoveFailureCheck.copy("RaiseUserSpeed2",
|
||||
"RaiseUserSpeed2LowerUserWeight")
|
||||
Battle::AI::Handlers::MoveEffectScore.copy("RaiseUserSpeed2",
|
||||
"RaiseUserSpeed2LowerUserWeight")
|
||||
Battle::AI::Handlers::MoveEffectScore.add("RaiseUserSpeed2LowerUserWeight",
|
||||
proc { |score, move, user, target, ai, battle|
|
||||
score = ai.get_score_for_user_stat_raise(score)
|
||||
if ai.trainer.medium_skill?
|
||||
# TODO: Take into account weight-modifying items/abilities? This "> 1"
|
||||
# line can probably ignore them, but these moves' powers will change
|
||||
# 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" }
|
||||
score -= 10
|
||||
end
|
||||
ai.each_foe_battler(user.side) do |b|
|
||||
if b.check_for_move { |m| m.function == "PowerHigherWithUserHeavierThanTarget" }
|
||||
score -= 10
|
||||
end
|
||||
if b.check_for_move { |m| m.function == "PowerHigherWithTargetWeight" }
|
||||
score += 10
|
||||
end
|
||||
# TODO: Check foes for Sky Drop and whether the user is too heavy for it
|
||||
# but the weight reduction will make it susceptible.
|
||||
end
|
||||
end
|
||||
end
|
||||
next score
|
||||
}
|
||||
)
|
||||
|
||||
#===============================================================================
|
||||
#
|
||||
@@ -246,12 +265,24 @@ Battle::AI::Handlers::MoveEffectScore.copy("RaiseUserEvasion1",
|
||||
"RaiseUserEvasion2")
|
||||
|
||||
#===============================================================================
|
||||
# TODO: Review score modifiers.
|
||||
#
|
||||
#===============================================================================
|
||||
Battle::AI::Handlers::MoveFailureCheck.copy("RaiseUserEvasion2",
|
||||
"RaiseUserEvasion2MinimizeUser")
|
||||
Battle::AI::Handlers::MoveEffectScore.copy("RaiseUserEvasion2",
|
||||
"RaiseUserEvasion2MinimizeUser")
|
||||
Battle::AI::Handlers::MoveEffectScore.add("RaiseUserEvasion2MinimizeUser",
|
||||
proc { |score, move, user, target, ai, battle|
|
||||
score = ai.get_score_for_user_stat_raise(score)
|
||||
if ai.trainer.medium_skill? && !user.effects[PBEffects::Minimize]
|
||||
ai.each_foe_battler(user.side) do |b|
|
||||
# Moves that do double damage and (in Gen 6+) have perfect accuracy
|
||||
if b.check_for_move { |m| m.tramplesMinimize? }
|
||||
score -= (Settings::MECHANICS_GENERATION >= 6) ? 15 : 10
|
||||
end
|
||||
end
|
||||
end
|
||||
next score
|
||||
}
|
||||
)
|
||||
|
||||
#===============================================================================
|
||||
#
|
||||
@@ -262,7 +293,7 @@ Battle::AI::Handlers::MoveEffectScore.copy("RaiseUserEvasion2",
|
||||
"RaiseUserEvasion3")
|
||||
|
||||
#===============================================================================
|
||||
# TODO: Review score modifiers.
|
||||
#
|
||||
#===============================================================================
|
||||
Battle::AI::Handlers::MoveFailureCheck.add("RaiseUserCriticalHitRate2",
|
||||
proc { |move, user, target, ai, battle|
|
||||
@@ -271,9 +302,22 @@ Battle::AI::Handlers::MoveFailureCheck.add("RaiseUserCriticalHitRate2",
|
||||
)
|
||||
Battle::AI::Handlers::MoveEffectScore.add("RaiseUserCriticalHitRate2",
|
||||
proc { |score, move, user, target, ai, battle|
|
||||
if move.statusMove? || user.effects[PBEffects::FocusEnergy] < 2
|
||||
next score + 30
|
||||
next score - 40 if !user.check_for_move { |m| m.damagingMove? }
|
||||
score += 15
|
||||
if ai.trainer.medium_skill?
|
||||
# Other effects that raise the critical hit rate
|
||||
if user.item_active?
|
||||
if [:RAZORCLAW, :SCOPELENS].include?(user.item_id) ||
|
||||
(user.item_id == :LUCKYPUNCH && user.battler.isSpecies?(:CHANSEY)) ||
|
||||
([:LEEK, :STICK].include?(user.item_id) &&
|
||||
(user.battler.isSpecies?(:FARFETCHD) || user.battler.isSpecies?(:SIRFETCHD)))
|
||||
score += 10
|
||||
end
|
||||
end
|
||||
# Critical hits do more damage
|
||||
score += 10 if user.has_active_ability?(:SNIPER)
|
||||
end
|
||||
next score
|
||||
}
|
||||
)
|
||||
|
||||
@@ -1438,44 +1482,31 @@ Battle::AI::Handlers::MoveEffectScore.add("RaiseGrassBattlersDef1",
|
||||
#===============================================================================
|
||||
Battle::AI::Handlers::MoveEffectScore.add("UserTargetSwapAtkSpAtkStages",
|
||||
proc { |score, move, user, target, ai, battle|
|
||||
if ai.trainer.medium_skill?
|
||||
aatk = user.stages[:ATTACK]
|
||||
aspa = user.stages[:SPECIAL_ATTACK]
|
||||
oatk = target.stages[:ATTACK]
|
||||
ospa = target.stages[:SPECIAL_ATTACK]
|
||||
if aatk >= oatk && aspa >= ospa
|
||||
score -= 80
|
||||
else
|
||||
score += (oatk - aatk) * 10
|
||||
score += (ospa - aspa) * 10
|
||||
end
|
||||
else
|
||||
score -= 50
|
||||
end
|
||||
user_attack = user.stages[:ATTACK]
|
||||
user_spatk = user.stages[:SPECIAL_ATTACK]
|
||||
target_attack = target.stages[:ATTACK]
|
||||
target_spatk = target.stages[:SPECIAL_ATTACK]
|
||||
next score - 40 if user_attack >= target_attack && user_spatk >= target_spatk
|
||||
next score - 20 if user_attack + user_spatk <= target_attack + target_spatk
|
||||
score += (target_attack - user_attack) * 10
|
||||
score += (target_spatk - user_spatk) * 10
|
||||
next score
|
||||
}
|
||||
)
|
||||
|
||||
#===============================================================================
|
||||
# TODO: Review score modifiers.
|
||||
# TODO: Review score modifiers.
|
||||
#===============================================================================
|
||||
Battle::AI::Handlers::MoveEffectScore.add("UserTargetSwapDefSpDefStages",
|
||||
proc { |score, move, user, target, ai, battle|
|
||||
if ai.trainer.medium_skill?
|
||||
adef = user.stages[:DEFENSE]
|
||||
aspd = user.stages[:SPECIAL_DEFENSE]
|
||||
odef = target.stages[:DEFENSE]
|
||||
ospd = target.stages[:SPECIAL_DEFENSE]
|
||||
if adef >= odef && aspd >= ospd
|
||||
score -= 80
|
||||
else
|
||||
score += (odef - adef) * 10
|
||||
score += (ospd - aspd) * 10
|
||||
end
|
||||
else
|
||||
score -= 50
|
||||
end
|
||||
user_def = user.stages[:DEFENSE]
|
||||
user_spdef = user.stages[:SPECIAL_DEFENSE]
|
||||
target_def = target.stages[:DEFENSE]
|
||||
target_spdef = target.stages[:SPECIAL_DEFENSE]
|
||||
next score - 40 if user_def >= target_def && user_spdef >= target_spdef
|
||||
next score - 20 if user_def + user_spdef <= target_def + target_spdef
|
||||
score += (target_def - user_def) * 10
|
||||
score += (target_spdef - user_spdef) * 10
|
||||
next score
|
||||
}
|
||||
)
|
||||
@@ -1485,17 +1516,16 @@ Battle::AI::Handlers::MoveEffectScore.add("UserTargetSwapDefSpDefStages",
|
||||
#===============================================================================
|
||||
Battle::AI::Handlers::MoveEffectScore.add("UserTargetSwapStatStages",
|
||||
proc { |score, move, user, target, ai, battle|
|
||||
if ai.trainer.medium_skill?
|
||||
userStages = 0
|
||||
targetStages = 0
|
||||
GameData::Stat.each_battle do |s|
|
||||
userStages += user.stages[s.id]
|
||||
targetStages += target.stages[s.id]
|
||||
end
|
||||
score += (targetStages - userStages) * 10
|
||||
else
|
||||
score -= 50
|
||||
user_stages = 0
|
||||
target_stages = 0
|
||||
target_stage_better = false
|
||||
GameData::Stat.each_battle do |s|
|
||||
user_stages += user.stages[s.id]
|
||||
target_stages += target.stages[s.id]
|
||||
target_stage_better = true if target.stages[s.id] > user.stages[s.id]
|
||||
end
|
||||
next score - 40 if !target_stage_better
|
||||
score += (target_stages - user_stages) * 10
|
||||
next score
|
||||
}
|
||||
)
|
||||
@@ -1505,17 +1535,13 @@ Battle::AI::Handlers::MoveEffectScore.add("UserTargetSwapStatStages",
|
||||
#===============================================================================
|
||||
Battle::AI::Handlers::MoveEffectScore.add("UserCopyTargetStatStages",
|
||||
proc { |score, move, user, target, ai, battle|
|
||||
if ai.trainer.medium_skill?
|
||||
equal = true
|
||||
GameData::Stat.each_battle do |s|
|
||||
stagediff = target.stages[s.id] - user.stages[s.id]
|
||||
score += stagediff * 10
|
||||
equal = false if stagediff != 0
|
||||
end
|
||||
score -= 80 if equal
|
||||
else
|
||||
score -= 50
|
||||
equal = true
|
||||
GameData::Stat.each_battle do |s|
|
||||
stagediff = target.stages[s.id] - user.stages[s.id]
|
||||
score += stagediff * 10
|
||||
equal = false if stagediff != 0
|
||||
end
|
||||
next 60 if equal # No stat changes
|
||||
next score
|
||||
}
|
||||
)
|
||||
@@ -1584,19 +1610,17 @@ Battle::AI::Handlers::MoveFailureCheck.add("ResetAllBattlersStatStages",
|
||||
)
|
||||
Battle::AI::Handlers::MoveEffectScore.add("ResetAllBattlersStatStages",
|
||||
proc { |score, move, user, target, ai, battle|
|
||||
if ai.trainer.medium_skill?
|
||||
stages = 0
|
||||
battle.allBattlers.each do |b|
|
||||
totalStages = 0
|
||||
GameData::Stat.each_battle { |s| totalStages += b.stages[s.id] }
|
||||
if b.opposes?(user.battler)
|
||||
stages += totalStages
|
||||
else
|
||||
stages -= totalStages
|
||||
end
|
||||
stages = 0
|
||||
battle.allBattlers.each do |b|
|
||||
totalStages = 0
|
||||
GameData::Stat.each_battle { |s| totalStages += b.stages[s.id] }
|
||||
if b.opposes?(user.battler)
|
||||
stages += totalStages
|
||||
else
|
||||
stages -= totalStages
|
||||
end
|
||||
next score + stages * 10
|
||||
end
|
||||
next score + stages * 10
|
||||
}
|
||||
)
|
||||
|
||||
@@ -1614,19 +1638,13 @@ Battle::AI::Handlers::MoveFailureCheck.add("StartUserSideImmunityToStatStageLowe
|
||||
#===============================================================================
|
||||
Battle::AI::Handlers::MoveEffectScore.add("UserSwapBaseAtkDef",
|
||||
proc { |score, move, user, target, ai, battle|
|
||||
if ai.trainer.medium_skill?
|
||||
aatk = user.rough_stat(:ATTACK)
|
||||
adef = user.rough_stat(:DEFENSE)
|
||||
if aatk == adef ||
|
||||
user.effects[PBEffects::PowerTrick] # No flip-flopping
|
||||
score -= 90
|
||||
elsif adef > aatk # Prefer a higher Attack
|
||||
score += 30
|
||||
else
|
||||
score -= 30
|
||||
end
|
||||
aatk = user.rough_stat(:ATTACK)
|
||||
adef = user.rough_stat(:DEFENSE)
|
||||
next score - 40 if aatk == adef || user.effects[PBEffects::PowerTrick] # No flip-flopping
|
||||
if adef > aatk # Prefer a higher Attack
|
||||
score += 20
|
||||
else
|
||||
score -= 30
|
||||
score -= 20
|
||||
end
|
||||
next score
|
||||
}
|
||||
@@ -1637,12 +1655,10 @@ Battle::AI::Handlers::MoveEffectScore.add("UserSwapBaseAtkDef",
|
||||
#===============================================================================
|
||||
Battle::AI::Handlers::MoveEffectScore.add("UserTargetSwapBaseSpeed",
|
||||
proc { |score, move, user, target, ai, battle|
|
||||
if ai.trainer.medium_skill?
|
||||
if user.speed > target.speed
|
||||
score += 50
|
||||
else
|
||||
score -= 70
|
||||
end
|
||||
if user.speed > target.speed
|
||||
score += 25
|
||||
else
|
||||
score -= 25
|
||||
end
|
||||
next score
|
||||
}
|
||||
@@ -1653,20 +1669,15 @@ Battle::AI::Handlers::MoveEffectScore.add("UserTargetSwapBaseSpeed",
|
||||
#===============================================================================
|
||||
Battle::AI::Handlers::MoveEffectScore.add("UserTargetAverageBaseAtkSpAtk",
|
||||
proc { |score, move, user, target, ai, battle|
|
||||
if ai.trainer.medium_skill?
|
||||
aatk = user.rough_stat(:ATTACK)
|
||||
aspatk = user.rough_stat(:SPECIAL_ATTACK)
|
||||
oatk = target.rough_stat(:ATTACK)
|
||||
ospatk = target.rough_stat(:SPECIAL_ATTACK)
|
||||
if aatk < oatk && aspatk < ospatk
|
||||
score += 50
|
||||
elsif aatk + aspatk < oatk + ospatk
|
||||
score += 30
|
||||
else
|
||||
score -= 50
|
||||
end
|
||||
user_atk = user.battler.attack
|
||||
user_spatk = user.battler.spatk
|
||||
target_atk = target.battler.attack
|
||||
target_spatk = target.battler.spatk
|
||||
next score - 40 if user_atk > target_atk && user_spatk > target_spatk
|
||||
if user_atk + user_spatk < target_atk + target_spatk
|
||||
score += 20
|
||||
else
|
||||
score -= 30
|
||||
score -= 20
|
||||
end
|
||||
next score
|
||||
}
|
||||
@@ -1677,20 +1688,15 @@ Battle::AI::Handlers::MoveEffectScore.add("UserTargetAverageBaseAtkSpAtk",
|
||||
#===============================================================================
|
||||
Battle::AI::Handlers::MoveEffectScore.add("UserTargetAverageBaseDefSpDef",
|
||||
proc { |score, move, user, target, ai, battle|
|
||||
if ai.trainer.medium_skill?
|
||||
adef = user.rough_stat(:DEFENSE)
|
||||
aspdef = user.rough_stat(:SPECIAL_DEFENSE)
|
||||
odef = target.rough_stat(:DEFENSE)
|
||||
ospdef = target.rough_stat(:SPECIAL_DEFENSE)
|
||||
if adef < odef && aspdef < ospdef
|
||||
score += 50
|
||||
elsif adef + aspdef < odef + ospdef
|
||||
score += 30
|
||||
else
|
||||
score -= 50
|
||||
end
|
||||
user_def = user.rough_stat(:DEFENSE)
|
||||
user_spdef = user.rough_stat(:SPECIAL_DEFENSE)
|
||||
target_def = target.rough_stat(:DEFENSE)
|
||||
target_spdef = target.rough_stat(:SPECIAL_DEFENSE)
|
||||
next score - 40 if user_def > target_def && user_spdef > target_spdef
|
||||
if user_def + user_spdef < target_def + target_spdef
|
||||
score += 20
|
||||
else
|
||||
score -= 30
|
||||
score -= 20
|
||||
end
|
||||
next score
|
||||
}
|
||||
@@ -1701,12 +1707,10 @@ Battle::AI::Handlers::MoveEffectScore.add("UserTargetAverageBaseDefSpDef",
|
||||
#===============================================================================
|
||||
Battle::AI::Handlers::MoveEffectScore.add("UserTargetAverageHP",
|
||||
proc { |score, move, user, target, ai, battle|
|
||||
if target.effects[PBEffects::Substitute] > 0
|
||||
score -= 90
|
||||
elsif user.hp >= (user.hp + target.hp) / 2
|
||||
score -= 90
|
||||
if user.hp >= (user.hp + target.hp) / 2
|
||||
score -= 25
|
||||
else
|
||||
score += 40
|
||||
score += 25
|
||||
end
|
||||
next score
|
||||
}
|
||||
|
||||
@@ -56,11 +56,25 @@ Battle::AI::Handlers::GeneralMoveScore.add(:dance_move_against_dancer,
|
||||
# lowered offences (Atk/Def or SpAtk/SpDef, whichever is relevant).
|
||||
|
||||
#===============================================================================
|
||||
# Don't prefer damaging moves that will knock out the target if they are using
|
||||
# Destiny Bond.
|
||||
# TODO: Review score modifier.
|
||||
#===============================================================================
|
||||
# TODO: Don't prefer damaging moves if target is Destiny Bonding.
|
||||
# => Also don't prefer damaging moves if user is slower than the target, move
|
||||
# is likely to be lethal, and target has previously used Destiny Bond
|
||||
#===============================================================================
|
||||
Battle::AI::Handlers::GeneralMoveScore.add(:avoid_knocking_out_destiny_bonder,
|
||||
proc { |score, move, user, target, ai, battle|
|
||||
if ai.trainer.medium_skill? && move.damagingMove? &&
|
||||
target && target.effects[PBEffects::DestinyBond]
|
||||
dmg = move.rough_damage
|
||||
if dmg > target.hp * 1.05 # Predicted to KO the target
|
||||
score -= 25
|
||||
score -= 20 if battle.pbAbleNonActiveCount(user.idxOwnSide) == 0
|
||||
end
|
||||
next score
|
||||
end
|
||||
}
|
||||
)
|
||||
|
||||
#===============================================================================
|
||||
# TODO: Review score modifier.
|
||||
@@ -88,24 +102,26 @@ Battle::AI::Handlers::GeneralMoveScore.add(:dance_move_against_dancer,
|
||||
# an effect that's good for the user (Poison Touch/Pickpocket).
|
||||
|
||||
#===============================================================================
|
||||
# Prefer damaging moves if the foe is down to their last Pokémon (opportunistic).
|
||||
# Prefer damaging moves if the AI is down to its last Pokémon but the foe has
|
||||
# more (desperate).
|
||||
# TODO: Review score modifier.
|
||||
#===============================================================================
|
||||
# TODO: Don't prefer a status move if user has a damaging move that will KO
|
||||
# the target.
|
||||
# => If target has previously used a move that will hurt the user by 30% of
|
||||
# its current HP or more, moreso don't prefer a status move.
|
||||
|
||||
#===============================================================================
|
||||
# Prefer damaging moves if AI has no more Pokémon or AI is less clever.
|
||||
# TODO: Review score modifier.
|
||||
#===============================================================================
|
||||
Battle::AI::Handlers::GeneralMoveScore.add(:damaging_moves_if_last_pokemon,
|
||||
Battle::AI::Handlers::GeneralMoveScore.add(:prefer_damaging_moves_if_last_pokemon,
|
||||
proc { |score, move, user, target, ai, battle|
|
||||
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 && target.battler.hp <= target.battler.totalhp / 2
|
||||
if ai.trainer.medium_skill? && move.damagingMove?
|
||||
reserves = battle.pbAbleNonActiveCount(user.idxOwnSide)
|
||||
foes = battle.pbAbleNonActiveCount(user.idxOpposingSide)
|
||||
# Don't mess with scores just because a move is damaging; need to play well
|
||||
next score if ai.trainer.high_skill? && foes > reserves # AI is outnumbered
|
||||
# Prefer damaging moves depending on remaining Pokémon
|
||||
if foes == 0 # Foe is down to their last Pokémon
|
||||
score *= 1.1 # => Go for the kill
|
||||
elsif reserves == 0 # AI is down to its last Pokémon, foe has reserves
|
||||
score *= 1.05 # => Go out with a bang
|
||||
end
|
||||
end
|
||||
next score
|
||||
}
|
||||
)
|
||||
|
||||
@@ -256,7 +272,11 @@ Battle::AI::Handlers::GeneralMoveScore.add(:flinching_effects,
|
||||
|
||||
#===============================================================================
|
||||
# Adjust score based on how much damage it can deal.
|
||||
# Prefer the move even more if it's predicted to do enough damage to KO the
|
||||
# target.
|
||||
# TODO: Review score modifier.
|
||||
# => If target has previously used a move that will hurt the user by 30% of
|
||||
# its current HP or more, moreso don't prefer a status move.
|
||||
#===============================================================================
|
||||
Battle::AI::Handlers::GeneralMoveScore.add(:add_predicted_damage,
|
||||
proc { |score, move, user, target, ai, battle|
|
||||
|
||||
@@ -48,14 +48,14 @@ def debug_test_auto_battle(logging = false)
|
||||
player_trainers, ally_items, player_party, player_party_starts = debug_set_up_trainer
|
||||
# Log the combatants
|
||||
echo_participant = lambda do |trainer, party, index|
|
||||
trainer_txt = "Trainer #{index}: #{trainer.full_name}"
|
||||
trainer_txt = "[Trainer #{index}] #{trainer.full_name} [skill: #{trainer.skill_level}]"
|
||||
($INTERNAL) ? PBDebug.log_header(trainer_txt) : echoln(trainer_txt)
|
||||
party.each do |pkmn|
|
||||
pkmn_txt = " #{pkmn.name}, Lv.#{pkmn.level}\r\n"
|
||||
pkmn_txt += " Ability: #{pkmn.ability&.name || "---"}\r\n"
|
||||
pkmn_txt += " Held item: #{pkmn.item&.name || "---"}"
|
||||
pkmn_txt = "* #{pkmn.name}, Lv.#{pkmn.level}"
|
||||
pkmn_txt += " [Ability: #{pkmn.ability&.name || "---"}]"
|
||||
pkmn_txt += " [Item: #{pkmn.item&.name || "---"}]"
|
||||
($INTERNAL) ? PBDebug.log(pkmn_txt) : echoln(pkmn_txt)
|
||||
moves_msg = " Moves: "
|
||||
moves_msg = " Moves: "
|
||||
pkmn.moves.each_with_index do |move, i|
|
||||
moves_msg += ", " if i > 0
|
||||
moves_msg += move.name
|
||||
@@ -64,6 +64,8 @@ def debug_test_auto_battle(logging = false)
|
||||
end
|
||||
end
|
||||
echo_participant.call(player_trainers[0], player_party, 1)
|
||||
PBDebug.log("")
|
||||
echoln "" if !$INTERNAL
|
||||
echo_participant.call(foe_trainers[0], foe_party, 2)
|
||||
echoln "" if !$INTERNAL
|
||||
# Create the battle scene (the visual side of it)
|
||||
|
||||
Reference in New Issue
Block a user