Added AI objects for trainers, battlers and the move being assessed, logging battle messages now also echoes them to the console

This commit is contained in:
Maruno17
2022-08-22 21:37:33 +01:00
parent b094a2fd8e
commit cfb870c944
24 changed files with 1856 additions and 1666 deletions

View File

@@ -16,14 +16,24 @@ module PBDebug
def self.flush def self.flush
if $DEBUG && $INTERNAL && @@log.length > 0 if $DEBUG && $INTERNAL && @@log.length > 0
File.open("Data/debuglog.txt", "a+b") { |f| f.write(@@log.to_s) } File.open("Data/debuglog.txt", "a+b") { |f| f.write(@@log.join) }
end end
@@log.clear @@log.clear
end end
def self.log(msg) def self.log(msg)
if $DEBUG && $INTERNAL if $DEBUG && $INTERNAL
@@log.push("#{msg}\r\n") echoln msg
@@log.push(msg + "\r\n")
PBDebug.flush # if @@log.length > 1024
end
end
def self.log_message(msg)
if $DEBUG && $INTERNAL
msg = "\"" + msg + "\""
echoln Console.markup_style(msg, text: :dark_gray)
@@log.push(msg + "\r\n")
PBDebug.flush # if @@log.length > 1024 PBDebug.flush # if @@log.length > 1024
end end
end end

View File

@@ -278,6 +278,7 @@ class Battle
def pbStartBattleCore def pbStartBattleCore
# Set up the battlers on each side # Set up the battlers on each side
sendOuts = pbSetUpSides sendOuts = pbSetUpSides
@battleAI.create_ai_objects
# Create all the sprites and play the battle intro animation # Create all the sprites and play the battle intro animation
@scene.pbStartBattle(self) @scene.pbStartBattle(self)
# Show trainers on both sides sending out Pokémon # Show trainers on both sides sending out Pokémon

View File

@@ -189,7 +189,7 @@ class Battle::Scene
pbShowWindow(MESSAGE_BOX) pbShowWindow(MESSAGE_BOX)
cw = @sprites["messageWindow"] cw = @sprites["messageWindow"]
cw.setText(msg) cw.setText(msg)
PBDebug.log(msg) PBDebug.log_message(msg)
yielded = false yielded = false
timer = 0.0 timer = 0.0
loop do loop do
@@ -235,7 +235,7 @@ class Battle::Scene
pbShowWindow(MESSAGE_BOX) pbShowWindow(MESSAGE_BOX)
cw = @sprites["messageWindow"] cw = @sprites["messageWindow"]
cw.text = _INTL("{1}\1", msg) cw.text = _INTL("{1}\1", msg)
PBDebug.log(msg) PBDebug.log_message(msg)
yielded = false yielded = false
timer = 0.0 timer = 0.0
loop do loop do
@@ -283,7 +283,7 @@ class Battle::Scene
cw.z = dw.z + 1 cw.z = dw.z + 1
cw.index = 0 cw.index = 0
cw.viewport = @viewport cw.viewport = @viewport
PBDebug.log(msg) PBDebug.log_message(msg)
loop do loop do
cw.visible = (!dw.busy?) cw.visible = (!dw.busy?)
pbUpdate(cw) pbUpdate(cw)

View File

@@ -2,93 +2,61 @@
# #
#=============================================================================== #===============================================================================
class Battle::AI class Battle::AI
# AI skill levels: attr_reader :battle
# 0: Wild Pokémon attr_reader :trainer
# 1-31: Basic trainer (young/inexperienced) attr_reader :user, :target, :move
# 32-47: Some skill
# 48-99: High skill
# 100+: Best trainers (Gym Leaders, Elite Four, Champion)
# NOTE: A trainer's skill value can range from 0-255, but by default only four
# distinct skill levels exist. The skill value is typically the same as
# the trainer's base money value.
module AILevel
# Minimum skill level to be in each AI skill bracket.
def self.minimum; return 1; end
def self.medium; return 32; end
def self.high; return 48; end
def self.best; return 100; end
end
#=============================================================================
#
#=============================================================================
def initialize(battle) def initialize(battle)
@battle = battle @battle = battle
@skill = 0
@user = nil # TODO: Move this elsewhere?
@wildBattler = @battle.wildBattle? # Whether AI is choosing for a wild Pokémon @roles = [Array.new(@battle.pbParty(0).length) { |i| determine_roles(0, i) },
@roles = [Array.new(@battle.pbParty(0).length) { |i| determine_roles(0, i) }, Array.new(@battle.pbParty(1).length) { |i| determine_roles(1, i) }]
Array.new(@battle.pbParty(1).length) { |i| determine_roles(1, i) }]
end end
def pbAIRandom(x); return rand(x); end def create_ai_objects
# Initialize AI trainers
def pbStdDev(choices) @trainers = [[], []]
sum = 0 @battle.player.each_with_index do |trainer, i|
n = 0 @trainers[0][i] = AITrainer.new(self, 0, i, trainer)
choices.each do |c|
sum += c[1]
n += 1
end end
return 0 if n < 2 if @battle.wildBattle?
mean = sum.to_f / n @trainers[1][0] = AITrainer.new(self, 1, 0, nil)
varianceTimesN = 0 else
choices.each do |c| @battle.opponent.each_with_index do |trainer, i|
next if c[1] <= 0 @trainers[1][i] = AITrainer.new(self, 1, i, trainer)
deviation = c[1].to_f - mean end
varianceTimesN += deviation * deviation
end end
# Using population standard deviation # Initialize AI battlers
# [(n-1) makes it a sample std dev, would be 0 with only 1 sample] @battlers = []
return Math.sqrt(varianceTimesN / n) @battle.battlers.each_with_index do |battler, i|
@battlers[i] = AIBattler.new(self, i) if battler
end
# Initialize AI move object
@move = AIMove.new(self)
end end
# Decide whether the opponent should Mega Evolve their Pokémon. # Set some class variables for the Pokémon whose action is being chosen
def pbEnemyShouldMegaEvolve? def set_up(idxBattler)
if @battle.pbCanMegaEvolve?(@user.index) # Simple "always should if possible" # Find the AI trainer choosing the action
PBDebug.log("[AI] #{@user.pbThis} (#{@user.index}) will Mega Evolve") opposes = @battle.opposes?(idxBattler)
return true trainer_index = @battle.pbGetOwnerIndexFromBattlerIndex(idxBattler)
end @trainer = @trainers[(opposes) ? 1 : 0][trainer_index]
return false # Find the AI battler for which the action is being chosen
@user = @battlers[idxBattler]
@user.refresh_battler
end end
# Choose an action. # Choose an action.
def pbDefaultChooseEnemyCommand(idxBattler) def pbDefaultChooseEnemyCommand(idxBattler)
set_up(idxBattler) set_up(idxBattler)
choices = pbGetMoveScores
return if pbEnemyShouldUseItem?
return if pbEnemyShouldWithdraw? return if pbEnemyShouldWithdraw?
return if pbEnemyShouldUseItem?
return if @battle.pbAutoFightMenu(idxBattler) return if @battle.pbAutoFightMenu(idxBattler)
@battle.pbRegisterMegaEvolution(idxBattler) if pbEnemyShouldMegaEvolve? @battle.pbRegisterMegaEvolution(idxBattler) if pbEnemyShouldMegaEvolve?
choices = pbGetMoveScores
pbChooseMove(choices) pbChooseMove(choices)
end end
# Set some class variables for the Pokémon whose action is being chosen
def set_up(idxBattler)
# TODO: Where relevant, pretend the user is Mega Evolved if it isn't but can
# be.
@user = @battle.battlers[idxBattler]
@wildBattler = (@battle.wildBattle? && @user.opposes?)
@skill = 0
if !@wildBattler
@skill = @battle.pbGetOwnerFromBattlerIndex(@user.index).skill_level || 0
@skill = AILevel.minimum if @skill < AILevel.minimum
end
end
def skill_check(threshold)
return @skill >= threshold
end
end end
#=============================================================================== #===============================================================================

View File

