Renamed/rearranged some script files

This commit is contained in:
Maruno17
2023-04-23 18:04:32 +01:00
parent ce549ab62a
commit b7a40d0344
34 changed files with 0 additions and 0 deletions

View File

@@ -0,0 +1,741 @@
#===============================================================================
#
#===============================================================================
# None
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveEffectScore.add("DoesNothingCongratulations",
proc { |score, move, user, ai, battle|
next Battle::AI::MOVE_USELESS_SCORE
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveEffectScore.copy("DoesNothingCongratulations",
"DoesNothingFailsIfNoAlly")
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveEffectScore.copy("DoesNothingCongratulations",
"DoesNothingUnusableInGravity")
#===============================================================================
#
#===============================================================================
# AddMoneyGainedFromBattle
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveEffectScore.copy("DoesNothingCongratulations",
"DoubleMoneyGainedFromBattle")
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.add("FailsIfNotUserFirstTurn",
proc { |move, user, ai, battle|
next user.turnCount > 0
}
)
Battle::AI::Handlers::MoveEffectScore.add("FailsIfNotUserFirstTurn",
proc { |score, move, user, ai, battle|
next score + 25 # Use it or lose it
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.add("FailsIfUserHasUnusedMove",
proc { |move, user, ai, battle|
has_another_move = false
has_unused_move = false
user.battler.eachMove do |m|
next if m.id == move.id
has_another_move = true
next if user.battler.movesUsed.include?(m.id)
has_unused_move = true
break
end
next !has_another_move || has_unused_move
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.add("FailsIfUserNotConsumedBerry",
proc { |move, user, ai, battle|
next !user.battler.belched?
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("FailsIfTargetHasNoItem",
proc { |move, user, target, ai, battle|
next !target.item || !target.item_active?
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("FailsUnlessTargetSharesTypeWithUser",
proc { |move, user, target, ai, battle|
user_types = user.pbTypes(true)
target_types = target.pbTypes(true)
next (user_types & target_types).empty?
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("FailsIfUserDamagedThisTurn",
proc { |score, move, user, target, ai, battle|
# Check whether user is faster than its foe(s) and could use this move
user_faster_count = 0
foe_faster_count = 0
ai.each_foe_battler(user.side) do |b, i|
if user.faster_than?(b)
user_faster_count += 1
else
foe_faster_count += 1
end
end
next Battle::AI::MOVE_USELESS_SCORE if user_faster_count == 0
score += 15 if foe_faster_count == 0
# Effects that make the target unlikely to act before the user
if ai.trainer.high_skill?
if !target.can_attack?
score += 15
elsif target.effects[PBEffects::Confusion] > 1 ||
target.effects[PBEffects::Attract] == user.index
score += 10
elsif target.battler.paralyzed?
score += 5
end
end
# Don't risk using this move if target is weak
if ai.trainer.has_skill_flag?("HPAware")
score -= 10 if target.hp <= target.totalhp / 2
score -= 10 if target.hp <= target.totalhp / 4
end
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("FailsIfTargetActed",
proc { |score, move, user, target, ai, battle|
# Check whether user is faster than its foe(s) and could use this move
next Battle::AI::MOVE_USELESS_SCORE if target.faster_than?(user)
# TODO: Predict the target switching/using an item.
# TODO: Predict the target using a damaging move or Me First.
# Don't risk using this move if target is weak
if ai.trainer.has_skill_flag?("HPAware")
score -= 10 if target.hp <= target.totalhp / 2
score -= 10 if target.hp <= target.totalhp / 4
end
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("CrashDamageIfFailsUnusableInGravity",
proc { |score, move, user, target, ai, battle|
if user.battler.takesIndirectDamage?
score -= (0.4 * (100 - move.rough_accuracy)).to_i # -0 (100%) to -40 (1%)
end
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.add("StartSunWeather",
proc { |move, user, ai, battle|
next [:HarshSun, :HeavyRain, :StrongWinds, move.move.weatherType].include?(battle.field.weather)
}
)
Battle::AI::Handlers::MoveEffectScore.add("StartSunWeather",
proc { |score, move, user, ai, battle|
next Battle::AI::MOVE_USELESS_SCORE if battle.pbCheckGlobalAbility(:AIRLOCK) ||
battle.pbCheckGlobalAbility(:CLOUDNINE)
# Not worth it at lower HP
if ai.trainer.has_skill_flag?("HPAware")
score -= 10 if user.hp < user.totalhp / 2
end
if ai.trainer.high_skill? && battle.field.weather != :None
score -= ai.get_score_for_weather(battle.field.weather, user)
end
score += ai.get_score_for_weather(:Sun, user, true)
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.copy("StartSunWeather",
"StartRainWeather")
Battle::AI::Handlers::MoveEffectScore.add("StartRainWeather",
proc { |score, move, user, ai, battle|
next Battle::AI::MOVE_USELESS_SCORE if battle.pbCheckGlobalAbility(:AIRLOCK) ||
battle.pbCheckGlobalAbility(:CLOUDNINE)
# Not worth it at lower HP
if ai.trainer.has_skill_flag?("HPAware")
score -= 10 if user.hp < user.totalhp / 2
end
if ai.trainer.high_skill? && battle.field.weather != :None
score -= ai.get_score_for_weather(battle.field.weather, user)
end
score += ai.get_score_for_weather(:Rain, user, true)
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.copy("StartSunWeather",
"StartSandstormWeather")
Battle::AI::Handlers::MoveEffectScore.add("StartSandstormWeather",
proc { |score, move, user, ai, battle|
next Battle::AI::MOVE_USELESS_SCORE if battle.pbCheckGlobalAbility(:AIRLOCK) ||
battle.pbCheckGlobalAbility(:CLOUDNINE)
# Not worth it at lower HP
if ai.trainer.has_skill_flag?("HPAware")
score -= 10 if user.hp < user.totalhp / 2
end
if ai.trainer.high_skill? && battle.field.weather != :None
score -= ai.get_score_for_weather(battle.field.weather, user)
end
score += ai.get_score_for_weather(:Sandstorm, user, true)
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.copy("StartSunWeather",
"StartHailWeather")
Battle::AI::Handlers::MoveEffectScore.add("StartHailWeather",
proc { |score, move, user, ai, battle|
next Battle::AI::MOVE_USELESS_SCORE if battle.pbCheckGlobalAbility(:AIRLOCK) ||
battle.pbCheckGlobalAbility(:CLOUDNINE)
# Not worth it at lower HP
if ai.trainer.has_skill_flag?("HPAware")
score -= 10 if user.hp < user.totalhp / 2
end
if ai.trainer.high_skill? && battle.field.weather != :None
score -= ai.get_score_for_weather(battle.field.weather, user)
end
score += ai.get_score_for_weather(:Hail, user, true)
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.add("StartElectricTerrain",
proc { |move, user, ai, battle|
next battle.field.terrain == :Electric
}
)
Battle::AI::Handlers::MoveEffectScore.add("StartElectricTerrain",
proc { |score, move, user, ai, battle|
# Not worth it at lower HP
if ai.trainer.has_skill_flag?("HPAware")
score -= 10 if user.hp < user.totalhp / 2
end
if ai.trainer.high_skill? && battle.field.terrain != :None
score -= ai.get_score_for_terrain(battle.field.terrain, user)
end
score += ai.get_score_for_terrain(:Electric, user, true)
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.add("StartGrassyTerrain",
proc { |move, user, ai, battle|
next battle.field.terrain == :Grassy
}
)
Battle::AI::Handlers::MoveEffectScore.add("StartGrassyTerrain",
proc { |score, move, user, ai, battle|
# Not worth it at lower HP
if ai.trainer.has_skill_flag?("HPAware")
score -= 10 if user.hp < user.totalhp / 2
end
if ai.trainer.high_skill? && battle.field.terrain != :None
score -= ai.get_score_for_terrain(battle.field.terrain, user)
end
score += ai.get_score_for_terrain(:Grassy, user, true)
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.add("StartMistyTerrain",
proc { |move, user, ai, battle|
next battle.field.terrain == :Misty
}
)
Battle::AI::Handlers::MoveEffectScore.add("StartMistyTerrain",
proc { |score, move, user, ai, battle|
# Not worth it at lower HP
if ai.trainer.has_skill_flag?("HPAware")
score -= 10 if user.hp < user.totalhp / 2
end
if ai.trainer.high_skill? && battle.field.terrain != :None
score -= ai.get_score_for_terrain(battle.field.terrain, user)
end
score += ai.get_score_for_terrain(:Misty, user, true)
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.add("StartPsychicTerrain",
proc { |move, user, ai, battle|
next battle.field.terrain == :Psychic
}
)
Battle::AI::Handlers::MoveEffectScore.add("StartPsychicTerrain",
proc { |score, move, user, ai, battle|
# Not worth it at lower HP
if ai.trainer.has_skill_flag?("HPAware")
score -= 10 if user.hp < user.totalhp / 2
end
if ai.trainer.high_skill? && battle.field.terrain != :None
score -= ai.get_score_for_terrain(battle.field.terrain, user)
end
score += ai.get_score_for_terrain(:Psychic, user, true)
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.add("RemoveTerrain",
proc { |move, user, ai, battle|
next battle.field.terrain == :None
}
)
Battle::AI::Handlers::MoveEffectScore.add("RemoveTerrain",
proc { |score, move, user, ai, battle|
next score - ai.get_score_for_terrain(battle.field.terrain, user)
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.add("AddSpikesToFoeSide",
proc { |move, user, ai, battle|
next user.pbOpposingSide.effects[PBEffects::Spikes] >= 3
}
)
Battle::AI::Handlers::MoveEffectScore.add("AddSpikesToFoeSide",
proc { |score, move, user, ai, battle|
inBattleIndices = battle.allSameSideBattlers(user.idxOpposingSide).map { |b| b.pokemonIndex }
foe_reserves = []
battle.pbParty(user.idxOpposingSide).each_with_index do |pkmn, idxParty|
next if !pkmn || !pkmn.able? || inBattleIndices.include?(idxParty)
if ai.trainer.medium_skill?
# Check affected by entry hazard
next if pkmn.hasItem?(:HEAVYDUTYBOOTS)
# Check can take indirect damage
next if pkmn.hasAbility?(:MAGICGUARD)
# Check airborne
if !pkmn.hasItem?(:IRONBALL) &&
battle.field.effects[PBEffects::Gravity] == 0
next if pkmn.hasType?(:FLYING)
next if pkmn.hasAbility?(:LEVITATE)
next if pkmn.hasItem?(:AIRBALLOON)
end
end
foe_reserves.push(pkmn) # pkmn will be affected by Spikes
end
next Battle::AI::MOVE_USELESS_SCORE if foe_reserves.empty?
multiplier = [10, 7, 5][user.pbOpposingSide.effects[PBEffects::Spikes]]
score += [multiplier * foe_reserves.length, 30].min
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.add("AddToxicSpikesToFoeSide",
proc { |move, user, ai, battle|
next user.pbOpposingSide.effects[PBEffects::ToxicSpikes] >= 2
}
)
Battle::AI::Handlers::MoveEffectScore.add("AddToxicSpikesToFoeSide",
proc { |score, move, user, ai, battle|
inBattleIndices = battle.allSameSideBattlers(user.idxOpposingSide).map { |b| b.pokemonIndex }
foe_reserves = []
battle.pbParty(user.idxOpposingSide).each_with_index do |pkmn, idxParty|
next if !pkmn || !pkmn.able? || inBattleIndices.include?(idxParty)
if ai.trainer.medium_skill?
# Check affected by entry hazard
next if pkmn.hasItem?(:HEAVYDUTYBOOTS)
# Check pkmn's immunity to being poisoned
next if battle.field.terrain == :Misty
next if pkmn.hasType?(:POISON)
next if pkmn.hasType?(:STEEL)
next if pkmn.hasAbility?(:IMMUNITY)
next if pkmn.hasAbility?(:PASTELVEIL)
next if pkmn.hasAbility?(:FLOWERVEIL) && pkmn.hasType?(:GRASS)
next if pkmn.hasAbility?(:LEAFGUARD) && [:Sun, :HarshSun].include?(battle.pbWeather)
next if pkmn.hasAbility?(:COMATOSE) && pkmn.isSpecies?(:KOMALA)
next if pkmn.hasAbility?(:SHIELDSDOWN) && pkmn.isSpecies?(:MINIOR) && pkmn.form < 7
# Check airborne
if !pkmn.hasItem?(:IRONBALL) &&
battle.field.effects[PBEffects::Gravity] == 0
next if pkmn.hasType?(:FLYING)
next if pkmn.hasAbility?(:LEVITATE)
next if pkmn.hasItem?(:AIRBALLOON)
end
end
foe_reserves.push(pkmn) # pkmn will be affected by Toxic Spikes
end
next Battle::AI::MOVE_USELESS_SCORE if foe_reserves.empty?
multiplier = [8, 5][user.pbOpposingSide.effects[PBEffects::ToxicSpikes]]
score += [multiplier * foe_reserves.length, 30].min
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.add("AddStealthRocksToFoeSide",
proc { |move, user, ai, battle|
next user.pbOpposingSide.effects[PBEffects::StealthRock]
}
)
Battle::AI::Handlers::MoveEffectScore.add("AddStealthRocksToFoeSide",
proc { |score, move, user, ai, battle|
inBattleIndices = battle.allSameSideBattlers(user.idxOpposingSide).map { |b| b.pokemonIndex }
foe_reserves = []
battle.pbParty(user.idxOpposingSide).each_with_index do |pkmn, idxParty|
next if !pkmn || !pkmn.able? || inBattleIndices.include?(idxParty)
if ai.trainer.medium_skill?
# Check affected by entry hazard
next if pkmn.hasItem?(:HEAVYDUTYBOOTS)
# Check can take indirect damage
next if pkmn.hasAbility?(:MAGICGUARD)
end
foe_reserves.push(pkmn) # pkmn will be affected by Stealth Rock
end
next Battle::AI::MOVE_USELESS_SCORE if foe_reserves.empty?
score += [10 * foe_reserves.length, 30].min
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.add("AddStickyWebToFoeSide",
proc { |move, user, ai, battle|
next user.pbOpposingSide.effects[PBEffects::StickyWeb]
}
)
Battle::AI::Handlers::MoveEffectScore.add("AddStickyWebToFoeSide",
proc { |score, move, user, ai, battle|
inBattleIndices = battle.allSameSideBattlers(user.idxOpposingSide).map { |b| b.pokemonIndex }
foe_reserves = []
battle.pbParty(user.idxOpposingSide).each_with_index do |pkmn, idxParty|
next if !pkmn || !pkmn.able? || inBattleIndices.include?(idxParty)
if ai.trainer.medium_skill?
# Check affected by entry hazard
next if pkmn.hasItem?(:HEAVYDUTYBOOTS)
# Check airborne
if !pkmn.hasItem?(:IRONBALL) &&
battle.field.effects[PBEffects::Gravity] == 0
next if pkmn.hasType?(:FLYING)
next if pkmn.hasAbility?(:LEVITATE)
next if pkmn.hasItem?(:AIRBALLOON)
end
end
foe_reserves.push(pkmn) # pkmn will be affected by Sticky Web
end
next Battle::AI::MOVE_USELESS_SCORE if foe_reserves.empty?
score += [8 * foe_reserves.length, 30].min
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.add("SwapSideEffects",
proc { |move, user, ai, battle|
has_effect = false
2.times do |side|
effects = battle.sides[side].effects
move.move.number_effects.each do |e|
next if effects[e] == 0
has_effect = true
break
end
break if has_effect
move.move.boolean_effects.each do |e|
next if !effects[e]
has_effect = true
break
end
break if has_effect
end
next !has_effect
}
)
Battle::AI::Handlers::MoveEffectScore.add("SwapSideEffects",
proc { |score, move, user, ai, battle|
if ai.trainer.medium_skill?
good_effects = [:AuroraVeil, :LightScreen, :Mist, :Rainbow, :Reflect,
:Safeguard, :SeaOfFire, :Swamp, :Tailwind].map! { |e| PBEffects.const_get(e) }
bad_effects = [:Spikes, :StealthRock, :StickyWeb, :ToxicSpikes].map! { |e| PBEffects.const_get(e) }
bad_effects.each do |e|
score += 10 if ![0, false, nil].include?(user.pbOwnSide.effects[e])
score -= 10 if ![0, 1, false, nil].include?(user.pbOpposingSide.effects[e])
end
if ai.trainer.high_skill?
good_effects.each do |e|
score += 10 if ![0, 1, false, nil].include?(user.pbOpposingSide.effects[e])
score -= 10 if ![0, false, nil].include?(user.pbOwnSide.effects[e])
end
end
end
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.add("UserMakeSubstitute",
proc { |move, user, ai, battle|
next true if user.effects[PBEffects::Substitute] > 0
next user.hp <= [user.totalhp / 4, 1].max
}
)
Battle::AI::Handlers::MoveEffectScore.add("UserMakeSubstitute",
proc { |score, move, user, ai, battle|
# Prefer more the higher the user's HP
if ai.trainer.has_skill_flag?("HPAware")
score += (10 * user.hp.to_f / user.totalhp).round
end
# Prefer if foes don't know any moves that can bypass a substitute
ai.each_foe_battler(user.side) do |b, i|
score += 5 if !b.check_for_move { |m| m.ignoresSubstitute?(b.battler) }
end
# Prefer if the user lost more than a Substitute's worth of HP from the last
# attack against it
score += 7 if user.battler.lastHPLost >= user.totalhp / 4
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveEffectScore.add("RemoveUserBindingAndEntryHazards",
proc { |score, move, user, ai, battle|
# Score for raising user's Speed
if Settings::MECHANICS_GENERATION >= 8
score = Battle::AI::Handlers.apply_move_effect_score("RaiseUserSpeed1",
score, move, user, ai, battle)
end
# Score for removing various effects
score += 10 if user.effects[PBEffects::Trapping] > 0
score += 15 if user.effects[PBEffects::LeechSeed] >= 0
if battle.pbAbleNonActiveCount(user.idxOwnSide) > 0
score += 15 if user.pbOwnSide.effects[PBEffects::Spikes] > 0
score += 15 if user.pbOwnSide.effects[PBEffects::ToxicSpikes] > 0
score += 20 if user.pbOwnSide.effects[PBEffects::StealthRock]
score += 15 if user.pbOwnSide.effects[PBEffects::StickyWeb]
end
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("AttackTwoTurnsLater",
proc { |move, user, target, ai, battle|
next battle.positions[target.index].effects[PBEffects::FutureSightCounter] > 0
}
)
Battle::AI::Handlers::MoveEffectScore.add("AttackTwoTurnsLater",
proc { |score, move, user, ai, battle|
# Future Sight tends to be wasteful if down to last Pokémon
score -= 20 if battle.pbAbleNonActiveCount(user.idxOwnSide) == 0
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.add("UserSwapsPositionsWithAlly",
proc { |move, user, ai, battle|
num_targets = 0
idxUserOwner = battle.pbGetOwnerIndexFromBattlerIndex(user.index)
ai.each_ally(user.side) do |b, i|
next if battle.pbGetOwnerIndexFromBattlerIndex(b.index) != idxUserOwner
next if !b.battler.near?(user.battler)
num_targets += 1
end
next num_targets != 1
}
)
Battle::AI::Handlers::MoveEffectScore.add("UserSwapsPositionsWithAlly",
proc { |score, move, user, ai, battle|
next score - 30 # Usually no point in using this
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveEffectScore.add("BurnAttackerBeforeUserActs",
proc { |score, move, user, ai, battle|
ai.each_foe_battler(user.side) do |b|
next if !b.battler.affectedByContactEffect?
next if !b.battler.pbCanBurn?(user.battler, false, move.move)
if ai.trainer.high_skill?
next if !b.check_for_move { |m| m.pbContactMove?(b.battler) }
end
score += 10 # Possible to burn
end
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveEffectScore.add("AllBattlersLoseHalfHPUserSkipsNextTurn",
proc { |score, move, user, ai, battle|
# HP halving
foe_hp_lost = 0
ally_hp_lost = 0
ai.each_battler do |b, i|
next if b.hp == 1
if b.battler.opposes?(user.battler)
foe_hp_lost += b.hp / 2
else
ally_hp_lost += b.hp / 2
end
end
score += 20 * foe_hp_lost / ally_hp_lost
score -= 20 * ally_hp_lost / foe_hp_lost
# Recharging
score = Battle::AI::Handlers.apply_move_effect_score("AttackAndSkipNextTurn",
score, move, user, ai, battle)
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveEffectScore.add("UserLosesHalfHP",
proc { |score, move, user, ai, battle|
score = Battle::AI::Handlers.apply_move_effect_score("UserLosesHalfOfTotalHP",
score, move, user, ai, battle)
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.copy("StartSunWeather",
"StartShadowSkyWeather")
Battle::AI::Handlers::MoveEffectScore.add("StartShadowSkyWeather",
proc { |score, move, user, ai, battle|
next Battle::AI::MOVE_USELESS_SCORE if battle.pbCheckGlobalAbility(:AIRLOCK) ||
battle.pbCheckGlobalAbility(:CLOUDNINE)
# Not worth it at lower HP
if ai.trainer.has_skill_flag?("HPAware")
score -= 15 if user.hp < user.totalhp / 2
end
if ai.trainer.high_skill? && battle.field.weather != :None
score -= ai.get_score_for_weather(battle.field.weather, user)
end
score += ai.get_score_for_weather(:ShadowSky, user, true)
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.add("RemoveAllScreensAndSafeguard",
proc { |move, user, ai, battle|
will_fail = true
battle.sides.each do |side|
will_fail = false if side.effects[PBEffects::AuroraVeil] > 0 ||
side.effects[PBEffects::LightScreen] > 0 ||
side.effects[PBEffects::Reflect] > 0 ||
side.effects[PBEffects::Safeguard] > 0
end
next will_fail
}
)
Battle::AI::Handlers::MoveEffectScore.add("RemoveAllScreensAndSafeguard",
proc { |score, move, user, ai, battle|
foe_side = user.pbOpposingSide
# Useless if the foe's side has no screens/Safeguard to remove, or if
# they'll end this round anyway
if foe_side.effects[PBEffects::AuroraVeil] <= 1 &&
foe_side.effects[PBEffects::LightScreen] <= 1 &&
foe_side.effects[PBEffects::Reflect] <= 1 &&
foe_side.effects[PBEffects::Safeguard] <= 1
next Battle::AI::MOVE_USELESS_SCORE
end
# Prefer removing opposing screens
score = Battle::AI::Handlers.apply_move_effect_score("RemoveScreens",
score, move, user, ai, battle)
# Don't prefer removing same side screens
ai.each_foe_battler(user.side) do |b, i|
score -= Battle::AI::Handlers.apply_move_effect_score("RemoveScreens",
0, move, b, ai, battle)
break
end
# Safeguard
score += 10 if foe_side.effects[PBEffects::Safeguard] > 0
score -= 10 if user.pbOwnSide.effects[PBEffects::Safeguard] > 0
next score
}
)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,534 @@
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveBasePower.add("HitTwoTimes",
proc { |power, move, user, target, ai, battle|
next power * move.move.pbNumHits(user.battler, [target.battler])
}
)
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("HitTwoTimes",
proc { |score, move, user, target, ai, battle|
# Prefer if the target has a Substitute and this move can break it before
# the last hit
if target.effects[PBEffects::Substitute] > 0 && !move.move.ignoresSubstitute?(user.battler)
dmg = move.rough_damage
num_hits = move.move.pbNumHits(user.battler, [target.battler])
score += 10 if target.effects[PBEffects::Substitute] < dmg * (num_hits - 1) / num_hits
end
# TODO: Consider effects that trigger per hit.
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveBasePower.copy("HitTwoTimes",
"HitTwoTimesPoisonTarget")
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("HitTwoTimesPoisonTarget",
proc { |score, move, user, target, ai, battle|
# Score for hitting multiple times
score = Battle::AI::Handlers.apply_move_effect_against_target_score("HitTwoTimes",
score, move, user, target, ai, battle)
# Score for poisoning
poison_score = Battle::AI::Handlers.apply_move_effect_against_target_score("PoisonTarget",
0, move, user, target, ai, battle)
score += poison_score if poison_score != Battle::AI::MOVE_USELESS_SCORE
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveBasePower.copy("HitTwoTimes",
"HitTwoTimesFlinchTarget")
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("HitTwoTimesFlinchTarget",
proc { |score, move, user, target, ai, battle|
# Score for hitting multiple times
score = Battle::AI::Handlers.apply_move_effect_against_target_score("HitTwoTimes",
score, move, user, target, ai, battle)
# Score for flinching
score = Battle::AI::Handlers.apply_move_effect_against_target_score("FlinchTarget",
score, move, user, target, ai, battle)
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveBasePower.add("HitTwoTimesTargetThenTargetAlly",
proc { |power, move, user, target, ai, battle|
next power * 2
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveBasePower.add("HitThreeTimesPowersUpWithEachHit",
proc { |power, move, user, target, ai, battle|
next power * 6 # Hits do x1, x2, x3 ret in turn, for x6 in total
}
)
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("HitThreeTimesPowersUpWithEachHit",
proc { |score, move, user, target, ai, battle|
# Prefer if the target has a Substitute and this move can break it before
# the last hit
if target.effects[PBEffects::Substitute] > 0 && !move.move.ignoresSubstitute?(user.battler)
dmg = move.rough_damage
score += 10 if target.effects[PBEffects::Substitute] < dmg / 2
end
# TODO: Consider effects that trigger per hit.
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveBasePower.copy("HitTwoTimes",
"HitThreeTimesAlwaysCriticalHit")
Battle::AI::Handlers::MoveEffectAgainstTargetScore.copy("HitTwoTimes",
"HitThreeTimesAlwaysCriticalHit")
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveBasePower.add("HitTwoToFiveTimes",
proc { |power, move, user, target, ai, battle|
next power * 5 if user.has_active_ability?(:SKILLLINK)
next power * 31 / 10 # Average damage dealt
}
)
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("HitTwoToFiveTimes",
proc { |score, move, user, target, ai, battle|
# Prefer if the target has a Substitute and this move can break it before
# the last/third hit
if target.effects[PBEffects::Substitute] > 0 && !move.move.ignoresSubstitute?(user.battler)
dmg = move.rough_damage
num_hits = (user.has_active_ability?(:SKILLLINK)) ? 5 : 3 # 3 is about average
score += 10 if target.effects[PBEffects::Substitute] < dmg * (num_hits - 1) / num_hits
end
# TODO: Consider effects that trigger per hit.
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveBasePower.add("HitTwoToFiveTimesOrThreeForAshGreninja",
proc { |power, move, user, target, ai, battle|
if user.battler.isSpecies?(:GRENINJA) && user.battler.form == 2
next move.move.pbBaseDamage(power, user.battler, target.battler) * move.move.pbNumHits(user.battler, [target.battler])
end
next power * 5 if user.has_active_ability?(:SKILLLINK)
next power * 31 / 10 # Average damage dealt
}
)
Battle::AI::Handlers::MoveEffectAgainstTargetScore.copy("HitTwoToFiveTimes",
"HitTwoToFiveTimesOrThreeForAshGreninja")
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveBasePower.copy("HitTwoToFiveTimes",
"HitTwoToFiveTimesRaiseUserSpd1LowerUserDef1")
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("HitTwoToFiveTimesRaiseUserSpd1LowerUserDef1",
proc { |score, move, user, target, ai, battle|
# Score for being a multi-hit attack
score = Battle::AI::Handlers.apply_move_effect_against_target_score("HitTwoToFiveTimes",
score, move, user, target, ai, battle)
# Score for user's stat changes
score = ai.get_score_for_target_stat_raise(score, user, [:SPEED, 1], false)
score = ai.get_score_for_target_stat_drop(score, user, [:DEFENSE, 1], false)
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.add("HitOncePerUserTeamMember",
proc { |move, user, ai, battle|
will_fail = true
battle.eachInTeamFromBattlerIndex(user.index) do |pkmn, i|
next if !pkmn.able? || pkmn.status != :NONE
will_fail = false
break
end
next will_fail
}
)
Battle::AI::Handlers::MoveBasePower.add("HitOncePerUserTeamMember",
proc { |power, move, user, target, ai, battle|
ret = 0
battle.eachInTeamFromBattlerIndex(user.index) do |pkmn, _i|
ret += 5 + (pkmn.baseStats[:ATTACK] / 10) if pkmn.able? && pkmn.status == :NONE
end
next ret
}
)
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("HitOncePerUserTeamMember",
proc { |score, move, user, target, ai, battle|
# Prefer if the target has a Substitute and this move can break it before
# the last hit
if target.effects[PBEffects::Substitute] > 0 && !move.move.ignoresSubstitute?(user.battler)
dmg = move.rough_damage
num_hits = 0
battle.eachInTeamFromBattlerIndex(user.index) do |pkmn, _i|
num_hits += 1 if pkmn.able? && pkmn.status == :NONE
end
score += 10 if target.effects[PBEffects::Substitute] < dmg * (num_hits - 1) / num_hits
end
# TODO: Consider effects that trigger per hit.
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveEffectScore.add("AttackAndSkipNextTurn",
proc { |score, move, user, ai, battle|
# Don't prefer if user is at a high HP (treat this move as a last resort)
if ai.trainer.has_skill_flag?("HPAware")
score -= 10 if user.hp >= user.totalhp / 2
end
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("TwoTurnAttack",
proc { |score, move, user, target, ai, battle|
# Power Herb makes this a 1 turn move, the same as a move with no effect
next score if user.has_active_item?(:POWERHERB)
# Treat as a failure if user has Truant (the charging turn has no effect)
next Battle::AI::MOVE_USELESS_SCORE if user.has_active_ability?(:TRUANT)
# Useless if user will faint from EoR damage before finishing this attack
next Battle::AI::MOVE_USELESS_SCORE if user.rough_end_of_round_damage >= user.hp
# Don't prefer because it uses up two turns
score -= 10
# Don't prefer if user is at a low HP (time is better spent on quicker moves)
if ai.trainer.has_skill_flag?("HPAware")
score -= 10 if user.hp < user.totalhp / 2
end
# Don't prefer if target has a protecting move
if ai.trainer.high_skill? && !(user.has_active_ability?(:UNSEENFIST) && move.move.contactMove?)
has_protect_move = false
if move.pbTarget(user).num_targets > 1 &&
(Settings::MECHANICS_GENERATION >= 7 || move.damagingMove?)
if target.has_move_with_function?("ProtectUserSideFromMultiTargetDamagingMoves")
has_protect_move = true
end
end
if move.move.canProtectAgainst?
if target.has_move_with_function?("ProtectUser",
"ProtectUserFromTargetingMovesSpikyShield",
"ProtectUserBanefulBunker")
has_protect_move = true
end
if move.damagingMove?
# NOTE: Doesn't check for Mat Block because it only works on its
# user's first turn in battle, so it can't be used in response
# to this move charging up.
if target.has_move_with_function?("ProtectUserFromDamagingMovesKingsShield",
"ProtectUserFromDamagingMovesObstruct")
has_protect_move = true
end
end
if move.rough_priority(user) > 0
if target.has_move_with_function?("ProtectUserSideFromPriorityMoves")
has_protect_move = true
end
end
end
score -= 20 if has_protect_move
end
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveBasePower.add("TwoTurnAttackOneTurnInSun",
proc { |power, move, user, target, ai, battle|
next move.move.pbBaseDamageMultiplier(power, user.battler, target.battler)
}
)
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("TwoTurnAttackOneTurnInSun",
proc { |score, move, user, target, ai, battle|
# In sunny weather this a 1 turn move, the same as a move with no effect
next score if [:Sun, :HarshSun].include?(user.battler.effectiveWeather)
# Score for being a two turn attack
next Battle::AI::Handlers.apply_move_effect_against_target_score("TwoTurnAttack",
score, move, user, target, ai, battle)
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("TwoTurnAttackParalyzeTarget",
proc { |score, move, user, target, ai, battle|
# Score for being a two turn attack
score = Battle::AI::Handlers.apply_move_effect_against_target_score("TwoTurnAttack",
score, move, user, target, ai, battle)
next score if score == Battle::AI::MOVE_USELESS_SCORE
# Score for paralysing
score = Battle::AI::Handlers.apply_move_effect_against_target_score("ParalyzeTarget",
score, move, user, target, ai, battle)
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("TwoTurnAttackBurnTarget",
proc { |score, move, user, target, ai, battle|
# Score for being a two turn attack
score = Battle::AI::Handlers.apply_move_effect_against_target_score("TwoTurnAttack",
score, move, user, target, ai, battle)
next score if score == Battle::AI::MOVE_USELESS_SCORE
# Score for burning
score = Battle::AI::Handlers.apply_move_effect_against_target_score("BurnTarget",
score, move, user, target, ai, battle)
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("TwoTurnAttackFlinchTarget",
proc { |score, move, user, target, ai, battle|
# Score for being a two turn attack
score = Battle::AI::Handlers.apply_move_effect_against_target_score("TwoTurnAttack",
score, move, user, target, ai, battle)
next score if score == Battle::AI::MOVE_USELESS_SCORE
# Score for flinching
score = Battle::AI::Handlers.apply_move_effect_against_target_score("FlinchTarget",
score, move, user, target, ai, battle)
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.copy("RaiseUserAtkDef1",
"TwoTurnAttackRaiseUserSpAtkSpDefSpd2")
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("TwoTurnAttackRaiseUserSpAtkSpDefSpd2",
proc { |score, move, user, target, ai, battle|
# Score for being a two turn attack
score = Battle::AI::Handlers.apply_move_effect_against_target_score("TwoTurnAttack",
score, move, user, target, ai, battle)
next score if score == Battle::AI::MOVE_USELESS_SCORE
# Score for raising user's stats
score = ai.get_score_for_target_stat_raise(score, user, move.move.statUp)
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("TwoTurnAttackChargeRaiseUserDefense1",
proc { |score, move, user, target, ai, battle|
# Score for being a two turn attack
score = Battle::AI::Handlers.apply_move_effect_against_target_score("TwoTurnAttack",
score, move, user, target, ai, battle)
next score if score == Battle::AI::MOVE_USELESS_SCORE
# Score for raising the user's stat
score = Battle::AI::Handlers.apply_move_effect_score("RaiseUserDefense1",
score, move, user, ai, battle)
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("TwoTurnAttackChargeRaiseUserSpAtk1",
proc { |score, move, user, target, ai, battle|
# Score for being a two turn attack
score = Battle::AI::Handlers.apply_move_effect_against_target_score("TwoTurnAttack",
score, move, user, target, ai, battle)
next score if score == Battle::AI::MOVE_USELESS_SCORE
# Score for raising the user's stat
score = Battle::AI::Handlers.apply_move_effect_score("RaiseUserSpAtk1",
score, move, user, ai, battle)
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("TwoTurnAttackInvulnerableUnderground",
proc { |score, move, user, target, ai, battle|
# Score for being a two turn attack
score = Battle::AI::Handlers.apply_move_effect_against_target_score("TwoTurnAttack",
score, move, user, target, ai, battle)
next score if score == Battle::AI::MOVE_USELESS_SCORE
# Score for being semi-invulnerable underground
ai.each_foe_battler(user.side) do |b, i|
if b.check_for_move { |m| m.hitsDiggingTargets? }
score -= 10
else
score += 8
end
end
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("TwoTurnAttackInvulnerableUnderwater",
proc { |score, move, user, target, ai, battle|
# Score for being a two turn attack
score = Battle::AI::Handlers.apply_move_effect_against_target_score("TwoTurnAttack",
score, move, user, target, ai, battle)
next score if score == Battle::AI::MOVE_USELESS_SCORE
# Score for being semi-invulnerable underwater
ai.each_foe_battler(user.side) do |b, i|
if b.check_for_move { |m| m.hitsDivingTargets? }
score -= 10
else
score += 8
end
end
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("TwoTurnAttackInvulnerableInSky",
proc { |score, move, user, target, ai, battle|
# Score for being a two turn attack
score = Battle::AI::Handlers.apply_move_effect_against_target_score("TwoTurnAttack",
score, move, user, target, ai, battle)
next score if score == Battle::AI::MOVE_USELESS_SCORE
# Score for being semi-invulnerable in the sky
ai.each_foe_battler(user.side) do |b, i|
if b.check_for_move { |m| m.hitsFlyingTargets? }
score -= 10
else
score += 8
end
end
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("TwoTurnAttackInvulnerableInSkyParalyzeTarget",
proc { |score, move, user, target, ai, battle|
# Score for being a two turn attack and semi-invulnerable in the sky
score = Battle::AI::Handlers.apply_move_effect_against_target_score("TwoTurnAttackInvulnerableInSky",
score, move, user, target, ai, battle)
next score if score == Battle::AI::MOVE_USELESS_SCORE
# Score for paralyzing the target
score = Battle::AI::Handlers.apply_move_effect_against_target_score("ParalyzeTarget",
score, move, user, target, ai, battle)
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("TwoTurnAttackInvulnerableInSkyTargetCannotAct",
proc { |move, user, target, ai, battle|
next true if !target.opposes?(user)
next true if target.effects[PBEffects::Substitute] > 0 && !move.move.ignoresSubstitute?(user.battler)
next true if Settings::MECHANICS_GENERATION >= 6 && target.battler.pbWeight >= 2000 # 200.0kg
next true if target.battler.semiInvulnerable? || target.effects[PBEffects::SkyDrop] >= 0
next false
}
)
Battle::AI::Handlers::MoveEffectAgainstTargetScore.copy("TwoTurnAttackInvulnerableInSky",
"TwoTurnAttackInvulnerableInSkyTargetCannotAct")
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("TwoTurnAttackInvulnerableRemoveProtections",
proc { |score, move, user, target, ai, battle|
# Score for being a two turn attack
score = Battle::AI::Handlers.apply_move_effect_against_target_score("TwoTurnAttack",
score, move, user, target, ai, battle)
next score if score == Battle::AI::MOVE_USELESS_SCORE
# Score for being invulnerable
score += 8
# Score for removing protections
score = Battle::AI::Handlers.apply_move_effect_against_target_score("RemoveProtections",
score, move, user, target, ai, battle)
next score
}
)
#===============================================================================
#
#===============================================================================
# MultiTurnAttackPreventSleeping
#===============================================================================
#
#===============================================================================
# MultiTurnAttackConfuseUserAtEnd
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveBasePower.add("MultiTurnAttackPowersUpEachTurn",
proc { |power, move, user, target, ai, battle|
# NOTE: The * 2 (roughly) incorporates the higher damage done in subsequent
# rounds. It is nearly the average damage this move will do per round,
# assuming it hits for 3 rounds (hoping for hits in all 5 rounds is
# optimistic).
next move.move.pbBaseDamage(power, user.battler, target.battler) * 2
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveBasePower.add("MultiTurnAttackBideThenReturnDoubleDamage",
proc { |power, move, user, target, ai, battle|
next 40 # Representative value
}
)
Battle::AI::Handlers::MoveEffectScore.add("MultiTurnAttackBideThenReturnDoubleDamage",
proc { |score, move, user, ai, battle|
# Useless if no foe has any damaging moves
has_damaging_move = false
ai.each_foe_battler(user.side) do |b, i|
next if b.status == :SLEEP && b.statusCount > 2
next if b.status == :FROZEN
has_damaging_move = true if b.check_for_move { |m| m.damagingMove? }
break if has_damaging_move
end
next Battle::AI::MOVE_USELESS_SCORE if !has_damaging_move
# Don't prefer if the user isn't at high HP
if ai.trainer.has_skill_flag?("HPAware")
next Battle::AI::MOVE_USELESS_SCORE if user.hp <= user.totalhp / 4
score -= 15 if user.hp <= user.totalhp / 2
score -= 8 if user.hp <= user.totalhp * 3 / 4
end
next score
}
)

View File

@@ -0,0 +1,683 @@
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.add("HealUserFullyAndFallAsleep",
proc { |move, user, ai, battle|
next true if !user.battler.canHeal?
next true if user.battler.asleep?
next true if !user.battler.pbCanSleep?(user.battler, false, move.move, true)
next false
}
)
Battle::AI::Handlers::MoveEffectScore.add("HealUserFullyAndFallAsleep",
proc { |score, move, user, ai, battle|
# Consider how much HP will be restored
if ai.trainer.has_skill_flag?("HPAware")
if user.hp >= user.totalhp * 0.5
score -= 10
else
score += 30 * (user.totalhp - user.hp) / user.totalhp # +15 to +30
end
end
# Check whether an existing status problem will be removed
if user.status != :NONE
score += (user.wants_status_problem?(user.status)) ? -10 : 8
end
# Check if user is happy to be asleep, e.g. can use moves while asleep
if ai.trainer.medium_skill?
score += (user.wants_status_problem?(:SLEEP)) ? 10 : -8
end
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.add("HealUserHalfOfTotalHP",
proc { |move, user, ai, battle|
next !user.battler.canHeal?
}
)
Battle::AI::Handlers::MoveEffectScore.add("HealUserHalfOfTotalHP",
proc { |score, move, user, ai, battle|
# Consider how much HP will be restored
if ai.trainer.has_skill_flag?("HPAware")
next score - 10 if user.hp >= user.totalhp * 0.5
score += 30 * (user.totalhp - user.hp) / user.totalhp # +15 to +30
end
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.copy("HealUserHalfOfTotalHP",
"HealUserDependingOnWeather")
Battle::AI::Handlers::MoveEffectScore.add("HealUserDependingOnWeather",
proc { |score, move, user, ai, battle|
# Consider how much HP will be restored
score = Battle::AI::Handlers.apply_move_effect_score("HealUserHalfOfTotalHP",
score, move, user, ai, battle)
case user.battler.effectiveWeather
when :Sun, :HarshSun
score += 5
when :None, :StrongWinds
else
score -= 10
end
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.copy("HealUserHalfOfTotalHP",
"HealUserDependingOnSandstorm")
Battle::AI::Handlers::MoveEffectScore.add("HealUserDependingOnSandstorm",
proc { |score, move, user, ai, battle|
# Consider how much HP will be restored
score = Battle::AI::Handlers.apply_move_effect_score("HealUserHalfOfTotalHP",
score, move, user, ai, battle)
score += 5 if user.battler.effectiveWeather == :Sandstorm
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.copy("HealUserHalfOfTotalHP",
"HealUserHalfOfTotalHPLoseFlyingTypeThisTurn")
Battle::AI::Handlers::MoveEffectScore.add("HealUserHalfOfTotalHPLoseFlyingTypeThisTurn",
proc { |score, move, user, ai, battle|
# Consider how much HP will be restored
score = Battle::AI::Handlers.apply_move_effect_score("HealUserHalfOfTotalHP",
score, move, user, ai, battle)
# User loses the Flying type this round
# NOTE: Not worth considering and scoring for.
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("CureTargetStatusHealUserHalfOfTotalHP",
proc { |move, user, target, ai, battle|
next !user.battler.canHeal? || target.status == :NONE
}
)
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("CureTargetStatusHealUserHalfOfTotalHP",
proc { |score, move, user, target, ai, battle|
# Consider how much HP will be restored
score = Battle::AI::Handlers.apply_move_effect_score("HealUserHalfOfTotalHP",
score, move, user, ai, battle)
# Will cure target's status
score += (target.wants_status_problem?(target.status)) ? 10 : -8
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("HealUserByTargetAttackLowerTargetAttack1",
proc { |move, user, target, ai, battle|
if !battle.moldBreaker && target.has_active_ability?(:CONTRARY)
next target.statStageAtMax?(:ATTACK)
end
next target.statStageAtMin?(:ATTACK)
}
)
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("HealUserByTargetAttackLowerTargetAttack1",
proc { |score, move, user, target, ai, battle|
# Check whether lowering the target's Attack will have any impact
if ai.trainer.medium_skill?
score = ai.get_score_for_target_stat_drop(score, target, move.move.statDown)
end
# Healing the user
if target.has_active_ability?(:LIQUIDOOZE)
score -= 20
elsif user.battler.canHeal?
score += 5 if user.has_active_item?(:BIGROOT)
if ai.trainer.has_skill_flag?("HPAware")
# Consider how much HP will be restored
heal_amt = target.rough_stat(:ATTACK)
heal_amt *= 1.3 if user.has_active_item?(:BIGROOT)
heal_amt = [heal_amt, user.totalhp - user.hp].min
if heal_amt > user.totalhp * 0.3 # Only modify the score if it'll heal a decent amount
if user.hp < user.totalhp * 0.5
score += 20 * (user.totalhp - user.hp) / user.totalhp # +10 to +20
end
score += 20 * heal_amt / user.totalhp # +6 to +20
end
end
end
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("HealUserByHalfOfDamageDone",
proc { |score, move, user, target, ai, battle|
rough_dmg = move.rough_damage
if target.has_active_ability?(:LIQUIDOOZE)
score -= 20 if rough_dmg < target.hp
elsif user.battler.canHeal?
score += 5 if user.has_active_item?(:BIGROOT)
if ai.trainer.has_skill_flag?("HPAware")
# Consider how much HP will be restored
heal_amt = rough_dmg / 2
heal_amt *= 1.3 if user.has_active_item?(:BIGROOT)
heal_amt = [heal_amt, user.totalhp - user.hp].min
if heal_amt > user.totalhp * 0.3 # Only modify the score if it'll heal a decent amount
if user.hp < user.totalhp * 0.5
score += 20 * (user.totalhp - user.hp) / user.totalhp # +10 to +20
end
score += 20 * heal_amt / user.totalhp # +6 to +20
end
end
end
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("HealUserByHalfOfDamageDoneIfTargetAsleep",
proc { |move, user, target, ai, battle|
next !target.battler.asleep?
}
)
Battle::AI::Handlers::MoveEffectAgainstTargetScore.copy("HealUserByHalfOfDamageDone",
"HealUserByHalfOfDamageDoneIfTargetAsleep")
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("HealUserByThreeQuartersOfDamageDone",
proc { |score, move, user, target, ai, battle|
rough_dmg = move.rough_damage
if target.has_active_ability?(:LIQUIDOOZE)
score -= 20 if rough_dmg < target.hp
elsif user.battler.canHeal?
score += 5 if user.has_active_item?(:BIGROOT)
if ai.trainer.has_skill_flag?("HPAware")
# Consider how much HP will be restored
heal_amt = rough_dmg * 0.75
heal_amt *= 1.3 if user.has_active_item?(:BIGROOT)
heal_amt = [heal_amt, user.totalhp - user.hp].min
if heal_amt > user.totalhp * 0.3 # Only modify the score if it'll heal a decent amount
if user.hp < user.totalhp * 0.5
score += 20 * (user.totalhp - user.hp) / user.totalhp # +10 to +20
end
score += 20 * heal_amt / user.totalhp # +6 to +20
end
end
end
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("HealUserAndAlliesQuarterOfTotalHP",
proc { |move, user, target, ai, battle|
next !target.battler.canHeal?
}
)
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("HealUserAndAlliesQuarterOfTotalHP",
proc { |score, move, user, target, ai, battle|
next score if !target.battler.canHeal?
# Consider how much HP will be restored
if ai.trainer.has_skill_flag?("HPAware")
if target.hp >= target.totalhp * 0.75
score -= 5
else
score += 15 * (target.totalhp - target.hp) / target.totalhp # +3 to +15
end
end
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("HealUserAndAlliesQuarterOfTotalHPCureStatus",
proc { |move, user, target, ai, battle|
next !target.battler.canHeal? && target.status == :NONE
}
)
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("HealUserAndAlliesQuarterOfTotalHPCureStatus",
proc { |score, move, user, target, ai, battle|
# Consider how much HP will be restored
score = Battle::AI::Handlers.apply_move_effect_score("HealUserAndAlliesQuarterOfTotalHP",
score, move, user, ai, battle)
# Check whether an existing status problem will be removed
if target.status != :NONE
score += (target.wants_status_problem?(target.status)) ? -10 : 10
end
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("HealTargetHalfOfTotalHP",
proc { |move, user, target, ai, battle|
next !target.battler.canHeal?
}
)
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("HealTargetHalfOfTotalHP",
proc { |score, move, user, target, ai, battle|
next Battle::AI::MOVE_USELESS_SCORE if target.opposes?(user)
# Consider how much HP will be restored
if ai.trainer.has_skill_flag?("HPAware")
if target.hp >= target.totalhp * 0.5
score -= 10
else
heal_amt = target.totalhp * 0.5
heal_amt = target.totalhp * 0.75 if move.move.pulseMove? &&
user.has_active_ability?(:MEGALAUNCHER)
heal_amt = [heal_amt, target.totalhp - target.hp].min
score += 20 * (target.totalhp - target.hp) / target.totalhp # +10 to +20
score += 20 * heal_amt / target.totalhp # +10 or +15
end
end
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.copy("HealTargetHalfOfTotalHP",
"HealTargetDependingOnGrassyTerrain")
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("HealTargetDependingOnGrassyTerrain",
proc { |score, move, user, target, ai, battle|
next Battle::AI::MOVE_USELESS_SCORE if user.opposes?(target)
# Consider how much HP will be restored
if ai.trainer.has_skill_flag?("HPAware")
if target.hp >= target.totalhp * 0.5
score -= 10
else
heal_amt = target.totalhp * 0.5
heal_amt = (target.totalhp * 2 / 3.0).round if battle.field.terrain == :Grassy
heal_amt = [heal_amt, target.totalhp - target.hp].min
score += 20 * (target.totalhp - target.hp) / target.totalhp # +10 to +20
score += 20 * heal_amt / target.totalhp # +10 or +13
end
end
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.add("HealUserPositionNextTurn",
proc { |move, user, ai, battle|
next battle.positions[user.index].effects[PBEffects::Wish] > 0
}
)
Battle::AI::Handlers::MoveEffectScore.add("HealUserPositionNextTurn",
proc { |score, move, user, ai, battle|
# Consider how much HP will be restored
if ai.trainer.has_skill_flag?("HPAware")
if user.hp >= user.totalhp * 0.5
score -= 10
else
score += 20 * (user.totalhp - user.hp) / user.totalhp # +10 to +20
end
end
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.add("StartHealUserEachTurn",
proc { |move, user, ai, battle|
next user.effects[PBEffects::AquaRing]
}
)
Battle::AI::Handlers::MoveEffectScore.add("StartHealUserEachTurn",
proc { |score, move, user, ai, battle|
score += 15
score += 5 if user.has_active_item?(:BIGROOT)
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.add("StartHealUserEachTurnTrapUserInBattle",
proc { |move, user, ai, battle|
next user.effects[PBEffects::Ingrain]
}
)
Battle::AI::Handlers::MoveEffectScore.add("StartHealUserEachTurnTrapUserInBattle",
proc { |score, move, user, ai, battle|
score += 8
score += 15 if user.turnCount < 2
score += 5 if user.has_active_item?(:BIGROOT)
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("StartDamageTargetEachTurnIfTargetAsleep",
proc { |move, user, target, ai, battle|
next !target.battler.asleep? || target.effects[PBEffects::Nightmare]
}
)
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("StartDamageTargetEachTurnIfTargetAsleep",
proc { |score, move, user, target, ai, battle|
next Battle::AI::MOVE_USELESS_SCORE if target.statusCount <= 1
next score + 8 * target.statusCount
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("StartLeechSeedTarget",
proc { |move, user, target, ai, battle|
next true if target.effects[PBEffects::LeechSeed] >= 0
next true if target.has_type?(:GRASS) || !target.battler.takesIndirectDamage?
next false
}
)
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("StartLeechSeedTarget",
proc { |score, move, user, target, ai, battle|
score += 15
# Prefer early on
score += 10 if user.turnCount < 2
if ai.trainer.medium_skill?
# Prefer if the user has no damaging moves
score += 10 if !user.check_for_move { |m| m.damagingMove? }
# Prefer if the target can't switch out to remove its seeding
score += 8 if !battle.pbCanChooseNonActive?(target.index)
# Don't prefer if the leeched HP will hurt the user
score -= 20 if target.has_active_ability?([:LIQUIDOOZE])
end
if ai.trainer.high_skill?
# Prefer if user can stall while damage is dealt
if user.check_for_move { |m| m.is_a?(Battle::Move::ProtectMove) }
score += 10
end
# Don't prefer if target can remove the seed
if target.has_move_with_function?("RemoveUserBindingAndEntryHazards")
score -= 15
end
end
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveEffectScore.add("UserLosesHalfOfTotalHP",
proc { |score, move, user, ai, battle|
score -= 15 # User will lose 50% HP, don't prefer this move
if ai.trainer.has_skill_flag?("HPAware")
score += 15 if user.hp >= user.totalhp * 0.75 # User has HP to spare
score += 15 if user.hp <= user.totalhp * 0.25 # User is near fainting anyway; suicide
end
if ai.trainer.high_skill?
reserves = battle.pbAbleNonActiveCount(user.idxOwnSide)
foes = battle.pbAbleNonActiveCount(user.idxOpposingSide)
if reserves == 0 # AI is down to its last Pokémon
score += 30 # => Go out with a bang
elsif foes == 0 # Foe is down to their last Pokémon, AI has reserves
score += 20 # => Go for the kill
end
end
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.add("UserLosesHalfOfTotalHPExplosive",
proc { |move, user, ai, battle|
next !battle.moldBreaker && battle.pbCheckGlobalAbility(:DAMP)
}
)
Battle::AI::Handlers::MoveEffectScore.copy("UserLosesHalfOfTotalHP",
"UserLosesHalfOfTotalHPExplosive")
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.copy("UserLosesHalfOfTotalHPExplosive",
"UserFaintsExplosive")
Battle::AI::Handlers::MoveEffectScore.add("UserFaintsExplosive",
proc { |score, move, user, ai, battle|
score -= 20 # User will faint, don't prefer this move
if ai.trainer.has_skill_flag?("HPAware")
score -= 10 if user.hp >= user.totalhp * 0.5
score += 20 if user.hp <= user.totalhp * 0.25 # User is near fainting anyway; suicide
end
if ai.trainer.high_skill?
reserves = battle.pbAbleNonActiveCount(user.idxOwnSide)
foes = battle.pbAbleNonActiveCount(user.idxOpposingSide)
if reserves == 0 # AI is down to its last Pokémon
score += 30 # => Go out with a bang
elsif foes == 0 # Foe is down to their last Pokémon, AI has reserves
score += 20 # => Go for the kill
end
end
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.copy("UserFaintsExplosive",
"UserFaintsPowersUpInMistyTerrainExplosive")
Battle::AI::Handlers::MoveBasePower.add("UserFaintsPowersUpInMistyTerrainExplosive",
proc { |power, move, user, target, ai, battle|
power = power * 3 / 2 if battle.field.terrain == :Misty
next power
}
)
Battle::AI::Handlers::MoveEffectScore.copy("UserFaintsExplosive",
"UserFaintsPowersUpInMistyTerrainExplosive")
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveBasePower.add("UserFaintsFixedDamageUserHP",
proc { |power, move, user, target, ai, battle|
next user.hp
}
)
Battle::AI::Handlers::MoveEffectScore.copy("UserFaintsExplosive",
"UserFaintsFixedDamageUserHP")
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("UserFaintsLowerTargetAtkSpAtk2",
proc { |score, move, user, target, ai, battle|
score -= 20 # User will faint, don't prefer this move
# Check the impact of lowering the target's stats
score = ai.get_score_for_target_stat_drop(score, target, move.move.statDown)
next score if score == Battle::AI::MOVE_USELESS_SCORE
# Score for the user fainting
if ai.trainer.has_skill_flag?("HPAware")
score -= 10 if user.hp >= user.totalhp * 0.5
score += 20 if user.hp <= user.totalhp * 0.25 # User is near fainting anyway; suicide
end
if ai.trainer.high_skill?
reserves = battle.pbAbleNonActiveCount(user.idxOwnSide)
foes = battle.pbAbleNonActiveCount(user.idxOpposingSide)
if reserves > 0 && foes == 0 # Foe is down to their last Pokémon, AI has reserves
score += 20 # => Can afford to lose this Pokémon
end
end
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.add("UserFaintsHealAndCureReplacement",
proc { |move, user, ai, battle|
next !battle.pbCanChooseNonActive?(user.index)
}
)
Battle::AI::Handlers::MoveEffectScore.add("UserFaintsHealAndCureReplacement",
proc { |score, move, user, ai, battle|
score -= 20 # User will faint, don't prefer this move
# Check whether the replacement user needs healing, and don't make the below
# calculations if not
if ai.trainer.medium_skill?
need_healing = false
battle.eachInTeamFromBattlerIndex(user.index) do |pkmn, party_index|
next if pkmn.hp >= pkmn.totalhp * 0.75 && pkmn.status == :NONE
need_healing = true
break
end
next Battle::AI::MOVE_USELESS_SCORE if !need_healing
score += 10
end
if ai.trainer.has_skill_flag?("HPAware")
score -= 10 if user.hp >= user.totalhp * 0.5
score += 20 if user.hp <= user.totalhp * 0.25 # User is near fainting anyway; suicide
end
if ai.trainer.high_skill?
reserves = battle.pbAbleNonActiveCount(user.idxOwnSide)
foes = battle.pbAbleNonActiveCount(user.idxOpposingSide)
if reserves > 0 && foes == 0 # Foe is down to their last Pokémon, AI has reserves
score += 20 # => Can afford to lose this Pokémon
end
end
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.copy("UserFaintsHealAndCureReplacement",
"UserFaintsHealAndCureReplacementRestorePP")
Battle::AI::Handlers::MoveEffectScore.copy("UserFaintsHealAndCureReplacement",
"UserFaintsHealAndCureReplacementRestorePP")
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("StartPerishCountsForAllBattlers",
proc { |move, user, target, ai, battle|
next true if target.effects[PBEffects::PerishSong] > 0
next false if !target.ability_active?
next Battle::AbilityEffects.triggerMoveImmunity(target.ability, user.battler, target.battler,
move.move, move.rough_type, battle, false)
}
)
Battle::AI::Handlers::MoveEffectScore.add("StartPerishCountsForAllBattlers",
proc { |score, move, user, ai, battle|
score -= 15
# Check which battlers will be affected by this move
if ai.trainer.medium_skill?
allies_affected = 0
foes_affected = 0
foes_with_high_hp = 0
ai.each_battler do |b|
next if Battle::AI::Handlers.move_will_fail_against_target?("StartPerishCountsForAllBattlers",
move, user, b, ai, battle)
if b.opposes?(user)
foes_affected += 1
foes_with_high_hp += 1 if b.hp >= b.totalhp * 0.75
else
allies_affected += 1
end
end
next Battle::AI::MOVE_USELESS_SCORE if foes_affected == 0
score += 15 if allies_affected == 0 # No downside for user; cancel out inherent negative score
score -= 15 * allies_affected
score += 20 * foes_affected
score += 10 * foes_with_high_hp if ai.trainer.has_skill_flag?("HPAware")
end
if ai.trainer.high_skill?
reserves = battle.pbAbleNonActiveCount(user.idxOwnSide)
foes = battle.pbAbleNonActiveCount(user.idxOpposingSide)
if foes == 0 # Foe is down to their last Pokémon, can't lose Perish count
score += 25 # => Want to auto-win in 3 turns
elsif reserves == 0 # AI is down to its last Pokémon, can't lose Perish count
score -= 15 # => Don't want to auto-lose in 3 turns
end
end
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.add("AttackerFaintsIfUserFaints",
proc { |move, user, ai, battle|
next Settings::MECHANICS_GENERATION >= 7 && user.effects[PBEffects::DestinyBondPrevious]
}
)
Battle::AI::Handlers::MoveEffectScore.add("AttackerFaintsIfUserFaints",
proc { |score, move, user, ai, battle|
score -= 25
# Check whether user is faster than its foe(s) and could use this move
user_faster_count = 0
ai.each_foe_battler(user.side) do |b, i|
user_faster_count += 1 if user.faster_than?(b)
end
next score if user_faster_count == 0 # Move will almost certainly have no effect
score += 7 * user_faster_count
# Prefer this move at lower user HP
if ai.trainer.has_skill_flag?("HPAware")
score += 20 if user.hp <= user.totalhp * 0.4
score += 10 if user.hp <= user.totalhp * 0.25
score += 15 if user.hp <= user.totalhp * 0.1
end
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveEffectScore.add("SetAttackerMovePPTo0IfUserFaints",
proc { |score, move, user, ai, battle|
score -= 25
# Check whether user is faster than its foe(s) and could use this move
user_faster_count = 0
ai.each_foe_battler(user.side) do |b, i|
user_faster_count += 1 if user.faster_than?(b)
end
next score if user_faster_count == 0 # Move will almost certainly have no effect
score += 7 * user_faster_count
# Prefer this move at lower user HP (not as preferred as Destiny Bond, though)
if ai.trainer.has_skill_flag?("HPAware")
score += 20 if user.hp <= user.totalhp * 0.4
score += 10 if user.hp <= user.totalhp * 0.25
score += 15 if user.hp <= user.totalhp * 0.1
end
next score
}
)

View File

@@ -0,0 +1,356 @@
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("UserTakesTargetItem",
proc { |score, move, user, target, ai, battle|
next score if user.wild? || user.item
next score if !target.item || target.battler.unlosableItem?(target.item)
next score if user.battler.unlosableItem?(target.item)
next score if target.effects[PBEffects::Substitute] > 0
next score if target.has_active_ability?(:STICKYHOLD) && !battle.moldBreaker
# User can steal the target's item; score it
user_item_preference = user.wants_item?(target.item_id)
user_no_item_preference = user.wants_item?(:NONE)
target_item_preference = target.wants_item?(target.item_id)
target_no_item_preference = target.wants_item?(:NONE)
score += user_item_preference - user_no_item_preference
score += target_item_preference - target_no_item_preference
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("TargetTakesUserItem",
proc { |move, user, target, ai, battle|
next true if !user.item || user.battler.unlosableItem?(user.item)
next true if target.item || target.battler.unlosableItem?(user.item)
next false
}
)
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("TargetTakesUserItem",
proc { |score, move, user, target, ai, battle|
user_item_preference = user.wants_item?(user.item_id)
user_no_item_preference = user.wants_item?(:NONE)
target_item_preference = target.wants_item?(user.item_id)
target_no_item_preference = target.wants_item?(:NONE)
score += user_no_item_preference - user_item_preference
score += target_no_item_preference - target_item_preference
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("UserTargetSwapItems",
proc { |move, user, target, ai, battle|
next true if user.wild?
next true if !user.item && !target.item
next true if user.battler.unlosableItem?(user.item) || user.battler.unlosableItem?(target.item)
next true if target.battler.unlosableItem?(target.item) || target.battler.unlosableItem?(user.item)
next true if target.has_active_ability?(:STICKYHOLD) && !battle.moldBreaker
next false
}
)
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("UserTargetSwapItems",
proc { |score, move, user, target, ai, battle|
user_new_item_preference = user.wants_item?(target.item_id)
user_old_item_preference = user.wants_item?(user.item_id)
target_new_item_preference = target.wants_item?(user.item_id)
target_old_item_preference = target.wants_item?(target.item_id)
score += user_new_item_preference - user_old_item_preference
score += target_old_item_preference - target_new_item_preference
# Don't prefer if user used this move in the last round
score -= 15 if user.battler.lastMoveUsed &&
GameData::Move.exists?(user.battler.lastMoveUsed) &&
GameData::Move.get(user.battler.lastMoveUsed).function_code == move.function
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.add("RestoreUserConsumedItem",
proc { |move, user, ai, battle|
next !user.battler.recycleItem || user.item
}
)
Battle::AI::Handlers::MoveEffectScore.add("RestoreUserConsumedItem",
proc { |score, move, user, ai, battle|
user_new_item_preference = user.wants_item?(user.battler.recycleItem)
user_old_item_preference = user.wants_item?(:NONE)
score += (user_new_item_preference - user_old_item_preference) * 2
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveBasePower.add("RemoveTargetItem",
proc { |power, move, user, target, ai, battle|
next move.move.pbBaseDamage(power, user.battler, target.battler)
}
)
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("RemoveTargetItem",
proc { |score, move, user, target, ai, battle|
next score if user.wild?
next score if !target.item || target.battler.unlosableItem?(target.item)
next score if target.effects[PBEffects::Substitute] > 0
next score if target.has_active_ability?(:STICKYHOLD) && !battle.moldBreaker
# User can knock off the target's item; score it
target_item_preference = target.wants_item?(target.item_id)
target_no_item_preference = target.wants_item?(:NONE)
score += (target_item_preference - target_no_item_preference) * 2
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("DestroyTargetBerryOrGem",
proc { |score, move, user, target, ai, battle|
next score if !target.item || (!target.item.is_berry? &&
!(Settings::MECHANICS_GENERATION >= 6 && target.item.is_gem?))
next score if user.battler.unlosableItem?(target.item)
next score if target.effects[PBEffects::Substitute] > 0
next score if target.has_active_ability?(:STICKYHOLD) && !battle.moldBreaker
# User can incinerate the target's item; score it
target_item_preference = target.wants_item?(target.item_id)
target_no_item_preference = target.wants_item?(:NONE)
score += (target_item_preference - target_no_item_preference) * 2
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("CorrodeTargetItem",
proc { |move, user, target, ai, battle|
next true if !target.item || target.unlosableItem?(target.item) ||
target.effects[PBEffects::Substitute] > 0
next true if target.has_active_ability?(:STICKYHOLD)
next true if battle.corrosiveGas[target.index % 2][target.party_index]
next false
}
)
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("CorrodeTargetItem",
proc { |score, move, user, target, ai, battle|
target_item_preference = target.wants_item?(target.item_id)
target_no_item_preference = target.wants_item?(:NONE)
score += (target_item_preference - target_no_item_preference) * 2
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("StartTargetCannotUseItem",
proc { |move, user, target, ai, battle|
next target.effects[PBEffects::Embargo] > 0
}
)
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("StartTargetCannotUseItem",
proc { |score, move, user, target, ai, battle|
next Battle::AI::MOVE_USELESS_SCORE if !target.item || !target.item_active?
# TODO: Useless if target's item cannot be negated or it has no effect.
item_score = target.wants_item?(target.item_id)
score += item_score * 2
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveEffectScore.add("StartNegateHeldItems",
proc { |score, move, user, ai, battle|
next if battle.field.effects[PBEffects::MagicRoom] == 1 # About to expire anyway
any_held_items = false
total_want = 0 # Positive means foes want their items more than allies do
ai.each_battler do |b, i|
next if !b.item
# Skip b if its item is disabled
if ai.trainer.medium_skill?
# TODO: Skip b if its item cannot be negated or it has no effect.
if battle.field.effects[PBEffects::MagicRoom] > 0
# NOTE: Same as b.item_active? but ignoring the Magic Room part.
next if b.effects[PBEffects::Embargo] > 0
next if battle.corrosiveGas[b.index % 2][b.party_index]
next if b.has_active_ability?(:KLUTZ)
else
next if !b.item_active?
end
end
# Rate b's held item and add it to total_want
any_held_items = true
want = b.wants_item?(b.item_id)
total_want += (b.opposes?(user)) ? want : -want
end
# Alter score
next Battle::AI::MOVE_USELESS_SCORE if !any_held_items
if battle.field.effects[PBEffects::MagicRoom] > 0
next Battle::AI::MOVE_USELESS_SCORE if total_want >= 0
score -= [total_want, -5].max * 4 # Will enable items, prefer if allies affected more
else
next Battle::AI::MOVE_USELESS_SCORE if total_want <= 0
score += [total_want, 5].min * 4 # Will disable items, prefer if foes affected more
end
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.add("UserConsumeBerryRaiseDefense2",
proc { |move, user, ai, battle|
item = user.item
next !item || !item.is_berry? || !user.item_active?
}
)
Battle::AI::Handlers::MoveEffectScore.add("UserConsumeBerryRaiseDefense2",
proc { |score, move, user, ai, battle|
# Score for raising the user's stat
stat_raise_score = Battle::AI::Handlers.apply_move_effect_score("RaiseUserDefense2",
0, move, user, ai, battle)
score += stat_raise_score if stat_raise_score != Battle::AI::MOVE_USELESS_SCORE
# Score for the consumed berry's effect
score += user.get_score_change_for_consuming_item(user.item_id, true)
# Score for other results of consuming the berry
if ai.trainer.medium_skill?
# Prefer if user will heal itself with Cheek Pouch
score += 8 if user.battler.canHeal? && user.hp < user.totalhp / 2 &&
user.has_active_ability?(:CHEEKPOUCH)
# Prefer if target can recover the consumed berry
score += 8 if user.has_active_ability?(:HARVEST) ||
user.has_move_with_function?("RestoreUserConsumedItem")
# Prefer if user couldn't normally consume the berry
score += 5 if !user.battler.canConsumeBerry?
# Prefer if user will become able to use Belch
score += 5 if !user.battler.belched? && user.has_move_with_function?("FailsIfUserNotConsumedBerry")
# Prefer if user will benefit from not having an item
score += 5 if user.has_active_ability?(:UNBURDEN)
end
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("AllBattlersConsumeBerry",
proc { |move, user, target, ai, battle|
next !target.item || !target.item.is_berry? || target.battler.semiInvulnerable?
}
)
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("AllBattlersConsumeBerry",
proc { |score, move, user, target, ai, battle|
# Score for the consumed berry's effect
score_change = target.get_score_change_for_consuming_item(target.item_id, !target.opposes?(user))
# Score for other results of consuming the berry
if ai.trainer.medium_skill?
# Prefer if target will heal itself with Cheek Pouch
score_change += 8 if target.battler.canHeal? && target.hp < target.totalhp / 2 &&
target.has_active_ability?(:CHEEKPOUCH)
# Prefer if target can recover the consumed berry
score_change += 8 if target.has_active_ability?(:HARVEST) ||
target.has_move_with_function?("RestoreUserConsumedItem")
# Prefer if target couldn't normally consume the berry
score_change += 5 if !target.battler.canConsumeBerry?
# Prefer if target will become able to use Belch
score_change += 5 if !target.battler.belched? && target.has_move_with_function?("FailsIfUserNotConsumedBerry")
# Prefer if target will benefit from not having an item
score_change += 5 if target.has_active_ability?(:UNBURDEN)
end
score += (target.opposes?(user)) ? -score_change : score_change
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("UserConsumeTargetBerry",
proc { |score, move, user, target, ai, battle|
next score if !target.item || !target.item.is_berry?
next score if user.battler.unlosableItem?(target.item)
next score if target.effects[PBEffects::Substitute] > 0
next score if target.has_active_ability?(:STICKYHOLD) && !battle.moldBreaker
# Score the user gaining the item's effect
score += user.get_score_change_for_consuming_item(target.item_id)
# Score for other results of consuming the berry
if ai.trainer.medium_skill?
# Prefer if user will heal itself with Cheek Pouch
score += 8 if user.battler.canHeal? && user.hp < user.totalhp / 2 &&
user.has_active_ability?(:CHEEKPOUCH)
# Prefer if user will become able to use Belch
score += 5 if !user.battler.belched? && user.has_move_with_function?("FailsIfUserNotConsumedBerry")
# Don't prefer if target will benefit from not having an item
score -= 5 if target.has_active_ability?(:UNBURDEN)
end
# Score the target no longer having the item
target_item_preference = target.wants_item?(target.item_id)
target_no_item_preference = target.wants_item?(:NONE)
score += (target_item_preference - target_no_item_preference) * 2
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.add("ThrowUserItemAtTarget",
proc { |move, user, ai, battle|
item = user.item
next true if !item || !user.item_active? || user.battler.unlosableItem?(item)
next true if item.is_berry? && !user.battler.canConsumeBerry?
next true if item.flags.none? { |f| f[/^Fling_/i] }
next false
}
)
Battle::AI::Handlers::MoveBasePower.add("ThrowUserItemAtTarget",
proc { |power, move, user, target, ai, battle|
next move.move.pbBaseDamage(power, user.battler, target.battler)
}
)
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("ThrowUserItemAtTarget",
proc { |score, move, user, target, ai, battle|
case user.item_id
when :POISONBARB, :TOXICORB
score = Battle::AI::Handlers.apply_move_effect_against_target_score("PoisonTarget",
score, move, user, target, ai, battle)
when :FLAMEORB
score = Battle::AI::Handlers.apply_move_effect_against_target_score("BurnTarget",
score, move, user, target, ai, battle)
when :LIGHTBALL
score = Battle::AI::Handlers.apply_move_effect_against_target_score("ParalyzeTarget",
score, move, user, target, ai, battle)
when :KINGSROCK, :RAZORFANG
score = Battle::AI::Handlers.apply_move_effect_against_target_score("FlinchTarget",
score, move, user, target, ai, battle)
else
score -= target.get_score_change_for_consuming_item(user.item_id)
end
# Score for other results of consuming the berry
if ai.trainer.medium_skill?
# Don't prefer if target will become able to use Belch
score -= 5 if user.item.is_berry? && !target.battler.belched? &&
target.has_move_with_function?("FailsIfUserNotConsumedBerry")
# Prefer if user will benefit from not having an item
score += 5 if user.has_active_ability?(:UNBURDEN)
end
# Prefer if the user doesn't want its held item/don't prefer if it wants to
# keep its held item
user_item_preference = user.wants_item?(user.item_id)
user_no_item_preference = user.wants_item?(:NONE)
score += (user_item_preference - user_no_item_preference) * 2
next score
}
)

View File

@@ -0,0 +1,623 @@
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveEffectScore.add("RedirectAllMovesToUser",
proc { |score, move, user, ai, battle|
# Useless if there is no ally to redirect attacks from
next Battle::AI::MOVE_USELESS_SCORE if user.battler.allAllies.length == 0
# Prefer if ally is at low HP and user is at high HP
if ai.trainer.has_skill_flag?("HPAware") && user.hp > user.totalhp * 2 / 3
ai.each_ally(user.index) do |b, i|
score += 10 if b.hp <= b.totalhp / 3
end
end
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("RedirectAllMovesToTarget",
proc { |score, move, user, target, ai, battle|
if target.opposes?(user)
# Useless if target is a foe but there is only one foe
next Battle::AI::MOVE_USELESS_SCORE if target.battler.allAllies.length == 0
# Useless if there is no ally to attack the spotlighted foe
next Battle::AI::MOVE_USELESS_SCORE if user.battler.allAllies.length == 0
end
# Generaly don't prefer this move, as it's a waste of the user's turn
next score - 20
}
)
#===============================================================================
#
#===============================================================================
# CannotBeRedirected
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveBasePower.add("RandomlyDamageOrHealTarget",
proc { |power, move, user, target, ai, battle|
next 50 # Average power, ish
}
)
Battle::AI::Handlers::MoveEffectScore.add("RandomlyDamageOrHealTarget",
proc { |score, move, user, ai, battle|
# Generaly don't prefer this move, as it may heal the target instead
next score - 10
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("HealAllyOrDamageFoe",
proc { |move, user, target, ai, battle|
next !target.opposes?(user) && !target.battler.canHeal?
}
)
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("HealAllyOrDamageFoe",
proc { |score, move, user, target, ai, battle|
next score if target.opposes?(user)
# Consider how much HP will be restored
if ai.trainer.has_skill_flag?("HPAware")
if target.hp >= target.totalhp * 0.5
score -= 10
else
score += 20 * (target.totalhp - target.hp) / target.totalhp # +10 to +20
end
end
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.add("CurseTargetOrLowerUserSpd1RaiseUserAtkDef1",
proc { |move, user, ai, battle|
next false if user.has_type?(:GHOST) ||
(move.rough_type == :GHOST && user.has_active_ability?([:LIBERO, :PROTEAN]))
will_fail = true
(move.move.statUp.length / 2).times do |i|
next if !user.battler.pbCanRaiseStatStage?(move.move.statUp[i * 2], user.battler, move.move)
will_fail = false
break
end
(move.move.statDown.length / 2).times do |i|
next if !user.battler.pbCanLowerStatStage?(move.move.statDown[i * 2], user.battler, move.move)
will_fail = false
break
end
next will_fail
}
)
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("CurseTargetOrLowerUserSpd1RaiseUserAtkDef1",
proc { |move, user, target, ai, battle|
next false if !user.has_type?(:GHOST) &&
!(move.rough_type == :GHOST && user.has_active_ability?([:LIBERO, :PROTEAN]))
next true if target.effects[PBEffects::Curse] || !target.battler.takesIndirectDamage?
next false
}
)
Battle::AI::Handlers::MoveEffectScore.add("CurseTargetOrLowerUserSpd1RaiseUserAtkDef1",
proc { |score, move, user, ai, battle|
next score if user.has_type?(:GHOST) ||
(move.rough_type == :GHOST && user.has_active_ability?([:LIBERO, :PROTEAN]))
score = ai.get_score_for_target_stat_raise(score, user, move.move.statUp)
next score if score == Battle::AI::MOVE_USELESS_SCORE
next ai.get_score_for_target_stat_drop(score, user, move.move.statDown, false)
}
)
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("CurseTargetOrLowerUserSpd1RaiseUserAtkDef1",
proc { |score, move, user, target, ai, battle|
next score if !user.has_type?(:GHOST) &&
!(move.rough_type == :GHOST && user.has_active_ability?([:LIBERO, :PROTEAN]))
# Don't prefer if user will faint because of using this move
if ai.trainer.has_skill_flag?("HPAware")
next Battle::AI::MOVE_USELESS_SCORE if user.hp <= user.totalhp / 2
end
# Prefer early on
score += 10 if user.turnCount < 2
if ai.trainer.medium_skill?
# Prefer if the user has no damaging moves
score += 15 if !user.check_for_move { |m| m.damagingMove? }
# Prefer if the target can't switch out to remove its curse
score += 10 if !battle.pbCanChooseNonActive?(target.index)
end
if ai.trainer.high_skill?
# Prefer if user can stall while damage is dealt
if user.check_for_move { |m| m.is_a?(Battle::Move::ProtectMove) }
score += 5
end
end
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("EffectDependsOnEnvironment",
proc { |score, move, user, target, ai, battle|
# Determine this move's effect
move.move.pbOnStartUse(user.battler, [target.battler])
function_code = nil
case move.move.secretPower
when 2
function_code = "SleepTarget"
when 10
function_code = "BurnTarget"
when 0, 1
function_code = "ParalyzeTarget"
when 9
function_code = "FreezeTarget"
when 5
function_code = "LowerTargetAttack1"
when 14
function_code = "LowerTargetDefense1"
when 3
function_code = "LowerTargetSpAtk1"
when 4, 6, 12
function_code = "LowerTargetSpeed1"
when 8
function_code = "LowerTargetAccuracy1"
when 7, 11, 13
function_code = "FlinchTarget"
end
if function_code
next Battle::AI::Handlers.apply_move_effect_against_target_score(function_code,
score, move, user, target, ai, battle)
end
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveBasePower.add("HitsAllFoesAndPowersUpInPsychicTerrain",
proc { |power, move, user, target, ai, battle|
next move.move.pbBaseDamage(power, user.battler, target.battler)
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("TargetNextFireMoveDamagesTarget",
proc { |move, user, target, ai, battle|
next target.effects[PBEffects::Powder]
}
)
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("TargetNextFireMoveDamagesTarget",
proc { |score, move, user, target, ai, battle|
# Prefer if target knows any Fire moves (moreso if that's the only type they know)
next Battle::AI::MOVE_USELESS_SCORE if !target.check_for_move { |m| m.pbCalcType(target.battler) == :FIRE }
score += 10
score += 10 if !target.check_for_move { |m| m.pbCalcType(target.battler) != :FIRE }
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveEffectScore.add("DoublePowerAfterFusionFlare",
proc { |score, move, user, ai, battle|
# Prefer if an ally knows Fusion Flare
ai.each_ally(user.index) do |b, i|
score += 10 if b.has_move_with_function?("DoublePowerAfterFusionBolt")
end
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveEffectScore.add("DoublePowerAfterFusionBolt",
proc { |score, move, user, ai, battle|
# Prefer if an ally knows Fusion Bolt
ai.each_ally(user.index) do |b, i|
score += 10 if b.has_move_with_function?("DoublePowerAfterFusionFlare")
end
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("PowerUpAllyMove",
proc { |move, user, target, ai, battle|
next target.effects[PBEffects::HelpingHand]
}
)
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("PowerUpAllyMove",
proc { |score, move, user, target, ai, battle|
next Battle::AI::MOVE_USELESS_SCORE if !target.check_for_move { |m| m.damagingMove? }
next score + 5
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveBasePower.add("CounterPhysicalDamage",
proc { |power, move, user, target, ai, battle|
next 60 # Representative value
}
)
Battle::AI::Handlers::MoveEffectScore.add("CounterPhysicalDamage",
proc { |score, move, user, ai, battle|
has_physical_move = false
ai.each_foe_battler(user.side) do |b, i|
next if !b.can_attack?
next if !b.check_for_move { |m| m.physicalMove?(m.type) &&
(user.effects[PBEffects::Substitute] == 0 ||
m.ignoresSubstitute?(b.battler)) }
has_physical_move = true
# Prefer if foe has a higher Attack than Special Attack
score += 5 if b.rough_stat(:ATTACK) > b.rough_stat(:SPECIAL_ATTACK)
# Prefer if the last move the foe used was physical
if ai.trainer.medium_skill? && b.battler.lastMoveUsed
score += 8 if GameData::Move.try_get(b.battler.lastMoveUsed)&.physical?
end
# Prefer if the foe is taunted into using a damaging move
score += 5 if b.effects[PBEffects::Taunt] > 0
end
# Useless if no foes have a physical move to counter
next Battle::AI::MOVE_USELESS_SCORE if !has_physical_move
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveBasePower.add("CounterSpecialDamage",
proc { |power, move, user, target, ai, battle|
next 60 # Representative value
}
)
Battle::AI::Handlers::MoveEffectScore.add("CounterSpecialDamage",
proc { |score, move, user, ai, battle|
has_special_move = false
ai.each_foe_battler(user.side) do |b, i|
next if !b.can_attack?
next if !b.check_for_move { |m| m.specialMove?(m.type) &&
(user.effects[PBEffects::Substitute] == 0 ||
m.ignoresSubstitute?(b.battler)) }
has_special_move = true
# Prefer if foe has a higher Special Attack than Attack
score += 5 if b.rough_stat(:SPECIAL_ATTACK) > b.rough_stat(:ATTACK)
# Prefer if the last move the foe used was special
if ai.trainer.medium_skill? && b.battler.lastMoveUsed
score += 8 if GameData::Move.try_get(b.battler.lastMoveUsed)&.special?
end
# Prefer if the foe is taunted into using a damaging move
score += 5 if b.effects[PBEffects::Taunt] > 0
end
# Useless if no foes have a special move to counter
next Battle::AI::MOVE_USELESS_SCORE if !has_special_move
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveBasePower.add("CounterDamagePlusHalf",
proc { |power, move, user, target, ai, battle|
next 60 # Representative value
}
)
Battle::AI::Handlers::MoveEffectScore.add("CounterDamagePlusHalf",
proc { |score, move, user, ai, battle|
has_damaging_move = false
ai.each_foe_battler(user.side) do |b, i|
next if !b.can_attack? || user.faster_than?(b)
next if !b.check_for_move { |m| m.damagingMove? &&
(user.effects[PBEffects::Substitute] == 0 ||
m.ignoresSubstitute?(b.battler)) }
has_damaging_move = true
# Prefer if the last move the foe used was damaging
if ai.trainer.medium_skill? && b.battler.lastMoveUsed
score += 8 if GameData::Move.try_get(b.battler.lastMoveUsed)&.damaging?
end
# Prefer if the foe is taunted into using a damaging move
score += 5 if b.effects[PBEffects::Taunt] > 0
end
# Useless if no foes have a damaging move to counter
next Battle::AI::MOVE_USELESS_SCORE if !has_damaging_move
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.add("UserAddStockpileRaiseDefSpDef1",
proc { |move, user, ai, battle|
next user.effects[PBEffects::Stockpile] >= 3
}
)
Battle::AI::Handlers::MoveEffectScore.add("UserAddStockpileRaiseDefSpDef1",
proc { |score, move, user, ai, battle|
score = ai.get_score_for_target_stat_raise(score, user, [:DEFENSE, 1, :SPECIAL_DEFENSE, 1], false)
# More preferable if user also has Spit Up/Swallow
if user.battler.pbHasMoveFunction?("PowerDependsOnUserStockpile",
"HealUserDependingOnUserStockpile")
score += [10, 10, 8, 5][user.effects[PBEffects::Stockpile]]
end
next score
}
)
#===============================================================================
# NOTE: Don't worry about the stat drops caused by losing the stockpile, because
# if these moves are known, they want to be used.
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.add("PowerDependsOnUserStockpile",
proc { |move, user, ai, battle|
next user.effects[PBEffects::Stockpile] == 0
}
)
Battle::AI::Handlers::MoveBasePower.add("PowerDependsOnUserStockpile",
proc { |power, move, user, target, ai, battle|
next move.move.pbBaseDamage(power, user.battler, target.battler)
}
)
Battle::AI::Handlers::MoveEffectScore.add("PowerDependsOnUserStockpile",
proc { |score, move, user, ai, battle|
# Slightly prefer to hold out for another Stockpile to make this move stronger
score -= 5 if user.effects[PBEffects::Stockpile] < 2
next score
}
)
#===============================================================================
# NOTE: Don't worry about the stat drops caused by losing the stockpile, because
# if these moves are known, they want to be used.
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.add("HealUserDependingOnUserStockpile",
proc { |move, user, ai, battle|
next true if user.effects[PBEffects::Stockpile] == 0
next true if !user.battler.canHeal? &&
user.effects[PBEffects::StockpileDef] == 0 &&
user.effects[PBEffects::StockpileSpDef] == 0
next false
}
)
Battle::AI::Handlers::MoveEffectScore.add("HealUserDependingOnUserStockpile",
proc { |score, move, user, ai, battle|
next Battle::AI::MOVE_USELESS_SCORE if !user.battler.canHeal?
# Consider how much HP will be restored
if ai.trainer.has_skill_flag?("HPAware")
next score - 10 if user.hp >= user.totalhp * 0.5
score += 20 * (user.totalhp - user.hp) / user.totalhp # +10 to +20
end
# Slightly prefer to hold out for another Stockpile to make this move stronger
score -= 5 if user.effects[PBEffects::Stockpile] < 2
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveEffectScore.add("GrassPledge",
proc { |score, move, user, ai, battle|
# Prefer if an ally knows a different Pledge move
ai.each_ally(user.index) do |b, i|
score += 10 if b.has_move_with_function?("FirePledge", "WaterPledge")
end
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveEffectScore.add("FirePledge",
proc { |score, move, user, ai, battle|
# Prefer if an ally knows a different Pledge move
ai.each_ally(user.index) do |b, i|
score += 10 if b.has_move_with_function?("GrassPledge", "WaterPledge")
end
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveEffectScore.add("WaterPledge",
proc { |score, move, user, ai, battle|
# Prefer if an ally knows a different Pledge move
ai.each_ally(user.index) do |b, i|
score += 10 if b.has_move_with_function?("GrassPledge", "FirePledge")
end
next score
}
)
#===============================================================================
# NOTE: The move that this move will become is determined in def
# set_up_move_check, and the score for that move is calculated instead. If
# this move cannot become another move and will fail, the score for this
# move is calculated as normal (and the code below says it fails).
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.add("UseLastMoveUsed",
proc { |move, user, ai, battle|
next true if !battle.lastMoveUsed || !GameData::Move.exists?(battle.lastMoveUsed)
next move.move.moveBlacklist.include?(GameData::Move.get(battle.lastMoveUsed).function_code)
}
)
#===============================================================================
# NOTE: The move that this move will become is determined in def
# set_up_move_check, and the score for that move is calculated instead. If
# this move cannot become another move and will fail, the score for this
# move is calculated as normal (and the code below says it fails).
#===============================================================================
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("UseLastMoveUsedByTarget",
proc { |move, user, target, ai, battle|
next true if !target.battler.lastRegularMoveUsed
next true if !GameData::Move.exists?(target.battler.lastRegularMoveUsed)
next !GameData::Move.get(target.battler.lastRegularMoveUsed).has_flag?("CanMirrorMove")
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("UseMoveTargetIsAboutToUse",
proc { |move, user, target, ai, battle|
next !target.check_for_move { |m| m.damagingMove? && !move.move.moveBlacklist.include?(m.function_code) }
}
)
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("UseMoveTargetIsAboutToUse",
proc { |score, move, user, target, ai, battle|
next Battle::AI::MOVE_USELESS_SCORE if target.faster_than?(user)
# Don't prefer if target knows any moves that can't be copied
if target.check_for_move { |m| m.statusMove? || move.move.moveBlacklist.include?(m.function_code) }
score -= 8
end
next score
}
)
#===============================================================================
# NOTE: The move that this move will become is determined in def
# set_up_move_check, and the score for that move is calculated instead.
#===============================================================================
# UseMoveDependingOnEnvironment
#===============================================================================
#
#===============================================================================
# UseRandomMove
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.add("UseRandomMoveFromUserParty",
proc { |move, user, ai, battle|
will_fail = true
battle.pbParty(user.index).each_with_index do |pkmn, i|
next if !pkmn || i == user.party_index
next if Settings::MECHANICS_GENERATION >= 6 && pkmn.egg?
pkmn.moves.each do |pkmn_move|
next if move.move.moveBlacklist.include?(pkmn_move.function_code)
next if pkmn_move.type == :SHADOW
will_fail = false
break
end
break if !will_fail
end
next will_fail
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.add("UseRandomUserMoveIfAsleep",
proc { |move, user, ai, battle|
will_fail = true
user.battler.eachMoveWithIndex do |m, i|
next if move.move.moveBlacklist.include?(m.function)
next if !battle.pbCanChooseMove?(user.index, i, false, true)
will_fail = false
break
end
next will_fail
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveEffectScore.add("BounceBackProblemCausingStatusMoves",
proc { |score, move, user, ai, battle|
next Battle::AI::MOVE_USELESS_SCORE if user.has_active_ability?(:MAGICBOUNCE)
useless = true
ai.each_foe_battler(user.side) do |b, i|
next if !b.can_attack?
next if !b.check_for_move { |m| m.statusMove? && m.canMagicCoat? }
score += 5
useless = false
end
next Battle::AI::MOVE_USELESS_SCORE if useless
# Don't prefer the lower the user's HP is (better to try something else)
if ai.trainer.has_skill_flag?("HPAware") && user.hp < user.totalhp / 2
score -= (20 * (1.0 - (user.hp.to_f / user.totalhp))).to_i # -10 to -20
end
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveEffectScore.add("StealAndUseBeneficialStatusMove",
proc { |score, move, user, ai, battle|
useless = true
ai.each_foe_battler(user.side) do |b, i|
next if !b.can_attack?
next if !b.check_for_move { |m| m.statusMove? && m.canSnatch? }
score += 5
useless = false
end
next Battle::AI::MOVE_USELESS_SCORE if useless
# Don't prefer the lower the user's HP is (better to try something else)
if ai.trainer.has_skill_flag?("HPAware") && user.hp < user.totalhp / 2
score -= (20 * (1.0 - (user.hp.to_f / user.totalhp))).to_i # -10 to -20
end
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.add("ReplaceMoveThisBattleWithTargetLastMoveUsed",
proc { |move, user, ai, battle|
next user.effects[PBEffects::Transform] || !user.battler.pbHasMove?(move.id)
}
)
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("ReplaceMoveThisBattleWithTargetLastMoveUsed",
proc { |move, user, target, ai, battle|
next false if !user.faster_than?(target)
last_move_data = GameData::Move.try_get(target.battler.lastRegularMoveUsed)
next true if !last_move_data ||
user.battler.pbHasMove?(target.battler.lastRegularMoveUsed) ||
move.move.moveBlacklist.include?(last_move_data.function_code) ||
last_move_data.type == :SHADOW
next false
}
)
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("ReplaceMoveThisBattleWithTargetLastMoveUsed",
proc { |score, move, user, target, ai, battle|
# Generally don't prefer, as this wastes the user's turn just to gain a move
# of unknown utility
score -= 10
# Slightly prefer if this move will definitely succeed, just for the sake of
# getting rid of this move
score += 5 if user.faster_than?(target)
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.copy("ReplaceMoveThisBattleWithTargetLastMoveUsed",
"ReplaceMoveWithTargetLastMoveUsed")
Battle::AI::Handlers::MoveEffectScore.copy("ReplaceMoveThisBattleWithTargetLastMoveUsed",
"ReplaceMoveWithTargetLastMoveUsed")

View File

@@ -0,0 +1,810 @@
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.add("FleeFromBattle",
proc { |move, user, ai, battle|
next !battle.pbCanRun?(user.index)
}
)
Battle::AI::Handlers::MoveEffectScore.add("FleeFromBattle",
proc { |score, move, user, ai, battle|
# Generally don't prefer (don't want to end the battle too easily)
next score - 20
}
)
#===============================================================================
# TODO: Review score modifiers.
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.add("SwitchOutUserStatusMove",
proc { |move, user, ai, battle|
next !battle.pbCanRun?(user.index) if user.wild?
next !battle.pbCanChooseNonActive?(user.index)
}
)
Battle::AI::Handlers::MoveEffectScore.add("SwitchOutUserStatusMove",
proc { |score, move, user, ai, battle|
# Wild Pokémon run from battle
next score - 20 if user.wild?
# Trainer-owned Pokémon switch out
if ai.trainer.has_skill_flag?("ReserveLastPokemon") && battle.pbTeamAbleNonActiveCount(user.index) == 1
next Battle::AI::MOVE_USELESS_SCORE # Don't switch in ace
end
# Prefer if the user switching out will lose a negative effect
score += 10 if user.effects[PBEffects::Confusion] > 1
# Prefer if the user doesn't have any damaging moves
# TODO: Check effectiveness of moves.
score += 15 if !user.check_for_move { |m| m.damagingMove? }
# Don't prefer the more stat raises the user has
GameData::Stat.each_battle { |s| score -= user.stages[s.id] * 5 }
next score
}
)
#===============================================================================
# TODO: Review score modifiers.
#===============================================================================
Battle::AI::Handlers::MoveEffectScore.add("SwitchOutUserDamagingMove",
proc { |score, move, user, ai, battle|
next score if !battle.pbCanChooseNonActive?(user.index)
# Don't want to switch in ace
score -= 20 if ai.trainer.has_skill_flag?("ReserveLastPokemon") &&
battle.pbTeamAbleNonActiveCount(user.index) == 1
# Prefer if the user switching out will lose a negative effect
score += 10 if user.effects[PBEffects::Confusion] > 1
# Don't prefer the more stat raises the user has
GameData::Stat.each_battle { |s| score -= user.stages[s.id] * 5 }
next score
}
)
#===============================================================================
# TODO: Review score modifiers.
# TODO: Might need both MoveEffectScore and MoveEffectAgainstTargetScore.
#===============================================================================
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("LowerTargetAtkSpAtk1SwitchOutUser",
proc { |move, user, target, ai, battle|
will_fail = true
(move.move.statDown.length / 2).times do |i|
next if !target.battler.pbCanLowerStatStage?(move.move.statDown[i * 2], user.battler, move.move)
will_fail = false
break
end
next will_fail
}
)
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("LowerTargetAtkSpAtk1SwitchOutUser",
proc { |score, move, user, target, ai, battle|
score = ai.get_score_for_target_stat_drop(score, target, move.move.statDown, false)
if battle.pbCanChooseNonActive?(user.index)
# Don't want to switch in ace
score -= 20 if ai.trainer.has_skill_flag?("ReserveLastPokemon") &&
battle.pbTeamAbleNonActiveCount(user.index) == 1
# Prefer if the user switching out will lose a negative effect
score += 10 if user.effects[PBEffects::Confusion] > 1
# Prefer if the user doesn't have any damaging moves
# TODO: Check effectiveness of moves.
score += 15 if !user.check_for_move { |m| m.damagingMove? }
# Don't prefer the more stat raises the user has
GameData::Stat.each_battle { |s| score -= user.stages[s.id] * 5 }
end
next score
}
)
#===============================================================================
# TODO: Review score modifiers.
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.add("SwitchOutUserPassOnEffects",
proc { |move, user, ai, battle|
next !battle.pbCanChooseNonActive?(user.index)
}
)
Battle::AI::Handlers::MoveEffectScore.add("SwitchOutUserPassOnEffects",
proc { |score, move, user, ai, battle|
# Don't want to switch in ace
score -= 20 if ai.trainer.has_skill_flag?("ReserveLastPokemon") &&
battle.pbTeamAbleNonActiveCount(user.index) == 1
# Don't prefer if the user will pass on a negative effect
score -= 10 if user.effects[PBEffects::Confusion] > 1
# Prefer if the user doesn't have any damaging moves
# TODO: Check effectiveness of moves.
score += 15 if !user.check_for_move { |m| m.damagingMove? }
# Prefer if the user will pass on good stat stages
GameData::Stat.each_battle { |s| score += user.stages[s.id] * 5 }
next score
}
)
#===============================================================================
# TODO: Review score modifiers.
#===============================================================================
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("SwitchOutTargetStatusMove",
proc { |move, user, target, ai, battle|
next true if (!battle.moldBreaker && target.has_active_ability?(:SUCTIONCUPS)) ||
target.effects[PBEffects::Ingrain]
next true if !battle.canRun
next true if battle.wildBattle? && target.level > user.level
if battle.trainerBattle?
will_fail = true
battle.eachInTeamFromBattlerIndex(target.index) do |_pkmn, i|
next if !battle.pbCanSwitchIn?(target.index, i)
will_fail = false
break
end
next will_fail
end
next false
}
)
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("SwitchOutTargetStatusMove",
proc { |score, move, user, target, ai, battle|
score += 15 if target.pbOwnSide.effects[PBEffects::Spikes] > 0
score += 15 if target.pbOwnSide.effects[PBEffects::ToxicSpikes] > 0
score += 15 if target.pbOwnSide.effects[PBEffects::StealthRock]
next score
}
)
#===============================================================================
# TODO: Review score modifiers.
#===============================================================================
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("SwitchOutTargetDamagingMove",
proc { |score, move, user, target, ai, battle|
if (battle.moldBreaker || !target.has_active_ability?(:SUCTIONCUPS)) &&
!target.effects[PBEffects::Ingrain]
score += 15 if target.pbOwnSide.effects[PBEffects::Spikes] > 0
score += 15 if target.pbOwnSide.effects[PBEffects::ToxicSpikes] > 0
score += 15 if target.pbOwnSide.effects[PBEffects::StealthRock]
end
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("BindTarget",
proc { |score, move, user, target, ai, battle|
next score if target.effects[PBEffects::Trapping] > 0
next score if target.effects[PBEffects::Substitute] > 0
# Prefer if the user has a Binding Band or Grip Claw (because why have it if
# you don't want to use it?)
score += 5 if user.has_active_item?([:BINDINGBAND, :GRIPCLAW])
# Target will take damage at the end of each round from the binding
score += 10 if target.battler.takesIndirectDamage?
# Check whether the target will be trapped in battle by the binding
if target.can_become_trapped?
score += 8 # Prefer if the target will become trapped by this move
eor_damage = target.rough_end_of_round_damage
if eor_damage > 0
# Prefer if the target will take damage at the end of each round on top
# of binding damage
score += 10
elsif eor_damage < 0
# Don't prefer if the target will heal itself at the end of each round
score -= 10
end
# Prefer if the target has been Perish Songed
score += 15 if target.effects[PBEffects::PerishSong] > 0
end
# Don't prefer if the target can remove the binding (and the binding has an
# effect)
if target.can_become_trapped? || target.battler.takesIndirectDamage?
if ai.trainer.medium_skill? &&
target.has_move_with_function?("RemoveUserBindingAndEntryHazards")
score -= 10
end
end
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveBasePower.add("BindTargetDoublePowerIfTargetUnderwater",
proc { |power, move, user, target, ai, battle|
next move.move.pbModifyDamage(power, user.battler, target.battler)
}
)
Battle::AI::Handlers::MoveEffectAgainstTargetScore.copy("BindTarget",
"BindTargetDoublePowerIfTargetUnderwater")
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("TrapTargetInBattle",
proc { |move, user, target, ai, battle|
next false if move.damagingMove?
next true if target.effects[PBEffects::MeanLook] >= 0
next true if Settings::MORE_TYPE_EFFECTS && target.has_type?(:GHOST)
next false
}
)
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("TrapTargetInBattle",
proc { |score, move, user, target, ai, battle|
if !target.can_become_trapped? || !battle.pbCanChooseNonActive?(target.index)
next (move.damagingMove?) ? score : Battle::AI::MOVE_USELESS_SCORE
end
# Not worth trapping if target will faint this round anyway
eor_damage = target.rough_end_of_round_damage
if eor_damage >= target.hp
next (move.damagingMove?) ? score : Battle::AI::MOVE_USELESS_SCORE
end
# Not worth trapping if target can remove the binding
if ai.trainer.medium_skill? &&
target.has_move_with_function?("RemoveUserBindingAndEntryHazards")
next (move.damagingMove?) ? score : Battle::AI::MOVE_USELESS_SCORE
end
# Score for being an additional effect
add_effect = move.get_score_change_for_additional_effect(user, target)
next score if add_effect == -999 # Additional effect will be negated
score += add_effect
# Score for target becoming trapped in battle
# TODO: These checks are related to desire to switch, and there can be a lot
# more things to consider, e.g. effectiveness of the target's moves
# against its foes. Also applies to other code that calls
# can_become_trapped?
if target.effects[PBEffects::PerishSong] > 0 ||
target.effects[PBEffects::Attract] >= 0 ||
eor_damage > 0
score += 15
end
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.copy("TrapTargetInBattle",
"TrapTargetInBattleMainEffect")
Battle::AI::Handlers::MoveEffectAgainstTargetScore.copy("TrapTargetInBattle",
"TrapTargetInBattleMainEffect")
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("TrapTargetInBattleLowerTargetDefSpDef1EachTurn",
proc { |move, user, target, ai, battle|
next false if move.damagingMove?
next true if target.effects[PBEffects::Octolock] >= 0
next true if Settings::MORE_TYPE_EFFECTS && target.has_type?(:GHOST)
next false
}
)
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("TrapTargetInBattleLowerTargetDefSpDef1EachTurn",
proc { |score, move, user, target, ai, battle|
# Score for stat drop
score = ai.get_score_for_target_stat_drop(score, target, [:DEFENSE, 1, :SPECIAL_DEFENSE, 1], false)
# Score for target becoming trapped in battle
if target.can_become_trapped? && battle.pbCanChooseNonActive?(target.index)
# Not worth trapping if target will faint this round anyway
eor_damage = target.rough_end_of_round_damage
if eor_damage >= target.hp
next (move.damagingMove?) ? score : Battle::AI::MOVE_USELESS_SCORE
end
# Not worth trapping if target can remove the binding
if target.has_move_with_function?("RemoveUserBindingAndEntryHazards")
next (move.damagingMove?) ? score : Battle::AI::MOVE_USELESS_SCORE
end
# Score for target becoming trapped in battle
# TODO: These checks are related to desire to switch, and there can be a lot
# more things to consider, e.g. effectiveness of the target's moves
# against its foes. Also applies to other code that calls
# can_become_trapped?
if target.effects[PBEffects::PerishSong] > 0 ||
target.effects[PBEffects::Attract] >= 0 ||
eor_damage > 0
score += 15
end
end
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("TrapUserAndTargetInBattle",
proc { |score, move, user, target, ai, battle|
# NOTE: Don't worry about scoring for the user also becoming trapped in
# battle, because it knows this move and accepts what it's getting
# itself into.
if target.can_become_trapped? && battle.pbCanChooseNonActive?(target.index)
# Not worth trapping if target will faint this round anyway
eor_damage = target.rough_end_of_round_damage
if eor_damage >= target.hp
next (move.damagingMove?) ? score : Battle::AI::MOVE_USELESS_SCORE
end
# Not worth trapping if target can remove the binding
if ai.trainer.medium_skill? &&
target.has_move_with_function?("RemoveUserBindingAndEntryHazards")
next (move.damagingMove?) ? score : Battle::AI::MOVE_USELESS_SCORE
end
# Score for target becoming trapped in battle
# TODO: These checks are related to desire to switch, and there can be a lot
# more things to consider, e.g. effectiveness of the target's moves
# against its foes. Also applies to other code that calls
# can_become_trapped?
if target.effects[PBEffects::PerishSong] > 0 ||
target.effects[PBEffects::Attract] >= 0 ||
eor_damage > 0
score += 15
end
end
next score
}
)
#===============================================================================
# TODO: Review score modifiers.
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.add("TrapAllBattlersInBattleForOneTurn",
proc { |move, user, ai, battle|
next battle.field.effects[PBEffects::FairyLock] > 0
}
)
#===============================================================================
# TODO: Review score modifiers.
#===============================================================================
# PursueSwitchingFoe
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.add("UsedAfterUserTakesPhysicalDamage",
proc { |move, user, ai, battle|
found_physical_move = false
ai.each_foe_battler(user.side) do |b, i|
next if !b.check_for_move { |m| m.physicalMove?(m.type) }
found_physical_move = true
break
end
next !found_physical_move
}
)
Battle::AI::Handlers::MoveEffectScore.add("UsedAfterUserTakesPhysicalDamage",
proc { |score, move, user, ai, battle|
next Battle::AI::MOVE_USELESS_SCORE if user.effects[PBEffects::Substitute] > 0
# Prefer if foes don't know any special moves
found_special_move = false
ai.each_foe_battler(user.side) do |b, i|
next if !b.check_for_move { |m| m.specialMove?(m.type) }
found_special_move = true
break
end
score += 10 if !found_special_move
# Generally not worth using
next score - 10
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveEffectScore.add("UsedAfterAllyRoundWithDoublePower",
proc { |score, move, user, ai, battle|
# No score change if no allies know this move
ally_has_move = false
ai.each_same_side_battler(user.side) do |b, i|
next if !b.has_move_with_function?(move.function)
ally_has_move = true
break
end
next score if !ally_has_move
# Prefer for the sake of doubling in power
score += 10
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("TargetActsNext",
proc { |score, move, user, target, ai, battle|
# Useless if the target is a foe
next Battle::AI::MOVE_USELESS_SCORE if target.opposes?(user)
# Compare the speeds of all battlers
speeds = []
ai.each_battler { |b, i| speeds.push([i, b.rough_stat(:SPEED)]) }
if battle.field.effects[PBEffects::TrickRoom] > 0
speeds.sort! { |a, b| a[1] <=> b[1] }
else
speeds.sort! { |a, b| b[1] <=> a[1] }
end
idx_user = speeds.index { |ele| ele[0] == user.index }
idx_target = speeds.index { |ele| ele[0] == target.index }
# Useless if the target is faster than the user
next Battle::AI::MOVE_USELESS_SCORE if idx_target < idx_user
# Useless if the target will move next anyway
next Battle::AI::MOVE_USELESS_SCORE if idx_target - idx_user <= 1
# Generally not worth using
# NOTE: Because this move can be used against a foe but is being used on an
# ally (since we're here in this code), this move's score will be
# inverted later. A higher score here means this move will be less
# preferred, which is the result we want.
next score + 10
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("TargetActsLast",
proc { |score, move, user, target, ai, battle|
# Useless if the target is an ally
next Battle::AI::MOVE_USELESS_SCORE if !target.opposes?(user)
# Useless if the user has no ally (the point of this move is to let the ally
# get in a hit before the foe)
has_ally = false
ai.each_ally(user.index) { |b, i| has_ally = true if b.can_attack? }
next Battle::AI::MOVE_USELESS_SCORE if !has_ally
# Compare the speeds of all battlers
speeds = []
ai.each_battler { |b, i| speeds.push([i, b.rough_stat(:SPEED)]) }
if battle.field.effects[PBEffects::TrickRoom] > 0
speeds.sort! { |a, b| a[1] <=> b[1] }
else
speeds.sort! { |a, b| b[1] <=> a[1] }
end
idx_user = speeds.index { |ele| ele[0] == user.index }
idx_target = speeds.index { |ele| ele[0] == target.index }
idx_slowest_ally = -1
speeds.each_with_index { |ele, i| idx_slowest_ally = i if user.index.even? == ele[0].even? }
# Useless if the target is faster than the user
next Battle::AI::MOVE_USELESS_SCORE if idx_target < idx_user
# Useless if the target will move last anyway
next Battle::AI::MOVE_USELESS_SCORE if idx_target == speeds.length - 1
# Useless if the slowest ally is faster than the target
next Battle::AI::MOVE_USELESS_SCORE if idx_slowest_ally < idx_target
# Generally not worth using
next score - 10
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("TargetUsesItsLastUsedMoveAgain",
proc { |move, user, target, ai, battle|
next target.battler.usingMultiTurnAttack?
}
)
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("TargetUsesItsLastUsedMoveAgain",
proc { |score, move, user, target, ai, battle|
# We don't ever want to make a foe act again
next Battle::AI::MOVE_USELESS_SCORE if target.opposes?(user)
# Useless if target will act before the user, as we don't know what move
# will be instructed
next Battle::AI::MOVE_USELESS_SCORE if target.faster_than?(user)
next Battle::AI::MOVE_USELESS_SCORE if !target.battler.lastRegularMoveUsed
mov = nil
target.battler.eachMove do |m|
mov = m if m.id == target.battler.lastRegularMoveUsed
break if mov
end
next Battle::AI::MOVE_USELESS_SCORE if mov.nil? || (mov.pp == 0 && mov.total_pp > 0)
next Battle::AI::MOVE_USELESS_SCORE if move.move.moveBlacklist.include?(mov.function)
# Without lots of code here to determine good/bad moves, using this move is
# likely to just be a waste of a turn
# NOTE: Because this move can be used against a foe but is being used on an
# ally (since we're here in this code), this move's score will be
# inverted later. A higher score here means this move will be less
# preferred, which is the result we want.
score += 10
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveEffectScore.add("StartSlowerBattlersActFirst",
proc { |score, move, user, ai, battle|
# Get the speeds of all battlers
ally_speeds = []
foe_speeds = []
ai.each_battler do |b, i|
if b.opposes?(user)
foe_speeds.push(b.rough_stat(:SPEED))
foe_speeds.last *= 2 if user.pbOpposingSide.effects[PBEffects::Tailwind] > 1
foe_speeds.last /= 2 if user.pbOpposingSide.effects[PBEffects::Swamp] > 1
else
ally_speeds.push(b.rough_stat(:SPEED))
ally_speeds.last *= 2 if user.pbOwnSide.effects[PBEffects::Tailwind] > 1
ally_speeds.last /= 2 if user.pbOwnSide.effects[PBEffects::Swamp] > 1
end
end
# Just in case a side has no battlers
next Battle::AI::MOVE_USELESS_SCORE if ally_speeds.length == 0 || foe_speeds.length == 0
# Invert the speeds if Trick Room applies (and will last longer than this round)
if battle.field.effects[PBEffects::TrickRoom] > 1
foe_speeds.map! { |val| 100_000 - val } # 100_000 is higher than speed can
ally_speeds.map! { |val| 100_000 - val } # possibly be; only order matters
end
# Score based on the relative speeds
next Battle::AI::MOVE_USELESS_SCORE if ally_speeds.min > foe_speeds.max
if foe_speeds.min > ally_speeds.max
score += 20
elsif ally_speeds.sum / ally_speeds.length < foe_speeds.sum / foe_speeds.length
score += 10
else
score -= 10
end
next score
}
)
#===============================================================================
#
#===============================================================================
# HigherPriorityInGrassyTerrain
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("LowerPPOfTargetLastMoveBy3",
proc { |score, move, user, target, ai, battle|
add_effect = move.get_score_change_for_additional_effect(user, target)
next score if add_effect == -999 # Additional effect will be negated
if user.faster_than?(target)
last_move = target.battler.pbGetMoveWithID(target.battler.lastRegularMoveUsed)
if last_move && last_move.total_pp > 0
score += add_effect
next score + 20 if last_move.pp <= 3 # Will fully deplete the move's PP
next score + 10 if last_move.pp <= 5
next score - 10 if last_move.pp > 9 # Too much PP left to make a difference
end
end
next score # Don't know which move it will affect; treat as just a damaging move
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("LowerPPOfTargetLastMoveBy4",
proc { |move, user, target, ai, battle|
next !target.check_for_move { |m| m.id == target.battler.lastRegularMoveUsed }
}
)
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("LowerPPOfTargetLastMoveBy4",
proc { |score, move, user, target, ai, battle|
if user.faster_than?(target)
last_move = target.battler.pbGetMoveWithID(target.battler.lastRegularMoveUsed)
next score + 20 if last_move.pp <= 4 # Will fully deplete the move's PP
next score + 10 if last_move.pp <= 6
next score - 10 if last_move.pp > 10 # Too much PP left to make a difference
end
next score - 10 # Don't know which move it will affect; don't prefer
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("DisableTargetLastMoveUsed",
proc { |move, user, target, ai, battle|
next true if target.effects[PBEffects::Disable] > 0 || !target.battler.lastRegularMoveUsed
next true if move.move.pbMoveFailedAromaVeil?(user.battler, target.battler, false)
next !target.check_for_move { |m| m.id == target.battler.lastRegularMoveUsed }
}
)
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("DisableTargetLastMoveUsed",
proc { |score, move, user, target, ai, battle|
next Battle::AI::MOVE_USELESS_SCORE if target.has_active_item?(:MENTALHERB)
# Inherent preference
score += 5
# Prefer if the target is locked into using a single move, or will be
if target.effects[PBEffects::ChoiceBand] ||
target.has_active_item?([:CHOICEBAND, :CHOICESPECS, :CHOICESCARF]) ||
target.has_active_ability?(:GORILLATACTICS)
score += 10
end
# Prefer disabling a damaging move
score += 8 if GameData::Move.try_get(target.battler.lastRegularMoveUsed)&.damaging?
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("DisableTargetUsingSameMoveConsecutively",
proc { |move, user, target, ai, battle|
next true if target.effects[PBEffects::Torment]
next true if move.move.pbMoveFailedAromaVeil?(user.battler, target.battler, false)
next false
}
)
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("DisableTargetUsingSameMoveConsecutively",
proc { |score, move, user, target, ai, battle|
next Battle::AI::MOVE_USELESS_SCORE if target.has_active_item?(:MENTALHERB)
# Inherent preference
score += 10
# Prefer if the target is locked into using a single move, or will be
if target.effects[PBEffects::ChoiceBand] ||
target.has_active_item?([:CHOICEBAND, :CHOICESPECS, :CHOICESCARF]) ||
target.has_active_ability?(:GORILLATACTICS)
score += 10
end
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("DisableTargetUsingDifferentMove",
proc { |move, user, target, ai, battle|
next true if target.effects[PBEffects::Encore] > 0
next true if !target.battler.lastRegularMoveUsed ||
!GameData::Move.exists?(target.battler.lastRegularMoveUsed) ||
move.move.moveBlacklist.include?(GameData::Move.get(target.battler.lastRegularMoveUsed).function_code)
next true if target.effects[PBEffects::ShellTrap]
next true if move.move.pbMoveFailedAromaVeil?(user.battler, target.battler, false)
will_fail = true
next !target.check_for_move { |m| m.id == target.battler.lastRegularMoveUsed }
}
)
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("DisableTargetUsingDifferentMove",
proc { |score, move, user, target, ai, battle|
next Battle::AI::MOVE_USELESS_SCORE if target.has_active_item?(:MENTALHERB)
if user.faster_than?(target)
# We know which move is going to be encored (assuming the target doesn't
# use a high priority move)
move_data = GameData::Move.get(target.battler.lastRegularMoveUsed)
if move_data.status?
# Prefer encoring status moves
if [:User, :BothSides].include?(move_data.target)
# TODO: This target distinction was in the old code. Is it appropriate?
score += 10
else
score += 8
end
elsif move_data.damaging? && [:NearOther, :Other].include?(move_data.target)
# Prefer encoring damaging moves depending on their type effectiveness
# against the user
eff = user.effectiveness_of_type_against_battler(move_data.type, target)
if Effectiveness.ineffective?(eff)
score += 20
elsif Effectiveness.not_very_effective?(eff)
score += 15
elsif Effectiveness.super_effective?(eff)
score -= 8
else
score += 8
end
end
else
# We don't know which move is going to be encored; just prefer limiting
# the target's options
score += 10
end
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("DisableTargetStatusMoves",
proc { |move, user, target, ai, battle|
next true if target.effects[PBEffects::Taunt] > 0
next true if move.move.pbMoveFailedAromaVeil?(user.battler, target.battler, false)
next true if Settings::MECHANICS_GENERATION >= 6 &&
!battle.moldBreaker && target.has_active_ability?(:OBLIVIOUS)
next false
}
)
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("DisableTargetStatusMoves",
proc { |score, move, user, target, ai, battle|
next Battle::AI::MOVE_USELESS_SCORE if !target.check_for_move { |m| m.statusMove? }
# Not worth using on a sleeping target that won't imminently wake up
if target.status == :SLEEP && target.statusCount > ((target.faster_than?(user)) ? 2 : 1)
if !target.check_for_move { |m| m.statusMove? && m.usableWhenAsleep? }
next Battle::AI::MOVE_USELESS_SCORE
end
end
# Move is likely useless if the target will lock themselves into a move,
# because they'll likely lock themselves into a damaging move
if !target.effects[PBEffects::ChoiceBand]
if target.has_active_item?([:CHOICEBAND, :CHOICESPECS, :CHOICESCARF]) ||
target.has_active_ability?(:GORILLATACTICS)
next Battle::AI::MOVE_USELESS_SCORE
end
end
# Prefer based on how many status moves the target knows
target.battler.eachMove do |m|
score += 5 if m.statusMove? && (m.pp > 0 || m.total_pp == 0)
end
# Prefer if the target has a protection move
protection_moves = [
"ProtectUser", # Detect, Protect
"ProtectUserSideFromPriorityMoves", # Quick Guard
"ProtectUserSideFromMultiTargetDamagingMoves", # Wide Guard
"UserEnduresFaintingThisTurn", # Endure
"ProtectUserSideFromDamagingMovesIfUserFirstTurn", # Mat Block
"ProtectUserSideFromStatusMoves", # Crafty Shield
"ProtectUserFromDamagingMovesKingsShield", # King's Shield
"ProtectUserFromDamagingMovesObstruct", # Obstruct
"ProtectUserFromTargetingMovesSpikyShield", # Spiky Shield
"ProtectUserBanefulBunker" # Baneful Bunker
]
if target.check_for_move { |m| m.statusMove? && protection_moves.include?(m.function) }
score += 10
end
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("DisableTargetHealingMoves",
proc { |move, user, target, ai, battle|
next true if target.effects[PBEffects::HealBlock] > 0
next true if move.move.pbMoveFailedAromaVeil?(user.battler, target.battler, false)
next false
}
)
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("DisableTargetHealingMoves",
proc { |score, move, user, target, ai, battle|
# Useless if the foe can't heal themselves with a move or some held items
if !target.check_for_move { |m| m.healingMove? }
if !target.has_active_item?(:LEFTOVERS) &&
!(target.has_active_item?(:BLACKSLUDGE) && target.has_type?(:POISON))
next Battle::AI::MOVE_USELESS_SCORE
end
end
# Inherent preference
score += 10
next score
}
)
#===============================================================================
#.
#===============================================================================
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("DisableTargetSoundMoves",
proc { |score, move, user, target, ai, battle|
next score if target.effects[PBEffects::ThroatChop] > 1
next score if !target.check_for_move { |m| m.soundMove? }
# Check additional effect chance
add_effect = move.get_score_change_for_additional_effect(user, target)
next score if add_effect == -999 # Additional effect will be negated
score += add_effect
# Inherent preference
score += 8
next score
}
)
#===============================================================================
#
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.add("DisableTargetMovesKnownByUser",
proc { |move, user, ai, battle|
next user.effects[PBEffects::Imprison]
}
)
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("DisableTargetMovesKnownByUser",
proc { |score, move, user, target, ai, battle|
# Useless if the foes have no moves that the user also knows
affected_foe_count = 0
user_moves = user.battler.moves.map { |m| m.id }
ai.each_foe_battler(user.side) do |b, i|
next if !b.check_for_move { |m| user_moves.include?(m.id) }
affected_foe_count += 1
break
end
next Battle::AI::MOVE_USELESS_SCORE if affected_foe_count == 0
# Inherent preference
score += 8 * affected_foe_count
next score
}
)