update 6.7

This commit is contained in:
chardub
2025-09-28 15:53:01 -04:00
parent ef5e023ae0
commit 318ff90d8d
696 changed files with 111759 additions and 198230 deletions

View File

@@ -8,11 +8,11 @@ class PokeBattle_AI
return false if !item
# Determine target of item (always the Pokémon choosing the action)
useType = GameData::Item.get(item).battle_use
if [1, 2, 3, 6, 7, 8].include?(useType) # Use on Pokémon
idxTarget = @battle.battlers[idxTarget].pokemonIndex # Party Pokémon
if [1, 2, 3, 6, 7, 8].include?(useType) # Use on Pokémon
idxTarget = @battle.battlers[idxTarget].pokemonIndex # Party Pokémon
end
# Register use of item
@battle.pbRegisterItem(idxBattler,item,idxTarget)
@battle.pbRegisterItem(idxBattler, item, idxTarget)
PBDebug.log("[AI] #{user.pbThis} (#{user.index}) will use item #{GameData::Item.get(item).name}")
return true
end
@@ -22,33 +22,33 @@ class PokeBattle_AI
def pbEnemyItemToUse(idxBattler)
return nil if !@battle.internalBattle
items = @battle.pbGetOwnerItems(idxBattler)
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)
idxTarget = idxBattler # Battler using the item
idxTarget = idxBattler # Battler using the item
battler = @battle.battlers[idxTarget]
pkmn = battler.pokemon
# Item categories
hpItems = {
:POTION => 20,
:SUPERPOTION => 50,
:HYPERPOTION => 200,
:MAXPOTION => 999,
:BERRYJUICE => 20,
:SWEETHEART => 20,
:FRESHWATER => 50,
:SODAPOP => 60,
:LEMONADE => 80,
:MOOMOOMILK => 100,
:ORANBERRY => 10,
:SITRUSBERRY => battler.totalhp/4,
:ENERGYPOWDER => 50,
:ENERGYROOT => 200
:POTION => 20,
:SUPERPOTION => 50,
:HYPERPOTION => 200,
:MAXPOTION => 999,
:BERRYJUICE => 20,
:SWEETHEART => 20,
:FRESHWATER => 50,
:SODAPOP => 60,
:LEMONADE => 80,
:MOOMOOMILK => 100,
:ORANBERRY => 10,
:SITRUSBERRY => battler.totalhp / 4,
:ENERGYPOWDER => 50,
:ENERGYROOT => 200
}
hpItems[:RAGECANDYBAR] = 20 if !Settings::RAGE_CANDY_BAR_CURES_STATUS_PROBLEMS
fullRestoreItems = [
:FULLRESTORE
:FULLRESTORE
]
oneStatusItems = [ # Preferred over items that heal all status problems
oneStatusItems = [# Preferred over items that heal all status problems
:AWAKENING, :CHESTOBERRY, :BLUEFLUTE,
:ANTIDOTE, :PECHABERRY,
:BURNHEAL, :RAWSTBERRY,
@@ -56,112 +56,112 @@ class PokeBattle_AI
:ICEHEAL, :ASPEARBERRY
]
allStatusItems = [
:FULLHEAL, :LAVACOOKIE, :OLDGATEAU, :CASTELIACONE, :LUMIOSEGALETTE,
:SHALOURSABLE, :BIGMALASADA, :LUMBERRY, :HEALPOWDER
:FULLHEAL, :LAVACOOKIE, :OLDGATEAU, :CASTELIACONE, :LUMIOSEGALETTE,
:SHALOURSABLE, :BIGMALASADA, :LUMBERRY, :HEALPOWDER
]
allStatusItems.push(:RAGECANDYBAR) if Settings::RAGE_CANDY_BAR_CURES_STATUS_PROBLEMS
xItems = {
:XATTACK => [:ATTACK, (Settings::X_STAT_ITEMS_RAISE_BY_TWO_STAGES) ? 2 : 1],
:XATTACK2 => [:ATTACK, 2],
:XATTACK3 => [:ATTACK, 3],
:XATTACK6 => [:ATTACK, 6],
:XDEFENSE => [:DEFENSE, (Settings::X_STAT_ITEMS_RAISE_BY_TWO_STAGES) ? 2 : 1],
:XDEFENSE2 => [:DEFENSE, 2],
:XDEFENSE3 => [:DEFENSE, 3],
:XDEFENSE6 => [:DEFENSE, 6],
:XDEFEND => [:DEFENSE, (Settings::X_STAT_ITEMS_RAISE_BY_TWO_STAGES) ? 2 : 1],
:XDEFEND2 => [:DEFENSE, 2],
:XDEFEND3 => [:DEFENSE, 3],
:XDEFEND6 => [:DEFENSE, 6],
:XSPATK => [:SPECIAL_ATTACK, (Settings::X_STAT_ITEMS_RAISE_BY_TWO_STAGES) ? 2 : 1],
:XSPATK2 => [:SPECIAL_ATTACK, 2],
:XSPATK3 => [:SPECIAL_ATTACK, 3],
:XSPATK6 => [:SPECIAL_ATTACK, 6],
:XSPECIAL => [:SPECIAL_ATTACK, (Settings::X_STAT_ITEMS_RAISE_BY_TWO_STAGES) ? 2 : 1],
:XSPECIAL2 => [:SPECIAL_ATTACK, 2],
:XSPECIAL3 => [:SPECIAL_ATTACK, 3],
:XSPECIAL6 => [:SPECIAL_ATTACK, 6],
:XSPDEF => [:SPECIAL_DEFENSE, (Settings::X_STAT_ITEMS_RAISE_BY_TWO_STAGES) ? 2 : 1],
:XSPDEF2 => [:SPECIAL_DEFENSE, 2],
:XSPDEF3 => [:SPECIAL_DEFENSE, 3],
:XSPDEF6 => [:SPECIAL_DEFENSE, 6],
:XSPEED => [:SPEED, (Settings::X_STAT_ITEMS_RAISE_BY_TWO_STAGES) ? 2 : 1],
:XSPEED2 => [:SPEED, 2],
:XSPEED3 => [:SPEED, 3],
:XSPEED6 => [:SPEED, 6],
:XACCURACY => [:ACCURACY, (Settings::X_STAT_ITEMS_RAISE_BY_TWO_STAGES) ? 2 : 1],
:XACCURACY2 => [:ACCURACY, 2],
:XACCURACY3 => [:ACCURACY, 3],
:XACCURACY6 => [:ACCURACY, 6]
:XATTACK => [:ATTACK, (Settings::X_STAT_ITEMS_RAISE_BY_TWO_STAGES) ? 2 : 1],
:XATTACK2 => [:ATTACK, 2],
:XATTACK3 => [:ATTACK, 3],
:XATTACK6 => [:ATTACK, 6],
:XDEFENSE => [:DEFENSE, (Settings::X_STAT_ITEMS_RAISE_BY_TWO_STAGES) ? 2 : 1],
:XDEFENSE2 => [:DEFENSE, 2],
:XDEFENSE3 => [:DEFENSE, 3],
:XDEFENSE6 => [:DEFENSE, 6],
:XDEFEND => [:DEFENSE, (Settings::X_STAT_ITEMS_RAISE_BY_TWO_STAGES) ? 2 : 1],
:XDEFEND2 => [:DEFENSE, 2],
:XDEFEND3 => [:DEFENSE, 3],
:XDEFEND6 => [:DEFENSE, 6],
:XSPATK => [:SPECIAL_ATTACK, (Settings::X_STAT_ITEMS_RAISE_BY_TWO_STAGES) ? 2 : 1],
:XSPATK2 => [:SPECIAL_ATTACK, 2],
:XSPATK3 => [:SPECIAL_ATTACK, 3],
:XSPATK6 => [:SPECIAL_ATTACK, 6],
:XSPECIAL => [:SPECIAL_ATTACK, (Settings::X_STAT_ITEMS_RAISE_BY_TWO_STAGES) ? 2 : 1],
:XSPECIAL2 => [:SPECIAL_ATTACK, 2],
:XSPECIAL3 => [:SPECIAL_ATTACK, 3],
:XSPECIAL6 => [:SPECIAL_ATTACK, 6],
:XSPDEF => [:SPECIAL_DEFENSE, (Settings::X_STAT_ITEMS_RAISE_BY_TWO_STAGES) ? 2 : 1],
:XSPDEF2 => [:SPECIAL_DEFENSE, 2],
:XSPDEF3 => [:SPECIAL_DEFENSE, 3],
:XSPDEF6 => [:SPECIAL_DEFENSE, 6],
:XSPEED => [:SPEED, (Settings::X_STAT_ITEMS_RAISE_BY_TWO_STAGES) ? 2 : 1],
:XSPEED2 => [:SPEED, 2],
:XSPEED3 => [:SPEED, 3],
:XSPEED6 => [:SPEED, 6],
:XACCURACY => [:ACCURACY, (Settings::X_STAT_ITEMS_RAISE_BY_TWO_STAGES) ? 2 : 1],
:XACCURACY2 => [:ACCURACY, 2],
:XACCURACY3 => [:ACCURACY, 3],
:XACCURACY6 => [:ACCURACY, 6]
}
# Determine lost HP
losthp = battler.totalhp - battler.hp
preferFullRestore = (battler.hp <= battler.totalhp * 2 / 3 &&
(battler.status != :NONE || battler.effects[PBEffects::Confusion] > 0))
# Decide if Full Restore is actually preferred
preferFullRestore = (battler.hp <= battler.totalhp / 2 &&
(battler.status != :NONE || battler.effects[PBEffects::Confusion] > 0))
# Find all usable items
usableHPItems = []
usableHPItems = []
usableStatusItems = []
usableXItems = []
usableXItems = []
items.each do |i|
next if !i
next if !@battle.pbCanUseItemOnPokemon?(i,pkmn,battler,@battle.scene,false)
next if !ItemHandlers.triggerCanUseInBattle(i,pkmn,battler,nil,
false,self,@battle.scene,false)
# Log HP healing items
if losthp > 0
power = hpItems[i]
if power
usableHPItems.push([i, 5, power])
next
end
next if !@battle.pbCanUseItemOnPokemon?(i, pkmn, battler, @battle.scene, false)
next if !ItemHandlers.triggerCanUseInBattle(i, pkmn, battler, nil, false, self, @battle.scene, false)
itemQuantity = @battle.pbGetOwnerItems(idxBattler).count(i)
# Healing items (potions, berries, etc.)
if hpItems[i] && losthp > 0
priority = 5
# Use lower priority if only 1 or 2 left
priority += 3 if itemQuantity <= 2
usableHPItems.push([i, priority, hpItems[i]])
next
end
# Log Full Restores (HP healer and status curer)
if losthp > 0 || battler.status != :NONE
if fullRestoreItems.include?(i)
usableHPItems.push([i, (preferFullRestore) ? 3 : 7, 999])
usableStatusItems.push([i, (preferFullRestore) ? 3 : 9])
next
# Full Restore items
if fullRestoreItems.include?(i)
if losthp >= battler.totalhp / 4 || battler.status != :NONE || battler.effects[PBEffects::Confusion] > 0
# Only consider Full Restore if HP is below 25% or has status/confusion
priority = preferFullRestore ? 3 : 7
# Raise priority if stock is low to discourage waste
priority += 5 if itemQuantity <= 2
usableHPItems.push([i, priority, battler.totalhp])
usableStatusItems.push([i, preferFullRestore ? 3 : 9])
end
next
end
# Log single status-curing items
if oneStatusItems.include?(i)
# Single-status curers
if oneStatusItems.include?(i) && battler.status != :NONE
usableStatusItems.push([i, 5])
next
end
# Log Full Heal-type items
if allStatusItems.include?(i)
# Full heal-type items
if allStatusItems.include?(i) && battler.status != :NONE
usableStatusItems.push([i, 7])
next
end
# Log stat-raising items
# Stat-raising items
if xItems[i]
data = xItems[i]
usableXItems.push([i, battler.stages[data[0]], data[1]])
next
end
end
# Prioritise using a HP restoration item
if usableHPItems.length>0 && (battler.hp<=battler.totalhp/4 ||
(battler.hp<=battler.totalhp/2 && pbAIRandom(100)<30))
usableHPItems.sort! { |a,b| (a[1]==b[1]) ? a[2]<=>b[2] : a[1]<=>b[1] }
# Prioritise using HP items (including Full Restore if really needed)
if usableHPItems.length > 0 && (battler.hp <= battler.totalhp / 4 ||
(battler.hp <= battler.totalhp / 2 && pbAIRandom(100) < 30))
usableHPItems.sort! { |a, b| (a[1] == b[1]) ? a[2] <=> b[2] : a[1] <=> b[1] }
prevItem = nil
usableHPItems.each do |i|
return i[0], idxTarget if i[2]>=losthp
prevItem = i
end
return prevItem[0], idxTarget
end
# Next prioritise using a status-curing item
if usableStatusItems.length>0 && pbAIRandom(100)<40
usableStatusItems.sort! { |a,b| a[1]<=>b[1] }
return usableStatusItems[0][0], idxTarget
end
# Next try using an X item
if usableXItems.length>0 && pbAIRandom(100)<30
usableXItems.sort! { |a,b| (a[1]==b[1]) ? a[2]<=>b[2] : a[1]<=>b[1] }
prevItem = nil
usableXItems.each do |i|
break if prevItem && i[1]>prevItem[1]
return i[0], idxTarget if i[1]+i[2]>=6
return i[0], idxTarget if i[2] >= losthp
prevItem = i
end
return prevItem[0], idxTarget

View File

@@ -4,77 +4,77 @@ class PokeBattle_AI
# chosen)
#=============================================================================
def pbChooseMoves(idxBattler)
user = @battle.battlers[idxBattler]
user = @battle.battlers[idxBattler]
wildBattler = (@battle.wildBattle? && @battle.opposes?(idxBattler))
skill = 0
skill = 0
if !wildBattler
skill = @battle.pbGetOwnerFromBattlerIndex(user.index).skill_level || 0
skill = @battle.pbGetOwnerFromBattlerIndex(user.index).skill_level || 0
end
# Get scores and targets for each move
# NOTE: A move is only added to the choices array if it has a non-zero
# score.
choices = []
user.eachMoveWithIndex do |_m,i|
next if !@battle.pbCanChooseMove?(idxBattler,i,false)
choices = []
user.eachMoveWithIndex do |_m, i|
next if !@battle.pbCanChooseMove?(idxBattler, i, false)
if wildBattler
pbRegisterMoveWild(user,i,choices)
pbRegisterMoveWild(user, i, choices)
else
pbRegisterMoveTrainer(user,i,choices,skill)
pbRegisterMoveTrainer(user, i, choices, skill)
end
end
# Figure out useful information about the choices
totalScore = 0
maxScore = 0
maxScore = 0
choices.each do |c|
totalScore += c[1]
maxScore = c[1] if maxScore<c[1]
maxScore = c[1] if maxScore < c[1]
end
# Log the available choices
if $INTERNAL
logMsg = "[AI] Move choices for #{user.pbThis(true)} (#{user.index}): "
choices.each_with_index do |c,i|
choices.each_with_index do |c, i|
logMsg += "#{user.moves[c[0]].name}=#{c[1]}"
logMsg += " (target #{c[2]})" if c[2]>=0
logMsg += ", " if i<choices.length-1
logMsg += " (target #{c[2]})" if c[2] >= 0
logMsg += ", " if i < choices.length - 1
end
PBDebug.log(logMsg)
end
# Find any preferred moves and just choose from them
if !wildBattler && skill>=PBTrainerAI.highSkill && maxScore>100
if !wildBattler && skill >= PBTrainerAI.highSkill && maxScore > 100
stDev = pbStdDev(choices)
if stDev>=40 && pbAIRandom(100)<90
if stDev >= 40 && pbAIRandom(100) < 90
preferredMoves = []
choices.each do |c|
next if c[1]<200 && c[1]<maxScore*0.8
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
preferredMoves.push(c) if c[1] == maxScore # Doubly prefer the best move
end
if preferredMoves.length>0
if preferredMoves.length > 0
m = preferredMoves[pbAIRandom(preferredMoves.length)]
PBDebug.log("[AI] #{user.pbThis} (#{user.index}) prefers #{user.moves[m[0]].name}")
@battle.pbRegisterMove(idxBattler,m[0],false)
@battle.pbRegisterTarget(idxBattler,m[2]) if m[2]>=0
@battle.pbRegisterMove(idxBattler, m[0], false)
@battle.pbRegisterTarget(idxBattler, 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>=PBTrainerAI.highSkill
if !wildBattler && skill >= PBTrainerAI.highSkill
badMoves = false
if (maxScore<=20 && user.turnCount>2) ||
(maxScore<=40 && user.turnCount>5)
badMoves = true if pbAIRandom(100)<80
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
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
badMoves = false if badMoves && pbAIRandom(100) < 10
end
if badMoves && pbEnemyShouldWithdrawEx?(idxBattler,true)
if badMoves && pbEnemyShouldWithdrawEx?(idxBattler, true)
if $INTERNAL
PBDebug.log("[AI] #{user.pbThis} (#{user.index}) will switch due to terrible moves")
end
@@ -82,13 +82,13 @@ class PokeBattle_AI
end
end
# If there are no calculated choices, pick one at random
if choices.length==0
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?(idxBattler,i,false)
choices.push([i,100,-1]) # Move index, score, target
user.eachMoveWithIndex do |_m, i|
next if !@battle.pbCanChooseMove?(idxBattler, 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
if choices.length == 0 # No moves are physically possible to use; use Struggle
@battle.pbAutoChooseMove(user.index)
end
end
@@ -96,9 +96,9 @@ class PokeBattle_AI
randNum = pbAIRandom(totalScore)
choices.each do |c|
randNum -= c[1]
next if randNum>=0
@battle.pbRegisterMove(idxBattler,c[0],false)
@battle.pbRegisterTarget(idxBattler,c[2]) if c[2]>=0
next if randNum >= 0
@battle.pbRegisterMove(idxBattler, c[0], false)
@battle.pbRegisterTarget(idxBattler, c[2]) if c[2] >= 0
break
end
# Log the result
@@ -111,40 +111,40 @@ class PokeBattle_AI
# Get scores for the given move against each possible target
#=============================================================================
# Wild Pokémon choose their moves randomly.
def pbRegisterMoveWild(_user,idxMove,choices)
choices.push([idxMove,100,-1]) # Move index, score, target
def pbRegisterMoveWild(_user, idxMove, choices)
choices.push([idxMove, 100, -1]) # Move index, score, target
end
# Trainer Pokémon calculate how much they want to use each of their moves.
def pbRegisterMoveTrainer(user,idxMove,choices,skill)
def pbRegisterMoveTrainer(user, idxMove, choices, skill)
move = user.moves[idxMove]
target_data = move.pbTarget(user)
if target_data.num_targets > 1
# If move affects multiple battlers and you don't choose a particular one
totalScore = 0
@battle.eachBattler do |b|
next if !@battle.pbMoveCanTarget?(user.index,b.index,target_data)
score = pbGetMoveScore(move,user,b,skill)
next if !@battle.pbMoveCanTarget?(user.index, b.index, target_data)
score = pbGetMoveScore(move, user, b, skill)
totalScore += ((user.opposes?(b)) ? score : -score)
end
choices.push([idxMove,totalScore,-1]) if totalScore>0
choices.push([idxMove, totalScore, -1]) if totalScore > 0
elsif target_data.num_targets == 0
# If move has no targets, affects the user, a side or the whole field
score = pbGetMoveScore(move,user,user,skill)
choices.push([idxMove,score,-1]) if score>0
score = pbGetMoveScore(move, user, user, skill)
choices.push([idxMove, score, -1]) if score > 0
else
# If move affects one battler and you have to choose which one
scoresAndTargets = []
@battle.eachBattler do |b|
next if !@battle.pbMoveCanTarget?(user.index,b.index,target_data)
next if !@battle.pbMoveCanTarget?(user.index, b.index, target_data)
next if target_data.targets_foe && !user.opposes?(b)
score = pbGetMoveScore(move,user,b,skill)
scoresAndTargets.push([score,b.index]) if score>0
score = pbGetMoveScore(move, user, b, skill)
scoresAndTargets.push([score, b.index]) if score > 0
end
if scoresAndTargets.length>0
if scoresAndTargets.length > 0
# Get the one best target for the move
scoresAndTargets.sort! { |a,b| b[0]<=>a[0] }
choices.push([idxMove,scoresAndTargets[0][0],scoresAndTargets[0][1]])
scoresAndTargets.sort! { |a, b| b[0] <=> a[0] }
choices.push([idxMove, scoresAndTargets[0][0], scoresAndTargets[0][1]])
end
end
end
@@ -152,38 +152,38 @@ class PokeBattle_AI
#=============================================================================
# Get a score for the given move being used against the given target
#=============================================================================
def pbGetMoveScore(move,user,target,skill=100)
skill = PBTrainerAI.minimumSkill if skill<PBTrainerAI.minimumSkill
def pbGetMoveScore(move, user, target, skill = 100)
skill = PBTrainerAI.minimumSkill if skill < PBTrainerAI.minimumSkill
score = 100
score = pbGetMoveScoreFunctionCode(score,move,user,target,skill)
score = pbGetMoveScoreFunctionCode(score, move, user, target, skill)
# A score of 0 here means it absolutely should not be used
return 0 if score<=0
if skill>=PBTrainerAI.mediumSkill
return 0 if score <= 0
if skill >= PBTrainerAI.mediumSkill
# Prefer damaging moves if AI has no more Pokémon or AI is less clever
if @battle.pbAbleNonActiveCount(user.idxOwnSide)==0
if !(skill>=PBTrainerAI.highSkill && @battle.pbAbleNonActiveCount(target.idxOwnSide)>0)
if @battle.pbAbleNonActiveCount(user.idxOwnSide) == 0
if !(skill >= PBTrainerAI.highSkill && @battle.pbAbleNonActiveCount(target.idxOwnSide) > 0)
if move.statusMove?
score /= 1.5
elsif target.hp<=target.totalhp/2
elsif target.hp <= target.totalhp / 2
score *= 1.5
end
end
end
# Don't prefer attacking the target if they'd be semi-invulnerable
if skill>=PBTrainerAI.highSkill && move.accuracy>0 &&
(target.semiInvulnerable? || target.effects[PBEffects::SkyDrop]>=0)
if skill >= PBTrainerAI.highSkill && move.accuracy > 0 &&
(target.semiInvulnerable? || target.effects[PBEffects::SkyDrop] >= 0)
miss = true
miss = false if user.hasActiveAbility?(:NOGUARD) || target.hasActiveAbility?(:NOGUARD)
if miss && pbRoughStat(user,:SPEED,skill)>pbRoughStat(target,:SPEED,skill)
if miss && pbRoughStat(user, :SPEED, skill) > pbRoughStat(target, :SPEED, skill)
# Knows what can get past semi-invulnerability
if target.effects[PBEffects::SkyDrop]>=0
if target.effects[PBEffects::SkyDrop] >= 0
miss = false if move.hitsFlyingTargets?
else
if target.inTwoTurnAttack?("0C9","0CC","0CE") # Fly, Bounce, Sky Drop
if target.inTwoTurnAttack?("0C9", "0CC", "0CE") # Fly, Bounce, Sky Drop
miss = false if move.hitsFlyingTargets?
elsif target.inTwoTurnAttack?("0CA") # Dig
elsif target.inTwoTurnAttack?("0CA") # Dig
miss = false if move.hitsDiggingTargets?
elsif target.inTwoTurnAttack?("0CB") # Dive
elsif target.inTwoTurnAttack?("0CB") # Dive
miss = false if move.hitsDivingTargets?
end
end
@@ -191,11 +191,15 @@ class PokeBattle_AI
score -= 80 if miss
end
# Pick a good move for the Choice items
if user.hasActiveItem?([:CHOICEBAND,:CHOICESPECS,:CHOICESCARF])
if move.baseDamage>=60; score += 60
elsif move.damagingMove?; score += 30
elsif move.function=="0F2"; score += 70 # Trick
else; score -= 60
if user.hasActiveItem?([:CHOICEBAND, :CHOICESPECS, :CHOICESCARF])
if move.baseDamage >= 60;
score += 60
elsif move.damagingMove?;
score += 30
elsif move.function == "0F2";
score += 70 # Trick
else
; score -= 60
end
end
# If user is asleep, prefer moves that are usable while asleep
@@ -229,17 +233,18 @@ class PokeBattle_AI
end
# Adjust score based on how much damage it can deal
if move.damagingMove?
score = pbGetMoveScoreDamage(score,move,user,target,skill)
else # Status moves
score = pbGetMoveScoreDamage(score, move, user, target, skill)
else
# Status moves
# Don't prefer attacks which don't deal damage
score -= 10
# Account for accuracy of move
accuracy = pbRoughAccuracy(move,user,target,skill)
score *= accuracy/100.0
score = 0 if score<=10 && skill>=PBTrainerAI.highSkill
accuracy = pbRoughAccuracy(move, user, target, skill)
score *= accuracy / 100.0
score = 0 if score <= 10 && skill >= PBTrainerAI.highSkill
end
score = score.to_i
score = 0 if score<0
score = 0 if score < 0
return score
end
@@ -247,27 +252,27 @@ class PokeBattle_AI
# Add to a move's score based on how much damage it will deal (as a percentage
# of the target's current HP)
#=============================================================================
def pbGetMoveScoreDamage(score,move,user,target,skill)
def pbGetMoveScoreDamage(score, move, user, target, skill)
# Don't prefer moves that are ineffective because of abilities or effects
return 0 if score<=0 || pbCheckMoveImmunity(score,move,user,target,skill)
return 0 if score <= 0 || pbCheckMoveImmunity(score, move, user, target, skill)
# Calculate how much damage the move will do (roughly)
baseDmg = pbMoveBaseDamage(move,user,target,skill)
realDamage = pbRoughDamage(move,user,target,skill,baseDmg)
baseDmg = pbMoveBaseDamage(move, user, target, skill)
realDamage = pbRoughDamage(move, user, target, skill, baseDmg)
# Account for accuracy of move
accuracy = pbRoughAccuracy(move,user,target,skill)
realDamage *= accuracy/100.0
accuracy = pbRoughAccuracy(move, user, target, skill)
realDamage *= accuracy / 100.0
# Two-turn attacks waste 2 turns to deal one lot of damage
if move.chargingTurnMove? || move.function=="0C2" # Hyper Beam
realDamage *= 2/3 # Not halved because semi-invulnerable during use or hits first turn
if move.chargingTurnMove? || move.function == "0C2" # Hyper Beam
realDamage *= 2 / 3 # Not halved because semi-invulnerable during use or hits first turn
end
# Prefer flinching external effects (note that move effects which cause
# flinching are dealt with in the function code part of score calculation)
if skill>=PBTrainerAI.mediumSkill
if skill >= PBTrainerAI.mediumSkill
if !target.hasActiveAbility?(:INNERFOCUS) &&
!target.hasActiveAbility?(:SHIELDDUST) &&
target.effects[PBEffects::Substitute]==0
!target.hasActiveAbility?(:SHIELDDUST) &&
target.effects[PBEffects::Substitute] == 0
canFlinch = false
if move.canKingsRock? && user.hasActiveItem?([:KINGSROCK,:RAZORFANG])
if move.canKingsRock? && user.hasActiveItem?([:KINGSROCK, :RAZORFANG])
canFlinch = true
end
if user.hasActiveAbility?(:STENCH) && !move.flinchingMove?
@@ -277,14 +282,14 @@ class PokeBattle_AI
end
end
# Convert damage to percentage of target's remaining HP
damagePercentage = realDamage*100.0/target.hp
damagePercentage = realDamage * 100.0 / target.hp
# Don't prefer weak attacks
# damagePercentage /= 2 if damagePercentage<20
# damagePercentage /= 2 if damagePercentage<20
# Prefer damaging attack if level difference is significantly high
damagePercentage *= 1.2 if user.level-10>target.level
damagePercentage *= 1.2 if user.level - 10 > target.level
# Adjust score
damagePercentage = 120 if damagePercentage>120 # Treat all lethal moves the same
damagePercentage += 40 if damagePercentage>100 # Prefer moves likely to be lethal
damagePercentage = 120 if damagePercentage > 120 # Treat all lethal moves the same
damagePercentage += 40 if damagePercentage > 100 # Prefer moves likely to be lethal
score += damagePercentage.to_i
return score
end