More AI checks and fixes

This commit is contained in:
Maruno17
2022-09-10 15:26:38 +01:00
parent 9bd31300ad
commit eb8fc1d298
7 changed files with 254 additions and 215 deletions

View File

@@ -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

View File

@@ -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]}"

View File

@@ -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

View File

@@ -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

View File

@@ -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
}

View File

@@ -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|

View File

@@ -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)