@@ -24,7 +24,7 @@ class Battle::AI
return nil if !items || items.length == 0 return nil if !items || items.length == 0
# Determine target of item (always the Pokémon choosing the action) # Determine target of item (always the Pokémon choosing the action)
idxTarget = @user.index # Battler using the item idxTarget = @user.index # Battler using the item
battler = @battle.battlers[idxTarget] battler = @user.battler
pkmn = battler.pokemon pkmn = battler.pokemon
# Item categories # Item categories
hpItems = { hpItems = {

View File

@@ -7,19 +7,20 @@ class Battle::AI
end end
def pbEnemyShouldWithdrawEx?(forceSwitch) def pbEnemyShouldWithdrawEx?(forceSwitch)
return false if @wildBattler return false if @user.wild?
shouldSwitch = forceSwitch shouldSwitch = forceSwitch
battler = @user.battler
batonPass = -1 batonPass = -1
moveType = nil moveType = nil
# If Pokémon is within 6 levels of the foe, and foe's last move was # If Pokémon is within 6 levels of the foe, and foe's last move was
# super-effective and powerful # super-effective and powerful
if !shouldSwitch && @user.turnCount > 0 && skill_check(AILevel.high) if !shouldSwitch && battler.turnCount > 0 && @trainer.high_skill?
target = @user.pbDirectOpposing(true) target = battler.pbDirectOpposing(true)
if !target.fainted? && target.lastMoveUsed && if !target.fainted? && target.lastMoveUsed &&
(target.level - @user.level).abs <= 6 (target.level - battler.level).abs <= 6
moveData = GameData::Move.get(target.lastMoveUsed) moveData = GameData::Move.get(target.lastMoveUsed)
moveType = moveData.type moveType = moveData.type
typeMod = pbCalcTypeMod(moveType, target, @user) typeMod = battler.effectiveness_of_type_against_battler(moveType, target)
if Effectiveness.super_effective?(typeMod) && moveData.base_damage > 50 if Effectiveness.super_effective?(typeMod) && moveData.base_damage > 50
switchChance = (moveData.base_damage > 70) ? 30 : 20 switchChance = (moveData.base_damage > 70) ? 30 : 20
shouldSwitch = (pbAIRandom(100) < switchChance) shouldSwitch = (pbAIRandom(100) < switchChance)
@@ -27,36 +28,36 @@ class Battle::AI
end end
end end
# Pokémon can't do anything (must have been in battle for at least 5 rounds) # Pokémon can't do anything (must have been in battle for at least 5 rounds)
if !@battle.pbCanChooseAnyMove?(@user.index) && if !shouldSwitch && !@battle.pbCanChooseAnyMove?(battler.index) &&
@user.turnCount && @user.turnCount >= 5 battler.turnCount && battler.turnCount >= 5
shouldSwitch = true shouldSwitch = true
end end
# Pokémon is Perish Songed and has Baton Pass # Pokémon is Perish Songed and has Baton Pass
if skill_check(AILevel.high) && @user.effects[PBEffects::PerishSong] == 1 if @trainer.high_skill? && battler.effects[PBEffects::PerishSong] == 1
@user.eachMoveWithIndex do |m, i| battler.eachMoveWithIndex do |m, i|
next if m.function != "SwitchOutUserPassOnEffects" # Baton Pass next if m.function != "SwitchOutUserPassOnEffects" # Baton Pass
next if !@battle.pbCanChooseMove?(@user.index, i, false) next if !@battle.pbCanChooseMove?(battler.index, i, false)
batonPass = i batonPass = i
break break
end end
end end
# Pokémon will faint because of bad poisoning at the end of this round, but # Pokémon will faint because of bad poisoning at the end of this round, but
# would survive at least one more round if it were regular poisoning instead # would survive at least one more round if it were regular poisoning instead
if @user.status == :POISON && @user.statusCount > 0 && skill_check(AILevel.high) if !shouldSwitch && battler.status == :POISON && battler.statusCount > 0 && @trainer.high_skill?
toxicHP = @user.totalhp / 16 toxicHP = battler.totalhp / 16
nextToxicHP = toxicHP * (@user.effects[PBEffects::Toxic] + 1) nextToxicHP = toxicHP * (battler.effects[PBEffects::Toxic] + 1)
if @user.hp <= nextToxicHP && @user.hp > toxicHP * 2 if battler.hp <= nextToxicHP && battler.hp > toxicHP * 2
shouldSwitch = true if pbAIRandom(100) < 80 shouldSwitch = true if pbAIRandom(100) < 80
end end
end end
# Pokémon is Encored into an unfavourable move # Pokémon is Encored into an unfavourable move
if @user.effects[PBEffects::Encore] > 0 && skill_check(AILevel.medium) if !shouldSwitch && battler.effects[PBEffects::Encore] > 0 && @trainer.medium_skill?
idxEncoredMove = @user.pbEncoredMoveIndex idxEncoredMove = battler.pbEncoredMoveIndex
if idxEncoredMove >= 0 if idxEncoredMove >= 0
scoreSum = 0 scoreSum = 0
scoreCount = 0 scoreCount = 0
@user.allOpposing.each do |b| battler.allOpposing.each do |b|
scoreSum += pbGetMoveScore(@user.moves[idxEncoredMove], b) scoreSum += pbGetMoveScore(battler.moves[idxEncoredMove], b)
scoreCount += 1 scoreCount += 1
end end
if scoreCount > 0 && scoreSum / scoreCount <= 20 if scoreCount > 0 && scoreSum / scoreCount <= 20
@@ -66,37 +67,37 @@ class Battle::AI
end end
# If there is a single foe and it is resting after Hyper Beam or is # If there is a single foe and it is resting after Hyper Beam or is
# Truanting (i.e. free turn) # Truanting (i.e. free turn)
if @battle.pbSideSize(@user.index + 1) == 1 && if shouldSwitch && @battle.pbSideSize(battler.index + 1) == 1 &&
!@user.pbDirectOpposing.fainted? && skill_check(AILevel.high) !battler.pbDirectOpposing.fainted? && @trainer.high_skill?
opp = @user.pbDirectOpposing opp = battler.pbDirectOpposing
if (opp.effects[PBEffects::HyperBeam] > 0 || if (opp.effects[PBEffects::HyperBeam] > 0 ||
(opp.hasActiveAbility?(:TRUANT) && opp.effects[PBEffects::Truant])) (opp.hasActiveAbility?(:TRUANT) && opp.effects[PBEffects::Truant]))
shouldSwitch = false if pbAIRandom(100) < 80 shouldSwitch = false if pbAIRandom(100) < 80
end end
end end
# Sudden Death rule - I'm not sure what this means # Sudden Death rule - I'm not sure what this means
if @battle.rules["suddendeath"] && @user.turnCount > 0 if !shouldSwitch && @battle.rules["suddendeath"] && battler.turnCount > 0
if @user.hp <= @user.totalhp / 4 && pbAIRandom(100) < 30 if battler.hp <= battler.totalhp / 4 && pbAIRandom(100) < 30
shouldSwitch = true shouldSwitch = true
elsif @user.hp <= @user.totalhp / 2 && pbAIRandom(100) < 80 elsif battler.hp <= battler.totalhp / 2 && pbAIRandom(100) < 80
shouldSwitch = true shouldSwitch = true
end end
end end
# Pokémon is about to faint because of Perish Song # Pokémon is about to faint because of Perish Song
if @user.effects[PBEffects::PerishSong] == 1 if !shouldSwitch && battler.effects[PBEffects::PerishSong] == 1
shouldSwitch = true shouldSwitch = true
end end
if shouldSwitch if shouldSwitch
list = [] list = []
idxPartyStart, idxPartyEnd = @battle.pbTeamIndexRangeFromBattlerIndex(@user.index) idxPartyStart, idxPartyEnd = @battle.pbTeamIndexRangeFromBattlerIndex(battler.index)
@battle.pbParty(@user.index).each_with_index do |pkmn, i| @battle.pbParty(battler.index).each_with_index do |pkmn, i|
next if i == idxPartyEnd - 1 # Don't choose to switch in ace next if i == idxPartyEnd - 1 # Don't choose to switch in ace
next if !@battle.pbCanSwitch?(@user.index, i) next if !@battle.pbCanSwitch?(battler.index, i)
# If perish count is 1, it may be worth it to switch # If perish count is 1, it may be worth it to switch
# even with Spikes, since Perish Song's effect will end # even with Spikes, since Perish Song's effect will end
if @user.effects[PBEffects::PerishSong] != 1 if battler.effects[PBEffects::PerishSong] != 1
# Will contain effects that recommend against switching # Will contain effects that recommend against switching
spikes = @user.pbOwnSide.effects[PBEffects::Spikes] spikes = battler.pbOwnSide.effects[PBEffects::Spikes]
# Don't switch to this if too little HP # Don't switch to this if too little HP
if spikes > 0 if spikes > 0
spikesDmg = [8, 6, 4][spikes - 1] spikesDmg = [8, 6, 4][spikes - 1]
@@ -105,17 +106,17 @@ class Battle::AI
end end
end end
# moveType is the type of the target's last used move # moveType is the type of the target's last used move
if moveType && Effectiveness.ineffective?(pbCalcTypeMod(moveType, @user, @user)) if moveType && Effectiveness.ineffective?(battler.effectiveness_of_type_against_battler(moveType))
weight = 65 weight = 65
typeMod = pbCalcTypeModPokemon(pkmn, @user.pbDirectOpposing(true)) typeMod = pbCalcTypeModPokemon(pkmn, battler.pbDirectOpposing(true))
if Effectiveness.super_effective?(typeMod) if Effectiveness.super_effective?(typeMod)
# Greater weight if new Pokemon's type is effective against target # Greater weight if new Pokemon's type is effective against target
weight = 85 weight = 85
end end
list.unshift(i) if pbAIRandom(100) < weight # Put this Pokemon first list.unshift(i) if pbAIRandom(100) < weight # Put this Pokemon first
elsif moveType && Effectiveness.resistant?(pbCalcTypeMod(moveType, @user, @user)) elsif moveType && Effectiveness.resistant?(battler.effectiveness_of_type_against_battler(moveType))
weight = 40 weight = 40
typeMod = pbCalcTypeModPokemon(pkmn, @user.pbDirectOpposing(true)) typeMod = pbCalcTypeModPokemon(pkmn, battler.pbDirectOpposing(true))
if Effectiveness.super_effective?(typeMod) if Effectiveness.super_effective?(typeMod)
# Greater weight if new Pokemon's type is effective against target # Greater weight if new Pokemon's type is effective against target
weight = 60 weight = 60
@@ -126,13 +127,13 @@ class Battle::AI
end end
end end
if list.length > 0 if list.length > 0
if batonPass >= 0 && @battle.pbRegisterMove(@user.index, batonPass, false) if batonPass >= 0 && @battle.pbRegisterMove(battler.index, batonPass, false)
PBDebug.log("[AI] #{@user.pbThis} (#{@user.index}) will use Baton Pass to avoid Perish Song") PBDebug.log("[AI] #{battler.pbThis} (#{battler.index}) will use Baton Pass to avoid Perish Song")
return true return true
end end
if @battle.pbRegisterSwitch(@user.index, list[0]) if @battle.pbRegisterSwitch(battler.index, list[0])
PBDebug.log("[AI] #{@user.pbThis} (#{@user.index}) will switch with " + PBDebug.log("[AI] #{battler.pbThis} (#{battler.index}) will switch with " +
@battle.pbParty(@user.index)[list[0]].name) @battle.pbParty(battler.index)[list[0]].name)
return true return true
end end
end end

View File

@@ -1,93 +1,10 @@
class Battle::AI class Battle::AI
#=============================================================================
# Main move-choosing method (moves with higher scores are more likely to be
# chosen)
#=============================================================================
def pbChooseMove(choices)
# Figure out useful information about the choices
totalScore = 0
maxScore = 0
choices.each do |c|
totalScore += c[1]
maxScore = c[1] if maxScore < c[1]
end
# Find any preferred moves and just choose from them
if skill_check(AILevel.high) && maxScore > 100
stDev = pbStdDev(choices)
if stDev >= 40 && pbAIRandom(100) < 90
preferredMoves = []
choices.each do |c|
next if c[1] < 200 && c[1] < maxScore * 0.8
preferredMoves.push(c)
preferredMoves.push(c) if c[1] == maxScore # Doubly prefer the best move
end
if preferredMoves.length > 0
m = preferredMoves[pbAIRandom(preferredMoves.length)]
PBDebug.log("[AI] #{@user.pbThis} (#{@user.index}) prefers #{@user.moves[m[0]].name}")
@battle.pbRegisterMove(@user.index, m[0], false)
@battle.pbRegisterTarget(@user.index, m[2]) if m[2] >= 0
return
end
end
end
# Decide whether all choices are bad, and if so, try switching instead
if !@wildBattler && skill_check(AILevel.high)
badMoves = false
if (maxScore <= 20 && @user.turnCount > 2) ||
(maxScore <= 40 && @user.turnCount > 5)
badMoves = true if pbAIRandom(100) < 80
end
if !badMoves && totalScore < 100 && @user.turnCount > 1
badMoves = true
choices.each do |c|
next if !@user.moves[c[0]].damagingMove?
badMoves = false
break
end
badMoves = false if badMoves && pbAIRandom(100) < 10
end
if badMoves && pbEnemyShouldWithdrawEx?(true)
if $INTERNAL
PBDebug.log("[AI] #{@user.pbThis} (#{@user.index}) will switch due to terrible moves")
end
return
end
end
# If there are no calculated choices, pick one at random
if choices.length == 0
PBDebug.log("[AI] #{@user.pbThis} (#{@user.index}) doesn't want to use any moves; picking one at random")
@user.eachMoveWithIndex do |_m, i|
next if !@battle.pbCanChooseMove?(@user.index, i, false)
choices.push([i, 100, -1]) # Move index, score, target
end
if choices.length == 0 # No moves are physically possible to use; use Struggle
@battle.pbAutoChooseMove(@user.index)
end
end
# Randomly choose a move from the choices and register it
randNum = pbAIRandom(totalScore)
choices.each do |c|
randNum -= c[1]
next if randNum >= 0
@battle.pbRegisterMove(@user.index, c[0], false)
@battle.pbRegisterTarget(@user.index, c[2]) if c[2] >= 0
break
end
# Log the result
if @battle.choices[@user.index][2]
PBDebug.log("[AI] #{@user.pbThis} (#{@user.index}) will use #{@battle.choices[@user.index][2].name}")
end
end
#============================================================================= #=============================================================================
# Get scores for the user's moves (done before any action is assessed) # Get scores for the user's moves (done before any action is assessed)
# NOTE: A move is only added to the choices array if it has a non-zero score. # NOTE: A move is only added to the choices array if it has a non-zero score.
#============================================================================= #=============================================================================
def pbGetMoveScores def pbGetMoveScores
battler = @user.battler
# Get scores and targets for each move # Get scores and targets for each move
choices = [] choices = []
# TODO: Split this into two, the first part being the calculation of all # TODO: Split this into two, the first part being the calculation of all
@@ -98,9 +15,9 @@ class Battle::AI
# whittled down to one per move which are chosen from. Multi-target # whittled down to one per move which are chosen from. Multi-target
# moves could be fiddly since damages should be calculated for each # moves could be fiddly since damages should be calculated for each
# target but they're all related. # target but they're all related.
@user.eachMoveWithIndex do |_m, i| battler.eachMoveWithIndex do |_m, i|
next if !@battle.pbCanChooseMove?(@user.index, i, false) next if !@battle.pbCanChooseMove?(battler.index, i, false)
if @wildBattler if @user.wild?
pbRegisterMoveWild(i, choices) pbRegisterMoveWild(i, choices)
else else
pbRegisterMoveTrainer(i, choices) pbRegisterMoveTrainer(i, choices)
@@ -108,9 +25,9 @@ class Battle::AI
end end
# Log the available choices # Log the available choices
if $INTERNAL if $INTERNAL
logMsg = "[AI] Move choices for #{@user.pbThis(true)} (#{@user.index}): " logMsg = "[AI] Move choices for #{battler.pbThis(true)} (#{battler.index}): "
choices.each_with_index do |c, i| choices.each_with_index do |c, i|
logMsg += "#{@user.moves[c[0]].name}=#{c[1]}" logMsg += "#{battler.moves[c[0]].name}=#{c[1]}"
logMsg += " (target #{c[2]})" if c[2] >= 0 logMsg += " (target #{c[2]})" if c[2] >= 0
logMsg += ", " if i < choices.length-1 logMsg += ", " if i < choices.length-1
end end
@@ -124,40 +41,42 @@ class Battle::AI
#============================================================================= #=============================================================================
# Wild Pokémon choose their moves randomly. # Wild Pokémon choose their moves randomly.
def pbRegisterMoveWild(idxMove, choices) def pbRegisterMoveWild(idxMove, choices)
battler = @user.battler
score = 100 score = 100
# Doubly prefer one of the user's moves (the choice is random but consistent # Doubly prefer one of the user's moves (the choice is random but consistent
# and does not correlate to any other property of the user) # and does not correlate to any other property of the user)
score *= 2 if @user.pokemon.personalID % @user.moves.length == idxMove score *= 2 if battler.pokemon.personalID % battler.moves.length == idxMove
choices.push([idxMove, 100, -1]) # Move index, score, target choices.push([idxMove, 100, -1]) # Move index, score, target
end end
# Trainer Pokémon calculate how much they want to use each of their moves. # Trainer Pokémon calculate how much they want to use each of their moves.
def pbRegisterMoveTrainer(idxMove, choices) def pbRegisterMoveTrainer(idxMove, choices)
move = @user.moves[idxMove] battler = @user.battler
target_data = move.pbTarget(@user) move = battler.moves[idxMove]
target_data = move.pbTarget(battler)
# TODO: Alter target_data if user has Protean and move is Curse. # TODO: Alter target_data if user has Protean and move is Curse.
if [:UserAndAllies, :AllAllies, :AllBattlers].include?(target_data.id) || if [:UserAndAllies, :AllAllies, :AllBattlers].include?(target_data.id) ||
target_data.num_targets == 0 target_data.num_targets == 0
# If move has no targets, affects the user, a side or the whole field, or # If move has no targets, affects the user, a side or the whole field, or
# specially affects multiple Pokémon and the AI calculates an overall # specially affects multiple Pokémon and the AI calculates an overall
# score at once instead of per target # score at once instead of per target
score = pbGetMoveScore(move, @user) score = pbGetMoveScore(move)
choices.push([idxMove, score, -1]) if score > 0 choices.push([idxMove, score, -1]) if score > 0
elsif target_data.num_targets > 1 elsif target_data.num_targets > 1
# If move affects multiple battlers and you don't choose a particular one # If move affects multiple battlers and you don't choose a particular one
totalScore = 0 totalScore = 0
@battle.allBattlers.each do |b| @battle.allBattlers.each do |b|
next if !@battle.pbMoveCanTarget?(@user.index, b.index, target_data) next if !@battle.pbMoveCanTarget?(battler.index, b.index, target_data)
score = pbGetMoveScore(move, b) score = pbGetMoveScore(move, b)
totalScore += ((@user.opposes?(b)) ? score : -score) totalScore += ((battler.opposes?(b)) ? score : -score)
end end
choices.push([idxMove, totalScore, -1]) if totalScore > 0 choices.push([idxMove, totalScore, -1]) if totalScore > 0
else else
# If move affects one battler and you have to choose which one # If move affects one battler and you have to choose which one
scoresAndTargets = [] scoresAndTargets = []
@battle.allBattlers.each do |b| @battle.allBattlers.each do |b|
next if !@battle.pbMoveCanTarget?(@user.index, b.index, target_data) next if !@battle.pbMoveCanTarget?(battler.index, b.index, target_data)
next if target_data.targets_foe && !@user.opposes?(b) next if target_data.targets_foe && !battler.opposes?(b)
score = pbGetMoveScore(move, b) score = pbGetMoveScore(move, b)
scoresAndTargets.push([score, b.index]) if score > 0 scoresAndTargets.push([score, b.index]) if score > 0
end end
@@ -170,21 +89,15 @@ class Battle::AI
end end
#============================================================================= #=============================================================================
# Set some class variables for the move being assessed # Set some extra class variables for the move/target combo being assessed
#============================================================================= #=============================================================================
def set_up_move_check(move, target) def set_up_move_check(move, target)
@move = move @move.set_up(move, @user)
@target = target @target = (target) ? @battlers[target.index] : @user
# TODO: Calculate pbRoughType once here. @target&.refresh_battler
# Determine whether user or target is faster, and store that result so it # Determine whether user or target is faster, and store that result so it
# doesn't need recalculating # doesn't need recalculating
if @target @user_faster = @user.faster_than?(@target)
user_speed = pbRoughStat(@user, :SPEED)
target_speed = pbRoughStat(@target, :SPEED)
@user_faster = (user_speed > target_speed) ^ (@battle.field.effects[PBEffects::TrickRoom] > 0)
else
@user_faster = false # Won't be used if there is no target
end
end end
#============================================================================= #=============================================================================
@@ -192,9 +105,11 @@ class Battle::AI
#============================================================================= #=============================================================================
def pbGetMoveScore(move, target = nil) def pbGetMoveScore(move, target = nil)
set_up_move_check(move, target) set_up_move_check(move, target)
user_battler = @user.battler
target_battler = @target.battler
# Get the base score for the move # Get the base score for the move
if @move.damagingMove? if @move.move.damagingMove?
# Is also the predicted damage amount as a percentage of target's current HP # Is also the predicted damage amount as a percentage of target's current HP
score = pbGetDamagingMoveBaseScore score = pbGetDamagingMoveBaseScore
else # Status moves else # Status moves
@@ -202,8 +117,8 @@ class Battle::AI
score = pbGetStatusMoveBaseScore score = pbGetStatusMoveBaseScore
end end
# Modify the score according to the move's effect # Modify the score according to the move's effect
score = Battle::AI::Handlers.apply_move_effect_score(move.function, score = Battle::AI::Handlers.apply_move_effect_score(@move.move.function,
score, move, @user, target, @skill, self, @battle) score, @move.move, user_battler, target_battler, self, @battle)
# A score of 0 here means it absolutely should not be used # A score of 0 here means it absolutely should not be used
return 0 if score <= 0 return 0 if score <= 0
@@ -230,7 +145,7 @@ class Battle::AI
# Don't prefer a dancing move if the target has the Dancer ability # Don't prefer a dancing move if the target has the Dancer ability
# TODO: Check all battlers, not just the target. # TODO: Check all battlers, not just the target.
if skill_check(AILevel.high) && @move.danceMove? && @target.hasActiveAbility?(:DANCER) if @move.move.danceMove? && @target.has_active_ability?(:DANCER)
score /= 2 score /= 2
end end
@@ -275,47 +190,46 @@ class Battle::AI
# => If target has previously used a move that will hurt the user by 30% of # => If target has previously used a move that will hurt the user by 30% of
# its current HP or more, moreso don't prefer a status move. # its current HP or more, moreso don't prefer a status move.
if skill_check(AILevel.medium) # Prefer damaging moves if AI has no more Pokémon or AI is less clever
if @trainer.medium_skill? && @battle.pbAbleNonActiveCount(user_battler.idxOwnSide) == 0 &&
!(@trainer.high_skill? && @battle.pbAbleNonActiveCount(target_battler.idxOwnSide) > 0)
if @move.move.statusMove?
score *= 0.9
elsif target_battler.hp <= target_battler.totalhp / 2
score *= 1.1
end
end
# Prefer damaging moves if AI has no more Pokémon or AI is less clever # Don't prefer attacking the target if they'd be semi-invulnerable
if @battle.pbAbleNonActiveCount(@user.idxOwnSide) == 0 && if @move.accuracy > 0 && @user_faster &&
!(skill_check(AILevel.high) && @battle.pbAbleNonActiveCount(@target.idxOwnSide) > 0) (target_battler.semiInvulnerable? || target_battler.effects[PBEffects::SkyDrop] >= 0)
if @move.statusMove? miss = true
score *= 0.9 miss = false if @user.has_active_ability?(:NOGUARD)
elsif @target.hp <= @target.totalhp / 2 miss = false if @trainer.best_skill? && @target.has_active_ability?(:NOGUARD)
score *= 1.1 if @trainer.best_skill? && miss
# Knows what can get past semi-invulnerability
if target_battler.effects[PBEffects::SkyDrop] >= 0 ||
target_battler.inTwoTurnAttack?("TwoTurnAttackInvulnerableInSky",
"TwoTurnAttackInvulnerableInSkyParalyzeTarget",
"TwoTurnAttackInvulnerableInSkyTargetCannotAct")
miss = false if move.hitsFlyingTargets?
elsif target.inTwoTurnAttack?("TwoTurnAttackInvulnerableUnderground")
miss = false if move.hitsDiggingTargets?
elsif target.inTwoTurnAttack?("TwoTurnAttackInvulnerableUnderwater")
miss = false if move.hitsDivingTargets?
end end
end end
score = 10 if miss
end
# Don't prefer attacking the target if they'd be semi-invulnerable # Pick a good move for the Choice items
if skill_check(AILevel.high) && @move.accuracy > 0 && @user_faster && if @trainer.medium_skill?
(@target.semiInvulnerable? || @target.effects[PBEffects::SkyDrop] >= 0) if @user.has_active_item?([:CHOICEBAND, :CHOICESPECS, :CHOICESCARF]) ||
miss = true @user.has_active_ability?(:GORILLATACTICS)
miss = false if @user.hasActiveAbility?(:NOGUARD)
miss = false if skill_check(AILevel.best) && @target.hasActiveAbility?(:NOGUARD)
if skill_check(AILevel.best) && miss
# Knows what can get past semi-invulnerability
if @target.effects[PBEffects::SkyDrop] >= 0 ||
@target.inTwoTurnAttack?("TwoTurnAttackInvulnerableInSky",
"TwoTurnAttackInvulnerableInSkyParalyzeTarget",
"TwoTurnAttackInvulnerableInSkyTargetCannotAct")
miss = false if move.hitsFlyingTargets?
elsif target.inTwoTurnAttack?("TwoTurnAttackInvulnerableUnderground")
miss = false if move.hitsDiggingTargets?
elsif target.inTwoTurnAttack?("TwoTurnAttackInvulnerableUnderwater")
miss = false if move.hitsDivingTargets?
end
end
score = 0 if miss
end
# Pick a good move for the Choice items
if @user.hasActiveItem?([:CHOICEBAND, :CHOICESPECS, :CHOICESCARF]) ||
@user.hasActiveAbility?(:GORILLATACTICS)
# Really don't prefer status moves (except Trick) # Really don't prefer status moves (except Trick)
score *= 0.1 if @move.statusMove? && @move.function != "UserTargetSwapItems" score *= 0.1 if @move.move.statusMove? && @move.move.function != "UserTargetSwapItems"
# Don't prefer moves of certain types # Don't prefer moves of certain types
move_type = pbRoughType(@move) move_type = @move.rough_type
# Most unpreferred types are 0x effective against another type, except # Most unpreferred types are 0x effective against another type, except
# Fire/Water/Grass # Fire/Water/Grass
# TODO: Actually check through the types for 0x instead of hardcoding # TODO: Actually check through the types for 0x instead of hardcoding
@@ -330,38 +244,38 @@ class Battle::AI
# Don't prefer moves with lower accuracy # Don't prefer moves with lower accuracy
score *= @move.accuracy / 100.0 if @move.accuracy > 0 score *= @move.accuracy / 100.0 if @move.accuracy > 0
# Don't prefer moves with low PP # Don't prefer moves with low PP
score *= 0.9 if @move.pp < 6 score *= 0.9 if @move.move.pp < 6
end end
end
# If user is asleep, don't prefer moves that can't be used while asleep # If user is asleep, don't prefer moves that can't be used while asleep
if skill_check(AILevel.medium) && @user.asleep? && @user.statusCount > 1 && if @trainer.medium_skill? && user_battler.asleep? && user_battler.statusCount > 1 &&
!@move.usableWhenAsleep? !@move.move.usableWhenAsleep?
score *= 0.2 score *= 0.2
end end
# If user is frozen, prefer a move that can thaw the user # If user is frozen, prefer a move that can thaw the user
if skill_check(AILevel.medium) && @user.status == :FROZEN if @trainer.medium_skill? && user_battler.status == :FROZEN
if @move.thawsUser? if @move.move.thawsUser?
score += 30 score += 30
else else
@user.eachMove do |m| user_battler.eachMove do |m|
next unless m.thawsUser? next unless m.thawsUser?
score = 0 # Discard this move if user knows another move that thaws score = 0 # Discard this move if user knows another move that thaws
break break
end
end
end
# If target is frozen, don't prefer moves that could thaw them
if @target.status == :FROZEN
if pbRoughType(@move) == :FIRE || (Settings::MECHANICS_GENERATION >= 6 && @move.thawsUser?)
score *= 0.1
end end
end end
end end
# If target is frozen, don't prefer moves that could thaw them
if @trainer.medium_skill? && target_battler.status == :FROZEN
if @move.rough_type == :FIRE || (Settings::MECHANICS_GENERATION >= 6 && @move.move.thawsUser?)
score *= 0.1
end
end
# Don't prefer hitting a wild shiny Pokémon # Don't prefer hitting a wild shiny Pokémon
if @battle.wildBattle? && @target.opposes? && @target.shiny? if @target.wild? && target_battler.shiny?
score *= 0.15 score *= 0.15
end end
@@ -369,18 +283,18 @@ class Battle::AI
# Bounce. # Bounce.
# Account for accuracy of move # Account for accuracy of move
accuracy = pbRoughAccuracy(@move, @target) accuracy = @move.rough_accuracy
score *= accuracy / 100.0 score *= accuracy / 100.0
# Prefer flinching external effects (note that move effects which cause # Prefer flinching external effects (note that move effects which cause
# flinching are dealt with in the function code part of score calculation) # flinching are dealt with in the function code part of score calculation)
if skill_check(AILevel.medium) if @trainer.medium_skill?
if !@target.hasActiveAbility?([:INNERFOCUS, :SHIELDDUST]) && if !@target.has_active_ability?([:INNERFOCUS, :SHIELDDUST]) &&
@target.effects[PBEffects::Substitute] == 0 target_battler.effects[PBEffects::Substitute] == 0
if @move.flinchingMove? || if @move.move.flinchingMove? ||
(@move.damagingMove? && (@move.move.damagingMove? &&
(@user.hasActiveItem?([:KINGSROCK, :RAZORFANG]) || (@user.has_active_item?([:KINGSROCK, :RAZORFANG]) ||
@user.hasActiveAbility?(:STENCH))) @user.has_active_ability?(:STENCH)))
score *= 1.3 score *= 1.3
end end
end end
@@ -388,14 +302,14 @@ class Battle::AI
# # Adjust score based on how much damage it can deal # # Adjust score based on how much damage it can deal
# if move.damagingMove? # if move.damagingMove?
# score = pbGetMoveScoreDamage(score, move, @user, @target, @skill) # score = pbGetMoveScoreDamage(score, move, @user, @target, @trainer.skill)
# else # Status moves # else # Status moves
# # Don't prefer attacks which don't deal damage # # Don't prefer attacks which don't deal damage
# score -= 10 # score -= 10
# # Account for accuracy of move # # Account for accuracy of move
# accuracy = pbRoughAccuracy(move, target) # accuracy = pbRoughAccuracy(move, target)
# score *= accuracy / 100.0 # score *= accuracy / 100.0
# score = 0 if score <= 10 && skill_check(AILevel.high) # score = 0 if score <= 10 && @trainer.high_skill?
# end # end
score = score.to_i score = score.to_i
score = 0 if score < 0 score = 0 if score < 0
@@ -408,21 +322,23 @@ class Battle::AI
#============================================================================= #=============================================================================
def pbGetDamagingMoveBaseScore def pbGetDamagingMoveBaseScore
# Don't prefer moves that are ineffective because of abilities or effects # Don't prefer moves that are ineffective because of abilities or effects
return 0 if pbCheckMoveImmunity(@move, @target) return 0 if @target.immune_to_move?
user_battler = @user.battler
target_battler = @target.battler
# Calculate how much damage the move will do (roughly) # Calculate how much damage the move will do (roughly)
base_damage = pbMoveBaseDamage(@move, @target) base_damage = @move.base_power
calc_damage = pbRoughDamage(@move, @target, base_damage) calc_damage = pbRoughDamage(@move, @target, base_damage)
# TODO: Maybe move this check elsewhere? Note that Reborn's base score does # TODO: Maybe move this check elsewhere? Note that Reborn's base score does
# not include this halving, but the predicted damage does. # not include this halving, but the predicted damage does.
# Two-turn attacks waste 2 turns to deal one lot of damage # Two-turn attacks waste 2 turns to deal one lot of damage
calc_damage /= 2 if @move.chargingTurnMove? calc_damage /= 2 if @move.move.chargingTurnMove?
# TODO: Maybe move this check elsewhere? # TODO: Maybe move this check elsewhere?
# Increased critical hit rate # Increased critical hit rate
if skill_check(AILevel.medium) if @trainer.medium_skill?
crit_stage = pbRoughCriticalHitStage(@move, @target) crit_stage = @move.rough_critical_hit_stage
if crit_stage >= 0 if crit_stage >= 0
crit_fraction = (crit_stage > 50) ? 1 : Battle::Move::CRITICAL_HIT_RATIOS[crit_stage] crit_fraction = (crit_stage > 50) ? 1 : Battle::Move::CRITICAL_HIT_RATIOS[crit_stage]
crit_mult = (Settings::NEW_CRITICAL_HIT_RATE_MECHANICS) ? 0.5 : 1 crit_mult = (Settings::NEW_CRITICAL_HIT_RATE_MECHANICS) ? 0.5 : 1
@@ -431,13 +347,13 @@ class Battle::AI
end end
# Convert damage to percentage of target's remaining HP # Convert damage to percentage of target's remaining HP
damage_percentage = calc_damage * 100.0 / @target.hp damage_percentage = calc_damage * 100.0 / target_battler.hp
# Don't prefer weak attacks # Don't prefer weak attacks
# damage_percentage /= 2 if damage_percentage < 20 # damage_percentage /= 2 if damage_percentage < 20
# Prefer damaging attack if level difference is significantly high # Prefer damaging attack if level difference is significantly high
# damage_percentage *= 1.2 if @user.level - 10 > @target.level # damage_percentage *= 1.2 if user_battler.level - 10 > target_battler.level
# Adjust score # Adjust score
damage_percentage = 110 if damage_percentage > 110 # Treat all lethal moves the same damage_percentage = 110 if damage_percentage > 110 # Treat all lethal moves the same
@@ -447,7 +363,7 @@ class Battle::AI
end end
def pbGetStatusMoveBaseScore def pbGetStatusMoveBaseScore
# TODO: Call pbCheckMoveImmunity here too, not just for damaging moves # TODO: Call @target.immune_to_move? here too, not just for damaging moves
# (only if this status move will be affected). # (only if this status move will be affected).
# TODO: Make sure all status moves are accounted for. # TODO: Make sure all status moves are accounted for.
@@ -465,7 +381,7 @@ class Battle::AI
# "LowerTargetAttack2" - Charm (10), Feather Dance (15) # "LowerTargetAttack2" - Charm (10), Feather Dance (15)
# "LowerTargetSpeed2" - String Shot (10), Cotton Spore (15), Scary Face (15) # "LowerTargetSpeed2" - String Shot (10), Cotton Spore (15), Scary Face (15)
# "LowerTargetSpDef2" - Metal Sound (10), Fake Tears (15) # "LowerTargetSpDef2" - Metal Sound (10), Fake Tears (15)
case @move.function case @move.move.function
when "ConfuseTarget", when "ConfuseTarget",
"LowerTargetAccuracy1", "LowerTargetAccuracy1",
"LowerTargetEvasion1RemoveSideEffects", "LowerTargetEvasion1RemoveSideEffects",
@@ -690,4 +606,90 @@ class Battle::AI
# "ProtectUserSideFromStatusMoves" # "ProtectUserSideFromStatusMoves"
return 0 return 0
end end
#=============================================================================
# Make the final choice of which move to use depending on the calculated
# scores for each move. Moves with higher scores are more likely to be chosen.
#=============================================================================
def pbChooseMove(choices)
user_battler = @user.battler
# Figure out useful information about the choices
totalScore = 0
maxScore = 0
choices.each do |c|
totalScore += c[1]
maxScore = c[1] if maxScore < c[1]
end
# Find any preferred moves and just choose from them
if @trainer.high_skill? && maxScore > 100
stDev = pbStdDev(choices)
if stDev >= 40 && pbAIRandom(100) < 90
preferredMoves = []
choices.each do |c|
next if c[1] < 200 && c[1] < maxScore * 0.8
preferredMoves.push(c)
preferredMoves.push(c) if c[1] == maxScore # Doubly prefer the best move
end
if preferredMoves.length > 0
m = preferredMoves[pbAIRandom(preferredMoves.length)]
PBDebug.log("[AI] #{user_battler.pbThis} (#{user_battler.index}) prefers #{user_battler.moves[m[0]].name}")
@battle.pbRegisterMove(user_battler.index, m[0], false)
@battle.pbRegisterTarget(user_battler.index, m[2]) if m[2] >= 0
return
end
end
end
# Decide whether all choices are bad, and if so, try switching instead
if @trainer.high_skill? && @user.can_switch_lax?
badMoves = false
if (maxScore <= 20 && user_battler.turnCount > 2) ||
(maxScore <= 40 && user_battler.turnCount > 5)
badMoves = true if pbAIRandom(100) < 80
end
if !badMoves && totalScore < 100 && user_battler.turnCount > 1
badMoves = true
choices.each do |c|
next if !user_battler.moves[c[0]].damagingMove?
badMoves = false
break
end
badMoves = false if badMoves && pbAIRandom(100) < 10
end
if badMoves && pbEnemyShouldWithdrawEx?(true)
if $INTERNAL
PBDebug.log("[AI] #{user_battler.pbThis} (#{user_battler.index}) will switch due to terrible moves")
end
return
end
end
# If there are no calculated choices, pick one at random
if choices.length == 0
PBDebug.log("[AI] #{user_battler.pbThis} (#{user_battler.index}) doesn't want to use any moves; picking one at random")
user_battler.eachMoveWithIndex do |_m, i|
next if !@battle.pbCanChooseMove?(user_battler.index, i, false)
choices.push([i, 100, -1]) # Move index, score, target
end
if choices.length == 0 # No moves are physically possible to use; use Struggle
@battle.pbAutoChooseMove(user_battler.index)
end
end
# Randomly choose a move from the choices and register it
randNum = pbAIRandom(totalScore)
choices.each do |c|
randNum -= c[1]
next if randNum >= 0
@battle.pbRegisterMove(user_battler.index, c[0], false)
@battle.pbRegisterTarget(user_battler.index, c[2]) if c[2] >= 0
break
end
# Log the result
if @battle.choices[user_battler.index][2]
PBDebug.log("[AI] #{user_battler.pbThis} (#{user_battler.index}) will use #{@battle.choices[user_battler.index][2].name}")
end
end
end end

View File

@@ -0,0 +1,14 @@
class Battle::AI
#=============================================================================
# Decide whether the opponent should Mega Evolve.
#=============================================================================
# TODO: Where relevant, pretend the user is Mega Evolved if it isn't but can
# be.
def pbEnemyShouldMegaEvolve?
if @battle.pbCanMegaEvolve?(@user.index) # Simple "always should if possible"
PBDebug.log("[AI] #{@user.pbThis} (#{@user.index}) will Mega Evolve")
return true
end
return false
end
end

View File

@@ -1,326 +1,72 @@
class Battle::AI class Battle::AI
#============================================================================= def pbAIRandom(x); return rand(x); end
#
#============================================================================= def pbStdDev(choices)
def pbTargetsMultiple?(move) sum = 0
target_data = move.pbTarget(@user) n = 0
return false if target_data.num_targets <= 1 choices.each do |c|
num_targets = 0 sum += c[1]
case target_data.id n += 1
when :AllAllies
@battle.allSameSideBattlers(@user).each { |b| num_targets += 1 if b.index != @user.index }
when :UserAndAllies
@battle.allSameSideBattlers(@user).each { |_b| num_targets += 1 }
when :AllNearFoes
@battle.allOtherSideBattlers(@user).each { |b| num_targets += 1 if b.near?(@user) }
when :AllFoes
@battle.allOtherSideBattlers(@user).each { |_b| num_targets += 1 }
when :AllNearOthers
@battle.allBattlers.each { |b| num_targets += 1 if b.near?(@user) }
when :AllBattlers
@battle.allBattlers.each { |_b| num_targets += 1 }
end end
return num_targets > 1 return 0 if n < 2
mean = sum.to_f / n
varianceTimesN = 0
choices.each do |c|
next if c[1] <= 0
deviation = c[1].to_f - mean
varianceTimesN += deviation * deviation
end
# Using population standard deviation
# [(n-1) makes it a sample std dev, would be 0 with only 1 sample]
return Math.sqrt(varianceTimesN / n)
end end
#============================================================================= #=============================================================================
# Move's type effectiveness # Move's type effectiveness
#============================================================================= #=============================================================================
def pbCalcTypeModSingle(moveType, defType, user, target)
ret = Effectiveness.calculate_one(moveType, defType)
if Effectiveness.ineffective_type?(moveType, defType)
# Ring Target
if target.hasActiveItem?(:RINGTARGET)
ret = Effectiveness::NORMAL_EFFECTIVE_ONE
end
# Foresight
if (user.hasActiveAbility?(:SCRAPPY) || target.effects[PBEffects::Foresight]) &&
defType == :GHOST
ret = Effectiveness::NORMAL_EFFECTIVE_ONE
end
# Miracle Eye
if target.effects[PBEffects::MiracleEye] && defType == :DARK
ret = Effectiveness::NORMAL_EFFECTIVE_ONE
end
elsif Effectiveness.super_effective_type?(moveType, defType)
# Delta Stream's weather
if target.effectiveWeather == :StrongWinds && defType == :FLYING
ret = Effectiveness::NORMAL_EFFECTIVE_ONE
end
end
# Grounded Flying-type Pokémon become susceptible to Ground moves
if !target.airborne? && defType == :FLYING && moveType == :GROUND
ret = Effectiveness::NORMAL_EFFECTIVE_ONE
end
return ret
end
def pbCalcTypeMod(moveType, user, target)
return Effectiveness::NORMAL_EFFECTIVE if !moveType
return Effectiveness::NORMAL_EFFECTIVE if moveType == :GROUND &&
target.pbHasType?(:FLYING) &&
target.hasActiveItem?(:IRONBALL)
# Determine types
tTypes = target.pbTypes(true)
# Get effectivenesses
typeMods = [Effectiveness::NORMAL_EFFECTIVE_ONE] * 3 # 3 types max
if moveType == :SHADOW
if target.shadowPokemon?
typeMods[0] = Effectiveness::NOT_VERY_EFFECTIVE_ONE
else
typeMods[0] = Effectiveness::SUPER_EFFECTIVE_ONE
end
else
tTypes.each_with_index do |type, i|
typeMods[i] = pbCalcTypeModSingle(moveType, type, user, target)
end
end
# Multiply all effectivenesses together
ret = 1
typeMods.each { |m| ret *= m }
return ret
end
# For switching. Determines the effectiveness of a potential switch-in against # For switching. Determines the effectiveness of a potential switch-in against
# an opposing battler. # an opposing battler.
def pbCalcTypeModPokemon(pkmn, target) def pbCalcTypeModPokemon(pkmn, target_battler)
mod1 = Effectiveness.calculate(pkmn.types[0], target.types[0], target.types[1]) mod1 = Effectiveness.calculate(pkmn.types[0], target_battler.types[0], target_battler.types[1])
mod2 = Effectiveness::NORMAL_EFFECTIVE mod2 = Effectiveness::NORMAL_EFFECTIVE
if pkmn.types.length > 1 if pkmn.types.length > 1
mod2 = Effectiveness.calculate(pkmn.types[1], target.types[0], target.types[1]) mod2 = Effectiveness.calculate(pkmn.types[1], target_battler.types[0], target_battler.types[1])
mod2 = mod2.to_f / Effectivenesss::NORMAL_EFFECTIVE mod2 = mod2.to_f / Effectivenesss::NORMAL_EFFECTIVE
end end
return mod1 * mod2 return mod1 * mod2
end end
#=============================================================================
# Immunity to a move because of the target's ability, item or other effects
#=============================================================================
def pbCheckMoveImmunity(move, target)
# TODO: Add consideration of user's Mold Breaker.
move_type = pbRoughType(move)
typeMod = pbCalcTypeMod(move_type, @user, target)
# Type effectiveness
return true if move.damagingMove? && Effectiveness.ineffective?(typeMod)
# Immunity due to ability/item/other effects
if skill_check(AILevel.medium)
case move_type
when :GROUND
# TODO: Split target.airborne? into separate parts to allow different
# skill levels to apply to each part.
return true if target.airborne? && !move.hitsFlyingTargets?
when :FIRE
return true if target.hasActiveAbility?(:FLASHFIRE)
when :WATER
return true if target.hasActiveAbility?([:DRYSKIN, :STORMDRAIN, :WATERABSORB])
when :GRASS
return true if target.hasActiveAbility?(:SAPSIPPER)
when :ELECTRIC
return true if target.hasActiveAbility?([:LIGHTNINGROD, :MOTORDRIVE, :VOLTABSORB])
end
return true if move.damagingMove? && Effectiveness.not_very_effective?(typeMod) &&
target.hasActiveAbility?(:WONDERGUARD)
return true if move.damagingMove? && @user.index != target.index && !target.opposes?(@user) &&
target.hasActiveAbility?(:TELEPATHY)
return true if move.statusMove? && move.canMagicCoat? && target.hasActiveAbility?(:MAGICBOUNCE) &&
target.opposes?(@user)
return true if move.soundMove? && target.hasActiveAbility?(:SOUNDPROOF)
return true if move.bombMove? && target.hasActiveAbility?(:BULLETPROOF)
if move.powderMove?
return true if target.pbHasType?(:GRASS)
return true if skill_check(AILevel.best) && target.hasActiveAbility?(:OVERCOAT)
return true if skill_check(AILevel.high) && target.hasActiveItem?(:SAFETYGOGGLES)
end
return true if move.statusMove? && target.effects[PBEffects::Substitute] > 0 &&
!move.ignoresSubstitute?(@user) && @user.index != target.index
return true if move.statusMove? && Settings::MECHANICS_GENERATION >= 7 &&
@user.hasActiveAbility?(:PRANKSTER) && target.pbHasType?(:DARK) &&
target.opposes?(@user)
return true if move.priority > 0 && @battle.field.terrain == :Psychic &&
target.affectedByTerrain? && target.opposes?(@user)
# TODO: Dazzling/Queenly Majesty go here.
end
return false
end
#=============================================================================
# Get approximate properties for a battler
#=============================================================================
def pbRoughType(move)
ret = move.type
ret = move.pbCalcType(@user) if skill_check(AILevel.high)
return ret
end
def pbRoughStat(battler, stat)
return battler.pbSpeed if skill_check(AILevel.high) && stat == :SPEED
stageMul = [2, 2, 2, 2, 2, 2, 2, 3, 4, 5, 6, 7, 8]
stageDiv = [8, 7, 6, 5, 4, 3, 2, 2, 2, 2, 2, 2, 2]
stage = battler.stages[stat] + 6
value = 0
case stat
when :ATTACK then value = battler.attack
when :DEFENSE then value = battler.defense
when :SPECIAL_ATTACK then value = battler.spatk
when :SPECIAL_DEFENSE then value = battler.spdef
when :SPEED then value = battler.speed
end
return (value.to_f * stageMul[stage] / stageDiv[stage]).floor
end
#=============================================================================
# Get a better move's base damage value
#=============================================================================
def pbMoveBaseDamage(move, target)
baseDmg = move.baseDamage
baseDmg = 60 if baseDmg == 1
return baseDmg if !skill_check(AILevel.medium)
# Covers all function codes which have their own def pbBaseDamage
case move.function
# Sonic Boom, Dragon Rage, Super Fang, Night Shade, Endeavor
when "FixedDamage20", "FixedDamage40", "FixedDamageHalfTargetHP",
"FixedDamageUserLevel", "LowerTargetHPToUserHP"
baseDmg = move.pbFixedDamage(@user, target)
when "FixedDamageUserLevelRandom" # Psywave
baseDmg = @user.level
when "OHKO", "OHKOIce", "OHKOHitsUndergroundTarget"
baseDmg = 200
when "CounterPhysicalDamage", "CounterSpecialDamage", "CounterDamagePlusHalf"
baseDmg = 60
when "DoublePowerIfTargetUnderwater", "DoublePowerIfTargetUnderground",
"BindTargetDoublePowerIfTargetUnderwater"
baseDmg = move.pbModifyDamage(baseDmg, @user, target)
# Gust, Twister, Venoshock, Smelling Salts, Wake-Up Slap, Facade, Hex, Brine,
# Retaliate, Weather Ball, Return, Frustration, Eruption, Crush Grip,
# Stored Power, Punishment, Hidden Power, Fury Cutter, Echoed Voice,
# Trump Card, Flail, Electro Ball, Low Kick, Fling, Spit Up
when "DoublePowerIfTargetInSky",
"FlinchTargetDoublePowerIfTargetInSky",
"DoublePowerIfTargetPoisoned",
"DoublePowerIfTargetParalyzedCureTarget",
"DoublePowerIfTargetAsleepCureTarget",
"DoublePowerIfUserPoisonedBurnedParalyzed",
"DoublePowerIfTargetStatusProblem",
"DoublePowerIfTargetHPLessThanHalf",
"DoublePowerIfAllyFaintedLastTurn",
"TypeAndPowerDependOnWeather",
"PowerHigherWithUserHappiness",
"PowerLowerWithUserHappiness",
"PowerHigherWithUserHP",
"PowerHigherWithTargetHP",
"PowerHigherWithUserPositiveStatStages",
"PowerHigherWithTargetPositiveStatStages",
"TypeDependsOnUserIVs",
"PowerHigherWithConsecutiveUse",
"PowerHigherWithConsecutiveUseOnUserSide",
"PowerHigherWithLessPP",
"PowerLowerWithUserHP",
"PowerHigherWithUserFasterThanTarget",
"PowerHigherWithTargetWeight",
"ThrowUserItemAtTarget",
"PowerDependsOnUserStockpile"
baseDmg = move.pbBaseDamage(baseDmg, @user, target)
when "DoublePowerIfUserHasNoItem" # Acrobatics
baseDmg *= 2 if !@user.item || @user.hasActiveItem?(:FLYINGGEM)
when "PowerHigherWithTargetFasterThanUser" # Gyro Ball
targetSpeed = pbRoughStat(target, :SPEED)
userSpeed = pbRoughStat(@user, :SPEED)
baseDmg = [[(25 * targetSpeed / userSpeed).floor, 150].min, 1].max
when "RandomlyDamageOrHealTarget" # Present
baseDmg = 50
when "RandomPowerDoublePowerIfTargetUnderground" # Magnitude
baseDmg = 71
baseDmg *= 2 if target.inTwoTurnAttack?("TwoTurnAttackInvulnerableUnderground") # Dig
when "TypeAndPowerDependOnUserBerry" # Natural Gift
baseDmg = move.pbNaturalGiftBaseDamage(@user.item_id)
when "PowerHigherWithUserHeavierThanTarget" # Heavy Slam
baseDmg = move.pbBaseDamage(baseDmg, @user, target)
baseDmg *= 2 if Settings::MECHANICS_GENERATION >= 7 && skill_check(AILevel.medium) &&
target.effects[PBEffects::Minimize]
when "AlwaysCriticalHit", "HitTwoTimes", "HitTwoTimesPoisonTarget" # Frost Breath, Double Kick, Twineedle
baseDmg *= 2
when "HitThreeTimesPowersUpWithEachHit" # Triple Kick
baseDmg *= 6 # Hits do x1, x2, x3 baseDmg in turn, for x6 in total
when "HitTwoToFiveTimes" # Fury Attack
if @user.hasActiveAbility?(:SKILLLINK)
baseDmg *= 5
else
baseDmg = (baseDmg * 31 / 10).floor # Average damage dealt
end
when "HitTwoToFiveTimesOrThreeForAshGreninja"
if @user.isSpecies?(:GRENINJA) && @user.form == 2
baseDmg *= 4 # 3 hits at 20 power = 4 hits at 15 power
elsif @user.hasActiveAbility?(:SKILLLINK)
baseDmg *= 5
else
baseDmg = (baseDmg * 31 / 10).floor # Average damage dealt
end
when "HitOncePerUserTeamMember" # Beat Up
mult = 0
@battle.eachInTeamFromBattlerIndex(@user.index) do |pkmn, _i|
mult += 1 if pkmn&.able? && pkmn.status == :NONE
end
baseDmg *= mult
when "TwoTurnAttackOneTurnInSun" # Solar Beam
baseDmg = move.pbBaseDamageMultiplier(baseDmg, @user, target)
when "MultiTurnAttackPowersUpEachTurn" # Rollout
baseDmg *= 2 if @user.effects[PBEffects::DefenseCurl]
when "MultiTurnAttackBideThenReturnDoubleDamage" # Bide
baseDmg = 40
when "UserFaintsFixedDamageUserHP" # Final Gambit
baseDmg = @user.hp
when "EffectivenessIncludesFlyingType" # Flying Press
if GameData::Type.exists?(:FLYING)
if skill_check(AILevel.high)
targetTypes = target.pbTypes(true)
mult = Effectiveness.calculate(
:FLYING, targetTypes[0], targetTypes[1], targetTypes[2]
)
else
mult = Effectiveness.calculate(
:FLYING, target.types[0], target.types[1], target.effects[PBEffects::Type3]
)
end
baseDmg = (baseDmg.to_f * mult / Effectiveness::NORMAL_EFFECTIVE).round
end
baseDmg *= 2 if skill_check(AILevel.medium) && target.effects[PBEffects::Minimize]
when "DoublePowerIfUserLastMoveFailed" # Stomping Tantrum
baseDmg *= 2 if @user.lastRoundMoveFailed
when "HitTwoTimesFlinchTarget" # Double Iron Bash
baseDmg *= 2
baseDmg *= 2 if skill_check(AILevel.medium) && target.effects[PBEffects::Minimize]
end
return baseDmg
end
#============================================================================= #=============================================================================
# Damage calculation # Damage calculation
#============================================================================= #=============================================================================
def pbRoughDamage(move, target, baseDmg) def pbRoughDamage(move, target, baseDmg)
# Fixed damage moves # Fixed damage moves
return baseDmg if move.is_a?(Battle::Move::FixedDamageMove) return baseDmg if move.move.is_a?(Battle::Move::FixedDamageMove)
user_battler = @user.battler
target_battler = target.battler
# Get the move's type # Get the move's type
type = pbRoughType(move) type = move.rough_type
##### Calculate user's attack stat ##### ##### Calculate user's attack stat #####
atk = pbRoughStat(@user, :ATTACK) atk = @user.rough_stat(:ATTACK)
if move.function == "UseTargetAttackInsteadOfUserAttack" # Foul Play if move.move.function == "UseTargetAttackInsteadOfUserAttack" # Foul Play
atk = pbRoughStat(target, :ATTACK) atk = target.rough_stat(:ATTACK)
elsif move.function == "UseUserBaseDefenseInsteadOfUserBaseAttack" # Body Press elsif move.move.function == "UseUserBaseDefenseInsteadOfUserBaseAttack" # Body Press
atk = pbRoughStat(@user, :DEFENSE) atk = @user.rough_stat(:DEFENSE)
elsif move.specialMove?(type) elsif move.move.specialMove?(type)
if move.function == "UseTargetAttackInsteadOfUserAttack" # Foul Play if move.move.function == "UseTargetAttackInsteadOfUserAttack" # Foul Play
atk = pbRoughStat(target, :SPECIAL_ATTACK) atk = target.rough_stat(:SPECIAL_ATTACK)
else else
atk = pbRoughStat(@user, :SPECIAL_ATTACK) atk = @user.rough_stat(:SPECIAL_ATTACK)
end end
end end
##### Calculate target's defense stat ##### ##### Calculate target's defense stat #####
defense = pbRoughStat(target, :DEFENSE) defense = target.rough_stat(:DEFENSE)
if move.specialMove?(type) && move.function != "UseTargetDefenseInsteadOfTargetSpDef" # Psyshock if move.move.specialMove?(type) && move.move.function != "UseTargetDefenseInsteadOfTargetSpDef" # Psyshock
defense = pbRoughStat(target, :SPECIAL_DEFENSE) defense = target.rough_stat(:SPECIAL_DEFENSE)
end end
##### Calculate all multiplier effects ##### ##### Calculate all multiplier effects #####
@@ -331,56 +77,56 @@ class Battle::AI
:final_damage_multiplier => 1.0 :final_damage_multiplier => 1.0
} }
# Ability effects that alter damage # Ability effects that alter damage
moldBreaker = skill_check(AILevel.high) && target.hasMoldBreaker? moldBreaker = @trainer.high_skill? && target_battler.hasMoldBreaker?
if skill_check(AILevel.medium) && @user.abilityActive? if @user.ability_active?
# NOTE: These abilities aren't suitable for checking at the start of the # NOTE: These abilities aren't suitable for checking at the start of the
# round. # round.
abilityBlacklist = [:ANALYTIC, :SNIPER, :TINTEDLENS, :AERILATE, :PIXILATE, :REFRIGERATE] abilityBlacklist = [:ANALYTIC, :SNIPER, :TINTEDLENS, :AERILATE, :PIXILATE, :REFRIGERATE]
canCheck = true canCheck = true
abilityBlacklist.each do |m| abilityBlacklist.each do |m|
next if move.id != m next if move.move.id != m
canCheck = false canCheck = false
break break
end end
if canCheck if canCheck
Battle::AbilityEffects.triggerDamageCalcFromUser( Battle::AbilityEffects.triggerDamageCalcFromUser(
@user.ability, @user, target, move, multipliers, baseDmg, type user_battler.ability, user_battler, target_battler, move.move, multipliers, baseDmg, type
) )
end end
end end
if skill_check(AILevel.medium) && !moldBreaker if @trainer.medium_skill? && !moldBreaker
@user.allAllies.each do |b| user_battler.allAllies.each do |b|
next if !b.abilityActive? next if !b.abilityActive?
Battle::AbilityEffects.triggerDamageCalcFromAlly( Battle::AbilityEffects.triggerDamageCalcFromAlly(
b.ability, @user, target, move, multipliers, baseDmg, type b.ability, user_battler, target_battler, move.move, multipliers, baseDmg, type
) )
end end
end end
if skill_check(AILevel.best) && !moldBreaker && target.abilityActive? if !moldBreaker && target.ability_active?
# NOTE: These abilities aren't suitable for checking at the start of the # NOTE: These abilities aren't suitable for checking at the start of the
# round. # round.
abilityBlacklist = [:FILTER, :SOLIDROCK] abilityBlacklist = [:FILTER, :SOLIDROCK]
canCheck = true canCheck = true
abilityBlacklist.each do |m| abilityBlacklist.each do |m|
next if move.id != m next if move.move.id != m
canCheck = false canCheck = false
break break
end end
if canCheck if canCheck
Battle::AbilityEffects.triggerDamageCalcFromTarget( Battle::AbilityEffects.triggerDamageCalcFromTarget(
target.ability, @user, target, move, multipliers, baseDmg, type target_battler.ability, user_battler, target_battler, move.move, multipliers, baseDmg, type
) )
end end
end end
if skill_check(AILevel.best) && !moldBreaker if @trainer.high_skill? && !moldBreaker
target.allAllies.each do |b| target_battler.allAllies.each do |b|
next if !b.abilityActive? next if !b.abilityActive?
Battle::AbilityEffects.triggerDamageCalcFromTargetAlly( Battle::AbilityEffects.triggerDamageCalcFromTargetAlly(
b.ability, @user, target, move, multipliers, baseDmg, type b.ability, user_battler, target_battler, move.move, multipliers, baseDmg, type
) )
end end
end end
@@ -388,28 +134,27 @@ class Battle::AI
# Item effects that alter damage # Item effects that alter damage
# NOTE: Type-boosting gems aren't suitable for checking at the start of the # NOTE: Type-boosting gems aren't suitable for checking at the start of the
# round. # round.
if skill_check(AILevel.medium) && @user.itemActive? if @user.item_active?
# NOTE: These items aren't suitable for checking at the start of the # NOTE: These items aren't suitable for checking at the start of the
# round. # round.
itemBlacklist = [:EXPERTBELT, :LIFEORB] itemBlacklist = [:EXPERTBELT, :LIFEORB]
if !itemBlacklist.include?(@user.item_id) if !itemBlacklist.include?(user_battler.item_id)
Battle::ItemEffects.triggerDamageCalcFromUser( Battle::ItemEffects.triggerDamageCalcFromUser(
@user.item, @user, target, move, multipliers, baseDmg, type user_battler.item, user_battler, target_battler, move.move, multipliers, baseDmg, type
) )
@user.effects[PBEffects::GemConsumed] = nil # Untrigger consuming of Gems user_battler.effects[PBEffects::GemConsumed] = nil # Untrigger consuming of Gems
end end
# TODO: Prefer (1.5x?) if item will be consumed and user has Unburden. # TODO: Prefer (1.5x?) if item will be consumed and user has Unburden.
end end
if skill_check(AILevel.best) && if target.item_active? && target_battler.item && !target_battler.item.is_berry?
target.itemActive? && target.item && !target.item.is_berry?
Battle::ItemEffects.triggerDamageCalcFromTarget( Battle::ItemEffects.triggerDamageCalcFromTarget(
target.item, @user, target, move, multipliers, baseDmg, type target_battler.item, user_battler, target_battler, move.move, multipliers, baseDmg, type
) )
end end
# Global abilities # Global abilities
if skill_check(AILevel.medium) && if @trainer.medium_skill? &&
((@battle.pbCheckGlobalAbility(:DARKAURA) && type == :DARK) || ((@battle.pbCheckGlobalAbility(:DARKAURA) && type == :DARK) ||
(@battle.pbCheckGlobalAbility(:FAIRYAURA) && type == :FAIRY)) (@battle.pbCheckGlobalAbility(:FAIRYAURA) && type == :FAIRY))
if @battle.pbCheckGlobalAbility(:AURABREAK) if @battle.pbCheckGlobalAbility(:AURABREAK)
@@ -420,7 +165,7 @@ class Battle::AI
end end
# Parental Bond # Parental Bond
if skill_check(AILevel.medium) && @user.hasActiveAbility?(:PARENTALBOND) if @user.has_active_ability?(:PARENTALBOND)
multipliers[:base_damage_multiplier] *= 1.25 multipliers[:base_damage_multiplier] *= 1.25
end end
@@ -430,13 +175,13 @@ class Battle::AI
# Helping Hand - n/a # Helping Hand - n/a
# Charge # Charge
if skill_check(AILevel.medium) && if @trainer.medium_skill? &&
@user.effects[PBEffects::Charge] > 0 && type == :ELECTRIC user_battler.effects[PBEffects::Charge] > 0 && type == :ELECTRIC
multipliers[:base_damage_multiplier] *= 2 multipliers[:base_damage_multiplier] *= 2
end end
# Mud Sport and Water Sport # Mud Sport and Water Sport
if skill_check(AILevel.medium) if @trainer.medium_skill?
if type == :ELECTRIC if type == :ELECTRIC
if @battle.allBattlers.any? { |b| b.effects[PBEffects::MudSport] } if @battle.allBattlers.any? { |b| b.effects[PBEffects::MudSport] }
multipliers[:base_damage_multiplier] /= 3 multipliers[:base_damage_multiplier] /= 3
@@ -456,38 +201,38 @@ class Battle::AI
end end
# Terrain moves # Terrain moves
if skill_check(AILevel.medium) if @trainer.medium_skill?
case @battle.field.terrain case @battle.field.terrain
when :Electric when :Electric
multipliers[:base_damage_multiplier] *= 1.5 if type == :ELECTRIC && @user.affectedByTerrain? multipliers[:base_damage_multiplier] *= 1.5 if type == :ELECTRIC && user_battler.affectedByTerrain?
when :Grassy when :Grassy
multipliers[:base_damage_multiplier] *= 1.5 if type == :GRASS && @user.affectedByTerrain? multipliers[:base_damage_multiplier] *= 1.5 if type == :GRASS && user_battler.affectedByTerrain?
when :Psychic when :Psychic
multipliers[:base_damage_multiplier] *= 1.5 if type == :PSYCHIC && @user.affectedByTerrain? multipliers[:base_damage_multiplier] *= 1.5 if type == :PSYCHIC && user_battler.affectedByTerrain?
when :Misty when :Misty
multipliers[:base_damage_multiplier] /= 2 if type == :DRAGON && target.affectedByTerrain? multipliers[:base_damage_multiplier] /= 2 if type == :DRAGON && target_battler.affectedByTerrain?
end end
end end
# Badge multipliers # Badge multipliers
if skill_check(AILevel.high) && @battle.internalBattle && target.pbOwnedByPlayer? if @trainer.high_skill? && @battle.internalBattle && target_battler.pbOwnedByPlayer?
# Don't need to check the Atk/Sp Atk-boosting badges because the AI # Don't need to check the Atk/Sp Atk-boosting badges because the AI
# won't control the player's Pokémon. # won't control the player's Pokémon.
if move.physicalMove?(type) && @battle.pbPlayer.badge_count >= Settings::NUM_BADGES_BOOST_DEFENSE if move.move.physicalMove?(type) && @battle.pbPlayer.badge_count >= Settings::NUM_BADGES_BOOST_DEFENSE
multipliers[:defense_multiplier] *= 1.1 multipliers[:defense_multiplier] *= 1.1
elsif move.specialMove?(type) && @battle.pbPlayer.badge_count >= Settings::NUM_BADGES_BOOST_SPDEF elsif move.move.specialMove?(type) && @battle.pbPlayer.badge_count >= Settings::NUM_BADGES_BOOST_SPDEF
multipliers[:defense_multiplier] *= 1.1 multipliers[:defense_multiplier] *= 1.1
end end
end end
# Multi-targeting attacks # Multi-targeting attacks
if skill_check(AILevel.high) && pbTargetsMultiple?(move) if @trainer.high_skill? && move.targets_multiple_battlers?
multipliers[:final_damage_multiplier] *= 0.75 multipliers[:final_damage_multiplier] *= 0.75
end end
# Weather # Weather
if skill_check(AILevel.medium) if @trainer.medium_skill?
case @user.effectiveWeather case user_battler.effectiveWeather
when :Sun, :HarshSun when :Sun, :HarshSun
case type case type
when :FIRE when :FIRE
@@ -503,8 +248,8 @@ class Battle::AI
multipliers[:final_damage_multiplier] *= 1.5 multipliers[:final_damage_multiplier] *= 1.5
end end
when :Sandstorm when :Sandstorm
if target.pbHasType?(:ROCK) && move.specialMove?(type) && if target.has_type?(:ROCK) && move.move.specialMove?(type) &&
move.function != "UseTargetDefenseInsteadOfTargetSpDef" # Psyshock move.move.function != "UseTargetDefenseInsteadOfTargetSpDef" # Psyshock
multipliers[:defense_multiplier] *= 1.5 multipliers[:defense_multiplier] *= 1.5
end end
end end
@@ -515,8 +260,8 @@ class Battle::AI
# Random variance - n/a # Random variance - n/a
# STAB # STAB
if skill_check(AILevel.medium) && type && @user.pbHasType?(type) if type && @user.has_type?(type)
if @user.hasActiveAbility?(:ADAPTABILITY) if @user.has_active_ability?(:ADAPTABILITY)
multipliers[:final_damage_multiplier] *= 2 multipliers[:final_damage_multiplier] *= 2
else else
multipliers[:final_damage_multiplier] *= 1.5 multipliers[:final_damage_multiplier] *= 1.5
@@ -524,35 +269,33 @@ class Battle::AI
end end
# Type effectiveness # Type effectiveness
if skill_check(AILevel.medium) typemod = target.effectiveness_of_type_against_battler(type, @user)
typemod = pbCalcTypeMod(type, @user, target) multipliers[:final_damage_multiplier] *= typemod.to_f / Effectiveness::NORMAL_EFFECTIVE
multipliers[:final_damage_multiplier] *= typemod.to_f / Effectiveness::NORMAL_EFFECTIVE
end
# Burn # Burn
if skill_check(AILevel.high) && move.physicalMove?(type) && if @trainer.high_skill? && move.move.physicalMove?(type) &&
@user.status == :BURN && !@user.hasActiveAbility?(:GUTS) && user_battler.status == :BURN && !@user.has_active_ability?(:GUTS) &&
!(Settings::MECHANICS_GENERATION >= 6 && !(Settings::MECHANICS_GENERATION >= 6 &&
move.function == "DoublePowerIfUserPoisonedBurnedParalyzed") # Facade move.move.function == "DoublePowerIfUserPoisonedBurnedParalyzed") # Facade
multipliers[:final_damage_multiplier] /= 2 multipliers[:final_damage_multiplier] /= 2
end end
# Aurora Veil, Reflect, Light Screen # Aurora Veil, Reflect, Light Screen
if skill_check(AILevel.high) && !move.ignoresReflect? && !@user.hasActiveAbility?(:INFILTRATOR) if @trainer.medium_skill? && !move.move.ignoresReflect? && !@user.has_active_ability?(:INFILTRATOR)
if target.pbOwnSide.effects[PBEffects::AuroraVeil] > 0 if target_battler.pbOwnSide.effects[PBEffects::AuroraVeil] > 0
if @battle.pbSideBattlerCount(target) > 1 if @battle.pbSideBattlerCount(target_battler) > 1
multipliers[:final_damage_multiplier] *= 2 / 3.0 multipliers[:final_damage_multiplier] *= 2 / 3.0
else else
multipliers[:final_damage_multiplier] /= 2 multipliers[:final_damage_multiplier] /= 2
end end
elsif target.pbOwnSide.effects[PBEffects::Reflect] > 0 && move.physicalMove?(type) elsif target_battler.pbOwnSide.effects[PBEffects::Reflect] > 0 && move.move.physicalMove?(type)
if @battle.pbSideBattlerCount(target) > 1 if @battle.pbSideBattlerCount(target_battler) > 1
multipliers[:final_damage_multiplier] *= 2 / 3.0 multipliers[:final_damage_multiplier] *= 2 / 3.0
else else
multipliers[:final_damage_multiplier] /= 2 multipliers[:final_damage_multiplier] /= 2
end end
elsif target.pbOwnSide.effects[PBEffects::LightScreen] > 0 && move.specialMove?(type) elsif target_battler.pbOwnSide.effects[PBEffects::LightScreen] > 0 && move.move.specialMove?(type)
if @battle.pbSideBattlerCount(target) > 1 if @battle.pbSideBattlerCount(target_battler) > 1
multipliers[:final_damage_multiplier] *= 2 / 3.0 multipliers[:final_damage_multiplier] *= 2 / 3.0
else else
multipliers[:final_damage_multiplier] /= 2 multipliers[:final_damage_multiplier] /= 2
@@ -561,7 +304,7 @@ class Battle::AI
end end
# Minimize # Minimize
if skill_check(AILevel.high) && target.effects[PBEffects::Minimize] && move.tramplesMinimize? if @trainer.medium_skill? && target_battler.effects[PBEffects::Minimize] && move.move.tramplesMinimize?
multipliers[:final_damage_multiplier] *= 2 multipliers[:final_damage_multiplier] *= 2
end end
@@ -575,156 +318,11 @@ class Battle::AI
baseDmg = [(baseDmg * multipliers[:base_damage_multiplier]).round, 1].max baseDmg = [(baseDmg * multipliers[:base_damage_multiplier]).round, 1].max
atk = [(atk * multipliers[:attack_multiplier]).round, 1].max atk = [(atk * multipliers[:attack_multiplier]).round, 1].max
defense = [(defense * multipliers[:defense_multiplier]).round, 1].max defense = [(defense * multipliers[:defense_multiplier]).round, 1].max
damage = ((((2.0 * @user.level / 5) + 2).floor * baseDmg * atk / defense).floor / 50).floor + 2 damage = ((((2.0 * user_battler.level / 5) + 2).floor * baseDmg * atk / defense).floor / 50).floor + 2
damage = [(damage * multipliers[:final_damage_multiplier]).round, 1].max damage = [(damage * multipliers[:final_damage_multiplier]).round, 1].max
return damage.floor return damage.floor
end end
#=============================================================================
# Critical hit rate calculation
#=============================================================================
def pbRoughCriticalHitStage(move, target)
return -1 if target.pbOwnSide.effects[PBEffects::LuckyChant] > 0
mold_breaker = (skill_check(AILevel.medium) && @user.hasMoldBreaker?)
crit_stage = 0
# Ability effects that alter critical hit rate
if skill_check(AILevel.medium) && @user.abilityActive?
crit_stage = BattleHandlers.triggerCriticalCalcUserAbility(@user.ability, @user, target, crit_stage)
return -1 if crit_stage < 0
end
if skill_check(AILevel.best) && !mold_breaker && target.abilityActive?
crit_stage = BattleHandlers.triggerCriticalCalcTargetAbility(target.ability, @user, target, crit_stage)
return -1 if crit_stage < 0
end
# Item effects that alter critical hit rate
if skill_check(AILevel.medium) && @user.itemActive?
crit_stage = BattleHandlers.triggerCriticalCalcUserItem(@user.item, @user, target, crit_stage)
return -1 if crit_stage < 0
end
if skill_check(AILevel.high) && target.itemActive?
crit_stage = BattleHandlers.triggerCriticalCalcTargetItem(target.item, @user, target, crit_stage)
return -1 if crit_stage < 0
end
# Other effects
case move.pbCritialOverride(@user, target)
when 1 then return 99
when -1 then return -1
end
return 99 if crit_stage > 50 # Merciless
return 99 if @user.effects[PBEffects::LaserFocus] > 0
crit_stage += 1 if move.highCriticalRate?
crit_stage += @user.effects[PBEffects::FocusEnergy]
crit_stage += 1 if @user.inHyperMode? && move.type == :SHADOW
crit_stage = [crit_stage, Battle::Move::CRITICAL_HIT_RATIOS.length - 1].min
return crit_stage
end
#=============================================================================
# Accuracy calculation
#=============================================================================
def pbRoughAccuracy(move, target)
# "Always hit" effects and "always hit" accuracy
if skill_check(AILevel.medium)
return 100 if target.effects[PBEffects::Minimize] && move.tramplesMinimize? &&
Settings::MECHANICS_GENERATION >= 6
return 100 if target.effects[PBEffects::Telekinesis] > 0
end
# Get base accuracy
baseAcc = move.accuracy
baseAcc = move.pbBaseAccuracy(@user, target) if skill_check(AILevel.medium)
return 100 if baseAcc == 0 && skill_check(AILevel.medium)
# Get the move's type
type = pbRoughType(move)
# Calculate all modifier effects
modifiers = {}
modifiers[:base_accuracy] = baseAcc
modifiers[:accuracy_stage] = @user.stages[:ACCURACY]
modifiers[:evasion_stage] = target.stages[:EVASION]
modifiers[:accuracy_multiplier] = 1.0
modifiers[:evasion_multiplier] = 1.0
pbCalcAccuracyModifiers(target, modifiers, move, type)
# Check if move certainly misses/can't miss
return 0 if modifiers[:base_accuracy] < 0
return 100 if modifiers[:base_accuracy] == 0
# Calculation
accStage = [[modifiers[:accuracy_stage], -6].max, 6].min + 6
evaStage = [[modifiers[:evasion_stage], -6].max, 6].min + 6
stageMul = [3, 3, 3, 3, 3, 3, 3, 4, 5, 6, 7, 8, 9]
stageDiv = [9, 8, 7, 6, 5, 4, 3, 3, 3, 3, 3, 3, 3]
accuracy = 100.0 * stageMul[accStage] / stageDiv[accStage]
evasion = 100.0 * stageMul[evaStage] / stageDiv[evaStage]
accuracy = (accuracy * modifiers[:accuracy_multiplier]).round
evasion = (evasion * modifiers[:evasion_multiplier]).round
evasion = 1 if evasion < 1
return modifiers[:base_accuracy] * accuracy / evasion
end
def pbCalcAccuracyModifiers(target, modifiers, move, type)
moldBreaker = (skill_check(AILevel.medium) && target.hasMoldBreaker?)
# Ability effects that alter accuracy calculation
if skill_check(AILevel.medium) && @user.abilityActive?
Battle::AbilityEffects.triggerAccuracyCalcFromUser(
@user.ability, modifiers, @user, target, move, type
)
end
if skill_check(AILevel.high)
@user.allAllies.each do |b|
next if !b.abilityActive?
Battle::AbilityEffects.triggerAccuracyCalcFromAlly(
b.ability, modifiers, @user, target, move, type
)
end
end
if skill_check(AILevel.best) && target.abilityActive? && !moldBreaker
Battle::AbilityEffects.triggerAccuracyCalcFromTarget(
target.ability, modifiers, @user, target, move, type
)
end
# Item effects that alter accuracy calculation
if skill_check(AILevel.medium) && @user.itemActive?
# TODO: Zoom Lens needs to be checked differently (compare speeds of
# user and target).
Battle::ItemEffects.triggerAccuracyCalcFromUser(
@user.item, modifiers, @user, target, move, type
)
end
if skill_check(AILevel.high) && target.itemActive?
Battle::ItemEffects.triggerAccuracyCalcFromTarget(
target.item, modifiers, @user, target, move, type
)
end
# Other effects, inc. ones that set accuracy_multiplier or evasion_stage to specific values
if @battle.field.effects[PBEffects::Gravity] > 0
modifiers[:accuracy_multiplier] *= 5 / 3.0
end
if skill_check(AILevel.medium)
if @user.effects[PBEffects::MicleBerry]
modifiers[:accuracy_multiplier] *= 1.2
end
modifiers[:evasion_stage] = 0 if target.effects[PBEffects::Foresight] && modifiers[:evasion_stage] > 0
modifiers[:evasion_stage] = 0 if target.effects[PBEffects::MiracleEye] && modifiers[:evasion_stage] > 0
end
# "AI-specific calculations below"
modifiers[:evasion_stage] = 0 if move.function == "IgnoreTargetDefSpDefEvaStatStages" # Chip Away
if skill_check(AILevel.medium)
modifiers[:base_accuracy] = 0 if @user.effects[PBEffects::LockOn] > 0 &&
@user.effects[PBEffects::LockOnPos] == target.index
end
if skill_check(AILevel.medium)
if move.function == "BadPoisonTarget" && # Toxic
Settings::MORE_TYPE_EFFECTS && move.statusMove? && @user.pbHasType?(:POISON)
modifiers[:base_accuracy] = 0
end
if ["OHKO", "OHKOIce", "OHKOHitsUndergroundTarget"].include?(move.function)
modifiers[:base_accuracy] = move.accuracy + @user.level - target.level
modifiers[:accuracy_multiplier] = 0 if target.level > @user.level
if skill_check(AILevel.best) && target.hasActiveAbility?(:STURDY)
modifiers[:accuracy_multiplier] = 0
end
end
end
end
#============================================================================= #=============================================================================
# Check if battler has a move that meets the criteria in the block provided # Check if battler has a move that meets the criteria in the block provided
#============================================================================= #=============================================================================

View File

@@ -112,7 +112,7 @@ class Battle::AI
# instead if the move raises evasion. Note this comes after the # instead if the move raises evasion. Note this comes after the
# dissociation of Bulk Up from sweeping_stat. # dissociation of Bulk Up from sweeping_stat.
if skill_check(AILevel.medium) if @trainer.medium_skill?
# TODO: Prefer if the maximum damage the target has dealt wouldn't hurt # TODO: Prefer if the maximum damage the target has dealt wouldn't hurt
# the user much. # the user much.
end end

View File

@@ -6,8 +6,8 @@
# None # None
Battle::AI::Handlers::MoveEffectScore.add("DoesNothingCongratulations", Battle::AI::Handlers::MoveEffectScore.add("DoesNothingCongratulations",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next 0 if ai.skill_check(Battle::AI::AILevel.high) next 0 if ai.trainer.high_skill?
next score - 95 next score - 95
} }
) )
@@ -20,7 +20,7 @@ Battle::AI::Handlers::MoveEffectScore.copy("DoesNothingCongratulations",
# AddMoneyGainedFromBattle # AddMoneyGainedFromBattle
Battle::AI::Handlers::MoveEffectScore.add("FailsIfNotUserFirstTurn", Battle::AI::Handlers::MoveEffectScore.add("FailsIfNotUserFirstTurn",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next score - 90 if user.turnCount > 0 next score - 90 if user.turnCount > 0
} }
) )
@@ -28,31 +28,31 @@ Battle::AI::Handlers::MoveEffectScore.add("FailsIfNotUserFirstTurn",
# FailsIfUserHasUnusedMove # FailsIfUserHasUnusedMove
Battle::AI::Handlers::MoveEffectScore.add("FailsIfUserNotConsumedBerry", Battle::AI::Handlers::MoveEffectScore.add("FailsIfUserNotConsumedBerry",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next score - 90 if !user.belched? next score - 90 if !user.battler.belched?
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("FailsIfTargetHasNoItem", Battle::AI::Handlers::MoveEffectScore.add("FailsIfTargetHasNoItem",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if ai.skill_check(Battle::AI::AILevel.medium) if ai.trainer.medium_skill?
next score - 90 if !target.item || !target.itemActive? next score - 90 if !target.item || !target.item_active?
next score + 50 next score + 50
end end
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("FailsUnlessTargetSharesTypeWithUser", Battle::AI::Handlers::MoveEffectScore.add("FailsUnlessTargetSharesTypeWithUser",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if !(user.types[0] && target.pbHasType?(user.types[0])) && if !(user.types[0] && target.has_type?(user.types[0])) &&
!(user.types[1] && target.pbHasType?(user.types[1])) !(user.types[1] && target.has_type?(user.types[1]))
next score - 90 next score - 90
end end
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("FailsIfUserDamagedThisTurn", Battle::AI::Handlers::MoveEffectScore.add("FailsIfUserDamagedThisTurn",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
score += 50 if target.effects[PBEffects::HyperBeam] > 0 score += 50 if target.effects[PBEffects::HyperBeam] > 0
score -= 35 if target.hp <= target.totalhp / 2 # If target is weak, no score -= 35 if target.hp <= target.totalhp / 2 # If target is weak, no
score -= 70 if target.hp <= target.totalhp / 4 # need to risk this move score -= 70 if target.hp <= target.totalhp / 4 # need to risk this move
@@ -63,20 +63,20 @@ Battle::AI::Handlers::MoveEffectScore.add("FailsIfUserDamagedThisTurn",
# FailsIfTargetActed # FailsIfTargetActed
Battle::AI::Handlers::MoveEffectScore.add("CrashDamageIfFailsUnusableInGravity", Battle::AI::Handlers::MoveEffectScore.add("CrashDamageIfFailsUnusableInGravity",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next score + 10 * (user.stages[:ACCURACY] - target.stages[:EVASION]) next score + 10 * (user.stages[:ACCURACY] - target.stages[:EVASION])
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("StartSunWeather", Battle::AI::Handlers::MoveEffectScore.add("StartSunWeather",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if battle.pbCheckGlobalAbility(:AIRLOCK) || if battle.pbCheckGlobalAbility(:AIRLOCK) ||
battle.pbCheckGlobalAbility(:CLOUDNINE) battle.pbCheckGlobalAbility(:CLOUDNINE)
next score - 90 next score - 90
elsif battle.field.weather == :Sun elsif battle.field.weather == :Sun
next score - 90 next score - 90
else else
user.eachMove do |m| user.battler.eachMove do |m|
next if !m.damagingMove? || m.type != :FIRE next if !m.damagingMove? || m.type != :FIRE
score += 20 score += 20
end end
@@ -86,14 +86,14 @@ Battle::AI::Handlers::MoveEffectScore.add("StartSunWeather",
) )
Battle::AI::Handlers::MoveEffectScore.add("StartRainWeather", Battle::AI::Handlers::MoveEffectScore.add("StartRainWeather",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if battle.pbCheckGlobalAbility(:AIRLOCK) || if battle.pbCheckGlobalAbility(:AIRLOCK) ||
battle.pbCheckGlobalAbility(:CLOUDNINE) battle.pbCheckGlobalAbility(:CLOUDNINE)
next score - 90 next score - 90
elsif battle.field.weather == :Rain elsif battle.field.weather == :Rain
next score - 90 next score - 90
else else
user.eachMove do |m| user.battler.eachMove do |m|
next if !m.damagingMove? || m.type != :WATER next if !m.damagingMove? || m.type != :WATER
score += 20 score += 20
end end
@@ -103,7 +103,7 @@ Battle::AI::Handlers::MoveEffectScore.add("StartRainWeather",
) )
Battle::AI::Handlers::MoveEffectScore.add("StartSandstormWeather", Battle::AI::Handlers::MoveEffectScore.add("StartSandstormWeather",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if battle.pbCheckGlobalAbility(:AIRLOCK) || if battle.pbCheckGlobalAbility(:AIRLOCK) ||
battle.pbCheckGlobalAbility(:CLOUDNINE) battle.pbCheckGlobalAbility(:CLOUDNINE)
next score - 90 next score - 90
@@ -114,7 +114,7 @@ Battle::AI::Handlers::MoveEffectScore.add("StartSandstormWeather",
) )
Battle::AI::Handlers::MoveEffectScore.add("StartHailWeather", Battle::AI::Handlers::MoveEffectScore.add("StartHailWeather",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if battle.pbCheckGlobalAbility(:AIRLOCK) || if battle.pbCheckGlobalAbility(:AIRLOCK) ||
battle.pbCheckGlobalAbility(:CLOUDNINE) battle.pbCheckGlobalAbility(:CLOUDNINE)
next score - 90 next score - 90
@@ -133,16 +133,16 @@ Battle::AI::Handlers::MoveEffectScore.add("StartHailWeather",
# StartPsychicTerrain # StartPsychicTerrain
Battle::AI::Handlers::MoveEffectScore.add("RemoveTerrain", Battle::AI::Handlers::MoveEffectScore.add("RemoveTerrain",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next 0 if battle.field.terrain == :None next 0 if battle.field.terrain == :None
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("AddSpikesToFoeSide", Battle::AI::Handlers::MoveEffectScore.add("AddSpikesToFoeSide",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if user.pbOpposingSide.effects[PBEffects::Spikes] >= 3 if user.pbOpposingSide.effects[PBEffects::Spikes] >= 3
next score - 90 next score - 90
elsif user.allOpposing.none? { |b| battle.pbCanChooseNonActive?(b.index) } elsif user.battler.allOpposing.none? { |b| battle.pbCanChooseNonActive?(b.index) }
next score - 90 # Opponent can't switch in any Pokemon next score - 90 # Opponent can't switch in any Pokemon
else else
score += 10 * battle.pbAbleNonActiveCount(user.idxOpposingSide) score += 10 * battle.pbAbleNonActiveCount(user.idxOpposingSide)
@@ -153,10 +153,10 @@ Battle::AI::Handlers::MoveEffectScore.add("AddSpikesToFoeSide",
) )
Battle::AI::Handlers::MoveEffectScore.add("AddToxicSpikesToFoeSide", Battle::AI::Handlers::MoveEffectScore.add("AddToxicSpikesToFoeSide",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if user.pbOpposingSide.effects[PBEffects::ToxicSpikes] >= 2 if user.pbOpposingSide.effects[PBEffects::ToxicSpikes] >= 2
next score - 90 next score - 90
elsif user.allOpposing.none? { |b| battle.pbCanChooseNonActive?(b.index) } elsif user.battler.allOpposing.none? { |b| battle.pbCanChooseNonActive?(b.index) }
next score - 90 # Opponent can't switch in any Pokemon next score - 90 # Opponent can't switch in any Pokemon
else else
score += 8 * battle.pbAbleNonActiveCount(user.idxOpposingSide) score += 8 * battle.pbAbleNonActiveCount(user.idxOpposingSide)
@@ -167,10 +167,10 @@ Battle::AI::Handlers::MoveEffectScore.add("AddToxicSpikesToFoeSide",
) )
Battle::AI::Handlers::MoveEffectScore.add("AddStealthRocksToFoeSide", Battle::AI::Handlers::MoveEffectScore.add("AddStealthRocksToFoeSide",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if user.pbOpposingSide.effects[PBEffects::StealthRock] if user.pbOpposingSide.effects[PBEffects::StealthRock]
next score - 90 next score - 90
elsif user.allOpposing.none? { |b| battle.pbCanChooseNonActive?(b.index) } elsif user.battler.allOpposing.none? { |b| battle.pbCanChooseNonActive?(b.index) }
next score - 90 # Opponent can't switch in any Pokemon next score - 90 # Opponent can't switch in any Pokemon
else else
next score + 10 * battle.pbAbleNonActiveCount(user.idxOpposingSide) next score + 10 * battle.pbAbleNonActiveCount(user.idxOpposingSide)
@@ -179,14 +179,14 @@ Battle::AI::Handlers::MoveEffectScore.add("AddStealthRocksToFoeSide",
) )
Battle::AI::Handlers::MoveEffectScore.add("AddStickyWebToFoeSide", Battle::AI::Handlers::MoveEffectScore.add("AddStickyWebToFoeSide",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next score - 95 if user.pbOpposingSide.effects[PBEffects::StickyWeb] next score - 95 if user.pbOpposingSide.effects[PBEffects::StickyWeb]
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("SwapSideEffects", Battle::AI::Handlers::MoveEffectScore.add("SwapSideEffects",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if ai.skill_check(Battle::AI::AILevel.medium) if ai.trainer.medium_skill?
good_effects = [:Reflect, :LightScreen, :AuroraVeil, :SeaOfFire, good_effects = [:Reflect, :LightScreen, :AuroraVeil, :SeaOfFire,
:Swamp, :Rainbow, :Mist, :Safeguard, :Swamp, :Rainbow, :Mist, :Safeguard,
:Tailwind].map! { |e| PBEffects.const_get(e) } :Tailwind].map! { |e| PBEffects.const_get(e) }
@@ -195,7 +195,7 @@ Battle::AI::Handlers::MoveEffectScore.add("SwapSideEffects",
score += 10 if ![0, false, nil].include?(user.pbOwnSide.effects[e]) score += 10 if ![0, false, nil].include?(user.pbOwnSide.effects[e])
score -= 10 if ![0, 1, false, nil].include?(user.pbOpposingSide.effects[e]) score -= 10 if ![0, 1, false, nil].include?(user.pbOpposingSide.effects[e])
end end
if ai.skill_check(Battle::AI::AILevel.high) if ai.trainer.high_skill?
good_effects.each do |e| good_effects.each do |e|
score += 10 if ![0, 1, false, nil].include?(user.pbOpposingSide.effects[e]) score += 10 if ![0, 1, false, nil].include?(user.pbOpposingSide.effects[e])
score -= 10 if ![0, false, nil].include?(user.pbOwnSide.effects[e]) score -= 10 if ![0, false, nil].include?(user.pbOwnSide.effects[e])
@@ -207,7 +207,7 @@ Battle::AI::Handlers::MoveEffectScore.add("SwapSideEffects",
) )
Battle::AI::Handlers::MoveEffectScore.add("UserMakeSubstitute", Battle::AI::Handlers::MoveEffectScore.add("UserMakeSubstitute",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if user.effects[PBEffects::Substitute] > 0 if user.effects[PBEffects::Substitute] > 0
next score - 90 next score - 90
elsif user.hp <= user.totalhp / 4 elsif user.hp <= user.totalhp / 4
@@ -217,7 +217,7 @@ Battle::AI::Handlers::MoveEffectScore.add("UserMakeSubstitute",
) )
Battle::AI::Handlers::MoveEffectScore.add("RemoveUserBindingAndEntryHazards", Battle::AI::Handlers::MoveEffectScore.add("RemoveUserBindingAndEntryHazards",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
score += 30 if user.effects[PBEffects::Trapping] > 0 score += 30 if user.effects[PBEffects::Trapping] > 0
score += 30 if user.effects[PBEffects::LeechSeed] >= 0 score += 30 if user.effects[PBEffects::LeechSeed] >= 0
if battle.pbAbleNonActiveCount(user.idxOwnSide) > 0 if battle.pbAbleNonActiveCount(user.idxOwnSide) > 0
@@ -230,7 +230,7 @@ Battle::AI::Handlers::MoveEffectScore.add("RemoveUserBindingAndEntryHazards",
) )
Battle::AI::Handlers::MoveEffectScore.add("AttackTwoTurnsLater", Battle::AI::Handlers::MoveEffectScore.add("AttackTwoTurnsLater",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if battle.positions[target.index].effects[PBEffects::FutureSightCounter] > 0 if battle.positions[target.index].effects[PBEffects::FutureSightCounter] > 0
next 0 next 0
elsif battle.pbAbleNonActiveCount(user.idxOwnSide) == 0 elsif battle.pbAbleNonActiveCount(user.idxOwnSide) == 0
@@ -243,7 +243,7 @@ Battle::AI::Handlers::MoveEffectScore.add("AttackTwoTurnsLater",
# UserSwapsPositionsWithAlly # UserSwapsPositionsWithAlly
Battle::AI::Handlers::MoveEffectScore.add("BurnAttackerBeforeUserActs", Battle::AI::Handlers::MoveEffectScore.add("BurnAttackerBeforeUserActs",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next score + 20 # Because of possible burning next score + 20 # Because of possible burning
} }
) )

View File

@@ -2,18 +2,16 @@
# #
#=============================================================================== #===============================================================================
Battle::AI::Handlers::MoveEffectScore.add("SleepTarget", Battle::AI::Handlers::MoveEffectScore.add("SleepTarget",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if target.pbCanSleep?(user, false) if target.battler.pbCanSleep?(user.battler, false)
score += 30 score += 30
if ai.skill_check(Battle::AI::AILevel.medium) if ai.trainer.medium_skill?
score -= 30 if target.effects[PBEffects::Yawn] > 0 score -= 30 if target.effects[PBEffects::Yawn] > 0
end end
if ai.skill_check(Battle::AI::AILevel.high) score -= 30 if target.has_active_ability?(:MARVELSCALE)
score -= 30 if target.hasActiveAbility?(:MARVELSCALE) if ai.trainer.best_skill?
end if target.battler.pbHasMoveFunction?("FlinchTargetFailsIfUserNotAsleep",
if ai.skill_check(Battle::AI::AILevel.best) "UseRandomUserMoveIfAsleep") # Snore, Sleep Talk
if target.pbHasMoveFunction?("FlinchTargetFailsIfUserNotAsleep",
"UseRandomUserMoveIfAsleep") # Snore, Sleep Talk
score -= 50 score -= 50
end end
end end
@@ -29,15 +27,14 @@ Battle::AI::Handlers::MoveEffectScore.copy("SleepTarget",
"SleepTargetChangeUserMeloettaForm") "SleepTargetChangeUserMeloettaForm")
Battle::AI::Handlers::MoveEffectScore.add("SleepTargetNextTurn", Battle::AI::Handlers::MoveEffectScore.add("SleepTargetNextTurn",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next 0 if target.effects[PBEffects::Yawn] > 0 || !target.pbCanSleep?(user, false) next 0 if target.effects[PBEffects::Yawn] > 0 ||
!target.battler.pbCanSleep?(user.battler, false)
score += 30 score += 30
if ai.skill_check(Battle::AI::AILevel.high) score -= 30 if target.has_active_ability?(:MARVELSCALE)
score -= 30 if target.hasActiveAbility?(:MARVELSCALE) if ai.trainer.best_skill?
end if target.battler.pbHasMoveFunction?("FlinchTargetFailsIfUserNotAsleep",
if ai.skill_check(Battle::AI::AILevel.best) "UseRandomUserMoveIfAsleep") # Snore, Sleep Talk
if target.pbHasMoveFunction?("FlinchTargetFailsIfUserNotAsleep",
"UseRandomUserMoveIfAsleep") # Snore, Sleep Talk
score -= 50 score -= 50
end end
end end
@@ -46,19 +43,19 @@ Battle::AI::Handlers::MoveEffectScore.add("SleepTargetNextTurn",
) )
Battle::AI::Handlers::MoveEffectScore.add("PoisonTarget", Battle::AI::Handlers::MoveEffectScore.add("PoisonTarget",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if target.pbCanPoison?(user, false) if target.battler.pbCanPoison?(user.battler, false)
score += 30 score += 30
if ai.skill_check(Battle::AI::AILevel.medium) if ai.trainer.medium_skill?
score += 30 if target.hp <= target.totalhp / 4 score += 30 if target.hp <= target.totalhp / 4
score += 50 if target.hp <= target.totalhp / 8 score += 50 if target.hp <= target.totalhp / 8
score -= 40 if target.effects[PBEffects::Yawn] > 0 score -= 40 if target.effects[PBEffects::Yawn] > 0
end end
if ai.skill_check(Battle::AI::AILevel.high) if ai.trainer.high_skill?
score += 10 if pbRoughStat(target, :DEFENSE) > 100 score += 10 if target.rough_stat(:DEFENSE) > 100
score += 10 if pbRoughStat(target, :SPECIAL_DEFENSE) > 100 score += 10 if target.rough_stat(:SPECIAL_DEFENSE) > 100
score -= 40 if target.hasActiveAbility?([:GUTS, :MARVELSCALE, :TOXICBOOST])
end end
score -= 40 if target.has_active_ability?([:GUTS, :MARVELSCALE, :TOXICBOOST])
else else
next 0 if move.statusMove? next 0 if move.statusMove?
end end
@@ -67,26 +64,27 @@ Battle::AI::Handlers::MoveEffectScore.add("PoisonTarget",
) )
Battle::AI::Handlers::MoveEffectScore.add("PoisonTargetLowerTargetSpeed1", Battle::AI::Handlers::MoveEffectScore.add("PoisonTargetLowerTargetSpeed1",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next 0 if !target.pbCanPoison?(user, false) && !target.pbCanLowerStatStage?(:SPEED, user) next 0 if !target.battler.pbCanPoison?(user.battler, false) &&
if target.pbCanPoison?(user, false) !target.battler.pbCanLowerStatStage?(:SPEED, user.battler)
if target.battler.pbCanPoison?(user.battler, false)
score += 30 score += 30
if ai.skill_check(Battle::AI::AILevel.medium) if ai.trainer.medium_skill?
score += 30 if target.hp <= target.totalhp / 4 score += 30 if target.hp <= target.totalhp / 4
score += 50 if target.hp <= target.totalhp / 8 score += 50 if target.hp <= target.totalhp / 8
score -= 40 if target.effects[PBEffects::Yawn] > 0 score -= 40 if target.effects[PBEffects::Yawn] > 0
end end
if ai.skill_check(Battle::AI::AILevel.high) if ai.trainer.high_skill?
score += 10 if pbRoughStat(target, :DEFENSE) > 100 score += 10 if target.rough_stat(:DEFENSE) > 100
score += 10 if pbRoughStat(target, :SPECIAL_DEFENSE) > 100 score += 10 if target.rough_stat(:SPECIAL_DEFENSE) > 100
score -= 40 if target.hasActiveAbility?([:GUTS, :MARVELSCALE, :TOXICBOOST])
end end
score -= 40 if target.has_active_ability?([:GUTS, :MARVELSCALE, :TOXICBOOST])
end end
if target.pbCanLowerStatStage?(:SPEED, user) if target.battler.pbCanLowerStatStage?(:SPEED, user.battler)
score += target.stages[:SPEED] * 10 score += target.stages[:SPEED] * 10
if ai.skill_check(Battle::AI::AILevel.high) if ai.trainer.high_skill?
aspeed = pbRoughStat(user, :SPEED) aspeed = user.rough_stat(:SPEED)
ospeed = pbRoughStat(target, :SPEED) ospeed = target.rough_stat(:SPEED)
score += 30 if aspeed < ospeed && aspeed * 2 > ospeed score += 30 if aspeed < ospeed && aspeed * 2 > ospeed
end end
end end
@@ -95,19 +93,19 @@ Battle::AI::Handlers::MoveEffectScore.add("PoisonTargetLowerTargetSpeed1",
) )
Battle::AI::Handlers::MoveEffectScore.add("BadPoisonTarget", Battle::AI::Handlers::MoveEffectScore.add("BadPoisonTarget",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if target.pbCanPoison?(user, false) if target.battler.pbCanPoison?(user.battler, false)
score += 30 score += 30
if ai.skill_check(Battle::AI::AILevel.medium) if ai.trainer.medium_skill?
score += 30 if target.hp <= target.totalhp / 4 score += 30 if target.hp <= target.totalhp / 4
score += 50 if target.hp <= target.totalhp / 8 score += 50 if target.hp <= target.totalhp / 8
score -= 40 if target.effects[PBEffects::Yawn] > 0 score -= 40 if target.effects[PBEffects::Yawn] > 0
end end
if ai.skill_check(Battle::AI::AILevel.high) if ai.trainer.high_skill?
score += 10 if pbRoughStat(target, :DEFENSE) > 100 score += 10 if target.rough_stat(:DEFENSE) > 100
score += 10 if pbRoughStat(target, :SPECIAL_DEFENSE) > 100 score += 10 if target.rough_stat(:SPECIAL_DEFENSE) > 100
score -= 40 if target.hasActiveAbility?([:GUTS, :MARVELSCALE, :TOXICBOOST])
end end
score -= 40 if target.has_active_ability?([:GUTS, :MARVELSCALE, :TOXICBOOST])
else else
score -= 90 if move.statusMove? score -= 90 if move.statusMove?
end end
@@ -116,24 +114,22 @@ Battle::AI::Handlers::MoveEffectScore.add("BadPoisonTarget",
) )
Battle::AI::Handlers::MoveEffectScore.add("ParalyzeTarget", Battle::AI::Handlers::MoveEffectScore.add("ParalyzeTarget",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if target.pbCanParalyze?(user, false) && if target.battler.pbCanParalyze?(user.battler, false) &&
!(ai.skill_check(Battle::AI::AILevel.medium) && !(ai.trainer.medium_skill? &&
move.id == :THUNDERWAVE && move.id == :THUNDERWAVE &&
Effectiveness.ineffective?(pbCalcTypeMod(move.type, user, target))) Effectiveness.ineffective?(target.effectiveness_of_type_against_battler(move.type, user)))
score += 30 score += 30
if ai.skill_check(Battle::AI::AILevel.medium) if ai.trainer.medium_skill?
aspeed = pbRoughStat(user, :SPEED) aspeed = user.rough_stat(:SPEED)
ospeed = pbRoughStat(target, :SPEED) ospeed = target.rough_stat(:SPEED)
if aspeed < ospeed if aspeed < ospeed
score += 30 score += 30
elsif aspeed > ospeed elsif aspeed > ospeed
score -= 40 score -= 40
end end
end end
if ai.skill_check(Battle::AI::AILevel.high) score -= 40 if target.has_active_ability?([:GUTS, :MARVELSCALE, :QUICKFEET])
score -= 40 if target.hasActiveAbility?([:GUTS, :MARVELSCALE, :QUICKFEET])
end
else else
score -= 90 if move.statusMove? score -= 90 if move.statusMove?
end end
@@ -147,12 +143,10 @@ Battle::AI::Handlers::MoveEffectScore.copy("ParalyzeTarget",
"ParalyzeFlinchTarget") "ParalyzeFlinchTarget")
Battle::AI::Handlers::MoveEffectScore.add("BurnTarget", Battle::AI::Handlers::MoveEffectScore.add("BurnTarget",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if target.pbCanBurn?(user, false) if target.battler.pbCanBurn?(user.battler, false)
score += 30 score += 30
if ai.skill_check(Battle::AI::AILevel.high) score -= 40 if target.has_active_ability?([:GUTS, :MARVELSCALE, :QUICKFEET, :FLAREBOOST])
score -= 40 if target.hasActiveAbility?([:GUTS, :MARVELSCALE, :QUICKFEET, :FLAREBOOST])
end
else else
score -= 90 if move.statusMove? score -= 90 if move.statusMove?
end end
@@ -165,12 +159,10 @@ Battle::AI::Handlers::MoveEffectScore.copy("BurnTarget",
"BurnFlinchTarget") "BurnFlinchTarget")
Battle::AI::Handlers::MoveEffectScore.add("FreezeTarget", Battle::AI::Handlers::MoveEffectScore.add("FreezeTarget",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if target.pbCanFreeze?(user, false) if target.battler.pbCanFreeze?(user.battler, false)
score += 30 score += 30
if ai.skill_check(Battle::AI::AILevel.high) score -= 20 if target.has_active_ability?(:MARVELSCALE)
score -= 20 if target.hasActiveAbility?(:MARVELSCALE)
end
else else
score -= 90 if move.statusMove? score -= 90 if move.statusMove?
end end
@@ -179,24 +171,20 @@ Battle::AI::Handlers::MoveEffectScore.add("FreezeTarget",
) )
Battle::AI::Handlers::MoveEffectScore.add("FreezeTargetSuperEffectiveAgainstWater", Battle::AI::Handlers::MoveEffectScore.add("FreezeTargetSuperEffectiveAgainstWater",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if target.pbCanFreeze?(user, false) if target.battler.pbCanFreeze?(user.battler, false)
score += 30 score += 30
if ai.skill_check(Battle::AI::AILevel.high) score -= 20 if target.has_active_ability?(:MARVELSCALE)
score -= 20 if target.hasActiveAbility?(:MARVELSCALE)
end
end end
next score next score
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("FreezeTargetAlwaysHitsInHail", Battle::AI::Handlers::MoveEffectScore.add("FreezeTargetAlwaysHitsInHail",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if target.pbCanFreeze?(user, false) if target.battler.pbCanFreeze?(user.battler, false)
score += 30 score += 30
if ai.skill_check(Battle::AI::AILevel.high) score -= 20 if target.has_active_ability?(:MARVELSCALE)
score -= 20 if target.hasActiveAbility?(:MARVELSCALE)
end
else else
score -= 90 if move.statusMove? score -= 90 if move.statusMove?
end end
@@ -208,27 +196,27 @@ Battle::AI::Handlers::MoveEffectScore.copy("FreezeTargetAlwaysHitsInHail",
"FreezeFlinchTarget") "FreezeFlinchTarget")
Battle::AI::Handlers::MoveEffectScore.add("ParalyzeBurnOrFreezeTarget", Battle::AI::Handlers::MoveEffectScore.add("ParalyzeBurnOrFreezeTarget",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next score + 30 if target.status == :NONE next score + 30 if target.status == :NONE
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("GiveUserStatusToTarget", Battle::AI::Handlers::MoveEffectScore.add("GiveUserStatusToTarget",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next 0 if user.status == :NONE next 0 if user.status == :NONE
next score + 40 next score + 40
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("CureUserBurnPoisonParalysis", Battle::AI::Handlers::MoveEffectScore.add("CureUserBurnPoisonParalysis",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
case user.status case user.status
when :POISON when :POISON
score += 40 score += 40
if ai.skill_check(Battle::AI::AILevel.medium) if ai.trainer.medium_skill?
if user.hp < user.totalhp / 8 if user.hp < user.totalhp / 8
score += 60 score += 60
elsif ai.skill_check(Battle::AI::AILevel.high) && elsif ai.trainer.high_skill? &&
user.hp < (user.effects[PBEffects::Toxic] + 1) * user.totalhp / 16 user.hp < (user.effects[PBEffects::Toxic] + 1) * user.totalhp / 16
score += 60 score += 60
end end
@@ -243,7 +231,7 @@ Battle::AI::Handlers::MoveEffectScore.add("CureUserBurnPoisonParalysis",
) )
Battle::AI::Handlers::MoveEffectScore.add("CureUserPartyStatus", Battle::AI::Handlers::MoveEffectScore.add("CureUserPartyStatus",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
statuses = 0 statuses = 0
battle.pbParty(user.index).each do |pkmn| battle.pbParty(user.index).each do |pkmn|
statuses += 1 if pkmn && pkmn.status != :NONE statuses += 1 if pkmn && pkmn.status != :NONE
@@ -258,7 +246,7 @@ Battle::AI::Handlers::MoveEffectScore.add("CureUserPartyStatus",
) )
Battle::AI::Handlers::MoveEffectScore.add("CureTargetBurn", Battle::AI::Handlers::MoveEffectScore.add("CureTargetBurn",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if target.opposes?(user) if target.opposes?(user)
score -= 40 if target.status == :BURN score -= 40 if target.status == :BURN
elsif target.status == :BURN elsif target.status == :BURN
@@ -269,7 +257,7 @@ Battle::AI::Handlers::MoveEffectScore.add("CureTargetBurn",
) )
Battle::AI::Handlers::MoveEffectScore.add("StartUserSideImmunityToInflictedStatus", Battle::AI::Handlers::MoveEffectScore.add("StartUserSideImmunityToInflictedStatus",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if user.pbOwnSide.effects[PBEffects::Safeguard] > 0 if user.pbOwnSide.effects[PBEffects::Safeguard] > 0
score -= 80 score -= 80
elsif user.status != :NONE elsif user.status != :NONE
@@ -282,52 +270,44 @@ Battle::AI::Handlers::MoveEffectScore.add("StartUserSideImmunityToInflictedStatu
) )
Battle::AI::Handlers::MoveEffectScore.add("FlinchTarget", Battle::AI::Handlers::MoveEffectScore.add("FlinchTarget",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
score += 30 score += 30
if ai.skill_check(Battle::AI::AILevel.high) score += 30 if !target.has_active_ability?(:INNERFOCUS) &&
score += 30 if !target.hasActiveAbility?(:INNERFOCUS) && target.effects[PBEffects::Substitute] == 0
target.effects[PBEffects::Substitute] == 0
end
next score next score
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("FlinchTargetFailsIfUserNotAsleep", Battle::AI::Handlers::MoveEffectScore.add("FlinchTargetFailsIfUserNotAsleep",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next 0 if !user.asleep? next 0 if !user.battler.asleep?
score += 100 # Because it can only be used while asleep score += 100 # Because it can only be used while asleep
if ai.skill_check(Battle::AI::AILevel.high) score += 30 if !target.has_active_ability?(:INNERFOCUS) &&
score += 30 if !target.hasActiveAbility?(:INNERFOCUS) && target.effects[PBEffects::Substitute] == 0
target.effects[PBEffects::Substitute] == 0
end
next score next score
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("FlinchTargetFailsIfNotUserFirstTurn", Battle::AI::Handlers::MoveEffectScore.add("FlinchTargetFailsIfNotUserFirstTurn",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next 0 if user.turnCount != 0 next 0 if user.turnCount != 0
if ai.skill_check(Battle::AI::AILevel.high) score += 30 if !target.has_active_ability?(:INNERFOCUS) &&
score += 30 if !target.hasActiveAbility?(:INNERFOCUS) && target.effects[PBEffects::Substitute] == 0
target.effects[PBEffects::Substitute] == 0
end
next score next score
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("FlinchTargetDoublePowerIfTargetInSky", Battle::AI::Handlers::MoveEffectScore.add("FlinchTargetDoublePowerIfTargetInSky",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if ai.skill_check(Battle::AI::AILevel.high) score += 30 if !target.has_active_ability?(:INNERFOCUS) &&
score += 30 if !target.hasActiveAbility?(:INNERFOCUS) && target.effects[PBEffects::Substitute] == 0
target.effects[PBEffects::Substitute] == 0
end
next score next score
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("ConfuseTarget", Battle::AI::Handlers::MoveEffectScore.add("ConfuseTarget",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next 0 if !target.pbCanConfuse?(user, false) next 0 if !target.battler.pbCanConfuse?(user.battler, false)
next score + 30 next score + 30
} }
) )
@@ -336,7 +316,7 @@ Battle::AI::Handlers::MoveEffectScore.copy("ConfuseTarget",
"ConfuseTargetAlwaysHitsInRainHitsTargetInSky") "ConfuseTargetAlwaysHitsInRainHitsTargetInSky")
Battle::AI::Handlers::MoveEffectScore.add("AttractTarget", Battle::AI::Handlers::MoveEffectScore.add("AttractTarget",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
canattract = true canattract = true
agender = user.gender agender = user.gender
ogender = target.gender ogender = target.gender
@@ -346,25 +326,23 @@ Battle::AI::Handlers::MoveEffectScore.add("AttractTarget",
elsif target.effects[PBEffects::Attract] >= 0 elsif target.effects[PBEffects::Attract] >= 0
score -= 80 score -= 80
canattract = false canattract = false
elsif ai.skill_check(Battle::AI::AILevel.best) && target.hasActiveAbility?(:OBLIVIOUS) elsif target.has_active_ability?(:OBLIVIOUS)
score -= 80 score -= 80
canattract = false canattract = false
end end
if ai.skill_check(Battle::AI::AILevel.high) if canattract && target.has_active_item?(:DESTINYKNOT) &&
if canattract && target.hasActiveItem?(:DESTINYKNOT) && user.battler.pbCanAttract?(target.battler, false)
user.pbCanAttract?(target, false) score -= 30
score -= 30
end
end end
next score next score
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("SetUserTypesBasedOnEnvironment", Battle::AI::Handlers::MoveEffectScore.add("SetUserTypesBasedOnEnvironment",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if !user.canChangeType? if !user.battler.canChangeType?
score -= 90 score -= 90
elsif ai.skill_check(Battle::AI::AILevel.medium) elsif ai.trainer.medium_skill?
new_type = nil new_type = nil
case battle.field.terrain case battle.field.terrain
when :Electric when :Electric
@@ -402,28 +380,28 @@ Battle::AI::Handlers::MoveEffectScore.add("SetUserTypesBasedOnEnvironment",
new_type = nil if !GameData::Type.exists?(new_type) new_type = nil if !GameData::Type.exists?(new_type)
new_type ||= :NORMAL new_type ||= :NORMAL
end end
score -= 90 if !user.pbHasOtherType?(new_type) score -= 90 if !user.battler.pbHasOtherType?(new_type)
end end
next score next score
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("SetUserTypesToResistLastAttack", Battle::AI::Handlers::MoveEffectScore.add("SetUserTypesToResistLastAttack",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next 0 if !user.canChangeType? next 0 if !user.battler.canChangeType?
next 0 if !target.lastMoveUsed || !target.lastMoveUsedType || next 0 if !target.battler.lastMoveUsed || !target.battler.lastMoveUsedType ||
GameData::Type.get(target.lastMoveUsedType).pseudo_type GameData::Type.get(target.battler.lastMoveUsedType).pseudo_type
aType = nil aType = nil
target.eachMove do |m| target.battler.eachMove do |m|
next if m.id != target.lastMoveUsed next if m.id != target.battler.lastMoveUsed
aType = m.pbCalcType(user) aType = m.pbCalcType(user.battler)
break break
end end
next 0 if !aType next 0 if !aType
has_possible_type = false has_possible_type = false
GameData::Type.each do |t| GameData::Type.each do |t|
next if t.pseudo_type || user.pbHasType?(t.id) || next if t.pseudo_type || user.has_type?(t.id) ||
!Effectiveness.resistant_type?(target.lastMoveUsedType, t.id) !Effectiveness.resistant_type?(target.battler.lastMoveUsedType, t.id)
has_possible_type = true has_possible_type = true
break break
end end
@@ -432,21 +410,21 @@ Battle::AI::Handlers::MoveEffectScore.add("SetUserTypesToResistLastAttack",
) )
Battle::AI::Handlers::MoveEffectScore.add("SetUserTypesToTargetTypes", Battle::AI::Handlers::MoveEffectScore.add("SetUserTypesToTargetTypes",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next 0 if !user.canChangeType? || target.pbTypes(true).length == 0 next 0 if !user.battler.canChangeType? || target.battler.pbTypes(true).length == 0
next 0 if user.pbTypes == target.pbTypes && next 0 if user.battler.pbTypes == target.battler.pbTypes &&
user.effects[PBEffects::Type3] == target.effects[PBEffects::Type3] user.effects[PBEffects::Type3] == target.effects[PBEffects::Type3]
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("SetUserTypesToUserMoveType", Battle::AI::Handlers::MoveEffectScore.add("SetUserTypesToUserMoveType",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next 0 if !user.canChangeType? next 0 if !user.battler.canChangeType?
has_possible_type = false has_possible_type = false
user.eachMoveWithIndex do |m, i| user.battler.eachMoveWithIndex do |m, i|
break if Settings::MECHANICS_GENERATION >= 6 && i > 0 break if Settings::MECHANICS_GENERATION >= 6 && i > 0
next if GameData::Type.get(m.type).pseudo_type next if GameData::Type.get(m.type).pseudo_type
next if user.pbHasType?(m.type) next if user.has_type?(m.type)
has_possible_type = true has_possible_type = true
break break
end end
@@ -455,10 +433,10 @@ Battle::AI::Handlers::MoveEffectScore.add("SetUserTypesToUserMoveType",
) )
Battle::AI::Handlers::MoveEffectScore.add("SetTargetTypesToPsychic", Battle::AI::Handlers::MoveEffectScore.add("SetTargetTypesToPsychic",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if target.pbHasOtherType?(:PSYCHIC) if !target.battler.canChangeType?
score -= 90 score -= 90
elsif !target.canChangeType? elsif !target.battler.pbHasOtherType?(:PSYCHIC)
score -= 90 score -= 90
end end
next score next score
@@ -466,10 +444,10 @@ Battle::AI::Handlers::MoveEffectScore.add("SetTargetTypesToPsychic",
) )
Battle::AI::Handlers::MoveEffectScore.add("SetTargetTypesToWater", Battle::AI::Handlers::MoveEffectScore.add("SetTargetTypesToWater",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if target.effects[PBEffects::Substitute] > 0 || !target.canChangeType? if !target.battler.canChangeType? || target.effects[PBEffects::Substitute] > 0
score -= 90 score -= 90
elsif !target.pbHasOtherType?(:WATER) elsif !target.battler.pbHasOtherType?(:WATER)
score -= 90 score -= 90
end end
next score next score
@@ -477,47 +455,47 @@ Battle::AI::Handlers::MoveEffectScore.add("SetTargetTypesToWater",
) )
Battle::AI::Handlers::MoveEffectScore.add("AddGhostTypeToTarget", Battle::AI::Handlers::MoveEffectScore.add("AddGhostTypeToTarget",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next 0 if target.pbHasType?(:GHOST) next 0 if target.has_type?(:GHOST)
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("AddGrassTypeToTarget", Battle::AI::Handlers::MoveEffectScore.add("AddGrassTypeToTarget",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next 0 if target.pbHasType?(:GRASS) next 0 if target.has_type?(:GRASS)
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("UserLosesFireType", Battle::AI::Handlers::MoveEffectScore.add("UserLosesFireType",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next 0 if !user.pbHasType?(:FIRE) next 0 if !user.has_type?(:FIRE)
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("SetTargetAbilityToSimple", Battle::AI::Handlers::MoveEffectScore.add("SetTargetAbilityToSimple",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next 0 if target.effects[PBEffects::Substitute] > 0 next 0 if target.effects[PBEffects::Substitute] > 0
if ai.skill_check(Battle::AI::AILevel.medium) if ai.trainer.medium_skill?
next 0 if target.unstoppableAbility? || next 0 if target.battler.unstoppableAbility? ||
[:TRUANT, :SIMPLE].include?(target.ability) [:TRUANT, :SIMPLE].include?(target.ability)
end end
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("SetTargetAbilityToInsomnia", Battle::AI::Handlers::MoveEffectScore.add("SetTargetAbilityToInsomnia",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next 0 if target.effects[PBEffects::Substitute] > 0 next 0 if target.effects[PBEffects::Substitute] > 0
if ai.skill_check(Battle::AI::AILevel.medium) if ai.trainer.medium_skill?
next 0 if target.unstoppableAbility? || next 0 if target.battler.unstoppableAbility? ||
[:TRUANT, :INSOMNIA].include?(target.ability) [:TRUANT, :INSOMNIA].include?(target.ability)
end end
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("SetUserAbilityToTargetAbility", Battle::AI::Handlers::MoveEffectScore.add("SetUserAbilityToTargetAbility",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
score -= 40 # don't prefer this move score -= 40 # don't prefer this move
if ai.skill_check(Battle::AI::AILevel.medium) if ai.trainer.medium_skill?
if !target.ability || user.ability == target.ability || if !target.ability || user.ability == target.ability ||
[:MULTITYPE, :RKSSYSTEM].include?(user.ability_id) || [:MULTITYPE, :RKSSYSTEM].include?(user.ability_id) ||
[:FLOWERGIFT, :FORECAST, :ILLUSION, :IMPOSTER, :MULTITYPE, :RKSSYSTEM, [:FLOWERGIFT, :FORECAST, :ILLUSION, :IMPOSTER, :MULTITYPE, :RKSSYSTEM,
@@ -525,7 +503,7 @@ Battle::AI::Handlers::MoveEffectScore.add("SetUserAbilityToTargetAbility",
score -= 90 score -= 90
end end
end end
if ai.skill_check(Battle::AI::AILevel.high) if ai.trainer.high_skill?
if target.ability == :TRUANT && user.opposes?(target) if target.ability == :TRUANT && user.opposes?(target)
score -= 90 score -= 90
elsif target.ability == :SLOWSTART && user.opposes?(target) elsif target.ability == :SLOWSTART && user.opposes?(target)
@@ -537,18 +515,18 @@ Battle::AI::Handlers::MoveEffectScore.add("SetUserAbilityToTargetAbility",
) )
Battle::AI::Handlers::MoveEffectScore.add("SetTargetAbilityToUserAbility", Battle::AI::Handlers::MoveEffectScore.add("SetTargetAbilityToUserAbility",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
score -= 40 # don't prefer this move score -= 40 # don't prefer this move
if target.effects[PBEffects::Substitute] > 0 if target.effects[PBEffects::Substitute] > 0
score -= 90 score -= 90
elsif ai.skill_check(Battle::AI::AILevel.medium) elsif ai.trainer.medium_skill?
if !user.ability || user.ability == target.ability || if !user.ability || user.ability == target.ability ||
[:MULTITYPE, :RKSSYSTEM, :TRUANT].include?(target.ability_id) || [:MULTITYPE, :RKSSYSTEM, :TRUANT].include?(target.ability_id) ||
[:FLOWERGIFT, :FORECAST, :ILLUSION, :IMPOSTER, :MULTITYPE, :RKSSYSTEM, [:FLOWERGIFT, :FORECAST, :ILLUSION, :IMPOSTER, :MULTITYPE, :RKSSYSTEM,
:TRACE, :ZENMODE].include?(user.ability_id) :TRACE, :ZENMODE].include?(user.ability_id)
score -= 90 score -= 90
end end
if ai.skill_check(Battle::AI::AILevel.high) if ai.trainer.high_skill?
if user.ability == :TRUANT && user.opposes?(target) if user.ability == :TRUANT && user.opposes?(target)
score += 90 score += 90
elsif user.ability == :SLOWSTART && user.opposes?(target) elsif user.ability == :SLOWSTART && user.opposes?(target)
@@ -561,9 +539,9 @@ Battle::AI::Handlers::MoveEffectScore.add("SetTargetAbilityToUserAbility",
) )
Battle::AI::Handlers::MoveEffectScore.add("UserTargetSwapAbilities", Battle::AI::Handlers::MoveEffectScore.add("UserTargetSwapAbilities",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
score -= 40 # don't prefer this move score -= 40 # don't prefer this move
if ai.skill_check(Battle::AI::AILevel.medium) if ai.trainer.medium_skill?
if (!user.ability && !target.ability) || if (!user.ability && !target.ability) ||
user.ability == target.ability || user.ability == target.ability ||
[:ILLUSION, :MULTITYPE, :RKSSYSTEM, :WONDERGUARD].include?(user.ability_id) || [:ILLUSION, :MULTITYPE, :RKSSYSTEM, :WONDERGUARD].include?(user.ability_id) ||
@@ -571,7 +549,7 @@ Battle::AI::Handlers::MoveEffectScore.add("UserTargetSwapAbilities",
score -= 90 score -= 90
end end
end end
if ai.skill_check(Battle::AI::AILevel.high) if ai.trainer.high_skill?
if target.ability == :TRUANT && user.opposes?(target) if target.ability == :TRUANT && user.opposes?(target)
score -= 90 score -= 90
elsif target.ability == :SLOWSTART && user.opposes?(target) elsif target.ability == :SLOWSTART && user.opposes?(target)
@@ -583,11 +561,11 @@ Battle::AI::Handlers::MoveEffectScore.add("UserTargetSwapAbilities",
) )
Battle::AI::Handlers::MoveEffectScore.add("NegateTargetAbility", Battle::AI::Handlers::MoveEffectScore.add("NegateTargetAbility",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if target.effects[PBEffects::Substitute] > 0 || if target.effects[PBEffects::Substitute] > 0 ||
target.effects[PBEffects::GastroAcid] target.effects[PBEffects::GastroAcid]
score -= 90 score -= 90
elsif ai.skill_check(Battle::AI::AILevel.high) elsif ai.trainer.high_skill?
score -= 90 if [:MULTITYPE, :RKSSYSTEM, :SLOWSTART, :TRUANT].include?(target.ability_id) score -= 90 if [:MULTITYPE, :RKSSYSTEM, :SLOWSTART, :TRUANT].include?(target.ability_id)
end end
next score next score
@@ -595,13 +573,9 @@ Battle::AI::Handlers::MoveEffectScore.add("NegateTargetAbility",
) )
Battle::AI::Handlers::MoveEffectScore.add("NegateTargetAbilityIfTargetActed", Battle::AI::Handlers::MoveEffectScore.add("NegateTargetAbilityIfTargetActed",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if ai.skill_check(Battle::AI::AILevel.medium) if ai.trainer.medium_skill?
userSpeed = pbRoughStat(user, :SPEED) score += 30 if target.faster_than?(user)
targetSpeed = pbRoughStat(target, :SPEED)
if userSpeed < targetSpeed
score += 30
end
else else
score += 30 score += 30
end end
@@ -612,7 +586,7 @@ Battle::AI::Handlers::MoveEffectScore.add("NegateTargetAbilityIfTargetActed",
# IgnoreTargetAbility # IgnoreTargetAbility
Battle::AI::Handlers::MoveEffectScore.add("StartUserAirborne", Battle::AI::Handlers::MoveEffectScore.add("StartUserAirborne",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if user.effects[PBEffects::MagnetRise] > 0 || if user.effects[PBEffects::MagnetRise] > 0 ||
user.effects[PBEffects::Ingrain] || user.effects[PBEffects::Ingrain] ||
user.effects[PBEffects::SmackDown] user.effects[PBEffects::SmackDown]
@@ -623,7 +597,7 @@ Battle::AI::Handlers::MoveEffectScore.add("StartUserAirborne",
) )
Battle::AI::Handlers::MoveEffectScore.add("StartTargetAirborneAndAlwaysHitByMoves", Battle::AI::Handlers::MoveEffectScore.add("StartTargetAirborneAndAlwaysHitByMoves",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if target.effects[PBEffects::Telekinesis] > 0 || if target.effects[PBEffects::Telekinesis] > 0 ||
target.effects[PBEffects::Ingrain] || target.effects[PBEffects::Ingrain] ||
target.effects[PBEffects::SmackDown] target.effects[PBEffects::SmackDown]
@@ -636,48 +610,48 @@ Battle::AI::Handlers::MoveEffectScore.add("StartTargetAirborneAndAlwaysHitByMove
# HitsTargetInSky # HitsTargetInSky
Battle::AI::Handlers::MoveEffectScore.add("HitsTargetInSkyGroundsTarget", Battle::AI::Handlers::MoveEffectScore.add("HitsTargetInSkyGroundsTarget",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if ai.skill_check(Battle::AI::AILevel.medium) if ai.trainer.medium_skill?
score += 20 if target.effects[PBEffects::MagnetRise] > 0 score += 20 if target.effects[PBEffects::MagnetRise] > 0
score += 20 if target.effects[PBEffects::Telekinesis] > 0 score += 20 if target.effects[PBEffects::Telekinesis] > 0
score += 20 if target.inTwoTurnAttack?("TwoTurnAttackInvulnerableInSky", score += 20 if target.battler.inTwoTurnAttack?("TwoTurnAttackInvulnerableInSky",
"TwoTurnAttackInvulnerableInSkyParalyzeTarget") "TwoTurnAttackInvulnerableInSkyParalyzeTarget")
score += 20 if target.pbHasType?(:FLYING) score += 20 if target.has_type?(:FLYING)
score += 20 if target.hasActiveAbility?(:LEVITATE) score += 20 if target.has_active_ability?(:LEVITATE)
score += 20 if target.hasActiveItem?(:AIRBALLOON) score += 20 if target.has_active_item?(:AIRBALLOON)
end end
next score next score
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("StartGravity", Battle::AI::Handlers::MoveEffectScore.add("StartGravity",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if battle.field.effects[PBEffects::Gravity] > 0 if battle.field.effects[PBEffects::Gravity] > 0
score -= 90 score -= 90
elsif ai.skill_check(Battle::AI::AILevel.medium) elsif ai.trainer.medium_skill?
score -= 30 score -= 30
score -= 20 if user.effects[PBEffects::SkyDrop] >= 0 score -= 20 if user.effects[PBEffects::SkyDrop] >= 0
score -= 20 if user.effects[PBEffects::MagnetRise] > 0 score -= 20 if user.effects[PBEffects::MagnetRise] > 0
score -= 20 if user.effects[PBEffects::Telekinesis] > 0 score -= 20 if user.effects[PBEffects::Telekinesis] > 0
score -= 20 if user.pbHasType?(:FLYING) score -= 20 if user.has_type?(:FLYING)
score -= 20 if user.hasActiveAbility?(:LEVITATE) score -= 20 if user.has_active_ability?(:LEVITATE)
score -= 20 if user.hasActiveItem?(:AIRBALLOON) score -= 20 if user.has_active_item?(:AIRBALLOON)
score += 20 if target.effects[PBEffects::SkyDrop] >= 0 score += 20 if target.effects[PBEffects::SkyDrop] >= 0
score += 20 if target.effects[PBEffects::MagnetRise] > 0 score += 20 if target.effects[PBEffects::MagnetRise] > 0
score += 20 if target.effects[PBEffects::Telekinesis] > 0 score += 20 if target.effects[PBEffects::Telekinesis] > 0
score += 20 if target.inTwoTurnAttack?("TwoTurnAttackInvulnerableInSky", score += 20 if target.battler.inTwoTurnAttack?("TwoTurnAttackInvulnerableInSky",
"TwoTurnAttackInvulnerableInSkyParalyzeTarget", "TwoTurnAttackInvulnerableInSkyParalyzeTarget",
"TwoTurnAttackInvulnerableInSkyTargetCannotAct") "TwoTurnAttackInvulnerableInSkyTargetCannotAct")
score += 20 if target.pbHasType?(:FLYING) score += 20 if target.has_type?(:FLYING)
score += 20 if target.hasActiveAbility?(:LEVITATE) score += 20 if target.has_active_ability?(:LEVITATE)
score += 20 if target.hasActiveItem?(:AIRBALLOON) score += 20 if target.has_active_item?(:AIRBALLOON)
end end
next score next score
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("TransformUserIntoTarget", Battle::AI::Handlers::MoveEffectScore.add("TransformUserIntoTarget",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next score - 70 next score - 70
} }
) )

View File

@@ -2,7 +2,7 @@
# #
#=============================================================================== #===============================================================================
Battle::AI::Handlers::MoveEffectScore.add("FixedDamage20", Battle::AI::Handlers::MoveEffectScore.add("FixedDamage20",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if target.hp <= 20 if target.hp <= 20
score += 80 score += 80
elsif target.level >= 25 elsif target.level >= 25
@@ -13,32 +13,32 @@ Battle::AI::Handlers::MoveEffectScore.add("FixedDamage20",
) )
Battle::AI::Handlers::MoveEffectScore.add("FixedDamage40", Battle::AI::Handlers::MoveEffectScore.add("FixedDamage40",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next score + 80 if target.hp <= 40 next score + 80 if target.hp <= 40
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("FixedDamageHalfTargetHP", Battle::AI::Handlers::MoveEffectScore.add("FixedDamageHalfTargetHP",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
score -= 50 score -= 50
next score + target.hp * 100 / target.totalhp next score + target.hp * 100 / target.totalhp
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("FixedDamageUserLevel", Battle::AI::Handlers::MoveEffectScore.add("FixedDamageUserLevel",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next score + 80 if target.hp <= user.level next score + 80 if target.hp <= user.level
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("FixedDamageUserLevelRandom", Battle::AI::Handlers::MoveEffectScore.add("FixedDamageUserLevelRandom",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next score + 30 if target.hp <= user.level next score + 30 if target.hp <= user.level
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("LowerTargetHPToUserHP", Battle::AI::Handlers::MoveEffectScore.add("LowerTargetHPToUserHP",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if user.hp >= target.hp if user.hp >= target.hp
score -= 90 score -= 90
elsif user.hp < target.hp / 2 elsif user.hp < target.hp / 2
@@ -49,8 +49,8 @@ Battle::AI::Handlers::MoveEffectScore.add("LowerTargetHPToUserHP",
) )
Battle::AI::Handlers::MoveEffectScore.add("OHKO", Battle::AI::Handlers::MoveEffectScore.add("OHKO",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next 0 if target.hasActiveAbility?(:STURDY) next 0 if target.has_active_ability?(:STURDY)
next 0 if target.level > user.level next 0 if target.level > user.level
} }
) )
@@ -60,9 +60,9 @@ Battle::AI::Handlers::MoveEffectScore.copy("OHKO",
"OHKOHitsUndergroundTarget") "OHKOHitsUndergroundTarget")
Battle::AI::Handlers::MoveEffectScore.add("DamageTargetAlly", Battle::AI::Handlers::MoveEffectScore.add("DamageTargetAlly",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
target.allAllies.each do |b| target.battler.allAllies.each do |b|
next if !b.near?(target) next if !b.near?(target.battler)
score += 10 score += 10
end end
next score next score
@@ -104,7 +104,7 @@ Battle::AI::Handlers::MoveEffectScore.add("DamageTargetAlly",
# DoublePowerIfUserPoisonedBurnedParalyzed # DoublePowerIfUserPoisonedBurnedParalyzed
Battle::AI::Handlers::MoveEffectScore.add("DoublePowerIfTargetAsleepCureTarget", Battle::AI::Handlers::MoveEffectScore.add("DoublePowerIfTargetAsleepCureTarget",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next score - 20 if target.status == :SLEEP && # Will cure status next score - 20 if target.status == :SLEEP && # Will cure status
target.statusCount > 1 target.statusCount > 1
} }
@@ -113,7 +113,7 @@ Battle::AI::Handlers::MoveEffectScore.add("DoublePowerIfTargetAsleepCureTarget",
# DoublePowerIfTargetPoisoned # DoublePowerIfTargetPoisoned
Battle::AI::Handlers::MoveEffectScore.add("DoublePowerIfTargetParalyzedCureTarget", Battle::AI::Handlers::MoveEffectScore.add("DoublePowerIfTargetParalyzedCureTarget",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next score - 20 if target.status == :PARALYSIS # Will cure status next score - 20 if target.status == :PARALYSIS # Will cure status
} }
) )
@@ -129,8 +129,8 @@ Battle::AI::Handlers::MoveEffectScore.add("DoublePowerIfTargetParalyzedCureTarge
# DoublePowerIfTargetInSky # DoublePowerIfTargetInSky
Battle::AI::Handlers::MoveEffectScore.add("DoublePowerInElectricTerrain", Battle::AI::Handlers::MoveEffectScore.add("DoublePowerInElectricTerrain",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next score + 40 if battle.field.terrain == :Electric && target.affectedByTerrain? next score + 40 if battle.field.terrain == :Electric && target.battler.affectedByTerrain?
} }
) )
@@ -139,26 +139,22 @@ Battle::AI::Handlers::MoveEffectScore.add("DoublePowerInElectricTerrain",
# DoublePowerIfAllyFaintedLastTurn # DoublePowerIfAllyFaintedLastTurn
Battle::AI::Handlers::MoveEffectScore.add("DoublePowerIfUserLostHPThisTurn", Battle::AI::Handlers::MoveEffectScore.add("DoublePowerIfUserLostHPThisTurn",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
attspeed = pbRoughStat(user, :SPEED) next score + 30 if target.faster_than?(user)
oppspeed = pbRoughStat(target, :SPEED)
next score + 30 if oppspeed > attspeed
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("DoublePowerIfTargetLostHPThisTurn", Battle::AI::Handlers::MoveEffectScore.add("DoublePowerIfTargetLostHPThisTurn",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next score + 20 if battle.pbOpposingBattlerCount(user) > 1 next score + 20 if battle.pbOpposingBattlerCount(user.battler) > 1
} }
) )
# DoublePowerIfUserStatsLoweredThisTurn # DoublePowerIfUserStatsLoweredThisTurn
Battle::AI::Handlers::MoveEffectScore.add("DoublePowerIfTargetActed", Battle::AI::Handlers::MoveEffectScore.add("DoublePowerIfTargetActed",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
attspeed = pbRoughStat(user, :SPEED) next score + 30 if target.faster_than?(user)
oppspeed = pbRoughStat(target, :SPEED)
next score + 30 if oppspeed > attspeed
} }
) )
@@ -167,7 +163,7 @@ Battle::AI::Handlers::MoveEffectScore.add("DoublePowerIfTargetActed",
# AlwaysCriticalHit # AlwaysCriticalHit
Battle::AI::Handlers::MoveEffectScore.add("EnsureNextCriticalHit", Battle::AI::Handlers::MoveEffectScore.add("EnsureNextCriticalHit",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if user.effects[PBEffects::LaserFocus] > 0 if user.effects[PBEffects::LaserFocus] > 0
score -= 90 score -= 90
else else
@@ -178,13 +174,13 @@ Battle::AI::Handlers::MoveEffectScore.add("EnsureNextCriticalHit",
) )
Battle::AI::Handlers::MoveEffectScore.add("EnsureNextCriticalHit", Battle::AI::Handlers::MoveEffectScore.add("EnsureNextCriticalHit",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next 0 if user.pbOwnSide.effects[PBEffects::LuckyChant] > 0 next 0 if user.pbOwnSide.effects[PBEffects::LuckyChant] > 0
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("CannotMakeTargetFaint", Battle::AI::Handlers::MoveEffectScore.add("CannotMakeTargetFaint",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next 0 if target.hp == 1 next 0 if target.hp == 1
if target.hp <= target.totalhp / 8 if target.hp <= target.totalhp / 8
score -= 60 score -= 60
@@ -196,9 +192,9 @@ Battle::AI::Handlers::MoveEffectScore.add("CannotMakeTargetFaint",
) )
Battle::AI::Handlers::MoveEffectScore.add("UserEnduresFaintingThisTurn", Battle::AI::Handlers::MoveEffectScore.add("UserEnduresFaintingThisTurn",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
score -= 25 if user.hp > user.totalhp / 2 score -= 25 if user.hp > user.totalhp / 2
if ai.skill_check(Battle::AI::AILevel.medium) if ai.trainer.medium_skill?
score -= 90 if user.effects[PBEffects::ProtectRate] > 1 score -= 90 if user.effects[PBEffects::ProtectRate] > 1
score -= 90 if target.effects[PBEffects::HyperBeam] > 0 score -= 90 if target.effects[PBEffects::HyperBeam] > 0
else else
@@ -209,38 +205,39 @@ Battle::AI::Handlers::MoveEffectScore.add("UserEnduresFaintingThisTurn",
) )
Battle::AI::Handlers::MoveEffectScore.add("StartWeakenElectricMoves", Battle::AI::Handlers::MoveEffectScore.add("StartWeakenElectricMoves",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next 0 if user.effects[PBEffects::MudSport] next 0 if user.effects[PBEffects::MudSport]
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("StartWeakenFireMoves", Battle::AI::Handlers::MoveEffectScore.add("StartWeakenFireMoves",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next 0 if user.effects[PBEffects::WaterSport] next 0 if user.effects[PBEffects::WaterSport]
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("StartWeakenPhysicalDamageAgainstUserSide", Battle::AI::Handlers::MoveEffectScore.add("StartWeakenPhysicalDamageAgainstUserSide",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next 0 if user.pbOwnSide.effects[PBEffects::Reflect] > 0 next 0 if user.pbOwnSide.effects[PBEffects::Reflect] > 0
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("StartWeakenSpecialDamageAgainstUserSide", Battle::AI::Handlers::MoveEffectScore.add("StartWeakenSpecialDamageAgainstUserSide",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next 0 if user.pbOwnSide.effects[PBEffects::LightScreen] > 0 next 0 if user.pbOwnSide.effects[PBEffects::LightScreen] > 0
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("StartWeakenDamageAgainstUserSideIfHail", Battle::AI::Handlers::MoveEffectScore.add("StartWeakenDamageAgainstUserSideIfHail",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next 0 if user.pbOwnSide.effects[PBEffects::AuroraVeil] > 0 || user.effectiveWeather != :Hail next 0 if user.pbOwnSide.effects[PBEffects::AuroraVeil] > 0 ||
user.battler.effectiveWeather != :Hail
next score + 40 next score + 40
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("RemoveScreens", Battle::AI::Handlers::MoveEffectScore.add("RemoveScreens",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
score += 20 if user.pbOpposingSide.effects[PBEffects::AuroraVeil] > 0 score += 20 if user.pbOpposingSide.effects[PBEffects::AuroraVeil] > 0
score += 20 if user.pbOpposingSide.effects[PBEffects::Reflect] > 0 score += 20 if user.pbOpposingSide.effects[PBEffects::Reflect] > 0
score += 20 if user.pbOpposingSide.effects[PBEffects::LightScreen] > 0 score += 20 if user.pbOpposingSide.effects[PBEffects::LightScreen] > 0
@@ -249,12 +246,12 @@ Battle::AI::Handlers::MoveEffectScore.add("RemoveScreens",
) )
Battle::AI::Handlers::MoveEffectScore.add("ProtectUser", Battle::AI::Handlers::MoveEffectScore.add("ProtectUser",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if user.effects[PBEffects::ProtectRate] > 1 || if user.effects[PBEffects::ProtectRate] > 1 ||
target.effects[PBEffects::HyperBeam] > 0 target.effects[PBEffects::HyperBeam] > 0
score -= 90 score -= 90
else else
if ai.skill_check(Battle::AI::AILevel.medium) if ai.trainer.medium_skill?
score -= user.effects[PBEffects::ProtectRate] * 40 score -= user.effects[PBEffects::ProtectRate] * 40
end end
score += 50 if user.turnCount == 0 score += 50 if user.turnCount == 0
@@ -265,12 +262,12 @@ Battle::AI::Handlers::MoveEffectScore.add("ProtectUser",
) )
Battle::AI::Handlers::MoveEffectScore.add("ProtectUserBanefulBunker", Battle::AI::Handlers::MoveEffectScore.add("ProtectUserBanefulBunker",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if user.effects[PBEffects::ProtectRate] > 1 || if user.effects[PBEffects::ProtectRate] > 1 ||
target.effects[PBEffects::HyperBeam] > 0 target.effects[PBEffects::HyperBeam] > 0
score -= 90 score -= 90
else else
if ai.skill_check(Battle::AI::AILevel.medium) if ai.trainer.medium_skill?
score -= user.effects[PBEffects::ProtectRate] * 40 score -= user.effects[PBEffects::ProtectRate] * 40
end end
score += 50 if user.turnCount == 0 score += 50 if user.turnCount == 0
@@ -282,12 +279,12 @@ Battle::AI::Handlers::MoveEffectScore.add("ProtectUserBanefulBunker",
) )
Battle::AI::Handlers::MoveEffectScore.add("ProtectUserFromDamagingMovesKingsShield", Battle::AI::Handlers::MoveEffectScore.add("ProtectUserFromDamagingMovesKingsShield",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if user.effects[PBEffects::ProtectRate] > 1 || if user.effects[PBEffects::ProtectRate] > 1 ||
target.effects[PBEffects::HyperBeam] > 0 target.effects[PBEffects::HyperBeam] > 0
score -= 90 score -= 90
else else
if ai.skill_check(Battle::AI::AILevel.medium) if ai.trainer.medium_skill?
score -= user.effects[PBEffects::ProtectRate] * 40 score -= user.effects[PBEffects::ProtectRate] * 40
end end
score += 50 if user.turnCount == 0 score += 50 if user.turnCount == 0
@@ -298,12 +295,12 @@ Battle::AI::Handlers::MoveEffectScore.add("ProtectUserFromDamagingMovesKingsShie
) )
Battle::AI::Handlers::MoveEffectScore.add("ProtectUserFromDamagingMovesObstruct", Battle::AI::Handlers::MoveEffectScore.add("ProtectUserFromDamagingMovesObstruct",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if user.effects[PBEffects::ProtectRate] > 1 || if user.effects[PBEffects::ProtectRate] > 1 ||
target.effects[PBEffects::HyperBeam] > 0 target.effects[PBEffects::HyperBeam] > 0
score -= 90 score -= 90
else else
if ai.skill_check(Battle::AI::AILevel.medium) if ai.trainer.medium_skill?
score -= user.effects[PBEffects::ProtectRate] * 40 score -= user.effects[PBEffects::ProtectRate] * 40
end end
score += 50 if user.turnCount == 0 score += 50 if user.turnCount == 0
@@ -314,12 +311,12 @@ Battle::AI::Handlers::MoveEffectScore.add("ProtectUserFromDamagingMovesObstruct"
) )
Battle::AI::Handlers::MoveEffectScore.add("ProtectUserFromTargetingMovesSpikyShield", Battle::AI::Handlers::MoveEffectScore.add("ProtectUserFromTargetingMovesSpikyShield",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if user.effects[PBEffects::ProtectRate] > 1 || if user.effects[PBEffects::ProtectRate] > 1 ||
target.effects[PBEffects::HyperBeam] > 0 target.effects[PBEffects::HyperBeam] > 0
score -= 90 score -= 90
else else
if ai.skill_check(Battle::AI::AILevel.medium) if ai.trainer.medium_skill?
score -= user.effects[PBEffects::ProtectRate] * 40 score -= user.effects[PBEffects::ProtectRate] * 40
end end
score += 50 if user.turnCount == 0 score += 50 if user.turnCount == 0
@@ -330,7 +327,7 @@ Battle::AI::Handlers::MoveEffectScore.add("ProtectUserFromTargetingMovesSpikyShi
) )
Battle::AI::Handlers::MoveEffectScore.add("ProtectUserSideFromDamagingMovesIfUserFirstTurn", Battle::AI::Handlers::MoveEffectScore.add("ProtectUserSideFromDamagingMovesIfUserFirstTurn",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next 0 if user.turnCount != 0 next 0 if user.turnCount != 0
next score + 30 next score + 30
} }
@@ -347,55 +344,51 @@ Battle::AI::Handlers::MoveEffectScore.add("ProtectUserSideFromDamagingMovesIfUse
# RemoveProtectionsBypassSubstitute # RemoveProtectionsBypassSubstitute
Battle::AI::Handlers::MoveEffectScore.add("HoopaRemoveProtectionsBypassSubstituteLowerUserDef1", Battle::AI::Handlers::MoveEffectScore.add("HoopaRemoveProtectionsBypassSubstituteLowerUserDef1",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next 0 if !user.isSpecies?(:HOOPA) || user.form != 1 next 0 if !user.battler.isSpecies?(:HOOPA) || user.battler.form != 1
next score + 20 if target.stages[:DEFENSE] > 0 next score + 20 if target.stages[:DEFENSE] > 0
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("RecoilQuarterOfDamageDealt", Battle::AI::Handlers::MoveEffectScore.add("RecoilQuarterOfDamageDealt",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next score - 25 next score - 25
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("RecoilThirdOfDamageDealtParalyzeTarget", Battle::AI::Handlers::MoveEffectScore.add("RecoilThirdOfDamageDealtParalyzeTarget",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
score -= 30 score -= 30
if target.pbCanParalyze?(user, false) if target.battler.pbCanParalyze?(user.battler, false)
score += 30 score += 30
if ai.skill_check(Battle::AI::AILevel.medium) if ai.trainer.medium_skill?
aspeed = pbRoughStat(user, :SPEED) aspeed = user.rough_stat(:SPEED)
ospeed = pbRoughStat(target, :SPEED) ospeed = target.rough_stat(:SPEED)
if aspeed < ospeed if aspeed < ospeed
score += 30 score += 30
elsif aspeed > ospeed elsif aspeed > ospeed
score -= 40 score -= 40
end end
end end
if ai.skill_check(Battle::AI::AILevel.high) score -= 40 if target.has_active_ability?([:GUTS, :MARVELSCALE, :QUICKFEET])
score -= 40 if target.hasActiveAbility?([:GUTS, :MARVELSCALE, :QUICKFEET])
end
end end
next score next score
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("RecoilThirdOfDamageDealtBurnTarget", Battle::AI::Handlers::MoveEffectScore.add("RecoilThirdOfDamageDealtBurnTarget",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
score -= 30 score -= 30
if target.pbCanBurn?(user, false) if target.battler.pbCanBurn?(user.battler, false)
score += 30 score += 30
if ai.skill_check(Battle::AI::AILevel.high) score -= 40 if target.has_active_ability?([:GUTS, :MARVELSCALE, :QUICKFEET, :FLAREBOOST])
score -= 40 if target.hasActiveAbility?([:GUTS, :MARVELSCALE, :QUICKFEET, :FLAREBOOST])
end
end end
next score next score
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("RecoilHalfOfDamageDealt", Battle::AI::Handlers::MoveEffectScore.add("RecoilHalfOfDamageDealt",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next score - 40 next score - 40
} }
) )
@@ -403,8 +396,8 @@ Battle::AI::Handlers::MoveEffectScore.add("RecoilHalfOfDamageDealt",
# EffectivenessIncludesFlyingType # EffectivenessIncludesFlyingType
Battle::AI::Handlers::MoveEffectScore.add("CategoryDependsOnHigherDamagePoisonTarget", Battle::AI::Handlers::MoveEffectScore.add("CategoryDependsOnHigherDamagePoisonTarget",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next score + 5 if target.pbCanPoison?(user, false) next score + 5 if target.battler.pbCanPoison?(user.battler, false)
} }
) )
@@ -417,17 +410,17 @@ Battle::AI::Handlers::MoveEffectScore.add("CategoryDependsOnHigherDamagePoisonTa
# UseTargetDefenseInsteadOfTargetSpDef # UseTargetDefenseInsteadOfTargetSpDef
Battle::AI::Handlers::MoveEffectScore.add("EnsureNextMoveAlwaysHits", Battle::AI::Handlers::MoveEffectScore.add("EnsureNextMoveAlwaysHits",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next 0 if target.effects[PBEffects::Substitute] > 0 next 0 if target.effects[PBEffects::Substitute] > 0
next 0 if user.effects[PBEffects::LockOn] > 0 next 0 if user.effects[PBEffects::LockOn] > 0
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("StartNegateTargetEvasionStatStageAndGhostImmunity", Battle::AI::Handlers::MoveEffectScore.add("StartNegateTargetEvasionStatStageAndGhostImmunity",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if target.effects[PBEffects::Foresight] if target.effects[PBEffects::Foresight]
score -= 90 score -= 90
elsif target.pbHasType?(:GHOST) elsif target.has_type?(:GHOST)
score += 70 score += 70
elsif target.stages[:EVASION] <= 0 elsif target.stages[:EVASION] <= 0
score -= 60 score -= 60
@@ -437,10 +430,10 @@ Battle::AI::Handlers::MoveEffectScore.add("StartNegateTargetEvasionStatStageAndG
) )
Battle::AI::Handlers::MoveEffectScore.add("StartNegateTargetEvasionStatStageAndDarkImmunity", Battle::AI::Handlers::MoveEffectScore.add("StartNegateTargetEvasionStatStageAndDarkImmunity",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if target.effects[PBEffects::MiracleEye] if target.effects[PBEffects::MiracleEye]
score -= 90 score -= 90
elsif target.pbHasType?(:DARK) elsif target.has_type?(:DARK)
score += 70 score += 70
elsif target.stages[:EVASION] <= 0 elsif target.stages[:EVASION] <= 0
score -= 60 score -= 60
@@ -456,8 +449,8 @@ Battle::AI::Handlers::MoveEffectScore.add("StartNegateTargetEvasionStatStageAndD
# TypeDependsOnUserIVs # TypeDependsOnUserIVs
Battle::AI::Handlers::MoveEffectScore.add("TypeAndPowerDependOnUserBerry", Battle::AI::Handlers::MoveEffectScore.add("TypeAndPowerDependOnUserBerry",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next 0 if !user.item || !user.item.is_berry? || !user.itemActive? next 0 if !user.item || !user.item.is_berry? || !user.item_active?
} }
) )
@@ -468,7 +461,7 @@ Battle::AI::Handlers::MoveEffectScore.add("TypeAndPowerDependOnUserBerry",
# TypeDependsOnUserDrive # TypeDependsOnUserDrive
Battle::AI::Handlers::MoveEffectScore.add("TypeDependsOnUserMorpekoFormRaiseUserSpeed1", Battle::AI::Handlers::MoveEffectScore.add("TypeDependsOnUserMorpekoFormRaiseUserSpeed1",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next score + 20 if user.stages[:SPEED] <= 0 next score + 20 if user.stages[:SPEED] <= 0
} }
) )
@@ -476,16 +469,14 @@ Battle::AI::Handlers::MoveEffectScore.add("TypeDependsOnUserMorpekoFormRaiseUser
# TypeAndPowerDependOnWeather # TypeAndPowerDependOnWeather
Battle::AI::Handlers::MoveEffectScore.add("TypeAndPowerDependOnTerrain", Battle::AI::Handlers::MoveEffectScore.add("TypeAndPowerDependOnTerrain",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next score + 40 if battle.field.terrain != :None next score + 40 if battle.field.terrain != :None
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("TargetMovesBecomeElectric", Battle::AI::Handlers::MoveEffectScore.add("TargetMovesBecomeElectric",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
aspeed = pbRoughStat(user, :SPEED) next 0 if user.faster_than?(target)
ospeed = pbRoughStat(target, :SPEED)
next 0 if aspeed > ospeed
} }
) )

View File

@@ -5,25 +5,25 @@
# HitTwoTimes # HitTwoTimes
Battle::AI::Handlers::MoveEffectScore.add("HitTwoTimesPoisonTarget", Battle::AI::Handlers::MoveEffectScore.add("HitTwoTimesPoisonTarget",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next 0 if !target.pbCanPoison?(user, false) next 0 if !target.battler.pbCanPoison?(user.battler, false)
score += 30 score += 30
if ai.skill_check(Battle::AI::AILevel.medium) if ai.trainer.medium_skill?
score += 30 if target.hp <= target.totalhp / 4 score += 30 if target.hp <= target.totalhp / 4
score += 50 if target.hp <= target.totalhp / 8 score += 50 if target.hp <= target.totalhp / 8
score -= 40 if target.effects[PBEffects::Yawn] > 0 score -= 40 if target.effects[PBEffects::Yawn] > 0
end end
if ai.skill_check(Battle::AI::AILevel.high) if ai.trainer.high_skill?
score += 10 if pbRoughStat(target, :DEFENSE) > 100 score += 10 if target.rough_stat(:DEFENSE) > 100
score += 10 if pbRoughStat(target, :SPECIAL_DEFENSE) > 100 score += 10 if target.rough_stat(:SPECIAL_DEFENSE) > 100
score -= 40 if target.hasActiveAbility?([:GUTS, :MARVELSCALE, :TOXICBOOST])
end end
score -= 40 if target.has_active_ability?([:GUTS, :MARVELSCALE, :TOXICBOOST])
next score next score
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("HitTwoTimesFlinchTarget", Battle::AI::Handlers::MoveEffectScore.add("HitTwoTimesFlinchTarget",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next score + 30 if target.effects[PBEffects::Minimize] next score + 30 if target.effects[PBEffects::Minimize]
} }
) )
@@ -33,10 +33,10 @@ Battle::AI::Handlers::MoveEffectScore.add("HitTwoTimesFlinchTarget",
# HitThreeTimesPowersUpWithEachHit # HitThreeTimesPowersUpWithEachHit
Battle::AI::Handlers::MoveEffectScore.add("HitThreeTimesAlwaysCriticalHit", Battle::AI::Handlers::MoveEffectScore.add("HitThreeTimesAlwaysCriticalHit",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if ai.skill_check(Battle::AI::AILevel.high) if ai.trainer.high_skill?
stat = (move.physicalMove?) ? :DEFENSE : :SPECIAL_DEFENSE stat = (move.physicalMove?) ? :DEFENSE : :SPECIAL_DEFENSE
next score + 50 if targets.stages[stat] > 1 next score + 50 if target.stages[stat] > 1
end end
} }
) )
@@ -46,9 +46,9 @@ Battle::AI::Handlers::MoveEffectScore.add("HitThreeTimesAlwaysCriticalHit",
# HitTwoToFiveTimesOrThreeForAshGreninja # HitTwoToFiveTimesOrThreeForAshGreninja
Battle::AI::Handlers::MoveEffectScore.add("HitTwoToFiveTimesRaiseUserSpd1LowerUserDef1", Battle::AI::Handlers::MoveEffectScore.add("HitTwoToFiveTimesRaiseUserSpd1LowerUserDef1",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
aspeed = pbRoughStat(user, :SPEED) aspeed = user.rough_stat(:SPEED)
ospeed = pbRoughStat(target, :SPEED) ospeed = target.rough_stat(:SPEED)
if aspeed > ospeed && aspeed * 2 / 3 < ospeed if aspeed > ospeed && aspeed * 2 / 3 < ospeed
score -= 50 score -= 50
elsif aspeed < ospeed && aspeed * 1.5 > ospeed elsif aspeed < ospeed && aspeed * 1.5 > ospeed
@@ -68,25 +68,20 @@ Battle::AI::Handlers::MoveEffectScore.add("HitTwoToFiveTimesRaiseUserSpd1LowerUs
# TwoTurnAttackOneTurnInSun # TwoTurnAttackOneTurnInSun
Battle::AI::Handlers::MoveEffectScore.add("TwoTurnAttackParalyzeTarget", Battle::AI::Handlers::MoveEffectScore.add("TwoTurnAttackParalyzeTarget",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if target.pbCanParalyze?(user, false) && if target.battler.pbCanParalyze?(user.battler, false)
!(ai.skill_check(Battle::AI::AILevel.medium) &&
move.id == :THUNDERWAVE &&
Effectiveness.ineffective?(pbCalcTypeMod(move.type, user, target)))
score += 30 score += 30
if ai.skill_check(Battle::AI::AILevel.medium) if ai.trainer.medium_skill?
aspeed = pbRoughStat(user, :SPEED) aspeed = user.rough_stat(:SPEED)
ospeed = pbRoughStat(target, :SPEED) ospeed = target.rough_stat(:SPEED)
if aspeed < ospeed if aspeed < ospeed
score += 30 score += 30
elsif aspeed > ospeed elsif aspeed > ospeed
score -= 40 score -= 40
end end
end end
if ai.skill_check(Battle::AI::AILevel.high) score -= 40 if target.has_active_ability?([:GUTS, :MARVELSCALE, :QUICKFEET])
score -= 40 if target.hasActiveAbility?([:GUTS, :MARVELSCALE, :QUICKFEET]) elsif ai.trainer.medium_skill?
end
elsif ai.skill_check(Battle::AI::AILevel.medium)
score -= 90 if move.statusMove? score -= 90 if move.statusMove?
end end
next score next score
@@ -94,29 +89,25 @@ Battle::AI::Handlers::MoveEffectScore.add("TwoTurnAttackParalyzeTarget",
) )
Battle::AI::Handlers::MoveEffectScore.add("TwoTurnAttackBurnTarget", Battle::AI::Handlers::MoveEffectScore.add("TwoTurnAttackBurnTarget",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next 0 if !target.pbCanBurn?(user, false) next 0 if !target.battler.pbCanBurn?(user.battler, false)
score += 30 score += 30
if ai.skill_check(Battle::AI::AILevel.high) score -= 40 if target.has_active_ability?([:GUTS, :MARVELSCALE, :QUICKFEET, :FLAREBOOST])
score -= 40 if target.hasActiveAbility?([:GUTS, :MARVELSCALE, :QUICKFEET, :FLAREBOOST])
end
next score next score
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("TwoTurnAttackFlinchTarget", Battle::AI::Handlers::MoveEffectScore.add("TwoTurnAttackFlinchTarget",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
score += 20 if user.effects[PBEffects::FocusEnergy] > 0 score += 20 if user.effects[PBEffects::FocusEnergy] > 0
if ai.skill_check(Battle::AI::AILevel.high) score += 20 if !target.has_active_ability?(:INNERFOCUS) &&
score += 20 if !target.hasActiveAbility?(:INNERFOCUS) && target.effects[PBEffects::Substitute] == 0
target.effects[PBEffects::Substitute] == 0
end
next score next score
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("TwoTurnAttackRaiseUserSpAtkSpDefSpd2", Battle::AI::Handlers::MoveEffectScore.add("TwoTurnAttackRaiseUserSpAtkSpDefSpd2",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if user.statStageAtMax?(:SPECIAL_ATTACK) && if user.statStageAtMax?(:SPECIAL_ATTACK) &&
user.statStageAtMax?(:SPECIAL_DEFENSE) && user.statStageAtMax?(:SPECIAL_DEFENSE) &&
user.statStageAtMax?(:SPEED) user.statStageAtMax?(:SPEED)
@@ -125,22 +116,22 @@ Battle::AI::Handlers::MoveEffectScore.add("TwoTurnAttackRaiseUserSpAtkSpDefSpd2"
score -= user.stages[:SPECIAL_ATTACK] * 10 # Only *10 instead of *20 score -= user.stages[:SPECIAL_ATTACK] * 10 # Only *10 instead of *20
score -= user.stages[:SPECIAL_DEFENSE] * 10 # because two-turn attack score -= user.stages[:SPECIAL_DEFENSE] * 10 # because two-turn attack
score -= user.stages[:SPEED] * 10 score -= user.stages[:SPEED] * 10
if ai.skill_check(Battle::AI::AILevel.medium) if ai.trainer.medium_skill?
hasSpecialAttack = false hasSpecialAttack = false
user.eachMove do |m| user.battler.eachMove do |m|
next if !m.specialMove?(m.type) next if !m.specialMove?(m.type)
hasSpecialAttack = true hasSpecialAttack = true
break break
end end
if hasSpecialAttack if hasSpecialAttack
score += 20 score += 20
elsif ai.skill_check(Battle::AI::AILevel.high) elsif ai.trainer.high_skill?
score -= 90 score -= 90
end end
end end
if ai.skill_check(Battle::AI::AILevel.high) if ai.trainer.high_skill?
aspeed = pbRoughStat(user, :SPEED) aspeed = user.rough_stat(:SPEED)
ospeed = pbRoughStat(target, :SPEED) ospeed = target.rough_stat(:SPEED)
score += 30 if aspeed < ospeed && aspeed * 2 > ospeed score += 30 if aspeed < ospeed && aspeed * 2 > ospeed
end end
end end
@@ -149,7 +140,7 @@ Battle::AI::Handlers::MoveEffectScore.add("TwoTurnAttackRaiseUserSpAtkSpDefSpd2"
) )
Battle::AI::Handlers::MoveEffectScore.add("TwoTurnAttackChargeRaiseUserDefense1", Battle::AI::Handlers::MoveEffectScore.add("TwoTurnAttackChargeRaiseUserDefense1",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if move.statusMove? if move.statusMove?
if user.statStageAtMax?(:DEFENSE) if user.statStageAtMax?(:DEFENSE)
score -= 90 score -= 90
@@ -164,9 +155,9 @@ Battle::AI::Handlers::MoveEffectScore.add("TwoTurnAttackChargeRaiseUserDefense1"
) )
Battle::AI::Handlers::MoveEffectScore.add("TwoTurnAttackChargeRaiseUserSpAtk1", Battle::AI::Handlers::MoveEffectScore.add("TwoTurnAttackChargeRaiseUserSpAtk1",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
aspeed = pbRoughStat(user, :SPEED) aspeed = user.rough_stat(:SPEED)
ospeed = pbRoughStat(target, :SPEED) ospeed = target.rough_stat(:SPEED)
if (aspeed > ospeed && user.hp > user.totalhp / 3) || user.hp > user.totalhp / 2 if (aspeed > ospeed && user.hp > user.totalhp / 3) || user.hp > user.totalhp / 2
score += 60 score += 60
else else
@@ -196,7 +187,7 @@ Battle::AI::Handlers::MoveEffectScore.add("TwoTurnAttackChargeRaiseUserSpAtk1",
# MultiTurnAttackPowersUpEachTurn # MultiTurnAttackPowersUpEachTurn
Battle::AI::Handlers::MoveEffectScore.add("MultiTurnAttackBideThenReturnDoubleDamage", Battle::AI::Handlers::MoveEffectScore.add("MultiTurnAttackBideThenReturnDoubleDamage",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if user.hp <= user.totalhp / 4 if user.hp <= user.totalhp / 4
score -= 90 score -= 90
elsif user.hp <= user.totalhp / 2 elsif user.hp <= user.totalhp / 2

View File

@@ -2,8 +2,9 @@
# #
#=============================================================================== #===============================================================================
Battle::AI::Handlers::MoveEffectScore.add("HealUserFullyAndFallAsleep", Battle::AI::Handlers::MoveEffectScore.add("HealUserFullyAndFallAsleep",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next 0 if user.hp == user.totalhp || !user.pbCanSleep?(user, false, nil, true) next 0 if user.hp == user.totalhp ||
!user.battler.pbCanSleep?(user.battler, false, nil, true)
score += 70 score += 70
score -= user.hp * 140 / user.totalhp score -= user.hp * 140 / user.totalhp
score += 30 if user.status != :NONE score += 30 if user.status != :NONE
@@ -12,8 +13,9 @@ Battle::AI::Handlers::MoveEffectScore.add("HealUserFullyAndFallAsleep",
) )
Battle::AI::Handlers::MoveEffectScore.add("HealUserHalfOfTotalHP", Battle::AI::Handlers::MoveEffectScore.add("HealUserHalfOfTotalHP",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next 0 if user.hp == user.totalhp || (ai.skill_check(Battle::AI::AILevel.medium) && !user.canHeal?) next 0 if user.hp == user.totalhp ||
(ai.trainer.medium_skill? && !user.battler.canHeal?)
score += 50 score += 50
score -= user.hp * 100 / user.totalhp score -= user.hp * 100 / user.totalhp
next score next score
@@ -21,9 +23,10 @@ Battle::AI::Handlers::MoveEffectScore.add("HealUserHalfOfTotalHP",
) )
Battle::AI::Handlers::MoveEffectScore.add("HealUserDependingOnWeather", Battle::AI::Handlers::MoveEffectScore.add("HealUserDependingOnWeather",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next 0 if user.hp == user.totalhp || (ai.skill_check(Battle::AI::AILevel.medium) && !user.canHeal?) next 0 if user.hp == user.totalhp ||
case user.effectiveWeather (ai.trainer.medium_skill? && !user.battler.canHeal?)
case user.battler.effectiveWeather
when :Sun, :HarshSun when :Sun, :HarshSun
score += 30 score += 30
when :None when :None
@@ -37,18 +40,20 @@ Battle::AI::Handlers::MoveEffectScore.add("HealUserDependingOnWeather",
) )
Battle::AI::Handlers::MoveEffectScore.add("HealUserDependingOnSandstorm", Battle::AI::Handlers::MoveEffectScore.add("HealUserDependingOnSandstorm",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next 0 if user.hp == user.totalhp || (ai.skill_check(Battle::AI::AILevel.medium) && !user.canHeal?) next 0 if user.hp == user.totalhp ||
(ai.trainer.medium_skill? && !user.battler.canHeal?)
score += 50 score += 50
score -= user.hp * 100 / user.totalhp score -= user.hp * 100 / user.totalhp
score += 30 if user.effectiveWeather == :Sandstorm score += 30 if user.battler.effectiveWeather == :Sandstorm
next score next score
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("HealUserHalfOfTotalHPLoseFlyingTypeThisTurn", Battle::AI::Handlers::MoveEffectScore.add("HealUserHalfOfTotalHPLoseFlyingTypeThisTurn",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next 0 if user.hp == user.totalhp || (ai.skill_check(Battle::AI::AILevel.medium) && !user.canHeal?) next 0 if user.hp == user.totalhp ||
(ai.trainer.medium_skill? && !user.battler.canHeal?)
score += 50 score += 50
score -= user.hp * 100 / user.totalhp score -= user.hp * 100 / user.totalhp
next score next score
@@ -56,7 +61,7 @@ Battle::AI::Handlers::MoveEffectScore.add("HealUserHalfOfTotalHPLoseFlyingTypeTh
) )
Battle::AI::Handlers::MoveEffectScore.add("CureTargetStatusHealUserHalfOfTotalHP", Battle::AI::Handlers::MoveEffectScore.add("CureTargetStatusHealUserHalfOfTotalHP",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if target.status == :NONE if target.status == :NONE
score -= 90 score -= 90
elsif user.hp == user.totalhp && target.opposes?(user) elsif user.hp == user.totalhp && target.opposes?(user)
@@ -70,22 +75,22 @@ Battle::AI::Handlers::MoveEffectScore.add("CureTargetStatusHealUserHalfOfTotalHP
) )
Battle::AI::Handlers::MoveEffectScore.add("HealUserByTargetAttackLowerTargetAttack1", Battle::AI::Handlers::MoveEffectScore.add("HealUserByTargetAttackLowerTargetAttack1",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if target.statStageAtMin?(:ATTACK) if target.statStageAtMin?(:ATTACK)
score -= 90 score -= 90
else else
if target.pbCanLowerStatStage?(:ATTACK, user) if target.battler.pbCanLowerStatStage?(:ATTACK, user.battler)
score += target.stages[:ATTACK] * 20 score += target.stages[:ATTACK] * 20
if ai.skill_check(Battle::AI::AILevel.medium) if ai.trainer.medium_skill?
hasPhysicalAttack = false hasPhysicalAttack = false
target.eachMove do |m| target.battler.eachMove do |m|
next if !m.physicalMove?(m.type) next if !m.physicalMove?(m.type)
hasPhysicalAttack = true hasPhysicalAttack = true
break break
end end
if hasPhysicalAttack if hasPhysicalAttack
score += 20 score += 20
elsif ai.skill_check(Battle::AI::AILevel.high) elsif ai.trainer.high_skill?
score -= 90 score -= 90
end end
end end
@@ -97,8 +102,8 @@ Battle::AI::Handlers::MoveEffectScore.add("HealUserByTargetAttackLowerTargetAtta
) )
Battle::AI::Handlers::MoveEffectScore.add("HealUserByHalfOfDamageDone", Battle::AI::Handlers::MoveEffectScore.add("HealUserByHalfOfDamageDone",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if ai.skill_check(Battle::AI::AILevel.high) && target.hasActiveAbility?(:LIQUIDOOZE) if target.has_active_ability?(:LIQUIDOOZE)
score -= 70 score -= 70
elsif user.hp <= user.totalhp / 2 elsif user.hp <= user.totalhp / 2
score += 20 score += 20
@@ -108,9 +113,9 @@ Battle::AI::Handlers::MoveEffectScore.add("HealUserByHalfOfDamageDone",
) )
Battle::AI::Handlers::MoveEffectScore.add("HealUserByHalfOfDamageDoneIfTargetAsleep", Battle::AI::Handlers::MoveEffectScore.add("HealUserByHalfOfDamageDoneIfTargetAsleep",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next 0 if !target.asleep? next 0 if !target.battler.asleep?
if ai.skill_check(Battle::AI::AILevel.high) && target.hasActiveAbility?(:LIQUIDOOZE) if target.has_active_ability?(:LIQUIDOOZE)
score -= 70 score -= 70
elsif user.hp <= user.totalhp / 2 elsif user.hp <= user.totalhp / 2
score += 20 score += 20
@@ -120,8 +125,8 @@ Battle::AI::Handlers::MoveEffectScore.add("HealUserByHalfOfDamageDoneIfTargetAsl
) )
Battle::AI::Handlers::MoveEffectScore.add("HealUserByThreeQuartersOfDamageDone", Battle::AI::Handlers::MoveEffectScore.add("HealUserByThreeQuartersOfDamageDone",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if ai.skill_check(Battle::AI::AILevel.high) && target.hasActiveAbility?(:LIQUIDOOZE) if target.has_active_ability?(:LIQUIDOOZE)
score -= 80 score -= 80
elsif user.hp <= user.totalhp / 2 elsif user.hp <= user.totalhp / 2
score += 40 score += 40
@@ -131,10 +136,10 @@ Battle::AI::Handlers::MoveEffectScore.add("HealUserByThreeQuartersOfDamageDone",
) )
Battle::AI::Handlers::MoveEffectScore.add("HealUserAndAlliesQuarterOfTotalHP", Battle::AI::Handlers::MoveEffectScore.add("HealUserAndAlliesQuarterOfTotalHP",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
ally_amt = 30 ally_amt = 30
battle.allSameSideBattlers(user.index).each do |b| battle.allSameSideBattlers(user.index).each do |b|
if b.hp == b.totalhp || (ai.skill_check(Battle::AI::AILevel.medium) && !b.canHeal?) if b.hp == b.totalhp || (ai.trainer.medium_skill? && !b.canHeal?)
score -= ally_amt / 2 score -= ally_amt / 2
elsif b.hp < b.totalhp * 3 / 4 elsif b.hp < b.totalhp * 3 / 4
score += ally_amt score += ally_amt
@@ -145,10 +150,10 @@ Battle::AI::Handlers::MoveEffectScore.add("HealUserAndAlliesQuarterOfTotalHP",
) )
Battle::AI::Handlers::MoveEffectScore.add("HealUserAndAlliesQuarterOfTotalHPCureStatus", Battle::AI::Handlers::MoveEffectScore.add("HealUserAndAlliesQuarterOfTotalHPCureStatus",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
ally_amt = 80 / battle.pbSideSize(user.index) ally_amt = 80 / battle.pbSideSize(user.index)
battle.allSameSideBattlers(user.index).each do |b| battle.allSameSideBattlers(user.index).each do |b|
if b.hp == b.totalhp || (ai.skill_check(Battle::AI::AILevel.medium) && !b.canHeal?) if b.hp == b.totalhp || (ai.trainer.medium_skill? && !b.canHeal?)
score -= ally_amt score -= ally_amt
elsif b.hp < b.totalhp * 3 / 4 elsif b.hp < b.totalhp * 3 / 4
score += ally_amt score += ally_amt
@@ -160,7 +165,7 @@ Battle::AI::Handlers::MoveEffectScore.add("HealUserAndAlliesQuarterOfTotalHPCure
) )
Battle::AI::Handlers::MoveEffectScore.add("HealTargetHalfOfTotalHP", Battle::AI::Handlers::MoveEffectScore.add("HealTargetHalfOfTotalHP",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next 0 if user.opposes?(target) next 0 if user.opposes?(target)
if target.hp < target.totalhp / 2 && target.effects[PBEffects::Substitute] == 0 if target.hp < target.totalhp / 2 && target.effects[PBEffects::Substitute] == 0
score += 20 score += 20
@@ -170,11 +175,12 @@ Battle::AI::Handlers::MoveEffectScore.add("HealTargetHalfOfTotalHP",
) )
Battle::AI::Handlers::MoveEffectScore.add("HealTargetDependingOnGrassyTerrain", Battle::AI::Handlers::MoveEffectScore.add("HealTargetDependingOnGrassyTerrain",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next 0 if user.hp == user.totalhp || (ai.skill_check(Battle::AI::AILevel.medium) && !user.canHeal?) next 0 if user.hp == user.totalhp ||
(ai.trainer.medium_skill? && !user.battler.canHeal?)
score += 50 score += 50
score -= user.hp * 100 / user.totalhp score -= user.hp * 100 / user.totalhp
if ai.skill_check(Battle::AI::AILevel.medium) if ai.trainer.medium_skill?
score += 30 if battle.field.terrain == :Grassy score += 30 if battle.field.terrain == :Grassy
end end
next score next score
@@ -182,29 +188,29 @@ Battle::AI::Handlers::MoveEffectScore.add("HealTargetDependingOnGrassyTerrain",
) )
Battle::AI::Handlers::MoveEffectScore.add("HealUserPositionNextTurn", Battle::AI::Handlers::MoveEffectScore.add("HealUserPositionNextTurn",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next 0 if battle.positions[user.index].effects[PBEffects::Wish] > 0 next 0 if battle.positions[user.index].effects[PBEffects::Wish] > 0
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("StartHealUserEachTurn", Battle::AI::Handlers::MoveEffectScore.add("StartHealUserEachTurn",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next 0 if user.effects[PBEffects::AquaRing] next 0 if user.effects[PBEffects::AquaRing]
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("StartHealUserEachTurnTrapUserInBattle", Battle::AI::Handlers::MoveEffectScore.add("StartHealUserEachTurnTrapUserInBattle",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next 0 if user.effects[PBEffects::Ingrain] next 0 if user.effects[PBEffects::Ingrain]
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("StartDamageTargetEachTurnIfTargetAsleep", Battle::AI::Handlers::MoveEffectScore.add("StartDamageTargetEachTurnIfTargetAsleep",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if target.effects[PBEffects::Nightmare] || if target.effects[PBEffects::Nightmare] ||
target.effects[PBEffects::Substitute] > 0 target.effects[PBEffects::Substitute] > 0
score -= 90 score -= 90
elsif !target.asleep? elsif !target.battler.asleep?
score -= 90 score -= 90
else else
score -= 90 if target.statusCount <= 1 score -= 90 if target.statusCount <= 1
@@ -215,10 +221,10 @@ Battle::AI::Handlers::MoveEffectScore.add("StartDamageTargetEachTurnIfTargetAsle
) )
Battle::AI::Handlers::MoveEffectScore.add("StartLeechSeedTarget", Battle::AI::Handlers::MoveEffectScore.add("StartLeechSeedTarget",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if target.effects[PBEffects::LeechSeed] >= 0 if target.effects[PBEffects::LeechSeed] >= 0
score -= 90 score -= 90
elsif ai.skill_check(Battle::AI::AILevel.medium) && target.pbHasType?(:GRASS) elsif target.has_type?(:GRASS)
score -= 90 score -= 90
elsif user.turnCount == 0 elsif user.turnCount == 0
score += 60 score += 60
@@ -228,20 +234,20 @@ Battle::AI::Handlers::MoveEffectScore.add("StartLeechSeedTarget",
) )
Battle::AI::Handlers::MoveEffectScore.add("UserLosesHalfOfTotalHP", Battle::AI::Handlers::MoveEffectScore.add("UserLosesHalfOfTotalHP",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next 0 if user.hp <= user.totalhp / 2 next 0 if user.hp <= user.totalhp / 2
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("UserLosesHalfOfTotalHPExplosive", Battle::AI::Handlers::MoveEffectScore.add("UserLosesHalfOfTotalHPExplosive",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
reserves = battle.pbAbleNonActiveCount(user.idxOwnSide) reserves = battle.pbAbleNonActiveCount(user.idxOwnSide)
foes = battle.pbAbleNonActiveCount(user.idxOpposingSide) foes = battle.pbAbleNonActiveCount(user.idxOpposingSide)
if battle.pbCheckGlobalAbility(:DAMP) if battle.pbCheckGlobalAbility(:DAMP)
score -= 100 score -= 100
elsif ai.skill_check(Battle::AI::AILevel.medium) && reserves == 0 && foes > 0 elsif ai.trainer.medium_skill? && reserves == 0 && foes > 0
score -= 100 # don't want to lose score -= 100 # don't want to lose
elsif ai.skill_check(Battle::AI::AILevel.high) && reserves == 0 && foes == 0 elsif ai.trainer.high_skill? && reserves == 0 && foes == 0
score += 80 # want to draw score += 80 # want to draw
else else
score -= (user.totalhp - user.hp) * 75 / user.totalhp score -= (user.totalhp - user.hp) * 75 / user.totalhp
@@ -251,14 +257,14 @@ Battle::AI::Handlers::MoveEffectScore.add("UserLosesHalfOfTotalHPExplosive",
) )
Battle::AI::Handlers::MoveEffectScore.add("UserFaintsExplosive", Battle::AI::Handlers::MoveEffectScore.add("UserFaintsExplosive",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
reserves = battle.pbAbleNonActiveCount(user.idxOwnSide) reserves = battle.pbAbleNonActiveCount(user.idxOwnSide)
foes = battle.pbAbleNonActiveCount(user.idxOpposingSide) foes = battle.pbAbleNonActiveCount(user.idxOpposingSide)
if battle.pbCheckGlobalAbility(:DAMP) if battle.pbCheckGlobalAbility(:DAMP)
score -= 100 score -= 100
elsif ai.skill_check(Battle::AI::AILevel.medium) && reserves == 0 && foes > 0 elsif ai.trainer.medium_skill? && reserves == 0 && foes > 0
score -= 100 # don't want to lose score -= 100 # don't want to lose
elsif ai.skill_check(Battle::AI::AILevel.high) && reserves == 0 && foes == 0 elsif ai.trainer.high_skill? && reserves == 0 && foes == 0
score += 80 # want to draw score += 80 # want to draw
else else
score -= user.hp * 100 / user.totalhp score -= user.hp * 100 / user.totalhp
@@ -268,14 +274,14 @@ Battle::AI::Handlers::MoveEffectScore.add("UserFaintsExplosive",
) )
Battle::AI::Handlers::MoveEffectScore.add("UserFaintsPowersUpInMistyTerrainExplosive", Battle::AI::Handlers::MoveEffectScore.add("UserFaintsPowersUpInMistyTerrainExplosive",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
reserves = battle.pbAbleNonActiveCount(user.idxOwnSide) reserves = battle.pbAbleNonActiveCount(user.idxOwnSide)
foes = battle.pbAbleNonActiveCount(user.idxOpposingSide) foes = battle.pbAbleNonActiveCount(user.idxOpposingSide)
if battle.pbCheckGlobalAbility(:DAMP) if battle.pbCheckGlobalAbility(:DAMP)
score -= 100 score -= 100
elsif ai.skill_check(Battle::AI::AILevel.medium) && reserves == 0 && foes > 0 elsif ai.trainer.medium_skill? && reserves == 0 && foes > 0
score -= 100 # don't want to lose score -= 100 # don't want to lose
elsif ai.skill_check(Battle::AI::AILevel.high) && reserves == 0 && foes == 0 elsif ai.trainer.high_skill? && reserves == 0 && foes == 0
score += 40 # want to draw score += 40 # want to draw
score += 40 if battle.field.terrain == :Misty score += 40 if battle.field.terrain == :Misty
else else
@@ -289,9 +295,9 @@ Battle::AI::Handlers::MoveEffectScore.add("UserFaintsPowersUpInMistyTerrainExplo
# UserFaintsFixedDamageUserHP # UserFaintsFixedDamageUserHP
Battle::AI::Handlers::MoveEffectScore.add("UserFaintsLowerTargetAtkSpAtk2", Battle::AI::Handlers::MoveEffectScore.add("UserFaintsLowerTargetAtkSpAtk2",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if !target.pbCanLowerStatStage?(:ATTACK, user) && if !target.battler.pbCanLowerStatStage?(:ATTACK, user.battler) &&
!target.pbCanLowerStatStage?(:SPECIAL_ATTACK, user) !target.battler.pbCanLowerStatStage?(:SPECIAL_ATTACK, user.battler)
score -= 100 score -= 100
elsif battle.pbAbleNonActiveCount(user.idxOwnSide) == 0 elsif battle.pbAbleNonActiveCount(user.idxOwnSide) == 0
score -= 100 score -= 100
@@ -305,7 +311,7 @@ Battle::AI::Handlers::MoveEffectScore.add("UserFaintsLowerTargetAtkSpAtk2",
) )
Battle::AI::Handlers::MoveEffectScore.add("UserFaintsHealAndCureReplacement", Battle::AI::Handlers::MoveEffectScore.add("UserFaintsHealAndCureReplacement",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next score - 70 next score - 70
} }
) )
@@ -314,7 +320,7 @@ Battle::AI::Handlers::MoveEffectScore.copy("UserFaintsHealAndCureReplacement",
"UserFaintsHealAndCureReplacementRestorePP") "UserFaintsHealAndCureReplacementRestorePP")
Battle::AI::Handlers::MoveEffectScore.add("StartPerishCountsForAllBattlers", Battle::AI::Handlers::MoveEffectScore.add("StartPerishCountsForAllBattlers",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if battle.pbAbleNonActiveCount(user.idxOwnSide) == 0 if battle.pbAbleNonActiveCount(user.idxOwnSide) == 0
score -= 90 score -= 90
elsif target.effects[PBEffects::PerishSong] > 0 elsif target.effects[PBEffects::PerishSong] > 0
@@ -325,7 +331,7 @@ Battle::AI::Handlers::MoveEffectScore.add("StartPerishCountsForAllBattlers",
) )
Battle::AI::Handlers::MoveEffectScore.add("AttackerFaintsIfUserFaints", Battle::AI::Handlers::MoveEffectScore.add("AttackerFaintsIfUserFaints",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
score += 50 score += 50
score -= user.hp * 100 / user.totalhp score -= user.hp * 100 / user.totalhp
score += 30 if user.hp <= user.totalhp / 10 score += 30 if user.hp <= user.totalhp / 10
@@ -334,7 +340,7 @@ Battle::AI::Handlers::MoveEffectScore.add("AttackerFaintsIfUserFaints",
) )
Battle::AI::Handlers::MoveEffectScore.add("SetAttackerMovePPTo0IfUserFaints", Battle::AI::Handlers::MoveEffectScore.add("SetAttackerMovePPTo0IfUserFaints",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
score += 50 score += 50
score -= user.hp * 100 / user.totalhp score -= user.hp * 100 / user.totalhp
score += 30 if user.hp <= user.totalhp / 10 score += 30 if user.hp <= user.totalhp / 10

View File

@@ -2,8 +2,8 @@
# #
#=============================================================================== #===============================================================================
Battle::AI::Handlers::MoveEffectScore.add("UserTakesTargetItem", Battle::AI::Handlers::MoveEffectScore.add("UserTakesTargetItem",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if ai.skill_check(Battle::AI::AILevel.high) if ai.trainer.high_skill?
if !user.item && target.item if !user.item && target.item
score += 40 score += 40
else else
@@ -17,11 +17,11 @@ Battle::AI::Handlers::MoveEffectScore.add("UserTakesTargetItem",
) )
Battle::AI::Handlers::MoveEffectScore.add("TargetTakesUserItem", Battle::AI::Handlers::MoveEffectScore.add("TargetTakesUserItem",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if !user.item || target.item if !user.item || target.item
score -= 90 score -= 90
elsif user.hasActiveItem?([:FLAMEORB, :TOXICORB, :STICKYBARB, :IRONBALL, elsif user.has_active_item?([:FLAMEORB, :TOXICORB, :STICKYBARB, :IRONBALL,
:CHOICEBAND, :CHOICESCARF, :CHOICESPECS]) :CHOICEBAND, :CHOICESCARF, :CHOICESPECS])
score += 50 score += 50
else else
score -= 80 score -= 80
@@ -31,27 +31,27 @@ Battle::AI::Handlers::MoveEffectScore.add("TargetTakesUserItem",
) )
Battle::AI::Handlers::MoveEffectScore.add("UserTargetSwapItems", Battle::AI::Handlers::MoveEffectScore.add("UserTargetSwapItems",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if !user.item && !target.item if !user.item && !target.item
score -= 90 score -= 90
elsif ai.skill_check(Battle::AI::AILevel.high) && target.hasActiveAbility?(:STICKYHOLD) elsif target.has_active_ability?(:STICKYHOLD)
score -= 90 score -= 90
elsif user.hasActiveItem?([:FLAMEORB, :TOXICORB, :STICKYBARB, :IRONBALL, elsif user.has_active_item?([:FLAMEORB, :TOXICORB, :STICKYBARB, :IRONBALL,
:CHOICEBAND, :CHOICESCARF, :CHOICESPECS]) :CHOICEBAND, :CHOICESCARF, :CHOICESPECS])
score += 50 score += 50
elsif !user.item && target.item elsif !user.item && target.item
score -= 30 if user.lastMoveUsed && score -= 30 if user.battler.lastMoveUsed &&
GameData::Move.get(user.lastMoveUsed).function_code == "UserTargetSwapItems" GameData::Move.get(user.battler.lastMoveUsed).function_code == "UserTargetSwapItems"
end end
next score next score
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("RestoreUserConsumedItem", Battle::AI::Handlers::MoveEffectScore.add("RestoreUserConsumedItem",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if !user.recycleItem || user.item if !user.battler.recycleItem || user.item
score -= 80 score -= 80
elsif user.recycleItem elsif user.battler.recycleItem
score += 30 score += 30
end end
next score next score
@@ -59,8 +59,8 @@ Battle::AI::Handlers::MoveEffectScore.add("RestoreUserConsumedItem",
) )
Battle::AI::Handlers::MoveEffectScore.add("RemoveTargetItem", Battle::AI::Handlers::MoveEffectScore.add("RemoveTargetItem",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if ai.skill_check(Battle::AI::AILevel.high) if ai.trainer.high_skill?
score += 20 if target.item score += 20 if target.item
end end
next score next score
@@ -68,9 +68,9 @@ Battle::AI::Handlers::MoveEffectScore.add("RemoveTargetItem",
) )
Battle::AI::Handlers::MoveEffectScore.add("DestroyTargetBerryOrGem", Battle::AI::Handlers::MoveEffectScore.add("DestroyTargetBerryOrGem",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if target.effects[PBEffects::Substitute] == 0 if target.effects[PBEffects::Substitute] == 0
if ai.skill_check(Battle::AI::AILevel.high) && target.item && target.item.is_berry? if ai.trainer.high_skill? && target.item && target.item.is_berry?
score += 30 score += 30
end end
end end
@@ -79,11 +79,11 @@ Battle::AI::Handlers::MoveEffectScore.add("DestroyTargetBerryOrGem",
) )
Battle::AI::Handlers::MoveEffectScore.add("CorrodeTargetItem", Battle::AI::Handlers::MoveEffectScore.add("CorrodeTargetItem",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if battle.corrosiveGas[target.index % 2][target.pokemonIndex] if battle.corrosiveGas[target.side][target.party_index]
score -= 100 score -= 100
elsif !target.item || !target.itemActive? || target.unlosableItem?(target.item) || elsif !target.item || !target.item_active? || target.battler.unlosableItem?(target.item) ||
target.hasActiveAbility?(:STICKYHOLD) target.has_active_ability?(:STICKYHOLD)
score -= 90 score -= 90
elsif target.effects[PBEffects::Substitute] > 0 elsif target.effects[PBEffects::Substitute] > 0
score -= 90 score -= 90
@@ -95,24 +95,24 @@ Battle::AI::Handlers::MoveEffectScore.add("CorrodeTargetItem",
) )
Battle::AI::Handlers::MoveEffectScore.add("StartTargetCannotUseItem", Battle::AI::Handlers::MoveEffectScore.add("StartTargetCannotUseItem",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next 0 if target.effects[PBEffects::Embargo] > 0 next 0 if target.effects[PBEffects::Embargo] > 0
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("StartNegateHeldItems", Battle::AI::Handlers::MoveEffectScore.add("StartNegateHeldItems",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next 0 if battle.field.effects[PBEffects::MagicRoom] > 0 next 0 if battle.field.effects[PBEffects::MagicRoom] > 0
next score + 30 if !user.item && target.item next score + 30 if !user.item && target.item
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("UserConsumeBerryRaiseDefense2", Battle::AI::Handlers::MoveEffectScore.add("UserConsumeBerryRaiseDefense2",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if !user.item || !user.item.is_berry? || !user.itemActive? if !user.item || !user.item.is_berry? || !user.item_active?
score -= 100 score -= 100
else else
if ai.skill_check(Battle::AI::AILevel.high) if ai.trainer.high_skill?
useful_berries = [ useful_berries = [
:ORANBERRY, :SITRUSBERRY, :AGUAVBERRY, :APICOTBERRY, :CHERIBERRY, :ORANBERRY, :SITRUSBERRY, :AGUAVBERRY, :APICOTBERRY, :CHERIBERRY,
:CHESTOBERRY, :FIGYBERRY, :GANLONBERRY, :IAPAPABERRY, :KEEBERRY, :CHESTOBERRY, :FIGYBERRY, :GANLONBERRY, :IAPAPABERRY, :KEEBERRY,
@@ -122,11 +122,12 @@ Battle::AI::Handlers::MoveEffectScore.add("UserConsumeBerryRaiseDefense2",
] ]
score += 30 if useful_berries.include?(user.item_id) score += 30 if useful_berries.include?(user.item_id)
end end
if ai.skill_check(Battle::AI::AILevel.medium) if ai.trainer.medium_skill?
score += 20 if user.canHeal? && user.hp < user.totalhp / 3 && user.hasActiveAbility?(:CHEEKPOUCH) score += 20 if user.battler.canHeal? && user.hp < user.totalhp / 3 &&
score += 20 if user.hasActiveAbility?([:HARVEST, :RIPEN]) || user.has_active_ability?(:CHEEKPOUCH)
user.pbHasMoveFunction?("RestoreUserConsumedItem") # Recycle score += 20 if user.has_active_ability?([:HARVEST, :RIPEN]) ||
score += 20 if !user.canConsumeBerry? user.battler.pbHasMoveFunction?("RestoreUserConsumedItem") # Recycle
score += 20 if !user.battler.canConsumeBerry?
end end
score -= user.stages[:DEFENSE] * 20 score -= user.stages[:DEFENSE] * 20
end end
@@ -135,7 +136,7 @@ Battle::AI::Handlers::MoveEffectScore.add("UserConsumeBerryRaiseDefense2",
) )
Battle::AI::Handlers::MoveEffectScore.add("AllBattlersConsumeBerry", Battle::AI::Handlers::MoveEffectScore.add("AllBattlersConsumeBerry",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
useful_berries = [ useful_berries = [
:ORANBERRY, :SITRUSBERRY, :AGUAVBERRY, :APICOTBERRY, :CHERIBERRY, :ORANBERRY, :SITRUSBERRY, :AGUAVBERRY, :APICOTBERRY, :CHERIBERRY,
:CHESTOBERRY, :FIGYBERRY, :GANLONBERRY, :IAPAPABERRY, :KEEBERRY, :CHESTOBERRY, :FIGYBERRY, :GANLONBERRY, :IAPAPABERRY, :KEEBERRY,
@@ -147,11 +148,11 @@ Battle::AI::Handlers::MoveEffectScore.add("AllBattlersConsumeBerry",
if !b.item || !b.item.is_berry? || !b.itemActive? if !b.item || !b.item.is_berry? || !b.itemActive?
score -= 100 / battle.pbSideSize(user.index) score -= 100 / battle.pbSideSize(user.index)
else else
if ai.skill_check(Battle::AI::AILevel.high) if ai.trainer.high_skill?
amt = 30 / battle.pbSideSize(user.index) amt = 30 / battle.pbSideSize(user.index)
score += amt if useful_berries.include?(b.item_id) score += amt if useful_berries.include?(b.item_id)
end end
if ai.skill_check(Battle::AI::AILevel.medium) if ai.trainer.medium_skill?
amt = 20 / battle.pbSideSize(user.index) amt = 20 / battle.pbSideSize(user.index)
score += amt if b.canHeal? && b.hp < b.totalhp / 3 && b.hasActiveAbility?(:CHEEKPOUCH) score += amt if b.canHeal? && b.hp < b.totalhp / 3 && b.hasActiveAbility?(:CHEEKPOUCH)
score += amt if b.hasActiveAbility?([:HARVEST, :RIPEN]) || score += amt if b.hasActiveAbility?([:HARVEST, :RIPEN]) ||
@@ -160,7 +161,7 @@ Battle::AI::Handlers::MoveEffectScore.add("AllBattlersConsumeBerry",
end end
end end
end end
if ai.skill_check(Battle::AI::AILevel.high) if ai.trainer.high_skill?
battle.allOtherSideBattlers(user.index).each do |b| battle.allOtherSideBattlers(user.index).each do |b|
amt = 10 / battle.pbSideSize(target.index) amt = 10 / battle.pbSideSize(target.index)
score -= amt if b.hasActiveItem?(useful_berries) score -= amt if b.hasActiveItem?(useful_berries)
@@ -175,9 +176,9 @@ Battle::AI::Handlers::MoveEffectScore.add("AllBattlersConsumeBerry",
) )
Battle::AI::Handlers::MoveEffectScore.add("UserConsumeTargetBerry", Battle::AI::Handlers::MoveEffectScore.add("UserConsumeTargetBerry",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if target.effects[PBEffects::Substitute] == 0 if target.effects[PBEffects::Substitute] == 0
if ai.skill_check(Battle::AI::AILevel.high) && target.item && target.item.is_berry? if ai.trainer.high_skill? && target.item && target.item.is_berry?
score += 30 score += 30
end end
end end
@@ -186,8 +187,8 @@ Battle::AI::Handlers::MoveEffectScore.add("UserConsumeTargetBerry",
) )
Battle::AI::Handlers::MoveEffectScore.add("ThrowUserItemAtTarget", Battle::AI::Handlers::MoveEffectScore.add("ThrowUserItemAtTarget",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next 0 if !user.item || !user.itemActive? || next 0 if !user.item || !user.item_active? ||
user.unlosableItem?(user.item) || user.item.is_poke_ball? user.battler.unlosableItem?(user.item) || user.item.is_poke_ball?
} }
) )

View File

@@ -2,21 +2,21 @@
# #
#=============================================================================== #===============================================================================
Battle::AI::Handlers::MoveEffectScore.add("RedirectAllMovesToUser", Battle::AI::Handlers::MoveEffectScore.add("RedirectAllMovesToUser",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next 0 if user.allAllies.length == 0 next 0 if user.battler.allAllies.length == 0
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("RedirectAllMovesToTarget", Battle::AI::Handlers::MoveEffectScore.add("RedirectAllMovesToTarget",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next 0 if user.allAllies.length == 0 next 0 if user.battler.allAllies.length == 0
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("CannotBeRedirected", Battle::AI::Handlers::MoveEffectScore.add("CannotBeRedirected",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
redirection = false redirection = false
user.allOpposing.each do |b| user.battler.allOpposing.each do |b|
next if b.index == target.index next if b.index == target.index
if b.effects[PBEffects::RagePowder] || if b.effects[PBEffects::RagePowder] ||
b.effects[PBEffects::Spotlight] > 0 || b.effects[PBEffects::Spotlight] > 0 ||
@@ -27,7 +27,7 @@ Battle::AI::Handlers::MoveEffectScore.add("CannotBeRedirected",
break break
end end
end end
score += 50 if redirection && ai.skill_check(Battle::AI::AILevel.medium) score += 50 if redirection && ai.trainer.medium_skill?
next score next score
} }
) )
@@ -35,9 +35,9 @@ Battle::AI::Handlers::MoveEffectScore.add("CannotBeRedirected",
# RandomlyDamageOrHealTarget # RandomlyDamageOrHealTarget
Battle::AI::Handlers::MoveEffectScore.add("HealAllyOrDamageFoe", Battle::AI::Handlers::MoveEffectScore.add("HealAllyOrDamageFoe",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if !target.opposes?(user) if !target.opposes?(user)
if target.hp == target.totalhp || (ai.skill_check(Battle::AI::AILevel.medium) && !target.canHeal?) if target.hp == target.totalhp || (ai.trainer.medium_skill? && !target.battler.canHeal?)
score -= 90 score -= 90
else else
score += 50 score += 50
@@ -49,8 +49,8 @@ Battle::AI::Handlers::MoveEffectScore.add("HealAllyOrDamageFoe",
) )
Battle::AI::Handlers::MoveEffectScore.add("CurseTargetOrLowerUserSpd1RaiseUserAtkDef1", Battle::AI::Handlers::MoveEffectScore.add("CurseTargetOrLowerUserSpd1RaiseUserAtkDef1",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if user.pbHasType?(:GHOST) if user.has_type?(:GHOST)
if target.effects[PBEffects::Curse] if target.effects[PBEffects::Curse]
score -= 90 score -= 90
elsif user.hp <= user.totalhp / 2 elsif user.hp <= user.totalhp / 2
@@ -74,18 +74,18 @@ Battle::AI::Handlers::MoveEffectScore.add("CurseTargetOrLowerUserSpd1RaiseUserAt
# EffectDependsOnEnvironment # EffectDependsOnEnvironment
Battle::AI::Handlers::MoveEffectScore.add("HitsAllFoesAndPowersUpInPsychicTerrain", Battle::AI::Handlers::MoveEffectScore.add("HitsAllFoesAndPowersUpInPsychicTerrain",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next score + 40 if battle.field.terrain == :Psychic && user.affectedByTerrain? next score + 40 if battle.field.terrain == :Psychic && user.battler.affectedByTerrain?
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("TargetNextFireMoveDamagesTarget", Battle::AI::Handlers::MoveEffectScore.add("TargetNextFireMoveDamagesTarget",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
aspeed = pbRoughStat(user, :SPEED) aspeed = user.rough_stat(:SPEED)
ospeed = pbRoughStat(target, :SPEED) ospeed = target.rough_stat(:SPEED)
if aspeed > ospeed if aspeed > ospeed
score -= 90 score -= 90
elsif target.pbHasMoveType?(:FIRE) elsif target.battler.pbHasMoveType?(:FIRE)
score += 30 score += 30
end end
next score next score
@@ -97,23 +97,23 @@ Battle::AI::Handlers::MoveEffectScore.add("TargetNextFireMoveDamagesTarget",
# DoublePowerAfterFusionBolt # DoublePowerAfterFusionBolt
Battle::AI::Handlers::MoveEffectScore.add("PowerUpAllyMove", Battle::AI::Handlers::MoveEffectScore.add("PowerUpAllyMove",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next 0 if user.allAllies.empty? next 0 if user.battler.allAllies.empty?
next score + 30 next score + 30
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("CounterPhysicalDamage", Battle::AI::Handlers::MoveEffectScore.add("CounterPhysicalDamage",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if target.effects[PBEffects::HyperBeam] > 0 if target.effects[PBEffects::HyperBeam] > 0
score -= 90 score -= 90
else else
attack = pbRoughStat(user, :ATTACK) attack = user.rough_stat(:ATTACK)
spatk = pbRoughStat(user, :SPECIAL_ATTACK) spatk = user.rough_stat(:SPECIAL_ATTACK)
if attack * 1.5 < spatk if attack * 1.5 < spatk
score -= 60 score -= 60
elsif ai.skill_check(Battle::AI::AILevel.medium) && target.lastMoveUsed elsif ai.trainer.medium_skill? && target.battler.lastMoveUsed
moveData = GameData::Move.get(target.lastMoveUsed) moveData = GameData::Move.get(target.battler.lastMoveUsed)
score += 60 if moveData.physical? score += 60 if moveData.physical?
end end
end end
@@ -122,16 +122,16 @@ Battle::AI::Handlers::MoveEffectScore.add("CounterPhysicalDamage",
) )
Battle::AI::Handlers::MoveEffectScore.add("CounterSpecialDamage", Battle::AI::Handlers::MoveEffectScore.add("CounterSpecialDamage",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if target.effects[PBEffects::HyperBeam] > 0 if target.effects[PBEffects::HyperBeam] > 0
score -= 90 score -= 90
else else
attack = pbRoughStat(user, :ATTACK) attack = user.rough_stat(:ATTACK)
spatk = pbRoughStat(user, :SPECIAL_ATTACK) spatk = user.rough_stat(:SPECIAL_ATTACK)
if attack > spatk * 1.5 if attack > spatk * 1.5
score -= 60 score -= 60
elsif ai.skill_check(Battle::AI::AILevel.medium) && target.lastMoveUsed elsif ai.trainer.medium_skill? && target.battler.lastMoveUsed
moveData = GameData::Move.get(target.lastMoveUsed) moveData = GameData::Move.get(target.battler.lastMoveUsed)
score += 60 if moveData.special? score += 60 if moveData.special?
end end
end end
@@ -140,21 +140,21 @@ Battle::AI::Handlers::MoveEffectScore.add("CounterSpecialDamage",
) )
Battle::AI::Handlers::MoveEffectScore.add("CounterDamagePlusHalf", Battle::AI::Handlers::MoveEffectScore.add("CounterDamagePlusHalf",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next score - 90 if target.effects[PBEffects::HyperBeam] > 0 next score - 90 if target.effects[PBEffects::HyperBeam] > 0
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("UserAddStockpileRaiseDefSpDef1", Battle::AI::Handlers::MoveEffectScore.add("UserAddStockpileRaiseDefSpDef1",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
avg = 0 avg = 0
avg -= user.stages[:DEFENSE] * 10 avg -= user.stages[:DEFENSE] * 10
avg -= user.stages[:SPECIAL_DEFENSE] * 10 avg -= user.stages[:SPECIAL_DEFENSE] * 10
score += avg / 2 score += avg / 2
if user.effects[PBEffects::Stockpile] >= 3 if user.effects[PBEffects::Stockpile] >= 3
score -= 80 score -= 80
elsif user.pbHasMoveFunction?("PowerDependsOnUserStockpile", elsif user.battler.pbHasMoveFunction?("PowerDependsOnUserStockpile",
"HealUserDependingOnUserStockpile") # Spit Up, Swallow "HealUserDependingOnUserStockpile") # Spit Up, Swallow
score += 20 # More preferable if user also has Spit Up/Swallow score += 20 # More preferable if user also has Spit Up/Swallow
end end
next score next score
@@ -162,13 +162,13 @@ Battle::AI::Handlers::MoveEffectScore.add("UserAddStockpileRaiseDefSpDef1",
) )
Battle::AI::Handlers::MoveEffectScore.add("PowerDependsOnUserStockpile", Battle::AI::Handlers::MoveEffectScore.add("PowerDependsOnUserStockpile",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next 0 if user.effects[PBEffects::Stockpile] == 0 next 0 if user.effects[PBEffects::Stockpile] == 0
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("HealUserDependingOnUserStockpile", Battle::AI::Handlers::MoveEffectScore.add("HealUserDependingOnUserStockpile",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next 0 if user.effects[PBEffects::Stockpile] == 0 next 0 if user.effects[PBEffects::Stockpile] == 0
next 0 if user.hp == user.totalhp next 0 if user.hp == user.totalhp
mult = [0, 25, 50, 100][user.effects[PBEffects::Stockpile]] mult = [0, 25, 50, 100][user.effects[PBEffects::Stockpile]]
@@ -187,11 +187,11 @@ Battle::AI::Handlers::MoveEffectScore.add("HealUserDependingOnUserStockpile",
# UseLastMoveUsed # UseLastMoveUsed
Battle::AI::Handlers::MoveEffectScore.add("UseLastMoveUsedByTarget", Battle::AI::Handlers::MoveEffectScore.add("UseLastMoveUsedByTarget",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
score -= 40 score -= 40
if ai.skill_check(Battle::AI::AILevel.high) if ai.trainer.high_skill?
score -= 100 if !target.lastRegularMoveUsed || score -= 100 if !target.battler.lastRegularMoveUsed ||
GameData::Move.get(target.lastRegularMoveUsed).flags.none? { |f| f[/^CanMirrorMove$/i] } GameData::Move.get(target.battler.lastRegularMoveUsed).flags.none? { |f| f[/^CanMirrorMove$/i] }
end end
next score next score
} }
@@ -206,8 +206,8 @@ Battle::AI::Handlers::MoveEffectScore.add("UseLastMoveUsedByTarget",
# UseRandomMoveFromUserParty # UseRandomMoveFromUserParty
Battle::AI::Handlers::MoveEffectScore.add("UseRandomUserMoveIfAsleep", Battle::AI::Handlers::MoveEffectScore.add("UseRandomUserMoveIfAsleep",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if user.asleep? if user.battler.asleep?
score += 100 # Because it can only be used while asleep score += 100 # Because it can only be used while asleep
else else
score -= 90 score -= 90
@@ -221,23 +221,23 @@ Battle::AI::Handlers::MoveEffectScore.add("UseRandomUserMoveIfAsleep",
# StealAndUseBeneficialStatusMove # StealAndUseBeneficialStatusMove
Battle::AI::Handlers::MoveEffectScore.add("ReplaceMoveThisBattleWithTargetLastMoveUsed", Battle::AI::Handlers::MoveEffectScore.add("ReplaceMoveThisBattleWithTargetLastMoveUsed",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
moveBlacklist = [ moveBlacklist = [
"Struggle", # Struggle "Struggle", # Struggle
"ReplaceMoveThisBattleWithTargetLastMoveUsed", # Mimic "ReplaceMoveThisBattleWithTargetLastMoveUsed", # Mimic
"ReplaceMoveWithTargetLastMoveUsed", # Sketch "ReplaceMoveWithTargetLastMoveUsed", # Sketch
"UseRandomMove" # Metronome "UseRandomMove" # Metronome
] ]
if user.effects[PBEffects::Transform] || !target.lastRegularMoveUsed if user.effects[PBEffects::Transform] || !target.battler.lastRegularMoveUsed
score -= 90 score -= 90
else else
lastMoveData = GameData::Move.get(target.lastRegularMoveUsed) lastMoveData = GameData::Move.get(target.battler.lastRegularMoveUsed)
if moveBlacklist.include?(lastMoveData.function_code) || if moveBlacklist.include?(lastMoveData.function_code) ||
lastMoveData.type == :SHADOW lastMoveData.type == :SHADOW
score -= 90 score -= 90
end end
user.eachMove do |m| user.battler.eachMove do |m|
next if m != target.lastRegularMoveUsed next if m != target.battler.lastRegularMoveUsed
score -= 90 score -= 90
break break
end end
@@ -247,21 +247,21 @@ Battle::AI::Handlers::MoveEffectScore.add("ReplaceMoveThisBattleWithTargetLastMo
) )
Battle::AI::Handlers::MoveEffectScore.add("ReplaceMoveWithTargetLastMoveUsed", Battle::AI::Handlers::MoveEffectScore.add("ReplaceMoveWithTargetLastMoveUsed",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
moveBlacklist = [ moveBlacklist = [
"Struggle", # Struggle "Struggle", # Struggle
"ReplaceMoveWithTargetLastMoveUsed" # Sketch "ReplaceMoveWithTargetLastMoveUsed" # Sketch
] ]
if user.effects[PBEffects::Transform] || !target.lastRegularMoveUsed if user.effects[PBEffects::Transform] || !target.battler.lastRegularMoveUsed
score -= 90 score -= 90
else else
lastMoveData = GameData::Move.get(target.lastRegularMoveUsed) lastMoveData = GameData::Move.get(target.battler.lastRegularMoveUsed)
if moveBlacklist.include?(lastMoveData.function_code) || if moveBlacklist.include?(lastMoveData.function_code) ||
lastMoveData.type == :SHADOW lastMoveData.type == :SHADOW
score -= 90 score -= 90
end end
user.eachMove do |m| user.battler.eachMove do |m|
next if m != target.lastRegularMoveUsed next if m != target.battler.lastRegularMoveUsed
score -= 90 # User already knows the move that will be Sketched score -= 90 # User already knows the move that will be Sketched
break break
end end

View File

@@ -2,13 +2,13 @@
# #
#=============================================================================== #===============================================================================
Battle::AI::Handlers::MoveEffectScore.add("FleeFromBattle", Battle::AI::Handlers::MoveEffectScore.add("FleeFromBattle",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next 0 if battle.trainerBattle? next 0 if battle.trainerBattle?
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("SwitchOutUserStatusMove", Battle::AI::Handlers::MoveEffectScore.add("SwitchOutUserStatusMove",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if !battle.pbCanChooseNonActive?(user.index) || if !battle.pbCanChooseNonActive?(user.index) ||
battle.pbTeamAbleNonActiveCount(user.index) > 1 # Don't switch in ace battle.pbTeamAbleNonActiveCount(user.index) > 1 # Don't switch in ace
score -= 100 score -= 100
@@ -22,7 +22,7 @@ Battle::AI::Handlers::MoveEffectScore.add("SwitchOutUserStatusMove",
score -= total * 10 score -= total * 10
# special case: user has no damaging moves # special case: user has no damaging moves
hasDamagingMove = false hasDamagingMove = false
user.eachMove do |m| user.battler.eachMove do |m|
next if !m.damagingMove? next if !m.damagingMove?
hasDamagingMove = true hasDamagingMove = true
break break
@@ -35,14 +35,14 @@ Battle::AI::Handlers::MoveEffectScore.add("SwitchOutUserStatusMove",
) )
Battle::AI::Handlers::MoveEffectScore.add("SwitchOutUserDamagingMove", Battle::AI::Handlers::MoveEffectScore.add("SwitchOutUserDamagingMove",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next 0 if !battle.pbCanChooseNonActive?(user.index) || next 0 if !battle.pbCanChooseNonActive?(user.index) ||
battle.pbTeamAbleNonActiveCount(user.index) > 1 # Don't switch in ace battle.pbTeamAbleNonActiveCount(user.index) > 1 # Don't switch in ace
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("LowerTargetAtkSpAtk1SwitchOutUser", Battle::AI::Handlers::MoveEffectScore.add("LowerTargetAtkSpAtk1SwitchOutUser",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
avg = target.stages[:ATTACK] * 10 avg = target.stages[:ATTACK] * 10
avg += target.stages[:SPECIAL_ATTACK] * 10 avg += target.stages[:SPECIAL_ATTACK] * 10
score += avg / 2 score += avg / 2
@@ -51,7 +51,7 @@ Battle::AI::Handlers::MoveEffectScore.add("LowerTargetAtkSpAtk1SwitchOutUser",
) )
Battle::AI::Handlers::MoveEffectScore.add("SwitchOutUserPassOnEffects", Battle::AI::Handlers::MoveEffectScore.add("SwitchOutUserPassOnEffects",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if battle.pbCanChooseNonActive?(user.index) if battle.pbCanChooseNonActive?(user.index)
score -= 40 if user.effects[PBEffects::Confusion] > 0 score -= 40 if user.effects[PBEffects::Confusion] > 0
total = 0 total = 0
@@ -62,7 +62,7 @@ Battle::AI::Handlers::MoveEffectScore.add("SwitchOutUserPassOnEffects",
score += total * 10 score += total * 10
# special case: user has no damaging moves # special case: user has no damaging moves
hasDamagingMove = false hasDamagingMove = false
user.eachMove do |m| user.battler.eachMove do |m|
next if !m.damagingMove? next if !m.damagingMove?
hasDamagingMove = true hasDamagingMove = true
break break
@@ -77,9 +77,9 @@ Battle::AI::Handlers::MoveEffectScore.add("SwitchOutUserPassOnEffects",
) )
Battle::AI::Handlers::MoveEffectScore.add("SwitchOutTargetStatusMove", Battle::AI::Handlers::MoveEffectScore.add("SwitchOutTargetStatusMove",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if target.effects[PBEffects::Ingrain] || if target.effects[PBEffects::Ingrain] ||
(ai.skill_check(Battle::AI::AILevel.high) && target.hasActiveAbility?(:SUCTIONCUPS)) target.has_active_ability?(:SUCTIONCUPS)
score -= 90 score -= 90
else else
ch = 0 ch = 0
@@ -98,9 +98,9 @@ Battle::AI::Handlers::MoveEffectScore.add("SwitchOutTargetStatusMove",
) )
Battle::AI::Handlers::MoveEffectScore.add("SwitchOutTargetDamagingMove", Battle::AI::Handlers::MoveEffectScore.add("SwitchOutTargetDamagingMove",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if !target.effects[PBEffects::Ingrain] && if !target.effects[PBEffects::Ingrain] &&
!(ai.skill_check(Battle::AI::AILevel.high) && target.hasActiveAbility?(:SUCTIONCUPS)) !target.has_active_ability?(:SUCTIONCUPS)
score += 40 if target.pbOwnSide.effects[PBEffects::Spikes] > 0 score += 40 if target.pbOwnSide.effects[PBEffects::Spikes] > 0
score += 40 if target.pbOwnSide.effects[PBEffects::ToxicSpikes] > 0 score += 40 if target.pbOwnSide.effects[PBEffects::ToxicSpikes] > 0
score += 40 if target.pbOwnSide.effects[PBEffects::StealthRock] score += 40 if target.pbOwnSide.effects[PBEffects::StealthRock]
@@ -110,37 +110,37 @@ Battle::AI::Handlers::MoveEffectScore.add("SwitchOutTargetDamagingMove",
) )
Battle::AI::Handlers::MoveEffectScore.add("BindTarget", Battle::AI::Handlers::MoveEffectScore.add("BindTarget",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next score + 40 if target.effects[PBEffects::Trapping] == 0 next score + 40 if target.effects[PBEffects::Trapping] == 0
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("BindTargetDoublePowerIfTargetUnderwater", Battle::AI::Handlers::MoveEffectScore.add("BindTargetDoublePowerIfTargetUnderwater",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next score + 40 if target.effects[PBEffects::Trapping] == 0 next score + 40 if target.effects[PBEffects::Trapping] == 0
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("TrapTargetInBattle", Battle::AI::Handlers::MoveEffectScore.add("TrapTargetInBattle",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next 0 if target.effects[PBEffects::MeanLook] >= 0 next 0 if target.effects[PBEffects::MeanLook] >= 0
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("TrapTargetInBattleLowerTargetDefSpDef1EachTurn", Battle::AI::Handlers::MoveEffectScore.add("TrapTargetInBattleLowerTargetDefSpDef1EachTurn",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next 0 if target.effects[PBEffects::Octolock] >= 0 next 0 if target.effects[PBEffects::Octolock] >= 0
score += 30 if !target.trappedInBattle? score += 30 if !target.battler.trappedInBattle?
score -= 100 if !target.pbCanLowerStatStage?(:DEFENSE, user, move) && score -= 100 if !target.battler.pbCanLowerStatStage?(:DEFENSE, user.battler, move.move) &&
!target.pbCanLowerStatStage?(:SPECIAL_DEFENSE, user, move) !target.battler.pbCanLowerStatStage?(:SPECIAL_DEFENSE, user.battler, move.move)
next score next score
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("TrapUserAndTargetInBattle", Battle::AI::Handlers::MoveEffectScore.add("TrapUserAndTargetInBattle",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if target.effects[PBEffects::JawLock] < 0 if target.effects[PBEffects::JawLock] < 0
score += 40 if !user.trappedInBattle? && !target.trappedInBattle? score += 40 if !user.battler.trappedInBattle? && !target.battler.trappedInBattle?
end end
next score next score
} }
@@ -151,10 +151,10 @@ Battle::AI::Handlers::MoveEffectScore.add("TrapUserAndTargetInBattle",
# PursueSwitchingFoe # PursueSwitchingFoe
Battle::AI::Handlers::MoveEffectScore.add("UsedAfterUserTakesPhysicalDamage", Battle::AI::Handlers::MoveEffectScore.add("UsedAfterUserTakesPhysicalDamage",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if ai.skill_check(Battle::AI::AILevel.medium) if ai.trainer.medium_skill?
hasPhysicalAttack = false hasPhysicalAttack = false
target.eachMove do |m| target.battler.eachMove do |m|
next if !m.physicalMove?(m.type) next if !m.physicalMove?(m.type)
hasPhysicalAttack = true hasPhysicalAttack = true
break break
@@ -166,9 +166,9 @@ Battle::AI::Handlers::MoveEffectScore.add("UsedAfterUserTakesPhysicalDamage",
) )
Battle::AI::Handlers::MoveEffectScore.add("UsedAfterAllyRoundWithDoublePower", Battle::AI::Handlers::MoveEffectScore.add("UsedAfterAllyRoundWithDoublePower",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if ai.skill_check(Battle::AI::AILevel.medium) if ai.trainer.medium_skill?
user.allAllies.each do |b| user.battler.allAllies.each do |b|
next if !b.pbHasMove?(move.id) next if !b.pbHasMove?(move.id)
score += 20 score += 20
end end
@@ -182,11 +182,11 @@ Battle::AI::Handlers::MoveEffectScore.add("UsedAfterAllyRoundWithDoublePower",
# TargetActsLast # TargetActsLast
Battle::AI::Handlers::MoveEffectScore.add("TargetUsesItsLastUsedMoveAgain", Battle::AI::Handlers::MoveEffectScore.add("TargetUsesItsLastUsedMoveAgain",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if ai.skill_check(Battle::AI::AILevel.medium) if ai.trainer.medium_skill?
if !target.lastRegularMoveUsed || if !target.battler.lastRegularMoveUsed ||
!target.pbHasMove?(target.lastRegularMoveUsed) || !target.battler.pbHasMove?(target.battler.lastRegularMoveUsed) ||
target.usingMultiTurnAttack? target.battler.usingMultiTurnAttack?
score -= 90 score -= 90
else else
# Without lots of code here to determine good/bad moves and relative # Without lots of code here to determine good/bad moves and relative
@@ -201,19 +201,17 @@ Battle::AI::Handlers::MoveEffectScore.add("TargetUsesItsLastUsedMoveAgain",
# StartSlowerBattlersActFirst # StartSlowerBattlersActFirst
Battle::AI::Handlers::MoveEffectScore.add("HigherPriorityInGrassyTerrain", Battle::AI::Handlers::MoveEffectScore.add("HigherPriorityInGrassyTerrain",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if ai.skill_check(Battle::AI::AILevel.medium) && @battle.field.terrain == :Grassy if ai.trainer.medium_skill? && @battle.field.terrain == :Grassy
aspeed = pbRoughStat(user, :SPEED) score += 40 if target.faster_than?(user)
ospeed = pbRoughStat(target, :SPEED)
score += 40 if aspeed < ospeed
end end
next score next score
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("LowerPPOfTargetLastMoveBy3", Battle::AI::Handlers::MoveEffectScore.add("LowerPPOfTargetLastMoveBy3",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
last_move = target.pbGetMoveWithID(target.lastRegularMoveUsed) last_move = target.battler.pbGetMoveWithID(target.battler.lastRegularMoveUsed)
if last_move && last_move.total_pp > 0 && last_move.pp <= 3 if last_move && last_move.total_pp > 0 && last_move.pp <= 3
score += 50 score += 50
end end
@@ -222,38 +220,36 @@ Battle::AI::Handlers::MoveEffectScore.add("LowerPPOfTargetLastMoveBy3",
) )
Battle::AI::Handlers::MoveEffectScore.add("LowerPPOfTargetLastMoveBy4", Battle::AI::Handlers::MoveEffectScore.add("LowerPPOfTargetLastMoveBy4",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next score - 40 next score - 40
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("DisableTargetLastMoveUsed", Battle::AI::Handlers::MoveEffectScore.add("DisableTargetLastMoveUsed",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next 0 if target.effects[PBEffects::Disable] > 0 next 0 if target.effects[PBEffects::Disable] > 0
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("DisableTargetUsingSameMoveConsecutively", Battle::AI::Handlers::MoveEffectScore.add("DisableTargetUsingSameMoveConsecutively",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next 0 if target.effects[PBEffects::Torment] next 0 if target.effects[PBEffects::Torment]
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("DisableTargetUsingDifferentMove", Battle::AI::Handlers::MoveEffectScore.add("DisableTargetUsingDifferentMove",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
aspeed = pbRoughStat(user, :SPEED)
ospeed = pbRoughStat(target, :SPEED)
if target.effects[PBEffects::Encore] > 0 if target.effects[PBEffects::Encore] > 0
score -= 90 score -= 90
elsif aspeed > ospeed elsif user.faster_than?(target)
if target.lastRegularMoveUsed if target.battler.lastRegularMoveUsed
moveData = GameData::Move.get(target.lastRegularMoveUsed) moveData = GameData::Move.get(target.battler.lastRegularMoveUsed)
if moveData.category == 2 && # Status move if moveData.category == 2 && # Status move
[:User, :BothSides].include?(moveData.target) [:User, :BothSides].include?(moveData.target)
score += 60 score += 60
elsif moveData.category != 2 && # Damaging move elsif moveData.category != 2 && # Damaging move
moveData.target == :NearOther && moveData.target == :NearOther &&
Effectiveness.ineffective?(pbCalcTypeMod(moveData.type, target, user)) Effectiveness.ineffective?(user.effectiveness_of_type_against_battler(moveData.type, target))
score += 60 score += 60
end end
else else
@@ -265,22 +261,22 @@ Battle::AI::Handlers::MoveEffectScore.add("DisableTargetUsingDifferentMove",
) )
Battle::AI::Handlers::MoveEffectScore.add("DisableTargetStatusMoves", Battle::AI::Handlers::MoveEffectScore.add("DisableTargetStatusMoves",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next 0 if target.effects[PBEffects::Taunt] > 0 next 0 if target.effects[PBEffects::Taunt] > 0
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("DisableTargetHealingMoves", Battle::AI::Handlers::MoveEffectScore.add("DisableTargetHealingMoves",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next 0 if target.effects[PBEffects::HealBlock] > 0 next 0 if target.effects[PBEffects::HealBlock] > 0
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("DisableTargetSoundMoves", Battle::AI::Handlers::MoveEffectScore.add("DisableTargetSoundMoves",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
if target.effects[PBEffects::ThroatChop] == 0 && ai.skill_check(Battle::AI::AILevel.high) if target.effects[PBEffects::ThroatChop] == 0 && ai.trainer.high_skill?
hasSoundMove = false hasSoundMove = false
user.eachMove do |m| user.battler.eachMove do |m|
next if !m.soundMove? next if !m.soundMove?
hasSoundMove = true hasSoundMove = true
break break
@@ -292,13 +288,13 @@ Battle::AI::Handlers::MoveEffectScore.add("DisableTargetSoundMoves",
) )
Battle::AI::Handlers::MoveEffectScore.add("DisableTargetMovesKnownByUser", Battle::AI::Handlers::MoveEffectScore.add("DisableTargetMovesKnownByUser",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
next 0 if target.effects[PBEffects::Imprison] next 0 if target.effects[PBEffects::Imprison]
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("AllBattlersLoseHalfHPUserSkipsNextTurn", Battle::AI::Handlers::MoveEffectScore.add("AllBattlersLoseHalfHPUserSkipsNextTurn",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
score += 20 # Shadow moves are more preferable score += 20 # Shadow moves are more preferable
score += 20 if target.hp >= target.totalhp / 2 score += 20 if target.hp >= target.totalhp / 2
score -= 20 if user.hp < user.hp / 2 score -= 20 if user.hp < user.hp / 2
@@ -307,7 +303,7 @@ Battle::AI::Handlers::MoveEffectScore.add("AllBattlersLoseHalfHPUserSkipsNextTur
) )
Battle::AI::Handlers::MoveEffectScore.add("AllBattlersLoseHalfHPUserSkipsNextTurn", Battle::AI::Handlers::MoveEffectScore.add("AllBattlersLoseHalfHPUserSkipsNextTurn",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
score += 20 # Shadow moves are more preferable score += 20 # Shadow moves are more preferable
score -= 40 score -= 40
next score next score
@@ -315,7 +311,7 @@ Battle::AI::Handlers::MoveEffectScore.add("AllBattlersLoseHalfHPUserSkipsNextTur
) )
Battle::AI::Handlers::MoveEffectScore.add("StartShadowSkyWeather", Battle::AI::Handlers::MoveEffectScore.add("StartShadowSkyWeather",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
score += 20 # Shadow moves are more preferable score += 20 # Shadow moves are more preferable
if battle.pbCheckGlobalAbility(:AIRLOCK) || if battle.pbCheckGlobalAbility(:AIRLOCK) ||
battle.pbCheckGlobalAbility(:CLOUDNINE) battle.pbCheckGlobalAbility(:CLOUDNINE)
@@ -328,7 +324,7 @@ Battle::AI::Handlers::MoveEffectScore.add("StartShadowSkyWeather",
) )
Battle::AI::Handlers::MoveEffectScore.add("RemoveAllScreens", Battle::AI::Handlers::MoveEffectScore.add("RemoveAllScreens",
proc { |score, move, user, target, skill, ai, battle| proc { |score, move, user, target, ai, battle|
score += 20 # Shadow moves are more preferable score += 20 # Shadow moves are more preferable
if target.pbOwnSide.effects[PBEffects::AuroraVeil] > 0 || if target.pbOwnSide.effects[PBEffects::AuroraVeil] > 0 ||
target.pbOwnSide.effects[PBEffects::Reflect] > 0 || target.pbOwnSide.effects[PBEffects::Reflect] > 0 ||

View File

@@ -0,0 +1,53 @@
#===============================================================================
# AI skill levels:
# 0: Wild Pokémon
# 1-31: Basic trainer (young/inexperienced)
# 32-47: Medium skill
# 48-99: High skill
# 100+: Best skill (Gym Leaders, Elite Four, Champion)
# NOTE: A trainer's skill value can range from 0-255, but by default only four
# distinct skill levels exist. The skill value is typically the same as
# the trainer's base money value.
#
# Skill flags:
#===============================================================================
class Battle::AI::AITrainer
attr_reader :side, :trainer_index
attr_reader :skill
def initialize(ai, side, index, trainer)
@ai = ai
@side = side
@trainer_index = index
@trainer = trainer
@skill = 0
@skill_flags = []
set_up_skill
end
def set_up_skill
return if !@trainer
@skill = @trainer.skill_level
# TODO: Add skill flags depending on @skill.
end
def has_skill_flag?(flag)
return @skill_flags.include?(flag)
end
# TODO: This will eventually be replaced by something else, maybe skill flags.
def medium_skill?
return @skill >= 32
end
# TODO: This will eventually be replaced by something else, maybe skill flags.
def high_skill?
return @skill >= 48
end
# TODO: This will eventually be replaced by something else, maybe skill flags.
def best_skill?
return @skill >= 100
end
end

View File

@@ -0,0 +1,239 @@
#===============================================================================
#
#===============================================================================
class Battle::AI::AIBattler
attr_reader :index, :side, :party_index
attr_reader :battler
def initialize(ai, index)
@ai = ai
@index = index
@side = (@ai.battle.opposes?(@index)) ? 1 : 0
refresh_battler
end
def refresh_battler
old_party_index = @party_index
@battler = @ai.battle.battlers[@index]
@party_index = @battler.pokemonIndex
if @party_index != old_party_index
# TODO: Start of battle or Pokémon switched/shifted; recalculate roles,
# etc.
end
end
def level; return @battler.level; end
def hp; return @battler.hp; end
def status; return @Battler.status; end
def statusCount; return @battler.statusCount; end
def totalhp; return @battler.totalhp; end
def gender; return @battler.gender; end
def turnCount; return @battler.turnCount; end
def effects; return @battler.effects; end
def stages; return @battler.stages; end
def statStageAtMax?(stat); return @battler.statStageAtMax?(stat); end
def statStageAtMin?(stat); return @battler.statStageAtMin?(stat); end
def wild?
return @ai.battle.wildBattle? && opposes?
end
def opposes?(other = nil)
return @side == 1 if other.nil?
return other.side != @side
end
def idxOwnSide; return @battler.idxOwnSide; end
def pbOwnSide; return @battler.pbOwnSide; end
def idxOpposingSide; return @battler.idxOpposingSide; end
def pbOpposingSide; return @battler.pbOpposingSide; end
def faster_than?(other)
return false if other.nil?
this_speed = rough_stat(:SPEED)
other_speed = other.rough_stat(:SPEED)
return (this_speed > other_speed) ^ (@ai.battle.field.effects[PBEffects::TrickRoom] > 0)
end
#=============================================================================
def speed; return @battler.speed; end
# TODO: Cache calculated rough stats? Forget them in def refresh_battler.
def rough_stat(stat)
return @battler.pbSpeed if stat == :SPEED && @ai.trainer.high_skill?
stageMul = [2, 2, 2, 2, 2, 2, 2, 3, 4, 5, 6, 7, 8]
stageDiv = [8, 7, 6, 5, 4, 3, 2, 2, 2, 2, 2, 2, 2]
stage = @battler.stages[stat] + 6
value = 0
case stat
when :ATTACK then value = @battler.attack
when :DEFENSE then value = @battler.defense
when :SPECIAL_ATTACK then value = @battler.spatk
when :SPECIAL_DEFENSE then value = @battler.spdef
when :SPEED then value = @battler.speed
end
return (value.to_f * stageMul[stage] / stageDiv[stage]).floor
end
#=============================================================================
def types; return @battler.types; end
def has_type?(type)
return @battler.pbHasType?(type)
end
def effectiveness_of_type_against_battler(type, user = nil)
return Effectiveness::NORMAL_EFFECTIVE if !type
return Effectiveness::NORMAL_EFFECTIVE if type == :GROUND &&
has_type?(:FLYING) &&
has_active_item?(:IRONBALL)
# Get effectivenesses
type_mults = [Effectiveness::NORMAL_EFFECTIVE_ONE] * 3 # 3 types max
if type == :SHADOW
if @battler.shadowPokemon?
type_mults[0] = Effectiveness::NOT_VERY_EFFECTIVE_ONE
else
type_mults[0] = Effectiveness::SUPER_EFFECTIVE_ONE
end
else
@battler.pbTypes(true).each_with_index do |defend_type, i|
type_mults[i] = effectiveness_of_type_against_single_battler_type(type, defend_type, user)
end
end
# Multiply all effectivenesses together
ret = 1
type_mults.each { |m| ret *= m }
return ret
end
#=============================================================================
def ability_id; return @battler.ability_id; end
def ability; return @battler.ability; end
def ability_active?
# Only a high skill AI knows what an opponent's ability is
return false if @ai.trainer.side != @side && !@ai.trainer.high_skill?
return @battler.abilityActive?
end
def has_active_ability?(ability)
# Only a high skill AI knows what an opponent's ability is
return false if @ai.trainer.side != @side && !@ai.trainer.high_skill?
return @battler.hasActiveAbility?(ability)
end
#=============================================================================
def item_id; return @battler.item_id; end
def item; return @battler.item; end
def item_active?
# Only a high skill AI knows what an opponent's held item is
return false if @ai.trainer.side != @side && !@ai.trainer.high_skill?
return @battler.itemActive?
end
def has_active_item?(item)
# Only a high skill AI knows what an opponent's held item is
return false if @ai.trainer.side != @side && !@ai.trainer.high_skill?
return @battler.hasActiveItem?(item)
end
#=============================================================================
def can_switch_lax?
return false if wild?
@ai.battle.eachInTeamFromBattlerIndex(@index) do |pkmn, i|
return true if @ai.battle.pbCanSwitchLax?(@index, i)
end
return false
end
#=============================================================================
def immune_to_move?
user = @ai.user
user_battler = user.battler
move = @ai.move
# TODO: Add consideration of user's Mold Breaker.
move_type = move.rough_type
typeMod = effectiveness_of_type_against_battler(move_type, user)
# Type effectiveness
return true if move.damagingMove? && Effectiveness.ineffective?(typeMod)
# Immunity due to ability/item/other effects
if @ai.trainer.medium_skill?
case move_type
when :GROUND
# TODO: Split target.airborne? into separate parts to allow different
# skill levels to apply to each part.
return true if @battler.airborne? && !move.move.hitsFlyingTargets?
when :FIRE
return true if has_active_ability?(:FLASHFIRE)
when :WATER
return true if has_active_ability?([:DRYSKIN, :STORMDRAIN, :WATERABSORB])
when :GRASS
return true if has_active_ability?(:SAPSIPPER)
when :ELECTRIC
return true if has_active_ability?([:LIGHTNINGROD, :MOTORDRIVE, :VOLTABSORB])
end
return true if move.damagingMove? && Effectiveness.not_very_effective?(typeMod) &&
has_active_ability?(:WONDERGUARD)
return true if move.damagingMove? && user.index != @index && !opposes?(user) &&
has_active_ability?(:TELEPATHY)
return true if move.statusMove? && move.move.canMagicCoat? && has_active_ability?(:MAGICBOUNCE) &&
opposes?(user)
return true if move.move.soundMove? && has_active_ability?(:SOUNDPROOF)
return true if move.move.bombMove? && has_active_ability?(:BULLETPROOF)
if move.move.powderMove?
return true if has_type?(:GRASS)
return true if has_active_ability?(:OVERCOAT)
return true if has_active_ability?(:SAFETYGOGGLES)
end
return true if move.move.statusMove? && @battler.effects[PBEffects::Substitute] > 0 &&
!move.move.ignoresSubstitute?(user) && user.index != @index
return true if move.move.statusMove? && Settings::MECHANICS_GENERATION >= 7 &&
user.has_active_ability?(:PRANKSTER) && has_type?(:DARK) &&
opposes?(user)
return true if move.move.priority > 0 && @ai.battle.field.terrain == :Psychic &&
@battler.affectedByTerrain? && opposes?(user)
# TODO: Dazzling/Queenly Majesty go here.
end
return false
end
#=============================================================================
private
def effectiveness_of_type_against_single_battler_type(type, defend_type, user = nil)
ret = Effectiveness.calculate_one(type, defend_type)
if Effectiveness.ineffective_type?(type, defend_type)
# Ring Target
if has_active_item?(:RINGTARGET)
ret = Effectiveness::NORMAL_EFFECTIVE_ONE
end
# Foresight
if (user&.has_active_ability?(:SCRAPPY) || @battler.effects[PBEffects::Foresight]) &&
defend_type == :GHOST
ret = Effectiveness::NORMAL_EFFECTIVE_ONE
end
# Miracle Eye
if @battler.effects[PBEffects::MiracleEye] && defend_type == :DARK
ret = Effectiveness::NORMAL_EFFECTIVE_ONE
end
elsif Effectiveness.super_effective_type?(type, defend_type)
# Delta Stream's weather
if @battler.effectiveWeather == :StrongWinds && defend_type == :FLYING
ret = Effectiveness::NORMAL_EFFECTIVE_ONE
end
end
# Grounded Flying-type Pokémon become susceptible to Ground moves
if !@battler.airborne? && type == :GROUND && defend_type == :FLYING
ret = Effectiveness::NORMAL_EFFECTIVE_ONE
end
return ret
end
end

View File

@@ -0,0 +1,366 @@
#===============================================================================
#
#===============================================================================
class Battle::AI::AIMove
attr_reader :move
def initialize(ai)
@ai = ai
end
def set_up(move, ai_battler)
@move = move
@ai_battler = ai_battler
end
#=============================================================================
# pp
# priority
# usableWhenAsleep?
# thawsUser?
# flinchingMove?
# tramplesMinimize?
# hitsFlyingTargets?
# canMagicCoat?
# soundMove?
# bombMove?
# powderMove?
# ignoresSubstitute?
# highCriticalRate?
# ignoresReflect?
def id; return @move.id; end
def physicalMove?(thisType = nil); return @move.physicalMove?(thisType); end
def specialMove?(thisType = nil); return @move.specialMove?(thisType); end
def damagingMove?; return @move.damagingMove?; end
def statusMove?; return @move.statusMove?; end
def function; return @move.function; end
#=============================================================================
# Returns whether this move targets multiple battlers.
def targets_multiple_battlers?
user_battler = @ai_battler.battler
target_data = @move.pbTarget(user_battler)
return false if target_data.num_targets <= 1
num_targets = 0
case target_data.id
when :AllAllies
@ai.battle.allSameSideBattlers(user_battler).each { |b| num_targets += 1 if b.index != user_battler.index }
when :UserAndAllies
@ai.battle.allSameSideBattlers(user_battler).each { |_b| num_targets += 1 }
when :AllNearFoes
@ai.battle.allOtherSideBattlers(user_battler).each { |b| num_targets += 1 if b.near?(user_battler) }
when :AllFoes
@ai.battle.allOtherSideBattlers(user_battler).each { |_b| num_targets += 1 }
when :AllNearOthers
@ai.battle.allBattlers.each { |b| num_targets += 1 if b.near?(user_battler) }
when :AllBattlers
@ai.battle.allBattlers.each { |_b| num_targets += 1 }
end
return num_targets > 1
end
#=============================================================================
def type; return @move.type; end
def rough_type
return @move.pbCalcType(@ai.user.battler) if @ai.trainer.high_skill?
return @move.type
end
def pbCalcType(user); return @move.pbCalcType(user); end
#=============================================================================
# Returns this move's base power, taking into account various effects that
# modify it.
def base_power
ret = @move.baseDamage
ret = 60 if ret == 1
return ret if !@ai.trainer.medium_skill?
user = @ai.user
user_battler = user.battler
target = @ai.target
target_battler = target.battler
# Covers all function codes which have their own def pbBaseDamage
case @move.function
when "FixedDamage20", "FixedDamage40", "FixedDamageHalfTargetHP",
"FixedDamageUserLevel", "LowerTargetHPToUserHP"
ret = @move.pbFixedDamage(user_battler, target_battler)
when "FixedDamageUserLevelRandom"
ret = user_battler.level
when "OHKO", "OHKOIce", "OHKOHitsUndergroundTarget"
ret = 200
when "CounterPhysicalDamage", "CounterSpecialDamage", "CounterDamagePlusHalf"
ret = 60
when "DoublePowerIfTargetUnderwater", "DoublePowerIfTargetUnderground",
"BindTargetDoublePowerIfTargetUnderwater"
ret = @move.pbModifyDamage(ret, user_battler, target_battler)
when "DoublePowerIfTargetInSky",
"FlinchTargetDoublePowerIfTargetInSky",
"DoublePowerIfTargetPoisoned",
"DoublePowerIfTargetParalyzedCureTarget",
"DoublePowerIfTargetAsleepCureTarget",
"DoublePowerIfUserPoisonedBurnedParalyzed",
"DoublePowerIfTargetStatusProblem",
"DoublePowerIfTargetHPLessThanHalf",
"DoublePowerIfAllyFaintedLastTurn",
"TypeAndPowerDependOnWeather",
"PowerHigherWithUserHappiness",
"PowerLowerWithUserHappiness",
"PowerHigherWithUserHP",
"PowerHigherWithTargetHP",
"PowerHigherWithUserPositiveStatStages",
"PowerHigherWithTargetPositiveStatStages",
"TypeDependsOnUserIVs",
"PowerHigherWithConsecutiveUse",
"PowerHigherWithConsecutiveUseOnUserSide",
"PowerHigherWithLessPP",
"PowerLowerWithUserHP",
"PowerHigherWithUserFasterThanTarget",
"PowerHigherWithTargetWeight",
"ThrowUserItemAtTarget",
"PowerDependsOnUserStockpile"
ret = @move.pbBaseDamage(ret, user_battler, target_battler)
when "DoublePowerIfUserHasNoItem"
ret *= 2 if !user_battler.item || user.has_active_item?(:FLYINGGEM)
when "PowerHigherWithTargetFasterThanUser"
targetSpeed = target.rough_stat(:SPEED)
userSpeed = user.rough_stat(:SPEED)
ret = [[(25 * targetSpeed / userSpeed).floor, 150].min, 1].max
when "RandomlyDamageOrHealTarget"
ret = 50
when "RandomPowerDoublePowerIfTargetUnderground"
ret = 71
ret *= 2 if target_battler.inTwoTurnAttack?("TwoTurnAttackInvulnerableUnderground") # Dig
when "TypeAndPowerDependOnUserBerry"
ret = @move.pbNaturalGiftBaseDamage(user_battler.item_id)
when "PowerHigherWithUserHeavierThanTarget"
ret = @move.pbBaseDamage(ret, user_battler, target_battler)
ret *= 2 if Settings::MECHANICS_GENERATION >= 7 && @trainer.medium_skill? &&
target_battler.effects[PBEffects::Minimize]
when "AlwaysCriticalHit", "HitTwoTimes", "HitTwoTimesPoisonTarget"
ret *= 2
when "HitThreeTimesPowersUpWithEachHit"
ret *= 6 # Hits do x1, x2, x3 ret in turn, for x6 in total
when "HitTwoToFiveTimes"
if user.has_active_ability?(:SKILLLINK)
ret *= 5
else
ret = (ret * 31 / 10).floor # Average damage dealt
end
when "HitTwoToFiveTimesOrThreeForAshGreninja"
if user_battler.isSpecies?(:GRENINJA) && user_battler.form == 2
ret *= 4 # 3 hits at 20 power = 4 hits at 15 power
elsif user.has_active_ability?(:SKILLLINK)
ret *= 5
else
ret = (ret * 31 / 10).floor # Average damage dealt
end
when "HitOncePerUserTeamMember"
mult = 0
@ai.battle.eachInTeamFromBattlerIndex(user.index) do |pkmn, _i|
mult += 1 if pkmn&.able? && pkmn.status == :NONE
end
ret *= mult
when "TwoTurnAttackOneTurnInSun"
ret = @move.pbBaseDamageMultiplier(ret, user_battler, target_battler)
when "MultiTurnAttackPowersUpEachTurn"
ret *= 2 if user_battler.effects[PBEffects::DefenseCurl]
when "MultiTurnAttackBideThenReturnDoubleDamage"
ret = 40
when "UserFaintsFixedDamageUserHP"
ret = user_battler.hp
when "EffectivenessIncludesFlyingType"
if GameData::Type.exists?(:FLYING)
if @trainer.high_skill?
targetTypes = target_battler.pbTypes(true)
mult = Effectiveness.calculate(
:FLYING, targetTypes[0], targetTypes[1], targetTypes[2]
)
else
mult = Effectiveness.calculate(
:FLYING, target.types[0], target.types[1], target.effects[PBEffects::Type3]
)
end
ret = (ret.to_f * mult / Effectiveness::NORMAL_EFFECTIVE).round
end
ret *= 2 if @trainer.medium_skill? && target_battler.effects[PBEffects::Minimize]
when "DoublePowerIfUserLastMoveFailed"
ret *= 2 if user_battler.lastRoundMoveFailed
when "HitTwoTimesFlinchTarget"
ret *= 2
ret *= 2 if @trainer.medium_skill? && target_battler.effects[PBEffects::Minimize]
end
return ret
end
#=============================================================================
def accuracy
return @move.accuracy
end
def rough_accuracy
baseAcc = self.accuracy
return 100 if baseAcc == 0
# Determine user and target
user = @ai.user
user_battler = user.battler
target = @ai.target
target_battler = target.battler
# Get better base accuracy
if @ai.trainer.medium_skill?
baseAcc = @move.pbBaseAccuracy(user_battler, target_battler)
return 100 if baseAcc == 0
end
# "Always hit" effects and "always hit" accuracy
if @ai.trainer.medium_skill?
return 100 if target_battler.effects[PBEffects::Minimize] && @move.tramplesMinimize? &&
Settings::MECHANICS_GENERATION >= 6
return 100 if target_battler.effects[PBEffects::Telekinesis] > 0
end
# Get the move's type
type = rough_type
# Calculate all modifier effects
modifiers = {}
modifiers[:base_accuracy] = baseAcc
modifiers[:accuracy_stage] = user_battler.stages[:ACCURACY]
modifiers[:evasion_stage] = target_battler.stages[:EVASION]
modifiers[:accuracy_multiplier] = 1.0
modifiers[:evasion_multiplier] = 1.0
apply_rough_accuracy_modifiers(user, target, type, modifiers)
# Check if move certainly misses/can't miss
return 0 if modifiers[:base_accuracy] < 0
return 100 if modifiers[:base_accuracy] == 0
# Calculation
accStage = [[modifiers[:accuracy_stage], -6].max, 6].min + 6
evaStage = [[modifiers[:evasion_stage], -6].max, 6].min + 6
stageMul = [3, 3, 3, 3, 3, 3, 3, 4, 5, 6, 7, 8, 9]
stageDiv = [9, 8, 7, 6, 5, 4, 3, 3, 3, 3, 3, 3, 3]
accuracy = 100.0 * stageMul[accStage] / stageDiv[accStage]
evasion = 100.0 * stageMul[evaStage] / stageDiv[evaStage]
accuracy = (accuracy * modifiers[:accuracy_multiplier]).round
evasion = (evasion * modifiers[:evasion_multiplier]).round
evasion = 1 if evasion < 1
return modifiers[:base_accuracy] * accuracy / evasion
end
def apply_rough_accuracy_modifiers(user, target, type, modifiers)
user_battler = user.battler
target_battler = target.battler
mold_breaker = (@ai.trainer.medium_skill? && target_battler.hasMoldBreaker?)
# Ability effects that alter accuracy calculation
if user.ability_active?
Battle::AbilityEffects.triggerAccuracyCalcFromUser(
user_battler.ability, modifiers, user_battler, target_battler, @move, type
)
end
user_battler.allAllies.each do |b|
next if !b.abilityActive?
Battle::AbilityEffects.triggerAccuracyCalcFromAlly(
b.ability, modifiers, user_battler, target_battler, @move, type
)
end
if !mold_breaker && target.ability_active?
Battle::AbilityEffects.triggerAccuracyCalcFromTarget(
target_battler.ability, modifiers, user_battler, target_battler, @move, type
)
end
# Item effects that alter accuracy calculation
if user.item_active?
# TODO: Zoom Lens needs to be checked differently (compare speeds of
# user and target).
Battle::ItemEffects.triggerAccuracyCalcFromUser(
user_battler.item, modifiers, user_battler, target_battler, @move, type
)
end
if target.item_active?
Battle::ItemEffects.triggerAccuracyCalcFromTarget(
target_battler.item, modifiers, user_battler, target_battler, @move, type
)
end
# Other effects, inc. ones that set accuracy_multiplier or evasion_stage to specific values
if @ai.battle.field.effects[PBEffects::Gravity] > 0
modifiers[:accuracy_multiplier] *= 5 / 3.0
end
if @ai.trainer.medium_skill?
if user_battler.effects[PBEffects::MicleBerry]
modifiers[:accuracy_multiplier] *= 1.2
end
modifiers[:evasion_stage] = 0 if target_battler.effects[PBEffects::Foresight] && modifiers[:evasion_stage] > 0
modifiers[:evasion_stage] = 0 if target_battler.effects[PBEffects::MiracleEye] && modifiers[:evasion_stage] > 0
end
# "AI-specific calculations below"
modifiers[:evasion_stage] = 0 if @move.function == "IgnoreTargetDefSpDefEvaStatStages" # Chip Away
if @ai.trainer.medium_skill?
modifiers[:base_accuracy] = 0 if user_battler.effects[PBEffects::LockOn] > 0 &&
user_battler.effects[PBEffects::LockOnPos] == target_battler.index
end
if @ai.trainer.medium_skill?
case @move.function
when "BadPoisonTarget"
modifiers[:base_accuracy] = 0 if Settings::MORE_TYPE_EFFECTS &&
@move.statusMove? && @user.has_type?(:POISON)
when "OHKO", "OHKOIce", "OHKOHitsUndergroundTarget"
modifiers[:base_accuracy] = self.accuracy + user_battler.level - target_battler.level
modifiers[:accuracy_multiplier] = 0 if target_battler.level > user_battler.level
modifiers[:accuracy_multiplier] = 0 if target.has_active_ability?(:STURDY)
end
end
end
#=============================================================================
def rough_critical_hit_stage
user = @ai.user
user_battler = user.battler
target = @ai.target
target_battler = target.battler
return -1 if target_battler.pbOwnSide.effects[PBEffects::LuckyChant] > 0
mold_breaker = (@ai.trainer.medium_skill? && user_battler.hasMoldBreaker?)
crit_stage = 0
# Ability effects that alter critical hit rate
if user.ability_active?
crit_stage = BattleHandlers.triggerCriticalCalcUserAbility(user_battler.ability,
user_battler, target_battler, crit_stage)
return -1 if crit_stage < 0
end
if !mold_breaker && target.ability_active?
crit_stage = BattleHandlers.triggerCriticalCalcTargetAbility(target_battler.ability,
user_battler, target_battler, crit_stage)
return -1 if crit_stage < 0
end
# Item effects that alter critical hit rate
if user.item_active?
crit_stage = BattleHandlers.triggerCriticalCalcUserItem(user_battler.item,
user_battler, target_battler, crit_stage)
return -1 if crit_stage < 0
end
if target.item_active?
crit_stage = BattleHandlers.triggerCriticalCalcTargetItem(user_battler.item,
user_battler, target_battler, crit_stage)
return -1 if crit_stage < 0
end
# Other effects
case @move.pbCritialOverride(user_battler, target_battler)
when 1 then return 99
when -1 then return -1
end
return 99 if crit_stage > 50 # Merciless
return 99 if user_battler.effects[PBEffects::LaserFocus] > 0
crit_stage += 1 if @move.highCriticalRate?
crit_stage += user_battler.effects[PBEffects::FocusEnergy]
crit_stage += 1 if user_battler.inHyperMode? && @move.type == :SHADOW
crit_stage = [crit_stage, Battle::Move::CRITICAL_HIT_RATIOS.length - 1].min
return crit_stage
end
#=============================================================================
# pbBaseAccuracy(@ai.user.battler, @ai.target.battler) if @ai.trainer.medium_skill?
# pbCriticalOverride(@ai.user.battler, @ai.target.battler)
end

View File

@@ -757,7 +757,7 @@ Description = The user stimulates its brain by thinking bad thoughts. It sharply
Name = Obstruct Name = Obstruct
Type = DARK Type = DARK
Category = Status Category = Status
Accuracy = 100 Accuracy = 0
TotalPP = 10 TotalPP = 10
Target = User Target = User
Priority = 4 Priority = 4
@@ -1102,7 +1102,7 @@ Description = This attack hits the target with a shock wave of pure rage. This a
Name = Clangorous Soul Name = Clangorous Soul
Type = DRAGON Type = DRAGON
Category = Status Category = Status
Accuracy = 100 Accuracy = 0
TotalPP = 5 TotalPP = 5
Target = User Target = User
FunctionCode = RaiseUserMainStats1LoseThirdOfTotalHP FunctionCode = RaiseUserMainStats1LoseThirdOfTotalHP
@@ -5846,7 +5846,7 @@ Description = The user mimics the move used immediately before it. The move fail
Name = Court Change Name = Court Change
Type = NORMAL Type = NORMAL
Category = Status Category = Status
Accuracy = 100 Accuracy = 0
TotalPP = 10 TotalPP = 10
Target = BothSides Target = BothSides
FunctionCode = SwapSideEffects FunctionCode = SwapSideEffects

View File

@@ -757,7 +757,7 @@ Description = The user stimulates its brain by thinking bad thoughts. It sharply
Name = Obstruct Name = Obstruct
Type = DARK Type = DARK
Category = Status Category = Status
Accuracy = 100 Accuracy = 0
TotalPP = 10 TotalPP = 10
Target = User Target = User
Priority = 4 Priority = 4
@@ -1102,7 +1102,7 @@ Description = This attack hits the target with a shock wave of pure rage. This a
Name = Clangorous Soul Name = Clangorous Soul
Type = DRAGON Type = DRAGON
Category = Status Category = Status
Accuracy = 100 Accuracy = 0
TotalPP = 5 TotalPP = 5
Target = User Target = User
FunctionCode = RaiseUserMainStats1LoseThirdOfTotalHP FunctionCode = RaiseUserMainStats1LoseThirdOfTotalHP
@@ -5846,7 +5846,7 @@ Description = The user mimics the move used immediately before it. The move fail
Name = Court Change Name = Court Change
Type = NORMAL Type = NORMAL
Category = Status Category = Status
Accuracy = 100 Accuracy = 0
TotalPP = 10 TotalPP = 10
Target = BothSides Target = BothSides
FunctionCode = SwapSideEffects FunctionCode = SwapSideEffects