mirror of
https://github.com/infinitefusion/infinitefusion-e18.git
synced 2025-12-09 14:14:59 +00:00
Tweaked AI threshold score, added "HPAware" skill flag, changed lots of AI scores
This commit is contained in:
@@ -1,12 +1,12 @@
|
||||
class Battle::AI
|
||||
MOVE_FAIL_SCORE = 25
|
||||
MOVE_FAIL_SCORE = 20
|
||||
MOVE_USELESS_SCORE = 60 # Move predicted to do nothing or just be detrimental
|
||||
MOVE_BASE_SCORE = 100
|
||||
|
||||
# Returns a value between 0.0 and 1.0. All move scores are lowered by this
|
||||
# value multiplied by the highest-scoring move's score.
|
||||
def move_score_threshold
|
||||
return 0.6 + 0.3 * (([@trainer.skill, 100].min / 100.0) ** 0.5) # 0.6 to 0.9
|
||||
return 0.6 + 0.35 * (([@trainer.skill, 100].min / 100.0) ** 0.5) # 0.635 to 0.95
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
|
||||
@@ -125,12 +125,17 @@ class Battle::AI
|
||||
"PowerHigherWithUserPositiveStatStages"
|
||||
]
|
||||
if !target.has_move_with_function?(*moves_that_prefer_high_speed)
|
||||
# TODO: Not worth it if the target is too much slower than its foe(s)
|
||||
# and can't be made fast enough.
|
||||
each_foe_battler(target.side) do |b, i|
|
||||
return true if b.faster_than?(target)
|
||||
end
|
||||
return false
|
||||
end
|
||||
when :ACCURACY
|
||||
# TODO: Yes if any of target's moves have lower accuracy, or target is
|
||||
# affected by accuracy-lowering effects, or if target's foe(s) have
|
||||
# increased evasion.
|
||||
when :EVASION
|
||||
end
|
||||
return true
|
||||
@@ -151,22 +156,14 @@ class Battle::AI
|
||||
# the foe anyway).
|
||||
# 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 * desire_mult * 4
|
||||
score += total_increment * desire_mult * 5
|
||||
end
|
||||
# Prefer if user is at high HP, don't prefer if user is at low HP
|
||||
if target.index != @user.index
|
||||
if @user.hp >= @user.totalhp * 0.7
|
||||
score += total_increment * desire_mult * 3
|
||||
else
|
||||
score += total_increment * desire_mult * ((100 * @user.hp / @user.totalhp) - 50) / 6 # +3 to -8 per stage
|
||||
end
|
||||
score += total_increment * desire_mult * ((100 * @user.hp / @user.totalhp) - 50) / 8 # +6 to -6 per stage
|
||||
end
|
||||
# Prefer if target is at high HP, don't prefer if target is at low HP
|
||||
if target.hp >= target.totalhp * 0.7
|
||||
score += total_increment * desire_mult * 4
|
||||
else
|
||||
score += total_increment * desire_mult * ((100 * target.hp / target.totalhp) - 50) / 4 # +5 to -12 per stage
|
||||
end
|
||||
score += total_increment * desire_mult * ((100 * target.hp / target.totalhp) - 50) / 8 # +6 to -6 per stage
|
||||
# TODO: Look at abilities that trigger upon stat raise. There are none.
|
||||
return score
|
||||
end
|
||||
@@ -193,16 +190,16 @@ class Battle::AI
|
||||
# Modify score depending on current stat stage
|
||||
# More strongly prefer if the target has no special moves
|
||||
if old_stage >= 2 && increment == 1
|
||||
score -= 15 * ((target.opposes?(@user)) ? 1 : desire_mult)
|
||||
score -= 10 * ((target.opposes?(@user)) ? 1 : desire_mult)
|
||||
else
|
||||
has_special_moves = target.check_for_move { |m| m.specialMove?(m.type) }
|
||||
inc = (has_special_moves) ? 10 : 20
|
||||
inc = (has_special_moves) ? 8 : 12
|
||||
score += inc * inc_mult
|
||||
end
|
||||
when :DEFENSE
|
||||
# Modify score depending on current stat stage
|
||||
if old_stage >= 2 && increment == 1
|
||||
score -= 15 * ((target.opposes?(@user)) ? 1 : desire_mult)
|
||||
score -= 10 * ((target.opposes?(@user)) ? 1 : desire_mult)
|
||||
else
|
||||
score += 10 * inc_mult
|
||||
end
|
||||
@@ -210,29 +207,35 @@ class Battle::AI
|
||||
# Modify score depending on current stat stage
|
||||
# More strongly prefer if the target has no physical moves
|
||||
if old_stage >= 2 && increment == 1
|
||||
score -= 15 * ((target.opposes?(@user)) ? 1 : desire_mult)
|
||||
score -= 10 * ((target.opposes?(@user)) ? 1 : desire_mult)
|
||||
else
|
||||
has_physical_moves = target.check_for_move { |m| m.physicalMove?(m.type) &&
|
||||
m.function != "UseUserDefenseInsteadOfUserAttack" &&
|
||||
m.function != "UseTargetAttackInsteadOfUserAttack" }
|
||||
inc = (has_physical_moves) ? 10 : 20
|
||||
inc = (has_physical_moves) ? 8 : 12
|
||||
score += inc * inc_mult
|
||||
end
|
||||
when :SPECIAL_DEFENSE
|
||||
# Modify score depending on current stat stage
|
||||
if old_stage >= 2 && increment == 1
|
||||
score -= 15 * ((target.opposes?(@user)) ? 1 : desire_mult)
|
||||
score -= 10 * ((target.opposes?(@user)) ? 1 : desire_mult)
|
||||
else
|
||||
score += 10 * inc_mult
|
||||
end
|
||||
when :SPEED
|
||||
# Prefer if target is slower than a foe
|
||||
# TODO: Don't prefer if the target is too much slower than any foe that it
|
||||
# can't catch up.
|
||||
target_speed = target.rough_stat(:SPEED)
|
||||
each_foe_battler(target.side) do |b, i|
|
||||
next if target.faster_than?(b)
|
||||
score += 15 * inc_mult
|
||||
break
|
||||
b_speed = b.rough_stat(:SPEED)
|
||||
next if b_speed > target_speed * 2.5 # Much too slow to reasonably catch up
|
||||
if b_speed > target_speed
|
||||
if b_speed < target_speed * (increment + 2) / 2
|
||||
score += 15 * inc_mult # Target will become faster than b
|
||||
else
|
||||
score += 8 * inc_mult
|
||||
end
|
||||
break
|
||||
end
|
||||
end
|
||||
# TODO: Prefer if the target is able to cause flinching (moves that
|
||||
# flinch, or has King's Rock/Stench).
|
||||
@@ -242,21 +245,21 @@ class Battle::AI
|
||||
"PowerHigherWithUserPositiveStatStages"
|
||||
]
|
||||
if target.has_move_with_function?(*moves_that_prefer_high_speed)
|
||||
score += 8 * inc_mult
|
||||
score += 5 * inc_mult
|
||||
end
|
||||
# Don't prefer if any foe has Gyro Ball
|
||||
each_foe_battler(target.side) do |b, i|
|
||||
next if !b.has_move_with_function?("PowerHigherWithTargetFasterThanUser")
|
||||
score -= 8 * inc_mult
|
||||
score -= 5 * inc_mult
|
||||
end
|
||||
# Don't prefer if target has Speed Boost (will be gaining Speed anyway)
|
||||
if target.has_active_ability?(:SPEEDBOOST)
|
||||
score -= 20 * ((target.opposes?(@user)) ? 1 : desire_mult)
|
||||
score -= 15 * ((target.opposes?(@user)) ? 1 : desire_mult)
|
||||
end
|
||||
when :ACCURACY
|
||||
# Modify score depending on current stat stage
|
||||
if old_stage >= 2 && increment == 1
|
||||
score -= 15 * ((target.opposes?(@user)) ? 1 : desire_mult)
|
||||
score -= 10 * ((target.opposes?(@user)) ? 1 : desire_mult)
|
||||
else
|
||||
min_accuracy = 100
|
||||
target.battler.moves.each do |m|
|
||||
@@ -272,11 +275,11 @@ class Battle::AI
|
||||
# Prefer if a foe of the target will take damage at the end of the round
|
||||
each_foe_battler(target.side) do |b, i|
|
||||
eor_damage = b.rough_end_of_round_damage
|
||||
score += 4 * inc_mult if eor_damage > 0
|
||||
score += 5 * inc_mult if eor_damage > 0
|
||||
end
|
||||
# Modify score depending on current stat stage
|
||||
if old_stage >= 2 && increment == 1
|
||||
score -= 15 * ((target.opposes?(@user)) ? 1 : desire_mult)
|
||||
score -= 10 * ((target.opposes?(@user)) ? 1 : desire_mult)
|
||||
else
|
||||
score += 10 * inc_mult
|
||||
end
|
||||
@@ -419,6 +422,8 @@ class Battle::AI
|
||||
"PowerHigherWithUserPositiveStatStages"
|
||||
]
|
||||
if !target.has_move_with_function?(*moves_that_prefer_high_speed)
|
||||
# TODO: Not worth it if the target is too much faster than its foe(s)
|
||||
# and can't be brought slow enough.
|
||||
each_foe_battler(target.side) do |b, i|
|
||||
return true if !b.faster_than?(target)
|
||||
end
|
||||
@@ -445,22 +450,14 @@ class Battle::AI
|
||||
# TODO: Don't prefer if target is semi-invulnerable and user is faster.
|
||||
# Prefer if move is a status move and it's the user's first/second turn
|
||||
if @user.turnCount < 2 && @move.statusMove?
|
||||
score += total_decrement * desire_mult * 4
|
||||
score += total_decrement * desire_mult * 5
|
||||
end
|
||||
# Prefer if user is at high HP, don't prefer if user is at low HP
|
||||
if target.index != @user.index
|
||||
if @user.hp >= @user.totalhp * 0.7
|
||||
score += total_decrement * desire_mult * 3
|
||||
else
|
||||
score += total_decrement * desire_mult * ((100 * @user.hp / @user.totalhp) - 50) / 6 # +3 to -8 per stage
|
||||
end
|
||||
score += total_decrement * desire_mult * ((100 * @user.hp / @user.totalhp) - 50) / 8 # +6 to -6 per stage
|
||||
end
|
||||
# Prefer if target is at high HP, don't prefer if target is at low HP
|
||||
if target.hp >= target.totalhp * 0.7
|
||||
score += total_decrement * desire_mult * 3
|
||||
else
|
||||
score += total_decrement * desire_mult * ((100 * target.hp / target.totalhp) - 50) / 6 # +3 to -8 per stage
|
||||
end
|
||||
score += total_decrement * desire_mult * ((100 * target.hp / target.totalhp) - 50) / 8 # +6 to -6 per stage
|
||||
# TODO: Look at abilities that trigger upon stat lowering.
|
||||
return score
|
||||
end
|
||||
@@ -488,70 +485,76 @@ class Battle::AI
|
||||
# Modify score depending on current stat stage
|
||||
# More strongly prefer if the target has no special moves
|
||||
if old_stage <= -2 && decrement == 1
|
||||
score -= 15 * ((target.opposes?(@user)) ? 1 : desire_mult)
|
||||
score -= 10 * ((target.opposes?(@user)) ? 1 : desire_mult)
|
||||
else
|
||||
has_special_moves = target.check_for_move { |m| m.specialMove?(m.type) }
|
||||
dec = (has_special_moves) ? 5 : 10
|
||||
dec = (has_special_moves) ? 8 : 12
|
||||
score += dec * dec_mult
|
||||
end
|
||||
when :DEFENSE
|
||||
# Modify score depending on current stat stage
|
||||
if old_stage <= -2 && decrement == 1
|
||||
score -= 15 * ((target.opposes?(@user)) ? 1 : desire_mult)
|
||||
score -= 10 * ((target.opposes?(@user)) ? 1 : desire_mult)
|
||||
else
|
||||
score += 5 * dec_mult
|
||||
score += 10 * dec_mult
|
||||
end
|
||||
when :SPECIAL_ATTACK
|
||||
# Modify score depending on current stat stage
|
||||
# More strongly prefer if the target has no physical moves
|
||||
if old_stage <= -2 && decrement == 1
|
||||
score -= 15 * ((target.opposes?(@user)) ? 1 : desire_mult)
|
||||
score -= 10 * ((target.opposes?(@user)) ? 1 : desire_mult)
|
||||
else
|
||||
has_physical_moves = target.check_for_move { |m| m.physicalMove?(m.type) &&
|
||||
m.function != "UseUserDefenseInsteadOfUserAttack" &&
|
||||
m.function != "UseTargetAttackInsteadOfUserAttack" }
|
||||
dec = (has_physical_moves) ? 5 : 10
|
||||
dec = (has_physical_moves) ? 8 : 12
|
||||
score += dec * dec_mult
|
||||
end
|
||||
when :SPECIAL_DEFENSE
|
||||
# Modify score depending on current stat stage
|
||||
if old_stage <= -2 && decrement == 1
|
||||
score -= 15 * ((target.opposes?(@user)) ? 1 : desire_mult)
|
||||
score -= 10 * ((target.opposes?(@user)) ? 1 : desire_mult)
|
||||
else
|
||||
score += 5 * dec_mult
|
||||
score += 10 * dec_mult
|
||||
end
|
||||
when :SPEED
|
||||
# Prefer if target is faster than an ally
|
||||
# TODO: Don't prefer if the target is too much faster than any ally and
|
||||
# can't be brought slow enough.
|
||||
target_speed = target.rough_stat(:SPEED)
|
||||
each_foe_battler(target.side) do |b, i|
|
||||
next if b.faster_than?(target)
|
||||
score += 15 * dec_mult
|
||||
break
|
||||
b_speed = b.rough_stat(:SPEED)
|
||||
next if target_speed > b_speed * 2.5 # Much too fast to reasonably be overtaken
|
||||
if target_speed > b_speed
|
||||
if target_speed < b_speed * 2 / (decrement + 2)
|
||||
score += 15 * inc_mult # Target will become slower than b
|
||||
else
|
||||
score += 8 * inc_mult
|
||||
end
|
||||
break
|
||||
end
|
||||
end
|
||||
# Prefer if any ally has Electro Ball
|
||||
each_foe_battler(target.side) do |b, i|
|
||||
next if !b.has_move_with_function?("PowerHigherWithUserFasterThanTarget")
|
||||
score += 8 * dec_mult
|
||||
score += 5 * dec_mult
|
||||
end
|
||||
# Don't prefer if target has Speed Boost (will be gaining Speed anyway)
|
||||
if target.has_active_ability?(:SPEEDBOOST)
|
||||
score -= 20 * ((target.opposes?(@user)) ? 1 : desire_mult)
|
||||
score -= 15 * ((target.opposes?(@user)) ? 1 : desire_mult)
|
||||
end
|
||||
when :ACCURACY
|
||||
# Modify score depending on current stat stage
|
||||
if old_stage <= -2 && decrement == 1
|
||||
score -= 15 * ((target.opposes?(@user)) ? 1 : desire_mult)
|
||||
score -= 10 * ((target.opposes?(@user)) ? 1 : desire_mult)
|
||||
else
|
||||
score += 5 * dec_mult
|
||||
score += 10 * dec_mult
|
||||
end
|
||||
# TODO: Prefer if target is poisoned/toxiced/Leech Seeded/cursed.
|
||||
when :EVASION
|
||||
# Modify score depending on current stat stage
|
||||
if old_stage <= -2 && decrement == 1
|
||||
score -= 15 * ((target.opposes?(@user)) ? 1 : desire_mult)
|
||||
score -= 10 * ((target.opposes?(@user)) ? 1 : desire_mult)
|
||||
else
|
||||
score += 5 * dec_mult
|
||||
score += 10 * dec_mult
|
||||
end
|
||||
end
|
||||
# Prefer if target has Stored Power
|
||||
@@ -588,40 +591,40 @@ class Battle::AI
|
||||
when :Sun
|
||||
# Check for Fire/Water moves
|
||||
if b.has_damaging_move_of_type?(:FIRE)
|
||||
ret += (b.opposes?(move_user)) ? -8 : 8
|
||||
ret += (b.opposes?(move_user)) ? -10 : 10
|
||||
end
|
||||
if b.has_damaging_move_of_type?(:WATER)
|
||||
ret += (b.opposes?(move_user)) ? 8 : -8
|
||||
ret += (b.opposes?(move_user)) ? 10 : -10
|
||||
end
|
||||
# TODO: Check for freezing moves.
|
||||
when :Rain
|
||||
# Check for Fire/Water moves
|
||||
if b.has_damaging_move_of_type?(:WATER)
|
||||
ret += (b.opposes?(move_user)) ? -8 : 8
|
||||
ret += (b.opposes?(move_user)) ? -10 : 10
|
||||
end
|
||||
if b.has_damaging_move_of_type?(:FIRE)
|
||||
ret += (b.opposes?(move_user)) ? 8 : -8
|
||||
ret += (b.opposes?(move_user)) ? 10 : -10
|
||||
end
|
||||
when :Sandstorm
|
||||
# Check for battlers affected by sandstorm's effects
|
||||
if b.battler.takesSandstormDamage? # End of round damage
|
||||
ret += (b.opposes?(move_user)) ? 8 : -8
|
||||
ret += (b.opposes?(move_user)) ? 10 : -10
|
||||
end
|
||||
if b.has_type?(:ROCK) # +SpDef for Rock types
|
||||
ret += (b.opposes?(move_user)) ? -8 : 8
|
||||
ret += (b.opposes?(move_user)) ? -10 : 10
|
||||
end
|
||||
when :Hail
|
||||
# Check for battlers affected by hail's effects
|
||||
if b.battler.takesHailDamage? # End of round damage
|
||||
ret += (b.opposes?(move_user)) ? 8 : -8
|
||||
ret += (b.opposes?(move_user)) ? 10 : -10
|
||||
end
|
||||
when :ShadowSky
|
||||
# Check for battlers affected by Shadow Sky's effects
|
||||
if b.has_damaging_move_of_type?(:SHADOW)
|
||||
ret += (b.opposes?(move_user)) ? 8 : -8
|
||||
ret += (b.opposes?(move_user)) ? 10 : -10
|
||||
end
|
||||
if b.battler.takesShadowSkyDamage? # End of round damage
|
||||
ret += (b.opposes?(move_user)) ? 8 : -8
|
||||
ret += (b.opposes?(move_user)) ? 10 : -10
|
||||
end
|
||||
end
|
||||
# Check each battler's abilities/other moves affected by the new weather
|
||||
@@ -698,32 +701,32 @@ class Battle::AI
|
||||
# Immunity to sleep
|
||||
# TODO: Check all battlers for sleep-inducing moves and other effects?
|
||||
if b.status == :NONE
|
||||
ret += (b.opposes?(move_user)) ? -5 : 5
|
||||
ret += (b.opposes?(move_user)) ? -8 : 8
|
||||
end
|
||||
if b.effects[PBEffects::Yawn] > 0
|
||||
ret += (b.opposes?(move_user)) ? -10 : 10
|
||||
end
|
||||
# Check for Electric moves
|
||||
if b.has_damaging_move_of_type?(:ELECTRIC)
|
||||
ret += (b.opposes?(move_user)) ? -15 : 15
|
||||
ret += (b.opposes?(move_user)) ? -10 : 10
|
||||
end
|
||||
when :Grassy
|
||||
# End of round healing
|
||||
ret += (b.opposes?(move_user)) ? -10 : 10
|
||||
ret += (b.opposes?(move_user)) ? -8 : 8
|
||||
# Check for Grass moves
|
||||
if b.has_damaging_move_of_type?(:GRASS)
|
||||
ret += (b.opposes?(move_user)) ? -15 : 15
|
||||
ret += (b.opposes?(move_user)) ? -10 : 10
|
||||
end
|
||||
when :Misty
|
||||
# Immunity to status problems/confusion
|
||||
# TODO: Check all battlers for status/confusion-inducing moves and other
|
||||
# effects?
|
||||
if b.status == :NONE || b.effects[PBEffects::Confusion] == 0
|
||||
ret += (b.opposes?(move_user)) ? -5 : 5
|
||||
ret += (b.opposes?(move_user)) ? -8 : 8
|
||||
end
|
||||
# Check for Dragon moves
|
||||
if b.has_damaging_move_of_type?(:DRAGON)
|
||||
ret += (b.opposes?(move_user)) ? 15 : -15
|
||||
ret += (b.opposes?(move_user)) ? 10 : -10
|
||||
end
|
||||
when :Psychic
|
||||
# Check for priority moves
|
||||
@@ -732,7 +735,7 @@ class Battle::AI
|
||||
end
|
||||
# Check for Psychic moves
|
||||
if b.has_damaging_move_of_type?(:PSYCHIC)
|
||||
ret += (b.opposes?(move_user)) ? -15 : 15
|
||||
ret += (b.opposes?(move_user)) ? -10 : 10
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -745,7 +748,7 @@ class Battle::AI
|
||||
}[terrain]
|
||||
each_battler do |b, i|
|
||||
if seed && b.has_active_item?(seed)
|
||||
ret += (b.opposes?(move_user)) ? -15 : 15
|
||||
ret += (b.opposes?(move_user)) ? -8 : 8
|
||||
end
|
||||
end
|
||||
# Check for abilities/moves affected by the terrain
|
||||
@@ -773,20 +776,20 @@ class Battle::AI
|
||||
ret += (b.opposes?(move_user)) ? -5 : 5
|
||||
end
|
||||
if abils && b.has_active_ability?(abils)
|
||||
ret += (b.opposes?(move_user)) ? -15 : 15
|
||||
ret += (b.opposes?(move_user)) ? -8 : 8
|
||||
end
|
||||
# Moves
|
||||
if b.has_move_with_function?("EffectDependsOnEnvironment",
|
||||
"SetUserTypesBasedOnEnvironment",
|
||||
"TypeAndPowerDependOnTerrain",
|
||||
"UseMoveDependingOnEnvironment")
|
||||
ret += (b.opposes?(move_user)) ? -10 : 10
|
||||
ret += (b.opposes?(move_user)) ? -5 : 5
|
||||
end
|
||||
if good_moves && b.has_move_with_function?(*good_moves)
|
||||
ret += (b.opposes?(move_user)) ? -10 : 10
|
||||
ret += (b.opposes?(move_user)) ? -5 : 5
|
||||
end
|
||||
if bad_moves && b.has_move_with_function?(*bad_moves)
|
||||
ret += (b.opposes?(move_user)) ? 10 : -10
|
||||
ret += (b.opposes?(move_user)) ? 5 : -5
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -29,7 +29,7 @@ Battle::AI::Handlers::GeneralMoveAgainstTargetScore.add(:shiny_target,
|
||||
proc { |score, move, user, target, ai, battle|
|
||||
if target.wild? && target.battler.shiny?
|
||||
old_score = score
|
||||
score -= 15
|
||||
score -= 20
|
||||
PBDebug.log_score_change(score - old_score, "avoid attacking a shiny wild Pokémon")
|
||||
end
|
||||
next score
|
||||
@@ -46,7 +46,7 @@ Battle::AI::Handlers::GeneralMoveAgainstTargetScore.add(:shiny_target,
|
||||
# => Include EOR damage in this?
|
||||
# => Prefer move if it will KO the target (moreso if user is slower than target)
|
||||
#===============================================================================
|
||||
Battle::AI::Handlers::GeneralMoveAgainstTargetScore.add(:add_predicted_damage,
|
||||
Battle::AI::Handlers::GeneralMoveAgainstTargetScore.add(:predicted_damage,
|
||||
proc { |score, move, user, target, ai, battle|
|
||||
if move.damagingMove?
|
||||
dmg = move.rough_damage
|
||||
@@ -128,7 +128,7 @@ Battle::AI::Handlers::GeneralMoveAgainstTargetScore.add(:thawing_move_against_fr
|
||||
if ai.trainer.medium_skill? && target.status == :FROZEN
|
||||
if move.rough_type == :FIRE || (Settings::MECHANICS_GENERATION >= 6 && move.move.thawsUser?)
|
||||
old_score = score
|
||||
score -= 15
|
||||
score -= 20
|
||||
PBDebug.log_score_change(score - old_score, "thaws the target")
|
||||
end
|
||||
end
|
||||
@@ -205,7 +205,7 @@ Battle::AI::Handlers::GeneralMoveAgainstTargetScore.add(:damaging_a_biding_targe
|
||||
hits_possible += 1 if user.faster_than?(target)
|
||||
if dmg * hits_possible + eor_dmg < target.hp * 1.05
|
||||
old_score = score
|
||||
score -= 15
|
||||
score -= 20
|
||||
PBDebug.log_score_change(score - old_score, "don't want to damage the Biding target")
|
||||
end
|
||||
end
|
||||
@@ -227,7 +227,7 @@ Battle::AI::Handlers::GeneralMoveAgainstTargetScore.add(:knocking_out_a_destiny_
|
||||
dmg = move.rough_damage
|
||||
if dmg > target.hp * 1.05 # Predicted to KO the target
|
||||
old_score = score
|
||||
score -= 15
|
||||
score -= 20
|
||||
score -= 10 if battle.pbAbleNonActiveCount(user.idxOwnSide) == 0
|
||||
PBDebug.log_score_change(score - old_score, "don't want to KO the Destiny Bonding target")
|
||||
end
|
||||
@@ -264,7 +264,7 @@ Battle::AI::Handlers::GeneralMoveAgainstTargetScore.add(:target_can_Magic_Coat_o
|
||||
score = Battle::AI::MOVE_USELESS_SCORE
|
||||
PBDebug.log_score_change(score - old_score, "useless because target will Magic Bounce it")
|
||||
elsif target.has_move_with_function?("BounceBackProblemCausingStatusMoves")
|
||||
score -= 8
|
||||
score -= 7
|
||||
PBDebug.log_score_change(score - old_score, "target knows Magic Coat and could bounce it")
|
||||
end
|
||||
end
|
||||
@@ -286,7 +286,7 @@ Battle::AI::Handlers::GeneralMoveScore.add(:any_foe_can_Magic_Coat_or_Bounce_mov
|
||||
PBDebug.log_score_change(score - old_score, "useless because a foe will Magic Bounce it")
|
||||
break
|
||||
elsif b.has_move_with_function?("BounceBackProblemCausingStatusMoves")
|
||||
score -= 8
|
||||
score -= 7
|
||||
PBDebug.log_score_change(score - old_score, "a foe knows Magic Coat and could bounce it")
|
||||
break
|
||||
end
|
||||
@@ -307,7 +307,7 @@ Battle::AI::Handlers::GeneralMoveScore.add(:any_battler_can_Snatch_move,
|
||||
next if b.effects[PBEffects::SkyDrop] >= 0
|
||||
next if !b.has_move_with_function?("StealAndUseBeneficialStatusMove")
|
||||
old_score = score
|
||||
score -= 8
|
||||
score -= 7
|
||||
PBDebug.log_score_change(score - old_score, "another battler could Snatch it")
|
||||
break
|
||||
end
|
||||
@@ -335,10 +335,10 @@ Battle::AI::Handlers::GeneralMoveScore.add(:thawing_move_when_frozen,
|
||||
if ai.trainer.medium_skill? && user.status == :FROZEN
|
||||
old_score = score
|
||||
if move.move.thawsUser?
|
||||
score += 30
|
||||
score += 20
|
||||
PBDebug.log_score_change(score - old_score, "move will thaw the user")
|
||||
elsif user.check_for_move { |m| m.thawsUser? }
|
||||
score -= 30 # Don't prefer this move if user knows another move that thaws
|
||||
score -= 20 # Don't prefer this move if user knows another move that thaws
|
||||
PBDebug.log_score_change(score - old_score, "user knows another move will thaw it")
|
||||
end
|
||||
end
|
||||
@@ -354,7 +354,7 @@ Battle::AI::Handlers::GeneralMoveScore.add(:dance_move_against_dancer,
|
||||
if move.move.danceMove?
|
||||
old_score = score
|
||||
ai.each_foe_battler(user.side) do |b, i|
|
||||
score -= 12 if b.has_active_ability?(:DANCER)
|
||||
score -= 10 if b.has_active_ability?(:DANCER)
|
||||
end
|
||||
PBDebug.log_score_change(score - old_score, "don't want to use a dance move because a foe has Dancer")
|
||||
end
|
||||
@@ -381,10 +381,12 @@ Battle::AI::Handlers::GeneralMoveScore.add(:good_move_for_choice_item,
|
||||
# Don't prefer moves which are 0x against at least one type
|
||||
move_type = move.rough_type
|
||||
GameData::Type.each do |type_data|
|
||||
score -= 5 if type_data.immunities.include?(move_type)
|
||||
score -= 8 if type_data.immunities.include?(move_type)
|
||||
end
|
||||
# Don't prefer moves with lower accuracy
|
||||
score = score * move.accuracy / 100 if move.accuracy > 0
|
||||
if move.accuracy > 0
|
||||
score -= (0.4 * (100 - move.accuracy)).to_i # -0 (100%) to -39 (1%)
|
||||
end
|
||||
# Don't prefer moves with low PP
|
||||
score -= 10 if move.move.pp <= 5
|
||||
PBDebug.log_score_change(score - old_score, "move is less suitable to be Choiced into")
|
||||
@@ -400,7 +402,7 @@ Battle::AI::Handlers::GeneralMoveScore.add(:good_move_for_choice_item,
|
||||
# more (desperate).
|
||||
# TODO: Review score modifier.
|
||||
#===============================================================================
|
||||
Battle::AI::Handlers::GeneralMoveScore.add(:either_side_down_to_last_pokemon,
|
||||
Battle::AI::Handlers::GeneralMoveScore.add(:damaging_move_and_either_side_no_reserves,
|
||||
proc { |score, move, user, ai, battle|
|
||||
if ai.trainer.medium_skill? && move.damagingMove?
|
||||
reserves = battle.pbAbleNonActiveCount(user.idxOwnSide)
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
# PredictMoveFailure
|
||||
# ScoreMoves
|
||||
# PreferMultiTargetMoves
|
||||
# HPAware (considers HP values of user/target for "worth it?" score changes)
|
||||
# ConsiderSwitching (can choose to switch out Pokémon)
|
||||
# ReserveLastPokemon (don't switch it in if possible)
|
||||
# UsePokemonInOrder (uses earliest-listed Pokémon possible)
|
||||
@@ -58,7 +59,10 @@ class Battle::AI::AITrainer
|
||||
@skill_flags.push("ScoreMoves")
|
||||
@skill_flags.push("PreferMultiTargetMoves")
|
||||
end
|
||||
@skill_flags.push("ConsiderSwitching") if medium_skill?
|
||||
if medium_skill?
|
||||
@skill_flags.push("ConsiderSwitching")
|
||||
@skill_flags.push("HPAware")
|
||||
end
|
||||
if !medium_skill?
|
||||
@skill_flags.push("UsePokemonInOrder")
|
||||
elsif best_skill?
|
||||
|
||||
@@ -55,13 +55,6 @@ class Battle::AI::AIBattler
|
||||
def idxOpposingSide; return @battler.idxOpposingSide; end
|
||||
def pbOpposingSide; return @battler.pbOpposingSide; end
|
||||
|
||||
def faster_than?(other)
|
||||
return false if other.nil?
|
||||
this_speed = rough_stat(:SPEED)
|
||||
other_speed = other.rough_stat(:SPEED)
|
||||
return (this_speed > other_speed) ^ (@ai.battle.field.effects[PBEffects::TrickRoom] > 0)
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
|
||||
# Returns how much damage this battler will take at the end of this round.
|
||||
@@ -167,8 +160,6 @@ class Battle::AI::AIBattler
|
||||
|
||||
#=============================================================================
|
||||
|
||||
def speed; return @battler.speed; end
|
||||
|
||||
def base_stat(stat)
|
||||
ret = 0
|
||||
case stat
|
||||
@@ -190,6 +181,13 @@ class Battle::AI::AIBattler
|
||||
return (value.to_f * stageMul[stage] / stageDiv[stage]).floor
|
||||
end
|
||||
|
||||
def faster_than?(other)
|
||||
return false if other.nil?
|
||||
this_speed = rough_stat(:SPEED)
|
||||
other_speed = other.rough_stat(:SPEED)
|
||||
return (this_speed > other_speed) ^ (@ai.battle.field.effects[PBEffects::TrickRoom] > 0)
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
|
||||
def types; return @battler.types; end
|
||||
@@ -423,6 +421,7 @@ class Battle::AI::AIBattler
|
||||
# Return values are typically between -10 and +10. 0 is indifferent, positive
|
||||
# values mean this battler benefits, negative values mean this battler suffers.
|
||||
def wants_item?(item)
|
||||
item = :NONE if !item
|
||||
item = item.id if !item.is_a?(Symbol) && item.respond_to?("id")
|
||||
return 0 if has_active_ability?(:KLUTZ)
|
||||
# TODO: Unnerve, other item-negating effects.
|
||||
@@ -511,7 +510,7 @@ class Battle::AI::AIBattler
|
||||
end
|
||||
# Prefer if this battler knows Fling and it will do a lot of damage/have an
|
||||
# additional (negative) effect when flung
|
||||
if has_move_with_function?("ThrowUserItemAtTarget")
|
||||
if item != :NONE && has_move_with_function?("ThrowUserItemAtTarget")
|
||||
GameData::Item.get(item).flags.each do |flag|
|
||||
next if !flag[/^Fling_(\d+)$/i]
|
||||
amt = $~[1].to_i
|
||||
@@ -533,12 +532,12 @@ class Battle::AI::AIBattler
|
||||
#=============================================================================
|
||||
|
||||
# Items can be consumed by Stuff Cheeks, Teatime, Bug Bite/Pluck and Fling.
|
||||
def get_score_change_for_consuming_item(item)
|
||||
def get_score_change_for_consuming_item(item, try_preserving_item = false)
|
||||
ret = 0
|
||||
case item
|
||||
when :ORANBERRY, :BERRYJUICE, :ENIGMABERRY, :SITRUSBERRY
|
||||
# Healing
|
||||
ret += (hp > totalhp * 3 / 4) ? -8 : 8
|
||||
ret += (hp > totalhp * 0.75) ? -6 : 6
|
||||
ret = ret * 3 / 2 if GameData::Item.get(item).is_berry? && has_active_ability?(:RIPEN)
|
||||
when :AGUAVBERRY, :FIGYBERRY, :IAPAPABERRY, :MAGOBERRY, :WIKIBERRY
|
||||
# Healing with confusion
|
||||
@@ -548,7 +547,7 @@ class Battle::AI::AIBattler
|
||||
elsif Settings::MECHANICS_GENERATION >= 8
|
||||
fraction_to_heal = 3
|
||||
end
|
||||
ret += (hp > totalhp * (1 - (1 / fraction_to_heal))) ? -8 : 8
|
||||
ret += (hp > totalhp * (1 - (1.0 / fraction_to_heal))) ? -6 : 6
|
||||
ret = ret * 3 / 2 if GameData::Item.get(item).is_berry? && has_active_ability?(:RIPEN)
|
||||
# TODO: Check whether the item will cause confusion?
|
||||
when :ASPEARBERRY, :CHERIBERRY, :CHESTOBERRY, :PECHABERRY, :RAWSTBERRY
|
||||
@@ -560,21 +559,25 @@ class Battle::AI::AIBattler
|
||||
:PECHABERRY => :POISON,
|
||||
:RAWSTBERRY => :BURN
|
||||
}[item]
|
||||
ret += (cured_status && status == cured_status) ? 8 : -8
|
||||
ret += (cured_status && status == cured_status) ? 6 : -6
|
||||
when :PERSIMBERRY
|
||||
# Confusion cure
|
||||
ret += (effects[PBEffects::Confusion] > 1) ? 8 : -8
|
||||
ret += (effects[PBEffects::Confusion] > 1) ? 6 : -6
|
||||
when :LUMBERRY
|
||||
# Any status/confusion cure
|
||||
ret += (status != :NONE || effects[PBEffects::Confusion] > 1) ? 8 : -8
|
||||
ret += (status != :NONE || effects[PBEffects::Confusion] > 1) ? 6 : -6
|
||||
when :MENTALHERB
|
||||
# Cure mental effects
|
||||
ret += 8 if effects[PBEffects::Attract] >= 0 ||
|
||||
effects[PBEffects::Taunt] > 1 ||
|
||||
effects[PBEffects::Encore] > 1 ||
|
||||
effects[PBEffects::Torment] ||
|
||||
effects[PBEffects::Disable] > 1 ||
|
||||
effects[PBEffects::HealBlock] > 1
|
||||
if effects[PBEffects::Attract] >= 0 ||
|
||||
effects[PBEffects::Taunt] > 1 ||
|
||||
effects[PBEffects::Encore] > 1 ||
|
||||
effects[PBEffects::Torment] ||
|
||||
effects[PBEffects::Disable] > 1 ||
|
||||
effects[PBEffects::HealBlock] > 1
|
||||
ret += 6
|
||||
else
|
||||
ret -= 6
|
||||
end
|
||||
when :APICOTBERRY, :GANLONBERRY, :LIECHIBERRY, :PETAYABERRY, :SALACBERRY,
|
||||
:KEEBERRY, :MARANGABERRY
|
||||
# Stat raise
|
||||
@@ -587,7 +590,7 @@ class Battle::AI::AIBattler
|
||||
:KEEBERRY => :DEFENSE,
|
||||
:MARANGABERRY => :SPECIAL_DEFENSE
|
||||
}[item]
|
||||
ret += 8 if stat && @ai.stat_raise_worthwhile?(self, stat)
|
||||
ret += (stat && @ai.stat_raise_worthwhile?(self, stat)) ? 8 : -8
|
||||
ret = ret * 3 / 2 if GameData::Item.get(item).is_berry? && has_active_ability?(:RIPEN)
|
||||
when :STARFBERRY
|
||||
# Random stat raise
|
||||
@@ -595,24 +598,19 @@ class Battle::AI::AIBattler
|
||||
ret = ret * 3 / 2 if GameData::Item.get(item).is_berry? && has_active_ability?(:RIPEN)
|
||||
when :WHITEHERB
|
||||
# Resets lowered stats
|
||||
reduced_stats = false
|
||||
GameData::Stat.each_battle do |s|
|
||||
next if stages[s.id] >= 0
|
||||
reduced_stats = true
|
||||
break
|
||||
end
|
||||
ret += 8 if reduced_stats
|
||||
ret += (@battler.hasLoweredStatStages?) ? 8 : -8
|
||||
when :MICLEBERRY
|
||||
# Raises accuracy of next move
|
||||
ret += 8
|
||||
ret += (@ai.stat_raise_worthwhile?(self, :ACCURACY, true)) ? 6 : -6
|
||||
when :LANSATBERRY
|
||||
# Focus energy
|
||||
ret += 8 if effects[PBEffects::FocusEnergy] < 2
|
||||
ret += (effects[PBEffects::FocusEnergy] < 2) ? 6 : -6
|
||||
when :LEPPABERRY
|
||||
# Restore PP
|
||||
ret += 8
|
||||
ret += 6
|
||||
ret = ret * 3 / 2 if GameData::Item.get(item).is_berry? && has_active_ability?(:RIPEN)
|
||||
end
|
||||
ret = 0 if ret < 0 && !try_preserving_item
|
||||
return ret
|
||||
end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user