mirror of
https://github.com/infinitefusion/infinitefusion-e18.git
synced 2025-12-07 21:24:59 +00:00
1491 lines
47 KiB
Ruby
1491 lines
47 KiB
Ruby
# Evasion when Foresighted
|
|
|
|
# cont 120: self destruct
|
|
|
|
class MKAI
|
|
class ScoreHandler
|
|
@@GeneralCode = []
|
|
@@MoveCode = {}
|
|
@@StatusCode = []
|
|
@@DamagingCode = []
|
|
|
|
def self.add_status(&code)
|
|
@@StatusCode << code
|
|
end
|
|
|
|
def self.add_damaging(&code)
|
|
@@DamagingCode << code
|
|
end
|
|
|
|
def self.add(*moves, &code)
|
|
if moves.size == 0
|
|
@@GeneralCode << code
|
|
else
|
|
moves.each do |move|
|
|
if move.is_a?(Symbol) # Specific move
|
|
id = getConst(PBMoves, move)
|
|
raise "Invalid move #{move}" if id.nil? || id == 0
|
|
@@MoveCode[id] = code
|
|
elsif move.is_a?(String) # Function code
|
|
@@MoveCode[move] = code
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
def self.trigger(list, score, ai, user, target, move)
|
|
return score if list.nil?
|
|
list = [list] if !list.is_a?(Array)
|
|
list.each do |code|
|
|
next if code.nil?
|
|
newscore = code.call(score, ai, user, target, move)
|
|
score = newscore if newscore.is_a?(Numeric)
|
|
end
|
|
return score
|
|
end
|
|
|
|
def self.trigger_general(score, ai, user, target, move)
|
|
return self.trigger(@@GeneralCode, score, ai, user, target, move)
|
|
end
|
|
|
|
def self.trigger_status_moves(score, ai, user, target, move)
|
|
return self.trigger(@@StatusCode, score, ai, user, target, move)
|
|
end
|
|
|
|
def self.trigger_damaging_moves(score, ai, user, target, move)
|
|
return self.trigger(@@DamagingCode, score, ai, user, target, move)
|
|
end
|
|
|
|
def self.trigger_move(move, score, ai, user, target)
|
|
id = move.id
|
|
id = move.function if !@@MoveCode[id]
|
|
return self.trigger(@@MoveCode[id], score, ai, user, target, move)
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
|
|
#=============================================================================#
|
|
# #
|
|
# Multipliers #
|
|
# #
|
|
#=============================================================================#
|
|
|
|
|
|
# Effectiveness modifier
|
|
# For this to have a more dramatic effect, this block could be moved lower down
|
|
# so that it factors in more score modifications before multiplying.
|
|
MKAI::ScoreHandler.add do |score, ai, user, target, move|
|
|
# Effectiveness doesn't add anything for fixed-damage moves.
|
|
next if move.is_a?(PokeBattle_FixedDamageMove) || move.statusMove?
|
|
# Add half the score times the effectiveness modifiers. Means super effective
|
|
# will be a 50% increase in score.
|
|
target_types = target.types
|
|
mod = move.pbCalcTypeMod(move.type, user, target) / PBTypeEffectiveness::NORMAL_EFFECTIVE.to_f
|
|
# If mod is 0, i.e. the target is immune to the move (based on type, at least),
|
|
# we do not multiply the score to 0, because immunity is handled as a final multiplier elsewhere.
|
|
if mod != 0 && mod != 1
|
|
score *= mod
|
|
MKAI.log("* #{mod} for effectiveness")
|
|
end
|
|
next score
|
|
end
|
|
|
|
|
|
|
|
#=============================================================================#
|
|
# #
|
|
# All Moves #
|
|
# #
|
|
#=============================================================================#
|
|
|
|
|
|
# Accuracy modifier to favor high-accuracy moves
|
|
MKAI::ScoreHandler.add do |score, ai, user, target, move|
|
|
next if user.battler == target.battler
|
|
accuracy = user.get_move_accuracy(move, target)
|
|
missing = 100 - accuracy
|
|
# (High) Jump Kick, a move that damages you when you miss
|
|
if move.function == "10B"
|
|
# Decrease the score more drastically if it has lower accuracy
|
|
missing *= 2.0
|
|
end
|
|
if missing > 0
|
|
score -= missing
|
|
MKAI.log("- #{missing} for accuracy")
|
|
end
|
|
next score
|
|
end
|
|
|
|
|
|
# Increase/decrease score for each positive/negative stat boost the move gives the user
|
|
MKAI::ScoreHandler.add do |score, ai, user, target, move|
|
|
next if !move.is_a?(PokeBattle_MultiStatUpMove) && !move.is_a?(PokeBattle_StatUpMove) &&
|
|
!move.is_a?(PokeBattle_StatDownMove)
|
|
boosts = 0
|
|
atkBoosts = 0
|
|
spAtkBoosts = 0
|
|
evBoosts = 0
|
|
stats = []
|
|
if move.statUp
|
|
for i in 0...move.statUp.size / 2
|
|
stat = move.statUp[i * 2]
|
|
incr = move.statUp[i * 2 + 1]
|
|
boosts += incr
|
|
atkBoosts += incr if stat == PBStats::ATTACK
|
|
spAtkBoosts += incr if stat == PBStats::SPATK
|
|
evBoosts += incr if stat == PBStats::EVASION
|
|
stats << stat
|
|
end
|
|
end
|
|
if move.statDown
|
|
for i in 0...move.statDown.size / 2
|
|
stat = move.statDown[i * 2]
|
|
decr = move.statDown[i * 2 + 1]
|
|
boosts -= decr if
|
|
atkBoosts -= decr if stat == PBStats::ATTACK
|
|
spAtkBoosts -= decr if stat == PBStats::SPATK
|
|
stats << stat if !stats.include?(stat)
|
|
end
|
|
end
|
|
# Increase score by 10 * (net stage differences)
|
|
# If attack is boosted and the user is a physical attacker,
|
|
# these stage increases are multiplied by 20 instead of 10.
|
|
if atkBoosts > 0 && user.is_physical_attacker?
|
|
atkIncr = (atkBoosts * 30 * (2 - (user.stages[PBStats::ATTACK] + 6) / 6.0)).round
|
|
if atkIncr > 0
|
|
score += atkIncr
|
|
MKAI.log("+ #{atkIncr} for attack boost and being a physical attacker")
|
|
boosts -= atkBoosts
|
|
end
|
|
end
|
|
# If spatk is boosted and the user is a special attacker,
|
|
# these stage increases are multiplied by 20 instead of 10.
|
|
if spAtkBoosts > 0 && user.is_special_attacker?
|
|
spatkIncr = (spAtkBoosts * 30 * (2 - (user.stages[PBStats::SPATK] + 6) / 6.0)).round
|
|
if spatkIncr > 0
|
|
score += spatkIncr
|
|
MKAI.log("+ #{spatkIncr} for spatk boost and being a special attacker")
|
|
boosts -= spAtkBoosts
|
|
end
|
|
end
|
|
# Boost to evasion
|
|
if evBoosts != 0
|
|
evIncr = (evBoosts * 50 * (2 - (user.stages[PBStats::EVASION] + 6) / 6.0)).round
|
|
if evIncr > 0
|
|
score += evIncr
|
|
MKAI.log("+ #{evIncr} for evasion boost")
|
|
boosts -= evBoosts
|
|
end
|
|
end
|
|
# All remaining stat increases (or decreases) are multiplied by 25 and added to the score.
|
|
if boosts != 0
|
|
total = 6 * stats.size
|
|
eff = total
|
|
user.stages.each_with_index do |value, stage|
|
|
if stats.include?(stage)
|
|
eff -= value
|
|
end
|
|
end
|
|
fact = 1.0
|
|
fact = eff / total.to_f if total != 0
|
|
incr = (boosts * 25 * fact).round
|
|
if incr > 0
|
|
score += incr
|
|
MKAI.log("+ #{incr} for general user buffs (#{eff}/#{total} effectiveness)")
|
|
end
|
|
end
|
|
next score
|
|
end
|
|
|
|
|
|
# Increase/decrease score for each positive/negative stat boost the move gives the target
|
|
MKAI::ScoreHandler.add do |score, ai, user, target, move|
|
|
next if !move.is_a?(PokeBattle_TargetStatDownMove) && !move.is_a?(PokeBattle_TargetMultiStatDownMove)
|
|
debuffs = 0
|
|
accDecreases = 0
|
|
stats = []
|
|
if move.statDown
|
|
for i in 0...move.statDown.size / 2
|
|
stat = move.statDown[i * 2]
|
|
decr = move.statDown[i * 2 + 1]
|
|
debuffs += decr
|
|
accDecreases += decr if stat == PBStats::ACCURACY
|
|
stats << stat if stat != PBStats::EVASION && stat != PBStats::ACCURACY
|
|
end
|
|
end
|
|
if accDecreases != 0 && target.stages[PBStats::ACCURACY] != -6
|
|
accIncr = (accDecreases * 50 * (target.stages[PBStats::ACCURACY] + 6) / 6.0).round
|
|
score += accIncr
|
|
debuffs -= accIncr
|
|
MKAI.log("+ #{accIncr} for target accuracy debuff")
|
|
end
|
|
# All remaining stat decrases are multiplied by 10 and added to the score.
|
|
if debuffs > 0
|
|
total = 6 * stats.size
|
|
eff = total
|
|
target.stages.each_with_index do |value, stage|
|
|
if stats.include?(stage)
|
|
eff += value
|
|
end
|
|
end
|
|
fact = 1.0
|
|
fact = eff / total.to_f if total != 0
|
|
incr = (debuffs * 25 * fact).round
|
|
score += incr
|
|
MKAI.log("+ #{incr} for general target debuffs (#{eff}/#{total} effectiveness)")
|
|
end
|
|
next score
|
|
end
|
|
|
|
|
|
# Prefer priority moves that deal enough damage to knock the target out.
|
|
# Use previous damage dealt to determine if it deals enough damage now,
|
|
# or make a rough estimate.
|
|
MKAI::ScoreHandler.add do |score, ai, user, target, move|
|
|
# Apply this logic only for priority moves
|
|
next if move.priority <= 0 || move.function == "0D4" # Bide
|
|
prevDmg = target.get_damage_by_user_and_move(user, move)
|
|
if prevDmg.size > 0
|
|
# We have the previous damage this user has done with this move.
|
|
# Use the average of the previous damage dealt, and if it's more than the target's hp,
|
|
# we can likely use this move to knock out the target.
|
|
avg = (prevDmg.map { |e| e[2] }.sum / prevDmg.size.to_f).floor
|
|
if avg >= target.battler.hp
|
|
MKAI.log("+ 250 for priority move with average damage (#{avg}) >= target hp (#{target.battler.hp})")
|
|
score += 250
|
|
end
|
|
else
|
|
# Calculate the damage this priority move will do.
|
|
# The AI kind of cheats here, because this takes all items, berries, abilities, etc. into account.
|
|
# It is worth for the effect though; the AI using a priority move to prevent
|
|
# you from using one last move before you faint.
|
|
dmg = user.get_move_damage(target, move)
|
|
if dmg >= target.battler.hp
|
|
MKAI.log("+ 250 for priority move with predicted damage (#{dmg}) >= target hp (#{target.battler.hp})")
|
|
score += 250
|
|
end
|
|
end
|
|
next score
|
|
end
|
|
|
|
|
|
# Encourage using fixed-damage moves if the fixed damage is more than the target has HP
|
|
MKAI::ScoreHandler.add do |score, ai, user, target, move|
|
|
next if !move.is_a?(PokeBattle_FixedDamageMove) || move.function == "070" || move.function == "0D4"
|
|
dmg = move.pbFixedDamage(user, target)
|
|
if dmg >= target.hp
|
|
score += 175
|
|
MKAI.log("+ 175 for this move's fixed damage being enough to knock out the target")
|
|
end
|
|
next score
|
|
end
|
|
|
|
|
|
# See if any moves used in the past did enough damage to now kill the target,
|
|
# and if so, give that move slightly more preference.
|
|
# There can be more powerful moves that might also take out the user,
|
|
# but if this move will also take the user out, this is a safer option.
|
|
MKAI::ScoreHandler.add do |score, ai, user, target, move|
|
|
next if move.function == "0D4" # Bide
|
|
# Get all times this move was used on the target
|
|
ary = target.get_damage_by_user_and_move(user, move)
|
|
# If this move has been used before, and the move is not a two-turn move
|
|
if ary.size > 0 && !move.chargingTurnMove? && move.function != "0C2" # Hyper Beam
|
|
# Calculate the average damage of every time this move was used on the target
|
|
avg = ary.map { |e| e[2] }.sum / ary.size.to_f
|
|
# If the average damage this move dealt is enough to kill the target, increase likelihood of choosing this move
|
|
if avg >= target.hp
|
|
score += 100
|
|
MKAI.log("+ 100 for this move being likely to take out the target")
|
|
end
|
|
end
|
|
next score
|
|
end
|
|
|
|
|
|
# Prefer moves that are usable while the user is asleep
|
|
MKAI::ScoreHandler.add do |score, ai, user, target, move|
|
|
# If the move is usable while asleep, and if the user won't wake up this turn
|
|
# Kind of cheating, but insignificant. This way the user can choose a more powerful move instead
|
|
if move.usableWhenAsleep?
|
|
if user.asleep? && user.statusCount > 1
|
|
score += 200
|
|
MKAI.log("+ 200 for being able to use this move while asleep")
|
|
else
|
|
score -= 50
|
|
MKAI.log("- 50 for this move will have no effect")
|
|
end
|
|
end
|
|
next score
|
|
end
|
|
|
|
|
|
# Prefer moves that can thaw the user if the user is frozen
|
|
MKAI::ScoreHandler.add do |score, ai, user, target, move|
|
|
# If the user is frozen and the move thaws the user
|
|
if user.frozen? && move.thawsUser?
|
|
score += 80
|
|
MKAI.log("+ 80 for being able to thaw the user")
|
|
end
|
|
next score
|
|
end
|
|
|
|
|
|
# Discourage using OHKO moves if the target is higher level or it has sturdy
|
|
MKAI::ScoreHandler.add do |score, ai, user, target, move|
|
|
if move.function == "070" # OHKO Move
|
|
if target.has_ability?(:STURDY)
|
|
score -= 100
|
|
MKAI.log("- 100 for the target has Sturdy")
|
|
end
|
|
if target.level > user.level
|
|
score -= 80
|
|
MKAI.log("- 80 for the move will fail due to level difference")
|
|
end
|
|
score -= 50
|
|
MKAI.log("- 50 for OHKO moves are generally considered bad")
|
|
end
|
|
next score
|
|
end
|
|
|
|
|
|
# Encourage using trapping moves, since they're generally weak
|
|
MKAI::ScoreHandler.add do |score, ai, user, target, move|
|
|
if move.function == "0CF" # Trapping Move
|
|
if target.effects[PBEffects::Trapping] == 0 # The target is not yet trapped
|
|
score += 60
|
|
MKAI.log("+ 60 for initiating a multi-turn trap")
|
|
end
|
|
end
|
|
next score
|
|
end
|
|
|
|
|
|
# Encourage using flinching moves if the user is faster
|
|
MKAI::ScoreHandler.add do |score, ai, user, target, move|
|
|
if move.flinchingMove? && (user.faster_than?(target) || move.priority > 0)
|
|
score += 50
|
|
MKAI.log("+ 50 for being able to flinch the target")
|
|
end
|
|
next score
|
|
end
|
|
|
|
|
|
# Discourage using a multi-hit physical move if the target has an item or ability
|
|
# that will damage the user on each contact.
|
|
# Also slightly discourages physical moves if the target has a bad ability in general.
|
|
MKAI::ScoreHandler.add do |score, ai, user, target, move|
|
|
if move.pbContactMove?(user)
|
|
if user.discourage_making_contact_with?(target)
|
|
if move.multiHitMove?
|
|
score -= 60
|
|
MKAI.log("- 60 for the target has an item or ability that activates on each contact")
|
|
else
|
|
score -= 30
|
|
MKAI.log("- 30 for the target has an item or ability that activates on contact")
|
|
end
|
|
end
|
|
end
|
|
next score
|
|
end
|
|
|
|
|
|
# Encourage using moves that can cause a burn.
|
|
MKAI::ScoreHandler.add do |score, ai, user, target, move|
|
|
if move.is_a?(PokeBattle_BurnMove) && !target.burned? && target.can_burn?(user, move)
|
|
chance = move.pbAdditionalEffectChance(user, target)
|
|
chance = 100 if chance == 0
|
|
if chance > 0 && chance <= 100
|
|
if target.is_physical_attacker?
|
|
add = 30 + chance * 2
|
|
score += add
|
|
MKAI.log("+ #{add} for being able to burn the physical-attacking target")
|
|
else
|
|
score += chance
|
|
MKAI.log("+ #{chance} for being able to burn the target")
|
|
end
|
|
end
|
|
end
|
|
next score
|
|
end
|
|
|
|
|
|
# Encourage using moves that can cause freezing.
|
|
MKAI::ScoreHandler.add do |score, ai, user, target, move|
|
|
if move.is_a?(PokeBattle_FreezeMove) && !target.frozen? && target.can_freeze?(user, move)
|
|
chance = move.pbAdditionalEffectChance(user, target)
|
|
chance = 100 if chance == 0
|
|
if chance > 0 && chance <= 100
|
|
score += chance * 2
|
|
MKAI.log("+ #{chance} for being able to freeze the target")
|
|
end
|
|
end
|
|
next score
|
|
end
|
|
|
|
|
|
# Encourage using moves that can cause paralysis.
|
|
MKAI::ScoreHandler.add do |score, ai, user, target, move|
|
|
if move.is_a?(PokeBattle_ParalysisMove) && !target.paralyzed? && target.can_paralyze?(user, move)
|
|
chance = move.pbAdditionalEffectChance(user, target)
|
|
chance = 100 if chance == 0
|
|
if chance > 0 && chance <= 100
|
|
score += chance
|
|
MKAI.log("+ #{chance} for being able to paralyze the target")
|
|
end
|
|
end
|
|
next score
|
|
end
|
|
|
|
|
|
# Encourage using moves that can cause sleep.
|
|
MKAI::ScoreHandler.add do |score, ai, user, target, move|
|
|
if move.is_a?(PokeBattle_SleepMove) && !target.asleep? && target.can_sleep?(user, move)
|
|
chance = move.pbAdditionalEffectChance(user, target)
|
|
chance = 100 if chance == 0
|
|
if chance > 0 && chance <= 100
|
|
score += chance
|
|
MKAI.log("+ #{chance} for being able to put the target to sleep")
|
|
end
|
|
end
|
|
next score
|
|
end
|
|
|
|
|
|
# Encourage using moves that can cause poison.
|
|
MKAI::ScoreHandler.add do |score, ai, user, target, move|
|
|
if move.is_a?(PokeBattle_PoisonMove) && !target.poisoned? && target.can_poison?(user, move)
|
|
chance = move.pbAdditionalEffectChance(user, target)
|
|
chance = 100 if chance == 0
|
|
if chance > 0 && chance <= 100
|
|
if move.toxic
|
|
add = chance * 1.4 * move.pbNumHits(user, [target])
|
|
score += add
|
|
MKAI.log("+ #{add} for being able to badly poison the target")
|
|
else
|
|
add = chance * move.pbNumHits(user, [target])
|
|
score += add
|
|
MKAI.log("+ #{add} for being able to poison the target")
|
|
end
|
|
end
|
|
end
|
|
next score
|
|
end
|
|
|
|
|
|
# Encourage using moves that can cause confusion.
|
|
MKAI::ScoreHandler.add do |score, ai, user, target, move|
|
|
if move.is_a?(PokeBattle_ConfuseMove) && !target.confused?
|
|
chance = move.pbAdditionalEffectChance(user, target)
|
|
chance = 100 if chance == 0
|
|
if chance > 0 && chance <= 100
|
|
add = chance * move.pbNumHits(user, [target])
|
|
# The higher the target's attack stats, the more beneficial it is to confuse the target.
|
|
stageMul = [2,2,2,2,2,2, 2, 3,4,5,6,7,8]
|
|
stageDiv = [8,7,6,5,4,3, 2, 2,2,2,2,2,2]
|
|
stage = target.stages[PBStats::ATTACK] + 6
|
|
factor = stageMul[stage] / stageDiv[stage].to_f
|
|
add *= factor
|
|
score += add
|
|
MKAI.log("+ #{add} for being able to confuse the target")
|
|
end
|
|
end
|
|
next score
|
|
end
|
|
|
|
|
|
#=============================================================================#
|
|
# #
|
|
# Damaging Moves #
|
|
# #
|
|
#=============================================================================#
|
|
|
|
|
|
# STAB modifier
|
|
MKAI::ScoreHandler.add_damaging do |score, ai, user, target, move|
|
|
# STAB doesn't add anything for fixed-damage moves.
|
|
next if move.is_a?(PokeBattle_FixedDamageMove)
|
|
calcType = move.pbCalcType(user.battler)
|
|
if calcType >= 0 && user.has_type?(calcType)
|
|
if user.has_ability?(:ADAPTABILITY)
|
|
MKAI.log("+ 90 for STAB with Adaptability")
|
|
score += 90
|
|
else
|
|
MKAI.log("+ 50 for STAB")
|
|
score += 50
|
|
end
|
|
end
|
|
next score
|
|
end
|
|
|
|
|
|
# Stat stages and physical/special attacker label
|
|
MKAI::ScoreHandler.add_damaging do |score, ai, user, target, move|
|
|
# Stat boosts don't add anything for fixed-damage moves.
|
|
next if move.is_a?(PokeBattle_FixedDamageMove)
|
|
# If the move is physical
|
|
if move.physicalMove?
|
|
# Increase the score by 25 per stage increase/decrease
|
|
if user.stages[PBStats::ATTACK] != 0
|
|
add = user.stages[PBStats::ATTACK] * 25
|
|
score += add
|
|
MKAI.log("#{add < 0 ? "-" : "+"} #{add.abs} for attack stages")
|
|
end
|
|
# Make the move more likely to be chosen if this user is also considered a physical attacker.
|
|
if user.is_physical_attacker?
|
|
score += 30
|
|
MKAI.log("+ 30 for being a physical attacker")
|
|
end
|
|
end
|
|
|
|
# If the move is special
|
|
if move.specialMove?
|
|
# Increase the score by 25 per stage increase/decrease
|
|
if user.stages[PBStats::SPATK] != 0
|
|
add = user.stages[PBStats::SPATK] * 25
|
|
score += add
|
|
MKAI.log("#{add < 0 ? "-" : "+"} #{add.abs} for attack stages")
|
|
end
|
|
# Make the move more likely to be chosen if this user is also considered a special attacker.
|
|
if user.is_special_attacker?
|
|
score += 30
|
|
MKAI.log("+ 30 for being a special attacker")
|
|
end
|
|
end
|
|
next score
|
|
end
|
|
|
|
|
|
# Discourage using damaging moves if the target is semi-invulnerable and slower,
|
|
# and encourage using damaging moves if they can break through the semi-invulnerability
|
|
# (e.g. prefer earthquake when target is underground)
|
|
MKAI::ScoreHandler.add_damaging do |score, ai, user, target, move|
|
|
# Target is semi-invulnerable
|
|
if target.semiInvulnerable? || target.effects[PBEffects::SkyDrop] >= 0
|
|
encourage = false
|
|
discourage = false
|
|
# User will hit first while target is still semi-invulnerable.
|
|
# If this move will do extra damage because the target is semi-invulnerable,
|
|
# encourage using this move. If not, discourage using it.
|
|
if user.faster_than?(target)
|
|
if target.in_two_turn_attack?("0C9", "0CC", "0CE") # Fly, Bounce, Sky Drop
|
|
encourage = move.hitsFlyingTargets?
|
|
discourage = !encourage
|
|
elsif target.in_two_turn_attack?("0CA") # Dig
|
|
# Do not encourage using Fissure, even though it can hit digging targets, because it's an OHKO move
|
|
encourage = move.hitsDiggingTargets? && move.function != "070"
|
|
discourage = !encourage
|
|
elsif target.in_two_turn_attack?("0CB") # Dive
|
|
encourage = move.hitsDivingTargets?
|
|
discourage = !encourage
|
|
else
|
|
discourage = true
|
|
end
|
|
end
|
|
# If the user has No Guard
|
|
if user.has_ability?(:NOGUARD)
|
|
# Then any move would be able to hit the target, meaning this move wouldn't be anything special.
|
|
encourage = false
|
|
discourage = false
|
|
end
|
|
if encourage
|
|
score += 100
|
|
MKAI.log("+ 100 for being able to hit through a semi-invulnerable state")
|
|
elsif discourage
|
|
score -= 150
|
|
MKAI.log("- 150 for not being able to hit target because of semi-invulnerability")
|
|
end
|
|
end
|
|
next score
|
|
end
|
|
|
|
|
|
# Lower the score of multi-turn moves, because they likely have quite high power and thus score.
|
|
MKAI::ScoreHandler.add_damaging do |score, ai, user, target, move|
|
|
if !user.has_item?(:POWERHERB) && (move.chargingTurnMove? || move.function == "0C2") # Hyper Beam
|
|
score -= 70
|
|
MKAI.log("- 70 for requiring a charging turn")
|
|
end
|
|
next score
|
|
end
|
|
|
|
|
|
# Prefer using damaging moves based on the level difference between the user and target,
|
|
# because if the user will get one-shot, then there's no point in using set-up moves.
|
|
# Furthermore, if the target is more than 5 levels higher than the user, priority
|
|
# get an additional boost to ensure the user can get a hit in before being potentially one-shot.
|
|
# TODO: Make "underdog" method, also for use by moves like perish song or explode and such
|
|
MKAI::ScoreHandler.add_damaging do |score, ai, user, target, move|
|
|
# Start counting factor this when there's a level difference of greater than 5
|
|
if user.underdog?(target)
|
|
add = 5 * (target.level - user.level - 5)
|
|
if add > 0
|
|
score += add
|
|
MKAI.log("+ #{5 * (target.level - user.level - 5)} for preferring damaging moves due to being a low level")
|
|
end
|
|
if move.priority > 0
|
|
score += 30
|
|
MKAI.log("+ 30 for being a priority move and being and underdog")
|
|
end
|
|
end
|
|
next score
|
|
end
|
|
|
|
|
|
# Discourage using physical moves when the user is burned
|
|
MKAI::ScoreHandler.add_damaging do |score, ai, user, target, move|
|
|
if user.burned?
|
|
if move.physicalMove? && move.function != "07E"
|
|
score -= 50
|
|
MKAI.log("- 50 for being a physical move and being burned")
|
|
end
|
|
end
|
|
next score
|
|
end
|
|
|
|
|
|
# Encourage high-critical hit rate moves, or damaging moves in general
|
|
# if Laser Focus or Focus Energy has been used
|
|
MKAI::ScoreHandler.add_damaging do |score, ai, user, target, move|
|
|
next if !move.pbCouldBeCritical?(user.battler, target.battler)
|
|
if move.highCriticalRate? || user.effects[PBEffects::LaserFocus] > 0 ||
|
|
user.effects[PBEffects::FocusEnergy] > 0
|
|
score += 30
|
|
MKAI.log("+ 30 for having a high critical-hit rate")
|
|
end
|
|
next score
|
|
end
|
|
|
|
|
|
# Discourage recoil moves if they would knock the user out
|
|
MKAI::ScoreHandler.add_damaging do |score, ai, user, target, move|
|
|
if move.is_a?(PokeBattle_RecoilMove)
|
|
dmg = move.pbRecoilDamage(user.battler, target.battler)
|
|
if dmg >= user.hp
|
|
score -= 50
|
|
MKAI.log("- 50 for the recoil will knock the user out")
|
|
end
|
|
end
|
|
next score
|
|
end
|
|
|
|
|
|
|
|
#=============================================================================#
|
|
# #
|
|
# Move-specific #
|
|
# #
|
|
#=============================================================================#
|
|
|
|
|
|
# Facade
|
|
MKAI::ScoreHandler.add("07E") do |score, ai, user, target, move|
|
|
if user.burned? || user.poisoned? || user.paralyzed?
|
|
score += 50
|
|
MKAI.log("+ 50 for doing more damage with a status condition")
|
|
end
|
|
next score
|
|
end
|
|
|
|
|
|
# Aromatherapy, Heal Bell
|
|
MKAI::ScoreHandler.add("019") do |score, ai, user, target, move|
|
|
count = 0
|
|
user.side.battlers.each do |proj|
|
|
next if proj.nil?
|
|
# + 80 for each active battler with a status condition
|
|
count += 2.0 if proj.has_non_volatile_status?
|
|
end
|
|
user.side.party.each do |proj|
|
|
next if proj.battler # Skip battlers
|
|
# Inactive party members do not have a battler attached,
|
|
# so we can't use has_non_volatile_status?
|
|
count += 1.0 if proj.pokemon.status > 0
|
|
# + 40 for each inactive pokemon with a status condition in the party
|
|
end
|
|
if count != 0
|
|
add = count * 40.0
|
|
score += add
|
|
MKAI.log("+ #{add} for curing status condition(s)")
|
|
else
|
|
score -= 30
|
|
MKAI.log("- 30 for not curing any status conditions")
|
|
end
|
|
next score
|
|
end
|
|
|
|
|
|
# Psycho Shift
|
|
MKAI::ScoreHandler.add("01B") do |score, ai, user, target, move|
|
|
# If the user has a status condition that is not frozen,
|
|
if user.has_non_volatile_status? && !user.frozen?
|
|
# And the target doesn't have any status conditions
|
|
if !target.has_non_volatile_status?
|
|
# Then we can transfer our status condition
|
|
transferrable = true
|
|
transferrable = false if user.burned? && !target.can_burn?(user, move)
|
|
transferrable = false if user.poisoned? && !target.can_poison?(user, move)
|
|
transferrable = false if user.paralyzed? && !target.can_paralyze?(user, move)
|
|
transferrable = false if user.asleep? && !target.can_sleep?(user, move)
|
|
if transferrable
|
|
score += 120
|
|
MKAI.log("+ 120 for being able to pass on our status condition")
|
|
if user.burned? && target.is_physical_attacker?
|
|
score += 50
|
|
MKAI.log("+ 50 for being able to burn the physical-attacking target")
|
|
end
|
|
end
|
|
end
|
|
else
|
|
score -= 30
|
|
MKAI.log("- 30 for not having a transferrable status condition")
|
|
end
|
|
next score
|
|
end
|
|
|
|
|
|
# Purify
|
|
MKAI::ScoreHandler.add("15B") do |score, ai, user, target, move|
|
|
if target.has_non_volatile_status?
|
|
factor = 1 - user.hp / user.totalhp.to_f
|
|
# At full hp, factor is 0 (thus not encouraging this move)
|
|
# At half hp, factor is 0.5 (thus slightly encouraging this move)
|
|
# At 1 hp, factor is about 1.0 (thus encouraging this move)
|
|
if user.flags[:will_be_healed]
|
|
score -= 30
|
|
MKAI.log("- 30 for the user will already be healed by something")
|
|
elsif factor != 0
|
|
if user.is_healing_pointless?(0.5)
|
|
score -= 10
|
|
MKAI.log("- 10 for we will take more damage than we can heal if the target repeats their move")
|
|
elsif user.is_healing_necessary?(0.5)
|
|
add = (factor * 250).round
|
|
score += add
|
|
MKAI.log("+ #{add} for we will likely die without healing")
|
|
else
|
|
add = (factor * 125).round
|
|
score += add
|
|
MKAI.log("+ #{add} for we have lost some hp")
|
|
end
|
|
end
|
|
else
|
|
score -= 30
|
|
MKAI.log("- 30 for the move will fail since the target has no status condition")
|
|
end
|
|
next score
|
|
end
|
|
|
|
|
|
# Refresh
|
|
MKAI::ScoreHandler.add("018") do |score, ai, user, target, move|
|
|
if user.burned? || user.poisoned? || user.paralyzed?
|
|
score += 70
|
|
MKAI.log("+ 70 for being able to cure our status condition")
|
|
end
|
|
next score
|
|
end
|
|
|
|
|
|
# Rest
|
|
MKAI::ScoreHandler.add("0D9") do |score, ai, user, target, move|
|
|
factor = 1 - user.hp / user.totalhp.to_f
|
|
if user.flags[:will_be_healed]
|
|
score -= 30
|
|
MKAI.log("- 30 for the user will already be healed by something")
|
|
elsif factor != 0
|
|
# Not at full hp
|
|
if user.can_sleep?(user, move, true)
|
|
add = (factor * 100).round
|
|
score += add
|
|
MKAI.log("+ #{add} for we have lost some hp")
|
|
else
|
|
score -= 10
|
|
MKAI.log("- 10 for the move will fail")
|
|
end
|
|
end
|
|
next score
|
|
end
|
|
|
|
|
|
# Smelling Salts
|
|
MKAI::ScoreHandler.add("07C") do |score, ai, user, target, move|
|
|
if target.paralyzed?
|
|
score += 50
|
|
MKAI.log("+ 50 for doing double damage")
|
|
end
|
|
next score
|
|
end
|
|
|
|
|
|
# Wake-Up Slap
|
|
MKAI::ScoreHandler.add("07D") do |score, ai, user, target, move|
|
|
if target.asleep?
|
|
score += 50
|
|
MKAI.log("+ 50 for doing double damage")
|
|
end
|
|
next score
|
|
end
|
|
|
|
|
|
# Fire Fang, Flare Blitz
|
|
MKAI::ScoreHandler.add("00B", "0FE") do |score, ai, user, target, move|
|
|
if !target.burned? && target.can_burn?(user, move)
|
|
if target.is_physical_attacker?
|
|
score += 40
|
|
MKAI.log("+ 40 for being able to burn the physical-attacking target")
|
|
else
|
|
score += 10
|
|
MKAI.log("+ 10 for being able to burn the target")
|
|
end
|
|
end
|
|
next score
|
|
end
|
|
|
|
|
|
# Ice Fang
|
|
MKAI::ScoreHandler.add("00E") do |score, ai, user, target, move|
|
|
if !target.frozen? && target.can_freeze?(user, move)
|
|
score += 20
|
|
MKAI.log("+ 20 for being able to freeze the target")
|
|
end
|
|
next score
|
|
end
|
|
|
|
|
|
# Thunder Fang
|
|
MKAI::ScoreHandler.add("009") do |score, ai, user, target, move|
|
|
if !target.paralyzed? && target.can_paralyze?(user, move)
|
|
score += 10
|
|
MKAI.log("+ 10 for being able to paralyze the target")
|
|
end
|
|
next score
|
|
end
|
|
|
|
|
|
# Ice Burn
|
|
MKAI::ScoreHandler.add("0C6") do |score, ai, user, target, move|
|
|
if !target.burned? && target.can_burn?(user, move)
|
|
if target.is_physical_attacker?
|
|
score += 80
|
|
MKAI.log("+ 80 for being able to burn the physical-attacking target")
|
|
else
|
|
score += 30
|
|
MKAI.log("+ 30 for being able to burn the target")
|
|
end
|
|
end
|
|
next score
|
|
end
|
|
|
|
|
|
# Secret Power
|
|
MKAI::ScoreHandler.add("0A4") do |score, ai, user, target, move|
|
|
score += 40
|
|
MKAI.log("+ 40 for its potential side effects")
|
|
next score
|
|
end
|
|
|
|
|
|
# Tri Attack
|
|
MKAI::ScoreHandler.add("017") do |score, ai, user, target, move|
|
|
if !target.has_non_volatile_status?
|
|
score += 50
|
|
MKAI.log("+ 50 for being able to cause a status condition")
|
|
end
|
|
next score
|
|
end
|
|
|
|
|
|
# Freeze Shock, Bounce
|
|
MKAI::ScoreHandler.add("0C5", "0CC") do |score, ai, user, target, move|
|
|
if !target.paralyzed? && target.can_paralyze?(user, move)
|
|
score += 30
|
|
MKAI.log("+ 30 for being able to paralyze the target")
|
|
end
|
|
next score
|
|
end
|
|
|
|
|
|
# Volt Tackle
|
|
MKAI::ScoreHandler.add("0FD") do |score, ai, user, target, move|
|
|
if !target.paralyzed? && target.can_paralyze?(user, move)
|
|
score += 10
|
|
MKAI.log("+ 10 for being able to paralyze the target")
|
|
end
|
|
next score
|
|
end
|
|
|
|
|
|
# Toxic Thread
|
|
MKAI::ScoreHandler.add("159") do |score, ai, user, target, move|
|
|
if !target.paralyzed? && target.can_paralyze?(user, move)
|
|
score += 50
|
|
MKAI.log("+ 50 for being able to poison the target")
|
|
end
|
|
if target.battler.pbCanLowerStatStage?(PBStats::SPEED, user, move) &&
|
|
target.faster_than?(user)
|
|
score += 30
|
|
MKAI.log("+ 30 for being able to lower target speed")
|
|
end
|
|
next score
|
|
end
|
|
|
|
|
|
# Dark Void
|
|
MKAI::ScoreHandler.add(:DARKVOID) do |score, ai, user, target, move|
|
|
if user.is_species?(:DARKRAI)
|
|
if !target.asleep? && target.can_sleep?(user, move)
|
|
score += 120
|
|
MKAI.log("+ 120 for damaging the target with Nightmare if it is asleep")
|
|
end
|
|
else
|
|
score -= 100
|
|
MKAI.log("- 100 for this move will fail")
|
|
end
|
|
next score
|
|
end
|
|
|
|
|
|
# Yawn
|
|
MKAI::ScoreHandler.add("004") do |score, ai, user, target, move|
|
|
if !target.has_non_volatile_status? && target.effects[PBEffects::Yawn] == 0
|
|
score += 60
|
|
MKAI.log("+ 60 for putting the target to sleep")
|
|
end
|
|
next score
|
|
end
|
|
|
|
|
|
# Flatter
|
|
MKAI::ScoreHandler.add("040") do |score, ai, user, target, move|
|
|
if target.confused?
|
|
score -= 30
|
|
MKAI.log("- 30 for only raising target stats without being able to confuse it")
|
|
else
|
|
score += 30
|
|
MKAI.log("+ 30 for confusing the target")
|
|
end
|
|
next score
|
|
end
|
|
|
|
|
|
# Swagger
|
|
MKAI::ScoreHandler.add("041") do |score, ai, user, target, move|
|
|
if target.confused?
|
|
score -= 50
|
|
MKAI.log("- 50 for only raising target stats without being able to confuse it")
|
|
else
|
|
score += 50
|
|
MKAI.log("+ 50 for confusing the target")
|
|
if !target.is_physical_attacker?
|
|
score += 50
|
|
MKAI.log("+ 50 for the target also is not a physical attacker")
|
|
end
|
|
end
|
|
next score
|
|
end
|
|
|
|
|
|
# Attract
|
|
MKAI::ScoreHandler.add("016") do |score, ai, user, target, move|
|
|
# If the target can be attracted by the user
|
|
if target.can_attract?(user)
|
|
score += 150
|
|
MKAI.log("+ 150 for being able to attract the target")
|
|
end
|
|
next score
|
|
end
|
|
|
|
|
|
# Rage
|
|
MKAI::ScoreHandler.add("093") do |score, ai, user, target, move|
|
|
dmg = user.get_move_damage(target, move)
|
|
perc = dmg / target.totalhp.to_f
|
|
perc /= 1.5 if user.discourage_making_contact_with?(target)
|
|
score += perc * 150
|
|
next score
|
|
end
|
|
|
|
|
|
# Uproar, Thrash, Petal Dance, Outrage, Ice Ball, Rollout
|
|
MKAI::ScoreHandler.add("0D1", "0D2", "0D3") do |score, ai, user, target, move|
|
|
dmg = user.get_move_damage(target, move)
|
|
perc = dmg / target.totalhp.to_f
|
|
perc /= 1.5 if user.discourage_making_contact_with?(target) && move.pbContactMove?(user)
|
|
if perc != 0
|
|
add = perc * 80
|
|
score += add
|
|
MKAI.log("+ #{add} for dealing about #{(perc * 100).round}% dmg")
|
|
end
|
|
next score
|
|
end
|
|
|
|
|
|
# Stealth Rock, Spikes, Toxic Spikes
|
|
MKAI::ScoreHandler.add("103", "104", "105") do |score, ai, user, target, move|
|
|
if move.function == "103" && user.opposing_side.effects[PBEffects::Spikes] >= 3 ||
|
|
move.function == "104" && user.opposing_side.effects[PBEffects::ToxicSpikes] >= 2 ||
|
|
move.function == "105" && user.opposing_side.effects[PBEffects::StealthRock]
|
|
score -= 30
|
|
MKAI.log("- 30 for the opposing side already has max spikes")
|
|
else
|
|
inactive = user.opposing_side.party.size - user.opposing_side.battlers.compact.size
|
|
add = inactive * 30
|
|
add *= (3 - user.opposing_side.effects[PBEffects::Spikes]) / 3.0 if move.function == "103"
|
|
add *= 3 / 4.0 if user.opposing_side.effects[PBEffects::ToxicSpikes] == 1 && move.function == "104"
|
|
score += add
|
|
MKAI.log("+ #{add} for there are #{inactive} pokemon to be sent out at some point")
|
|
end
|
|
next score
|
|
end
|
|
|
|
|
|
# Disable
|
|
MKAI::ScoreHandler.add("0B9") do |score, ai, user, target, move|
|
|
# Already disabled one of the target's moves
|
|
if target.effects[PBEffects::Disable] > 1
|
|
score -= 30
|
|
MKAI.log("- 30 for the target is already disabled")
|
|
else
|
|
# Get previous damage done by the target
|
|
prevDmg = target.get_damage_by_user(user)
|
|
if prevDmg.size > 0
|
|
lastDmg = prevDmg[-1]
|
|
# If the last move did more than 50% damage and the target was faster,
|
|
# we can't disable the move in time thus using Disable is pointless.
|
|
if user.is_healing_pointless?(0.5) && target.faster_than?(user)
|
|
score -= 30
|
|
MKAI.log("- 30 for the target move is too strong and the target is faster")
|
|
else
|
|
add = (lastDmg[3] * 150).round
|
|
score += add
|
|
MKAI.log("+ #{add} for we disable a strong move")
|
|
end
|
|
else
|
|
# Target hasn't used a damaging move yet
|
|
score -= 30
|
|
MKAI.log("- 30 for the target hasn't used a damaging move yet.")
|
|
end
|
|
end
|
|
next score
|
|
end
|
|
|
|
|
|
# Counter
|
|
MKAI::ScoreHandler.add("071") do |score, ai, user, target, move|
|
|
expect = false
|
|
expect = true if target.is_physical_attacker? && !target.is_healing_necessary?(0.5)
|
|
prevDmg = user.get_damage_by_user(target)
|
|
if prevDmg.size > 0
|
|
lastDmg = prevDmg[-1]
|
|
lastMove = lastDmg[1]
|
|
expect = true if lastMove.physicalMove?
|
|
end
|
|
# If we can reasonably expect the target to use a physical move
|
|
if expect
|
|
score += 60
|
|
MKAI.log("+ 60 for we can reasonably expect the target to use a physical move")
|
|
end
|
|
next score
|
|
end
|
|
|
|
|
|
# Aqua Ring
|
|
MKAI::ScoreHandler.add("0DA") do |score, ai, user, target, move|
|
|
if !user.effects[PBEffects::AquaRing]
|
|
if !user.underdog?(target)
|
|
score += 80
|
|
MKAI.log("+ 80 for gaining hp each round")
|
|
else
|
|
# Underdogs are likely to die fast, so setting up healing for each round
|
|
# is likely useless and only a waste of a turn.
|
|
score += 40
|
|
MKAI.log("+ 40 for gaining hp each round despite being an underdog")
|
|
end
|
|
else
|
|
score -= 30
|
|
MKAI.log("- 30 for the user already has an aqua ring")
|
|
end
|
|
next score
|
|
end
|
|
|
|
|
|
# Ingrain
|
|
MKAI::ScoreHandler.add("0DB") do |score, ai, user, target, move|
|
|
if !user.effects[PBEffects::Ingrain]
|
|
if !user.underdog?(target)
|
|
score += 80
|
|
MKAI.log("+ 80 for gaining hp each round")
|
|
else
|
|
# Underdogs are likely to die fast, so setting up healing for each round
|
|
# is likely useless and only a waste of a turn.
|
|
score += 40
|
|
MKAI.log("+ 40 for gaining hp each round despite being an underdog")
|
|
end
|
|
else
|
|
score -= 30
|
|
MKAI.log("- 30 for the user is already ingrained")
|
|
end
|
|
next score
|
|
end
|
|
|
|
|
|
# Leech Seed
|
|
MKAI::ScoreHandler.add("0DC") do |score, ai, user, target, move|
|
|
if !user.underdog?(target) && !target.has_type?(:GRASS) && target.effects[PBEffects::LeechSeed] == 0
|
|
score += 60
|
|
MKAI.log("+ 60 for sapping hp from the target")
|
|
end
|
|
next score
|
|
end
|
|
|
|
|
|
# Leech Life, Parabolic Charge, Drain Punch, Giga Drain, Horn Leech, Mega Drain, Absorb
|
|
MKAI::ScoreHandler.add("0DD") do |score, ai, user, target, move|
|
|
dmg = user.get_move_damage(target, move)
|
|
add = dmg / 2
|
|
score += add
|
|
MKAI.log("+ #{add} for hp gained")
|
|
next score
|
|
end
|
|
|
|
|
|
# Dream Eater
|
|
MKAI::ScoreHandler.add("0DE") do |score, ai, user, target, move|
|
|
if target.asleep?
|
|
dmg = user.get_move_damage(target, move)
|
|
add = dmg / 2
|
|
score += add
|
|
MKAI.log("+ #{add} for hp gained")
|
|
else
|
|
score -= 30
|
|
MKAI.log("- 30 for the move will fail")
|
|
end
|
|
next score
|
|
end
|
|
|
|
|
|
# Heal Pulse
|
|
MKAI::ScoreHandler.add("0DF") do |score, ai, user, target, move|
|
|
# If the target is an ally
|
|
ally = false
|
|
target.battler.eachAlly do |battler|
|
|
ally = true if battler == user.battler
|
|
end
|
|
if ally
|
|
factor = 1 - target.hp / target.totalhp.to_f
|
|
# At full hp, factor is 0 (thus not encouraging this move)
|
|
# At half hp, factor is 0.5 (thus slightly encouraging this move)
|
|
# At 1 hp, factor is about 1.0 (thus encouraging this move)
|
|
if target.flags[:will_be_healed]
|
|
score -= 30
|
|
MKAI.log("- 30 for the target will already be healed by something")
|
|
elsif factor != 0
|
|
if target.is_healing_pointless?(0.5)
|
|
score -= 10
|
|
MKAI.log("- 10 for the target will take more damage than we can heal if the opponent repeats their move")
|
|
elsif target.is_healing_necessary?(0.5)
|
|
add = (factor * 250).round
|
|
score += add
|
|
MKAI.log("+ #{add} for the target will likely die without healing")
|
|
else
|
|
add = (factor * 125).round
|
|
score += add
|
|
MKAI.log("+ #{add} for the target has lost some hp")
|
|
end
|
|
else
|
|
score -= 30
|
|
MKAI.log("- 30 for the target is at full hp")
|
|
end
|
|
else
|
|
score -= 30
|
|
MKAI.log("- 30 for the target is not an ally")
|
|
end
|
|
next score
|
|
end
|
|
|
|
|
|
# Whirlwind, Roar, Circle Throw, Dragon Tail, U-Turn, Volt Switch
|
|
MKAI::ScoreHandler.add("0EB", "0EC", "0EE") do |score, ai, user, target, move|
|
|
if user.bad_against?(target) && user.level >= target.level &&
|
|
!target.has_ability?(:SUCTIONCUPS) && !target.effects[PBEffects::Ingrain]
|
|
score += 100
|
|
MKAI.log("+ 100 for forcing our target to switch and we're bad against our target")
|
|
end
|
|
next score
|
|
end
|
|
|
|
|
|
# Anchor Shot, Block, Mean Look, Spider Web, Spirit Shackle, Thousand Waves
|
|
MKAI::ScoreHandler.add("0EF") do |score, ai, user, target, move|
|
|
if target.bad_against?(user) && !target.has_type?(:GHOST)
|
|
score += 100
|
|
MKAI.log("+ 100 for locking our target in battle with us and they're bad against us")
|
|
end
|
|
next score
|
|
end
|
|
|
|
|
|
# Mimic
|
|
MKAI::ScoreHandler.add("05C") do |score, ai, user, target, move|
|
|
blacklisted = ["002", "014", "05C", "05D", "0B6"] # Struggle, Chatter, Mimic, Sketch, Metronome
|
|
last_move = pbGetMoveData(target.battler.lastRegularMoveUsed)
|
|
# Don't mimic if no move has been used or we can't mimic the move
|
|
if target.battler.lastRegularMoveUsed <= 0 || blacklisted.include?(last_move[MOVE_FUNCTION_CODE])
|
|
score -= 30
|
|
MKAI.log("- 30 for we can't mimic any move used prior")
|
|
else
|
|
move_id = last_move[MOVE_ID]
|
|
matchup = target.calculate_move_matchup(move_id)
|
|
# If our target used a move that would also be super effective against them,
|
|
# it would be a good idea to mimic that move now so we can use it against them.
|
|
if matchup > 1
|
|
add = (matchup * 75.0).round
|
|
score += add
|
|
MKAI.log("+ #{add} for we can mimic a move that would be super effective against the target too.")
|
|
end
|
|
end
|
|
next score
|
|
end
|
|
|
|
|
|
# Recover, Slack Off, Soft-Boiled, Heal Order, Milk Drink, Roost, Wish
|
|
MKAI::ScoreHandler.add("0D5", "0D6", "0D7") do |score, ai, user, target, move|
|
|
factor = 1 - user.hp / user.totalhp.to_f
|
|
# At full hp, factor is 0 (thus not encouraging this move)
|
|
# At half hp, factor is 0.5 (thus slightly encouraging this move)
|
|
# At 1 hp, factor is about 1.0 (thus encouraging this move)
|
|
if user.flags[:will_be_healed]
|
|
score -= 30
|
|
MKAI.log("- 30 for the user will already be healed by something")
|
|
elsif factor != 0
|
|
if user.is_healing_pointless?(0.5)
|
|
score -= 10
|
|
MKAI.log("- 10 for we will take more damage than we can heal if the target repeats their move")
|
|
elsif user.is_healing_necessary?(0.5)
|
|
add = (factor * 250).round
|
|
score += add
|
|
MKAI.log("+ #{add} for we will likely die without healing")
|
|
else
|
|
add = (factor * 125).round
|
|
score += add
|
|
MKAI.log("+ #{add} for we have lost some hp")
|
|
end
|
|
else
|
|
score -= 30
|
|
MKAI.log("- 30 for we are at full hp")
|
|
end
|
|
next score
|
|
end
|
|
|
|
|
|
# Moonlight, Morning Sun, Synthesis
|
|
MKAI::ScoreHandler.add("0D8") do |score, ai, user, target, move|
|
|
heal_factor = 0.5
|
|
case ai.battle.pbWeather
|
|
when PBWeather::Sun, PBWeather::HarshSun
|
|
heal_factor = 2.0 / 3.0
|
|
when PBWeather::None, PBWeather::StrongWinds
|
|
heal_factor = 0.5
|
|
else
|
|
heal_factor = 0.25
|
|
end
|
|
effi_factor = 1.0
|
|
effi_factor = 0.5 if heal_factor == 0.25
|
|
factor = 1 - user.hp / user.totalhp.to_f
|
|
# At full hp, factor is 0 (thus not encouraging this move)
|
|
# At half hp, factor is 0.5 (thus slightly encouraging this move)
|
|
# At 1 hp, factor is about 1.0 (thus encouraging this move)
|
|
if user.flags[:will_be_healed]
|
|
score -= 30
|
|
MKAI.log("- 30 for the user will already be healed by something")
|
|
elsif factor != 0
|
|
if user.is_healing_pointless?(heal_factor)
|
|
score -= 10
|
|
MKAI.log("- 10 for we will take more damage than we can heal if the target repeats their move")
|
|
elsif user.is_healing_necessary?(heal_factor)
|
|
add = (factor * 250 * effi_factor).round
|
|
score += add
|
|
MKAI.log("+ #{add} for we will likely die without healing")
|
|
else
|
|
add = (factor * 125 * effi_factor).round
|
|
score += add
|
|
MKAI.log("+ #{add} for we have lost some hp")
|
|
end
|
|
else
|
|
score -= 30
|
|
MKAI.log("- 30 for we are at full hp")
|
|
end
|
|
next score
|
|
end
|
|
|
|
|
|
# Minimize
|
|
MKAI::ScoreHandler.add("034") do |score, ai, user, target, move|
|
|
accuracy = false
|
|
double = false
|
|
target.side.battlers.any? do |proj|
|
|
accuracy = true if proj.moves.any? { |move| move.tramplesMinimize?(1) && !proj.target_is_immune?(move, user) }
|
|
double = true if proj.moves.any? { |move| move.tramplesMinimize?(2) && !proj.target_is_immune?(move, user) }
|
|
end
|
|
if accuracy
|
|
score -= 40
|
|
MKAI.log("- 40 for the target has moves that will hit with perfect accuracy against minimized targets")
|
|
end
|
|
if double
|
|
score -= 90
|
|
MKAI.log("- 90 for the target has moves that will deal double damage against minimized targets")
|
|
end
|
|
next score
|
|
end
|
|
|
|
|
|
# Lucky Chant
|
|
MKAI::ScoreHandler.add("0A1") do |score, ai, user, target, move|
|
|
if user.side.effects[PBEffects::LuckyChant] > 0
|
|
score -= 30
|
|
MKAI.log("- 30 for lucky chant is already active")
|
|
elsif user.side.flags[:will_luckychant]
|
|
score -= 30
|
|
MKAI.log("- 30 for another battler will already use lucky chant")
|
|
else
|
|
enemies = target.side.battlers.select { |proj| !proj.fainted? }.size
|
|
critenemies = target.side.battlers.select { |proj| proj.moves.any? { |m| m.highCriticalRate? } }.size
|
|
add = enemies * 20 + critenemies * 30
|
|
score += add
|
|
MKAI.log("+ #{add} based on enemy and high-crit-dealing enemy moves count")
|
|
end
|
|
next score
|
|
end
|
|
|
|
|
|
# Reflect
|
|
MKAI::ScoreHandler.add("0A2") do |score, ai, user, target, move|
|
|
if user.side.effects[PBEffects::Reflect] > 0
|
|
score -= 30
|
|
MKAI.log("- 30 for reflect is already active")
|
|
elsif user.side.flags[:will_reflect]
|
|
score -= 30
|
|
MKAI.log("- 30 for another battler will already use reflect")
|
|
else
|
|
enemies = target.side.battlers.select { |proj| !proj.fainted? }.size
|
|
physenemies = target.side.battlers.select { |proj| proj.is_physical_attacker? }.size
|
|
add = enemies * 20 + physenemies * 30
|
|
score += add
|
|
MKAI.log("+ #{add} based on enemy and physical enemy count")
|
|
end
|
|
next score
|
|
end
|
|
|
|
|
|
# Light Screen
|
|
MKAI::ScoreHandler.add("0A3") do |score, ai, user, target, move|
|
|
if user.side.effects[PBEffects::LightScreen] > 0
|
|
score -= 30
|
|
MKAI.log("- 30 for light screen is already active")
|
|
elsif user.side.flags[:will_lightscreen]
|
|
score -= 30
|
|
MKAI.log("- 30 for another battler will already use light screen")
|
|
else
|
|
enemies = target.side.battlers.select { |proj| !proj.fainted? }.size
|
|
specenemies = target.side.battlers.select { |proj| proj.is_special_attacker? }.size
|
|
add = enemies * 20 + specenemies * 30
|
|
score += add
|
|
MKAI.log("+ #{add} based on enemy and special enemy count")
|
|
end
|
|
next score
|
|
end
|
|
|
|
|
|
# Haze
|
|
MKAI::ScoreHandler.add("051") do |score, ai, user, target, move|
|
|
if user.side.flags[:will_haze]
|
|
score -= 30
|
|
MKAI.log("- 30 for another battler will already use haze")
|
|
else
|
|
net = 0
|
|
# User buffs: net goes up
|
|
# User debuffs: net goes down
|
|
# Target buffs: net goes down
|
|
# Target debuffs: net goes up
|
|
# The lower net is, the better Haze is to choose.
|
|
user.side.battlers.each do |proj|
|
|
PBStats.eachBattleStat { |s| net += proj.stages[s] }
|
|
end
|
|
target.side.battlers.each do |proj|
|
|
PBStats.eachBattleStat { |s| net -= proj.stages[s] }
|
|
end
|
|
# As long as the target's stat stages are more advantageous than ours (i.e. net < 0), Haze is a good choice
|
|
if net < 0
|
|
add = -net * 20
|
|
score += add
|
|
MKAI.log("+ #{add} to reset disadvantageous stat stages")
|
|
else
|
|
score -= 30
|
|
MKAI.log("- 30 for our stat stages are advantageous")
|
|
end
|
|
end
|
|
next score
|
|
end
|
|
|
|
|
|
# Bide
|
|
MKAI::ScoreHandler.add("0D4") do |score, ai, user, target, move|
|
|
# If we've been hit at least once, use Bide if we could take two hits of the last attack and survive
|
|
prevDmg = target.get_damage_by_user(user)
|
|
if prevDmg.size > 0
|
|
lastDmg = prevDmg[-1]
|
|
predDmg = lastDmg[2] * 2
|
|
# We would live if we took two hits of the last move
|
|
if user.hp - predDmg > 0
|
|
score += 120
|
|
MKAI.log("+ 120 for we can survive two subsequent attacks")
|
|
else
|
|
score -= 10
|
|
MKAI.log("- 10 for we would not survive two subsequent attacks")
|
|
end
|
|
else
|
|
score -= 10
|
|
MKAI.log("- 10 for we don't know whether we'd survive two subsequent attacks")
|
|
end
|
|
next score
|
|
end
|
|
|
|
|
|
# Metronome
|
|
MKAI::ScoreHandler.add("0B6") do |score, ai, user, target, move|
|
|
score += 20
|
|
MKAI.log("+ 20 to make this move an option if all other choices also have a low score")
|
|
next score
|
|
end
|
|
|
|
|
|
# Mirror Move
|
|
MKAI::ScoreHandler.add("0AE") do |score, ai, user, target, move|
|
|
if target.battler.lastRegularMoveUsed <= 0 || target.faster_than?(user)
|
|
score -= 10
|
|
MKAI.log("- 10 for we don't know what move our target will use")
|
|
elsif target.battler.lastRegularMoveUsed <= 0 && user.faster_than?(target)
|
|
score -= 30
|
|
MKAI.log("- 30 for our target has not made a move yet")
|
|
else
|
|
# Can Mirror Move
|
|
if pbGetMoveData(target.battler.lastRegularMoveUsed, MOVE_FLAGS)[/e/]
|
|
matchup = target.calculate_move_matchup(pbGetMoveData(target.battler.lastRegularMoveUsed, MOVE_ID))
|
|
# Super Effective
|
|
if matchup > 1
|
|
add = (matchup * 75.0).round
|
|
score += add
|
|
MKAI.log("+ #{add} for being able to mirror a super effective move")
|
|
else
|
|
score -= 30
|
|
MKAI.log("- 30 for we would likely mirror a not very effective move")
|
|
end
|
|
else
|
|
score -= 30
|
|
MKAI.log("- 30 for we would not be able to mirror the move the target will likely use")
|
|
end
|
|
end
|
|
next score
|
|
end |