mirror of
https://github.com/infinitefusion/infinitefusion-e18.git
synced 2025-12-10 06:34:59 +00:00
Added more debug logging to AI, fixed some bugs in AI
This commit is contained in:
@@ -48,6 +48,27 @@ module PBDebug
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.log_ai(msg)
|
||||||
|
if $DEBUG && $INTERNAL
|
||||||
|
msg = "[AI] " + msg
|
||||||
|
echoln msg.gsub("%", "%%")
|
||||||
|
@@log.push(msg + "\r\n")
|
||||||
|
PBDebug.flush # if @@log.length > 1024
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.log_score_change(amt, msg)
|
||||||
|
return if amt == 0
|
||||||
|
if $DEBUG && $INTERNAL
|
||||||
|
sign = (amt > 0) ? "+" : "-"
|
||||||
|
amt_text = sprintf("%3d", amt.abs)
|
||||||
|
msg = " #{sign}#{amt_text}: #{msg}"
|
||||||
|
echoln msg.gsub("%", "%%")
|
||||||
|
@@log.push(msg + "\r\n")
|
||||||
|
PBDebug.flush # if @@log.length > 1024
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def self.dump(msg)
|
def self.dump(msg)
|
||||||
if $DEBUG && $INTERNAL
|
if $DEBUG && $INTERNAL
|
||||||
File.open("Data/dumplog.txt", "a+b") { |f| f.write("#{msg}\r\n") }
|
File.open("Data/dumplog.txt", "a+b") { |f| f.write("#{msg}\r\n") }
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ class Battle
|
|||||||
# For choosing a replacement Pokémon when prompted in the middle of other
|
# For choosing a replacement Pokémon when prompted in the middle of other
|
||||||
# things happening (U-turn, Baton Pass, in def pbEORSwitch).
|
# things happening (U-turn, Baton Pass, in def pbEORSwitch).
|
||||||
def pbSwitchInBetween(idxBattler, checkLaxOnly = false, canCancel = false)
|
def pbSwitchInBetween(idxBattler, checkLaxOnly = false, canCancel = false)
|
||||||
return pbPartyScreen(idxBattler, checkLaxOnly, canCancel) if pbOwnedByPlayer?(idxBattler)
|
return pbPartyScreen(idxBattler, checkLaxOnly, canCancel) if !@controlPlayer && pbOwnedByPlayer?(idxBattler)
|
||||||
return @battleAI.pbDefaultChooseNewEnemy(idxBattler, pbParty(idxBattler))
|
return @battleAI.pbDefaultChooseNewEnemy(idxBattler, pbParty(idxBattler))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -207,7 +207,7 @@ class Battle
|
|||||||
next if !@battlers[idxBattler] || pbOwnedByPlayer?(idxBattler) != isPlayer
|
next if !@battlers[idxBattler] || pbOwnedByPlayer?(idxBattler) != isPlayer
|
||||||
if @choices[idxBattler][0] != :None || !pbCanShowCommands?(idxBattler)
|
if @choices[idxBattler][0] != :None || !pbCanShowCommands?(idxBattler)
|
||||||
# Action is forced, can't choose one
|
# Action is forced, can't choose one
|
||||||
PBDebug.log("[AI] #{@battlers[idxBattler].pbThis} (#{idxBattler}) is forced into using a multi-turn move")
|
PBDebug.log_ai("#{@battlers[idxBattler].pbThis} (#{idxBattler}) is forced to use a multi-turn move")
|
||||||
next
|
next
|
||||||
end
|
end
|
||||||
# AI controls this battler
|
# AI controls this battler
|
||||||
|
|||||||
@@ -187,7 +187,6 @@ class Battle
|
|||||||
b.effects[PBEffects::Rage] = false if !pbChoseMoveFunctionCode?(i, "StartRaiseUserAtk1WhenDamaged")
|
b.effects[PBEffects::Rage] = false if !pbChoseMoveFunctionCode?(i, "StartRaiseUserAtk1WhenDamaged")
|
||||||
end
|
end
|
||||||
# Calculate move order for this round
|
# Calculate move order for this round
|
||||||
PBDebug.log("")
|
|
||||||
pbCalculatePriority(true)
|
pbCalculatePriority(true)
|
||||||
PBDebug.log("")
|
PBDebug.log("")
|
||||||
# Perform actions
|
# Perform actions
|
||||||
|
|||||||
@@ -100,11 +100,18 @@ end
|
|||||||
# Poisons the target and decreases its Speed by 1 stage. (Toxic Thread)
|
# Poisons the target and decreases its Speed by 1 stage. (Toxic Thread)
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
class Battle::Move::PoisonTargetLowerTargetSpeed1 < Battle::Move
|
class Battle::Move::PoisonTargetLowerTargetSpeed1 < Battle::Move
|
||||||
|
attr_reader :statDown
|
||||||
|
|
||||||
|
def initialize(battle, move)
|
||||||
|
super
|
||||||
|
@statDown = [:SPEED, 1]
|
||||||
|
end
|
||||||
|
|
||||||
def canMagicCoat?; return true; end
|
def canMagicCoat?; return true; end
|
||||||
|
|
||||||
def pbFailsAgainstTarget?(user, target, show_message)
|
def pbFailsAgainstTarget?(user, target, show_message)
|
||||||
if !target.pbCanPoison?(user, false, self) &&
|
if !target.pbCanPoison?(user, false, self) &&
|
||||||
!target.pbCanLowerStatStage?(:SPEED, user, self)
|
!target.pbCanLowerStatStage?(@statDown[0], user, self)
|
||||||
@battle.pbDisplay(_INTL("But it failed!")) if show_message
|
@battle.pbDisplay(_INTL("But it failed!")) if show_message
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
@@ -113,8 +120,8 @@ class Battle::Move::PoisonTargetLowerTargetSpeed1 < Battle::Move
|
|||||||
|
|
||||||
def pbEffectAgainstTarget(user, target)
|
def pbEffectAgainstTarget(user, target)
|
||||||
target.pbPoison(user) if target.pbCanPoison?(user, false, self)
|
target.pbPoison(user) if target.pbCanPoison?(user, false, self)
|
||||||
if target.pbCanLowerStatStage?(:SPEED, user, self)
|
if target.pbCanLowerStatStage?(@statDown[0], user, self)
|
||||||
target.pbLowerStatStage(:SPEED, 1, user)
|
target.pbLowerStatStage(@statDown[0], @statDown[1], user)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -334,13 +334,20 @@ end
|
|||||||
# (Skull Bash)
|
# (Skull Bash)
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
class Battle::Move::TwoTurnAttackChargeRaiseUserDefense1 < Battle::Move::TwoTurnMove
|
class Battle::Move::TwoTurnAttackChargeRaiseUserDefense1 < Battle::Move::TwoTurnMove
|
||||||
|
attr_reader :statUp
|
||||||
|
|
||||||
|
def initialize(battle, move)
|
||||||
|
super
|
||||||
|
@statUp = [:DEFENSE, 1]
|
||||||
|
end
|
||||||
|
|
||||||
def pbChargingTurnMessage(user, targets)
|
def pbChargingTurnMessage(user, targets)
|
||||||
@battle.pbDisplay(_INTL("{1} tucked in its head!", user.pbThis))
|
@battle.pbDisplay(_INTL("{1} tucked in its head!", user.pbThis))
|
||||||
end
|
end
|
||||||
|
|
||||||
def pbChargingTurnEffect(user, target)
|
def pbChargingTurnEffect(user, target)
|
||||||
if user.pbCanRaiseStatStage?(:DEFENSE, user, self)
|
if user.pbCanRaiseStatStage?(@statUp[0], user, self)
|
||||||
user.pbRaiseStatStage(:DEFENSE, 1, user)
|
user.pbRaiseStatStage(@statUp[0], @statUp[1], user)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -109,6 +109,13 @@ end
|
|||||||
# it). (Strength Sap)
|
# it). (Strength Sap)
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
class Battle::Move::HealUserByTargetAttackLowerTargetAttack1 < Battle::Move
|
class Battle::Move::HealUserByTargetAttackLowerTargetAttack1 < Battle::Move
|
||||||
|
attr_reader :statDown
|
||||||
|
|
||||||
|
def initialize(battle, move)
|
||||||
|
super
|
||||||
|
@statDown = [:ATTACK, 1]
|
||||||
|
end
|
||||||
|
|
||||||
def healingMove?; return true; end
|
def healingMove?; return true; end
|
||||||
def canMagicCoat?; return true; end
|
def canMagicCoat?; return true; end
|
||||||
|
|
||||||
@@ -119,11 +126,11 @@ class Battle::Move::HealUserByTargetAttackLowerTargetAttack1 < Battle::Move
|
|||||||
# works even if the stat stage cannot be changed due to an ability or
|
# works even if the stat stage cannot be changed due to an ability or
|
||||||
# other effect.
|
# other effect.
|
||||||
if !@battle.moldBreaker && target.hasActiveAbility?(:CONTRARY)
|
if !@battle.moldBreaker && target.hasActiveAbility?(:CONTRARY)
|
||||||
if target.statStageAtMax?(:ATTACK)
|
if target.statStageAtMax?(@statDown[0])
|
||||||
@battle.pbDisplay(_INTL("But it failed!")) if show_message
|
@battle.pbDisplay(_INTL("But it failed!")) if show_message
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
elsif target.statStageAtMin?(:ATTACK)
|
elsif target.statStageAtMin?(@statDown[0])
|
||||||
@battle.pbDisplay(_INTL("But it failed!")) if show_message
|
@battle.pbDisplay(_INTL("But it failed!")) if show_message
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
@@ -135,11 +142,11 @@ class Battle::Move::HealUserByTargetAttackLowerTargetAttack1 < Battle::Move
|
|||||||
stageMul = [2, 2, 2, 2, 2, 2, 2, 3, 4, 5, 6, 7, 8]
|
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]
|
stageDiv = [8, 7, 6, 5, 4, 3, 2, 2, 2, 2, 2, 2, 2]
|
||||||
atk = target.attack
|
atk = target.attack
|
||||||
atkStage = target.stages[:ATTACK] + 6
|
atkStage = target.stages[@statDown[0]] + 6
|
||||||
healAmt = (atk.to_f * stageMul[atkStage] / stageDiv[atkStage]).floor
|
healAmt = (atk.to_f * stageMul[atkStage] / stageDiv[atkStage]).floor
|
||||||
# Reduce target's Attack stat
|
# Reduce target's Attack stat
|
||||||
if target.pbCanLowerStatStage?(:ATTACK, user, self)
|
if target.pbCanLowerStatStage?(@statDown[0], user, self)
|
||||||
target.pbLowerStatStage(:ATTACK, 1, user)
|
target.pbLowerStatStage(@statDown[0], @statDown[1], user)
|
||||||
end
|
end
|
||||||
# Heal user
|
# Heal user
|
||||||
if target.hasActiveAbility?(:LIQUIDOOZE, true)
|
if target.hasActiveAbility?(:LIQUIDOOZE, true)
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ class Battle::AI
|
|||||||
@battle.pbRegisterMegaEvolution(idxBattler) if pbEnemyShouldMegaEvolve?
|
@battle.pbRegisterMegaEvolution(idxBattler) if pbEnemyShouldMegaEvolve?
|
||||||
choices = pbGetMoveScores
|
choices = pbGetMoveScores
|
||||||
pbChooseMove(choices)
|
pbChooseMove(choices)
|
||||||
|
PBDebug.log("")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
class Battle::AI
|
class Battle::AI
|
||||||
#=============================================================================
|
#=============================================================================
|
||||||
# Decide whether the opponent should use an item on the Pokémon
|
# Decide whether the opponent should use an item on the Pokémon
|
||||||
|
# TODO: Maybe don't cure a status problem if the Pokémon has an ability or
|
||||||
|
# something that makes it benefit from having that problem.
|
||||||
#=============================================================================
|
#=============================================================================
|
||||||
def pbEnemyShouldUseItem?
|
def pbEnemyShouldUseItem?
|
||||||
item = nil
|
item = nil
|
||||||
@@ -14,7 +16,7 @@ class Battle::AI
|
|||||||
end
|
end
|
||||||
# Register use of item
|
# Register use of item
|
||||||
@battle.pbRegisterItem(@user.index, item, idxTarget)
|
@battle.pbRegisterItem(@user.index, item, idxTarget)
|
||||||
PBDebug.log("[AI] #{@user.pbThis} (#{@user.index}) will use item #{GameData::Item.get(item).name}")
|
PBDebug.log_ai("#{@user.name} will use item #{GameData::Item.get(item).name}")
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -133,12 +133,11 @@ class Battle::AI
|
|||||||
end
|
end
|
||||||
if list.length > 0
|
if list.length > 0
|
||||||
if batonPass >= 0 && @battle.pbRegisterMove(battler.index, batonPass, false)
|
if batonPass >= 0 && @battle.pbRegisterMove(battler.index, batonPass, false)
|
||||||
PBDebug.log("[AI] #{battler.pbThis} (#{battler.index}) will use Baton Pass to avoid Perish Song")
|
PBDebug.log_ai("#{@user.name} will use Baton Pass to avoid Perish Song")
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
if @battle.pbRegisterSwitch(battler.index, list[0])
|
if @battle.pbRegisterSwitch(battler.index, list[0])
|
||||||
PBDebug.log("[AI] #{battler.pbThis} (#{battler.index}) will switch with " +
|
PBDebug.log_ai("#{@user.name} will switch with #{@battle.pbParty(battler.index)[list[0]].name}")
|
||||||
@battle.pbParty(battler.index)[list[0]].name)
|
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -23,16 +23,18 @@ class Battle::AI
|
|||||||
# Unchoosable moves aren't considered
|
# Unchoosable moves aren't considered
|
||||||
if !@battle.pbCanChooseMove?(@user.index, idxMove, false)
|
if !@battle.pbCanChooseMove?(@user.index, idxMove, false)
|
||||||
if move.pp == 0 && move.total_pp > 0
|
if move.pp == 0 && move.total_pp > 0
|
||||||
PBDebug.log("[AI] #{@user.battler.pbThis} (#{@user.index}) cannot use move #{move.name} as it has no PP left")
|
PBDebug.log_ai("#{@user.name} cannot use #{move.name} (no PP left)")
|
||||||
else
|
else
|
||||||
PBDebug.log("[AI] #{@user.battler.pbThis} (#{@user.index}) cannot choose to use #{move.name}")
|
PBDebug.log_ai("#{@user.name} cannot choose to use #{move.name}")
|
||||||
end
|
end
|
||||||
next
|
next
|
||||||
end
|
end
|
||||||
|
PBDebug.log_ai("#{@user.name} is considering using #{move.name}...")
|
||||||
# Set up move in class variables
|
# Set up move in class variables
|
||||||
set_up_move_check(move)
|
set_up_move_check(move)
|
||||||
# Predict whether the move will fail (generally)
|
# Predict whether the move will fail (generally)
|
||||||
if @trainer.has_skill_flag?("PredictMoveFailure") && pbPredictMoveFailure
|
if @trainer.has_skill_flag?("PredictMoveFailure") && pbPredictMoveFailure
|
||||||
|
PBDebug.log_score_change(MOVE_FAIL_SCORE - MOVE_BASE_SCORE, "move will fail")
|
||||||
add_move_to_choices(choices, idxMove, MOVE_FAIL_SCORE)
|
add_move_to_choices(choices, idxMove, MOVE_FAIL_SCORE)
|
||||||
next
|
next
|
||||||
end
|
end
|
||||||
@@ -49,6 +51,7 @@ class Battle::AI
|
|||||||
# TODO: Figure out first which targets are valid. Includes the call to
|
# TODO: Figure out first which targets are valid. Includes the call to
|
||||||
# pbMoveCanTarget?, but also includes move-redirecting effects
|
# pbMoveCanTarget?, but also includes move-redirecting effects
|
||||||
# like Lightning Rod. Skip any battlers that can't be targeted.
|
# like Lightning Rod. Skip any battlers that can't be targeted.
|
||||||
|
num_targets = 0
|
||||||
@battle.allBattlers.each do |b|
|
@battle.allBattlers.each do |b|
|
||||||
next if !@battle.pbMoveCanTarget?(@user.battler.index, b.index, target_data)
|
next if !@battle.pbMoveCanTarget?(@user.battler.index, b.index, target_data)
|
||||||
# TODO: Should this sometimes consider targeting an ally? See def
|
# TODO: Should this sometimes consider targeting an ally? See def
|
||||||
@@ -57,7 +60,9 @@ class Battle::AI
|
|||||||
score = MOVE_BASE_SCORE
|
score = MOVE_BASE_SCORE
|
||||||
PBDebug.logonerr { score = pbGetMoveScore([b]) }
|
PBDebug.logonerr { score = pbGetMoveScore([b]) }
|
||||||
add_move_to_choices(choices, idxMove, score, b.index)
|
add_move_to_choices(choices, idxMove, score, b.index)
|
||||||
|
num_targets += 1
|
||||||
end
|
end
|
||||||
|
PBDebug.log(" no valid targets") if num_targets == 0
|
||||||
else # Multiple targets at once
|
else # Multiple targets at once
|
||||||
# Includes: AllAllies, AllBattlers, AllFoes, AllNearFoes, AllNearOthers, UserAndAllies
|
# Includes: AllAllies, AllBattlers, AllFoes, AllNearFoes, AllNearOthers, UserAndAllies
|
||||||
targets = []
|
targets = []
|
||||||
@@ -100,7 +105,7 @@ class Battle::AI
|
|||||||
move = Battle::Move.from_pokemon_move(@battle, Pokemon::Move.new(target.battler.lastRegularMoveUsed))
|
move = Battle::Move.from_pokemon_move(@battle, Pokemon::Move.new(target.battler.lastRegularMoveUsed))
|
||||||
end
|
end
|
||||||
when "UseMoveDependingOnEnvironment"
|
when "UseMoveDependingOnEnvironment"
|
||||||
move.move.pbOnStartUse(@user.battler, []) # Determine which move is used instead
|
move.pbOnStartUse(@user.battler, []) # Determine which move is used instead
|
||||||
move = Battle::Move.from_pokemon_move(@battle, Pokemon::Move.new(move.npMove))
|
move = Battle::Move.from_pokemon_move(@battle, Pokemon::Move.new(move.npMove))
|
||||||
end
|
end
|
||||||
@move.set_up(move, @user)
|
@move.set_up(move, @user)
|
||||||
@@ -197,13 +202,18 @@ class Battle::AI
|
|||||||
end
|
end
|
||||||
# Score based on how many targets were affected
|
# Score based on how many targets were affected
|
||||||
if affected_targets == 0 && @trainer.has_skill_flag?("PredictMoveFailure")
|
if affected_targets == 0 && @trainer.has_skill_flag?("PredictMoveFailure")
|
||||||
return MOVE_FAIL_SCORE if !@move.move.worksWithNoTargets?
|
if !@move.move.worksWithNoTargets?
|
||||||
|
PBDebug.log_score_change(MOVE_FAIL_SCORE - MOVE_BASE_SCORE, "move will fail")
|
||||||
|
return MOVE_FAIL_SCORE
|
||||||
|
end
|
||||||
else
|
else
|
||||||
# TODO: Can this accounting for multiple targets be improved somehow?
|
# TODO: Can this accounting for multiple targets be improved somehow?
|
||||||
score /= affected_targets if affected_targets > 1 # Average the score against multiple targets
|
score /= affected_targets if affected_targets > 1 # Average the score against multiple targets
|
||||||
# Bonus for affecting multiple targets
|
# Bonus for affecting multiple targets
|
||||||
if @trainer.has_skill_flag?("PreferMultiTargetMoves") && affected_targets > 1
|
if @trainer.has_skill_flag?("PreferMultiTargetMoves") && affected_targets > 1
|
||||||
|
old_score = score
|
||||||
score += (affected_targets - 1) * 10
|
score += (affected_targets - 1) * 10
|
||||||
|
PBDebug.log_score_change(score - old_score, "affects multiple battlers")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -212,8 +222,10 @@ class Battle::AI
|
|||||||
# Self-Destruct)
|
# Self-Destruct)
|
||||||
if @trainer.has_skill_flag?("ScoreMoves")
|
if @trainer.has_skill_flag?("ScoreMoves")
|
||||||
# Modify the score according to the move's effect
|
# Modify the score according to the move's effect
|
||||||
|
old_score = score
|
||||||
score = Battle::AI::Handlers.apply_move_effect_score(@move.function,
|
score = Battle::AI::Handlers.apply_move_effect_score(@move.function,
|
||||||
score, @move, @user, self, @battle)
|
score, @move, @user, self, @battle)
|
||||||
|
PBDebug.log_score_change(score - old_score, "function code modifier (generic)")
|
||||||
# Modify the score according to various other effects
|
# Modify the score according to various other effects
|
||||||
score = Battle::AI::Handlers.apply_general_move_score_modifiers(
|
score = Battle::AI::Handlers.apply_general_move_score_modifiers(
|
||||||
score, @move, @user, self, @battle)
|
score, @move, @user, self, @battle)
|
||||||
@@ -240,15 +252,18 @@ class Battle::AI
|
|||||||
#=============================================================================
|
#=============================================================================
|
||||||
def pbGetMoveScoreAgainstTarget
|
def pbGetMoveScoreAgainstTarget
|
||||||
# Predict whether the move will fail against the target
|
# Predict whether the move will fail against the target
|
||||||
if @trainer.has_skill_flag?("PredictMoveFailure")
|
if @trainer.has_skill_flag?("PredictMoveFailure") && pbPredictMoveFailureAgainstTarget
|
||||||
return -1 if pbPredictMoveFailureAgainstTarget
|
PBDebug.log(" move will not affect #{@target.name}")
|
||||||
|
return -1
|
||||||
end
|
end
|
||||||
# Score the move
|
# Score the move
|
||||||
score = MOVE_BASE_SCORE
|
score = MOVE_BASE_SCORE
|
||||||
if @trainer.has_skill_flag?("ScoreMoves")
|
if @trainer.has_skill_flag?("ScoreMoves")
|
||||||
# Modify the score according to the move's effect against the target
|
# Modify the score according to the move's effect against the target
|
||||||
|
old_score = score
|
||||||
score = Battle::AI::Handlers.apply_move_effect_against_target_score(@move.function,
|
score = Battle::AI::Handlers.apply_move_effect_against_target_score(@move.function,
|
||||||
MOVE_BASE_SCORE, @move, @user, @target, self, @battle)
|
MOVE_BASE_SCORE, @move, @user, @target, self, @battle)
|
||||||
|
PBDebug.log_score_change(score - old_score, "function code modifier (against target)")
|
||||||
# Modify the score according to various other effects against the target
|
# Modify the score according to various other effects against the target
|
||||||
score = Battle::AI::Handlers.apply_general_move_against_target_score_modifiers(
|
score = Battle::AI::Handlers.apply_general_move_against_target_score_modifiers(
|
||||||
score, @move, @user, @target, self, @battle)
|
score, @move, @user, @target, self, @battle)
|
||||||
@@ -256,9 +271,14 @@ class Battle::AI
|
|||||||
# Add the score against the target to the overall score
|
# Add the score against the target to the overall score
|
||||||
target_data = @move.pbTarget(@user.battler)
|
target_data = @move.pbTarget(@user.battler)
|
||||||
if target_data.targets_foe && !@target.opposes?(@user) && @target.index != @user.index
|
if target_data.targets_foe && !@target.opposes?(@user) && @target.index != @user.index
|
||||||
return -1 if score == MOVE_USELESS_SCORE
|
if score == MOVE_USELESS_SCORE
|
||||||
|
PBDebug.log(" move is useless against #{@target.name}")
|
||||||
|
return -1
|
||||||
|
end
|
||||||
# TODO: Is this reversal of the score okay?
|
# TODO: Is this reversal of the score okay?
|
||||||
|
old_score = score
|
||||||
score = 175 - score
|
score = 175 - score
|
||||||
|
PBDebug.log_score_change(score - old_score, "score inverted (move targets ally but can target foe)")
|
||||||
end
|
end
|
||||||
return score
|
return score
|
||||||
end
|
end
|
||||||
@@ -272,7 +292,7 @@ class Battle::AI
|
|||||||
# If no moves can be chosen, auto-choose a move or Struggle
|
# If no moves can be chosen, auto-choose a move or Struggle
|
||||||
if choices.length == 0
|
if choices.length == 0
|
||||||
@battle.pbAutoChooseMove(user_battler.index)
|
@battle.pbAutoChooseMove(user_battler.index)
|
||||||
PBDebug.log("[AI] #{user_battler.pbThis} (#{user_battler.index}) will auto-use a move or Struggle")
|
PBDebug.log_ai("#{@user.name} will auto-use a move or Struggle")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
# Figure out useful information about the choices
|
# Figure out useful information about the choices
|
||||||
@@ -289,9 +309,10 @@ class Battle::AI
|
|||||||
badMoves = choices.none? { |c| user_battler.moves[c[0]].damagingMove? }
|
badMoves = choices.none? { |c| user_battler.moves[c[0]].damagingMove? }
|
||||||
badMoves = false if badMoves && pbAIRandom(100) < 10
|
badMoves = false if badMoves && pbAIRandom(100) < 10
|
||||||
end
|
end
|
||||||
if badMoves && pbEnemyShouldWithdrawEx?(true)
|
if badMoves
|
||||||
PBDebug.log("[AI] #{user_battler.pbThis} (#{user_battler.index}) will switch due to terrible moves")
|
PBDebug.log_ai("#{@user.name} wants to switch due to terrible moves")
|
||||||
return
|
return if pbEnemyShouldWithdrawEx?(true)
|
||||||
|
PBDebug.log_ai("#{@user.name} won't switch after all")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
# Calculate a minimum score threshold and reduce all move scores by it
|
# Calculate a minimum score threshold and reduce all move scores by it
|
||||||
@@ -300,12 +321,12 @@ class Battle::AI
|
|||||||
total_score = choices.sum { |c| c[3] }
|
total_score = choices.sum { |c| c[3] }
|
||||||
# Log the available choices
|
# Log the available choices
|
||||||
if $INTERNAL
|
if $INTERNAL
|
||||||
PBDebug.log("[AI] Move choices for #{user_battler.pbThis(true)} (#{user_battler.index}):")
|
PBDebug.log_ai("Move choices for #{@user.name}:")
|
||||||
choices.each_with_index do |c, i|
|
choices.each_with_index do |c, i|
|
||||||
chance = sprintf("%5.1f", (c[3] > 0) ? 100.0 * c[3] / total_score : 0)
|
chance = sprintf("%5.1f", (c[3] > 0) ? 100.0 * c[3] / total_score : 0)
|
||||||
log_msg = " * #{chance}% chance: #{user_battler.moves[c[0]].name}"
|
log_msg = " * #{chance}% to use #{user_battler.moves[c[0]].name}"
|
||||||
log_msg += " (against target #{c[2]})" if c[2] >= 0
|
log_msg += " (target #{c[2]})" if c[2] >= 0
|
||||||
log_msg += " = score #{c[1]}"
|
log_msg += ": score #{c[1]}"
|
||||||
PBDebug.log(log_msg)
|
PBDebug.log(log_msg)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -320,7 +341,12 @@ class Battle::AI
|
|||||||
end
|
end
|
||||||
# Log the result
|
# Log the result
|
||||||
if @battle.choices[user_battler.index][2]
|
if @battle.choices[user_battler.index][2]
|
||||||
PBDebug.log(" => will use #{@battle.choices[user_battler.index][2].name}")
|
move_name = @battle.choices[user_battler.index][2].name
|
||||||
|
if @battle.choices[user_battler.index][3] >= 0
|
||||||
|
PBDebug.log(" => will use #{move_name} (target #{@battle.choices[user_battler.index][3]})")
|
||||||
|
else
|
||||||
|
PBDebug.log(" => will use #{move_name}")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ class Battle::AI
|
|||||||
# be.
|
# be.
|
||||||
def pbEnemyShouldMegaEvolve?
|
def pbEnemyShouldMegaEvolve?
|
||||||
if @battle.pbCanMegaEvolve?(@user.index) # Simple "always should if possible"
|
if @battle.pbCanMegaEvolve?(@user.index) # Simple "always should if possible"
|
||||||
PBDebug.log("[AI] #{@user.pbThis} (#{@user.index}) will Mega Evolve")
|
PBDebug.log_ai("#{@user.name} will Mega Evolve")
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
return false
|
return false
|
||||||
|
|||||||
@@ -18,12 +18,16 @@ class Battle::AI
|
|||||||
# Discard status move/don't prefer damaging move if target has Contrary
|
# Discard status move/don't prefer damaging move if target has Contrary
|
||||||
# TODO: Maybe this should return get_score_for_target_stat_drop if Contrary
|
# TODO: Maybe this should return get_score_for_target_stat_drop if Contrary
|
||||||
# applies and desire_mult < 1.
|
# applies and desire_mult < 1.
|
||||||
if !fixed_change && !@battle.moldBreaker && target.has_active_ability?(:CONTRARY) && desire_mult > 1
|
if !fixed_change && !@battle.moldBreaker && target.has_active_ability?(:CONTRARY) && desire_mult > 0
|
||||||
return (whole_effect) ? MOVE_USELESS_SCORE : score - 20
|
ret = (whole_effect) ? MOVE_USELESS_SCORE : score - 20
|
||||||
|
PBDebug.log_score_change(ret - score, "don't prefer raising target's stats (it has Contrary)")
|
||||||
|
return ret
|
||||||
end
|
end
|
||||||
# Don't make score changes if target will faint from EOR damage
|
# Don't make score changes if target will faint from EOR damage
|
||||||
if target.rough_end_of_round_damage >= target.hp
|
if target.rough_end_of_round_damage >= target.hp
|
||||||
return (whole_effect) ? MOVE_USELESS_SCORE : score
|
ret = (whole_effect) ? MOVE_USELESS_SCORE : score
|
||||||
|
PBDebug.log(" ignore stat change (target predicted to faint this round)")
|
||||||
|
return ret
|
||||||
end
|
end
|
||||||
# Don't make score changes if foes have Unaware and target can't make use of
|
# Don't make score changes if foes have Unaware and target can't make use of
|
||||||
# extra stat stages
|
# extra stat stages
|
||||||
@@ -33,7 +37,9 @@ class Battle::AI
|
|||||||
foe_is_aware = true if !b.has_active_ability?(:UNAWARE)
|
foe_is_aware = true if !b.has_active_ability?(:UNAWARE)
|
||||||
end
|
end
|
||||||
if !foe_is_aware
|
if !foe_is_aware
|
||||||
return (whole_effect) ? MOVE_USELESS_SCORE : score
|
ret = (whole_effect) ? MOVE_USELESS_SCORE : score
|
||||||
|
PBDebug.log(" ignore stat change (target's foes have Unaware)")
|
||||||
|
return ret
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -41,7 +47,14 @@ class Battle::AI
|
|||||||
real_stat_changes = []
|
real_stat_changes = []
|
||||||
stat_changes.each_with_index do |stat, idx|
|
stat_changes.each_with_index do |stat, idx|
|
||||||
next if idx.odd?
|
next if idx.odd?
|
||||||
next if !stat_raise_worthwhile?(target, stat, fixed_change)
|
if !stat_raise_worthwhile?(target, stat, fixed_change)
|
||||||
|
if target.index == @user.index
|
||||||
|
PBDebug.log(" raising the user's #{GameData::Stat.get(stat).name} isn't worthwhile")
|
||||||
|
else
|
||||||
|
PBDebug.log(" raising the target's #{GameData::Stat.get(stat).name} isn't worthwhile")
|
||||||
|
end
|
||||||
|
next
|
||||||
|
end
|
||||||
# Calculate amount that stat will be raised by
|
# Calculate amount that stat will be raised by
|
||||||
increment = stat_changes[idx + 1]
|
increment = stat_changes[idx + 1]
|
||||||
increment *= 2 if !fixed_change && !@battle.moldBreaker && target.has_active_ability?(:SIMPLE)
|
increment *= 2 if !fixed_change && !@battle.moldBreaker && target.has_active_ability?(:SIMPLE)
|
||||||
@@ -60,7 +73,13 @@ class Battle::AI
|
|||||||
# Make score changes based on the specific changes to each stat that will be
|
# Make score changes based on the specific changes to each stat that will be
|
||||||
# raised
|
# raised
|
||||||
real_stat_changes.each do |change|
|
real_stat_changes.each do |change|
|
||||||
|
old_score = score
|
||||||
score = get_target_stat_raise_score_one(score, target, change[0], change[1], desire_mult)
|
score = get_target_stat_raise_score_one(score, target, change[0], change[1], desire_mult)
|
||||||
|
if target.index == @user.index
|
||||||
|
PBDebug.log_score_change(score - old_score, "raising the user's #{GameData::Stat.get(change[0]).name} by #{change[1]}")
|
||||||
|
else
|
||||||
|
PBDebug.log_score_change(score - old_score, "raising the target's #{GameData::Stat.get(change[0]).name} by #{change[1]}")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return score
|
return score
|
||||||
@@ -601,12 +620,16 @@ class Battle::AI
|
|||||||
# Discard status move/don't prefer damaging move if target has Contrary
|
# Discard status move/don't prefer damaging move if target has Contrary
|
||||||
# TODO: Maybe this should return get_score_for_target_stat_raise if Contrary
|
# TODO: Maybe this should return get_score_for_target_stat_raise if Contrary
|
||||||
# applies and desire_mult < 1.
|
# applies and desire_mult < 1.
|
||||||
if !fixed_change && !@battle.moldBreaker && target.has_active_ability?(:CONTRARY) && desire_mult > 1
|
if !fixed_change && !@battle.moldBreaker && target.has_active_ability?(:CONTRARY) && desire_mult > 0
|
||||||
return (whole_effect) ? MOVE_USELESS_SCORE : score - 20
|
ret = (whole_effect) ? MOVE_USELESS_SCORE : score - 20
|
||||||
|
PBDebug.log_score_change(ret - score, "don't prefer lowering target's stats (it has Contrary)")
|
||||||
|
return ret
|
||||||
end
|
end
|
||||||
# Don't make score changes if target will faint from EOR damage
|
# Don't make score changes if target will faint from EOR damage
|
||||||
if target.rough_end_of_round_damage >= target.hp
|
if target.rough_end_of_round_damage >= target.hp
|
||||||
return (whole_effect) ? MOVE_USELESS_SCORE : score
|
ret = (whole_effect) ? MOVE_USELESS_SCORE : score
|
||||||
|
PBDebug.log(" ignore stat change (target predicted to faint this round)")
|
||||||
|
return ret
|
||||||
end
|
end
|
||||||
# Don't make score changes if foes have Unaware and target can't make use of
|
# Don't make score changes if foes have Unaware and target can't make use of
|
||||||
# its lowered stat stages
|
# its lowered stat stages
|
||||||
@@ -615,14 +638,23 @@ class Battle::AI
|
|||||||
foe_is_aware = true if !b.has_active_ability?(:UNAWARE)
|
foe_is_aware = true if !b.has_active_ability?(:UNAWARE)
|
||||||
end
|
end
|
||||||
if !foe_is_aware
|
if !foe_is_aware
|
||||||
return (whole_effect) ? MOVE_USELESS_SCORE : score
|
ret = (whole_effect) ? MOVE_USELESS_SCORE : score
|
||||||
|
PBDebug.log(" ignore stat change (target's foes have Unaware)")
|
||||||
|
return ret
|
||||||
end
|
end
|
||||||
|
|
||||||
# Figure out which stat raises can happen
|
# Figure out which stat raises can happen
|
||||||
real_stat_changes = []
|
real_stat_changes = []
|
||||||
stat_changes.each_with_index do |stat, idx|
|
stat_changes.each_with_index do |stat, idx|
|
||||||
next if idx.odd?
|
next if idx.odd?
|
||||||
next if !stat_drop_worthwhile?(target, stat, fixed_change)
|
if !stat_drop_worthwhile?(target, stat, fixed_change)
|
||||||
|
if target.index == @user.index
|
||||||
|
PBDebug.log(" lowering the user's #{GameData::Stat.get(stat).name} isn't worthwhile")
|
||||||
|
else
|
||||||
|
PBDebug.log(" lowering the target's #{GameData::Stat.get(stat).name} isn't worthwhile")
|
||||||
|
end
|
||||||
|
next
|
||||||
|
end
|
||||||
# Calculate amount that stat will be raised by
|
# Calculate amount that stat will be raised by
|
||||||
decrement = stat_changes[idx + 1]
|
decrement = stat_changes[idx + 1]
|
||||||
decrement *= 2 if !fixed_change && !@battle.moldBreaker && @user.has_active_ability?(:SIMPLE)
|
decrement *= 2 if !fixed_change && !@battle.moldBreaker && @user.has_active_ability?(:SIMPLE)
|
||||||
@@ -641,7 +673,13 @@ class Battle::AI
|
|||||||
# Make score changes based on the specific changes to each stat that will be
|
# Make score changes based on the specific changes to each stat that will be
|
||||||
# lowered
|
# lowered
|
||||||
real_stat_changes.each do |change|
|
real_stat_changes.each do |change|
|
||||||
|
old_score = score
|
||||||
score = get_target_stat_drop_score_one(score, target, change[0], change[1], desire_mult)
|
score = get_target_stat_drop_score_one(score, target, change[0], change[1], desire_mult)
|
||||||
|
if target.index == @user.index
|
||||||
|
PBDebug.log_score_change(score - old_score, "lowering the user's #{GameData::Stat.get(change[0]).name} by #{change[1]}")
|
||||||
|
else
|
||||||
|
PBDebug.log_score_change(score - old_score, "lowering the target's #{GameData::Stat.get(change[0]).name} by #{change[1]}")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return score
|
return score
|
||||||
@@ -886,7 +924,7 @@ class Battle::AI
|
|||||||
end
|
end
|
||||||
when :Psychic
|
when :Psychic
|
||||||
# Check for priority moves
|
# Check for priority moves
|
||||||
if b.check_for_move { |m| m.priority > 0 && m.pbTarget&.can_target_one_foe? }
|
if b.check_for_move { |m| m.priority > 0 && m.pbTarget(b.battler)&.can_target_one_foe? }
|
||||||
ret += (b.opposes?(move_user)) ? 10 : -10
|
ret += (b.opposes?(move_user)) ? 10 : -10
|
||||||
end
|
end
|
||||||
# Check for Psychic moves
|
# Check for Psychic moves
|
||||||
|
|||||||
@@ -719,7 +719,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("RaiseTargetRandomStat2",
|
|||||||
score += 8
|
score += 8
|
||||||
end
|
end
|
||||||
# Don't prefer if any foe has Punishment
|
# Don't prefer if any foe has Punishment
|
||||||
each_foe_battler(target.side) do |b, i|
|
ai.each_foe_battler(target.side) do |b, i|
|
||||||
next if !b.check_for_move { |m| m.function == "PowerHigherWithTargetPositiveStatStages" }
|
next if !b.check_for_move { |m| m.function == "PowerHigherWithTargetPositiveStatStages" }
|
||||||
score -= 5
|
score -= 5
|
||||||
end
|
end
|
||||||
@@ -1182,7 +1182,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("RaisePlusMinusUserAndAll
|
|||||||
#===============================================================================
|
#===============================================================================
|
||||||
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("RaiseGroundedGrassBattlersAtkSpAtk1",
|
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("RaiseGroundedGrassBattlersAtkSpAtk1",
|
||||||
proc { |move, user, target, ai, battle|
|
proc { |move, user, target, ai, battle|
|
||||||
next true if !b.pbHasType?(:GRASS) || b.airborne? || b.semiInvulnerable?
|
next true if !target.has_type?(:GRASS) || target.battler.airborne? || target.battler.semiInvulnerable?
|
||||||
next !target.battler.pbCanRaiseStatStage?(:ATTACK, user.battler, move.move) &&
|
next !target.battler.pbCanRaiseStatStage?(:ATTACK, user.battler, move.move) &&
|
||||||
!target.battler.pbCanRaiseStatStage?(:SPECIAL_ATTACK, user.battler, move.move)
|
!target.battler.pbCanRaiseStatStage?(:SPECIAL_ATTACK, user.battler, move.move)
|
||||||
}
|
}
|
||||||
@@ -1198,7 +1198,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("RaiseGroundedGrassBattle
|
|||||||
#===============================================================================
|
#===============================================================================
|
||||||
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("RaiseGrassBattlersDef1",
|
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("RaiseGrassBattlersDef1",
|
||||||
proc { |move, user, target, ai, battle|
|
proc { |move, user, target, ai, battle|
|
||||||
next true if !b.pbHasType?(:GRASS) || b.semiInvulnerable?
|
next true if !target.has_type?(:GRASS) || target.battler.semiInvulnerable?
|
||||||
next !target.battler.pbCanRaiseStatStage?(:DEFENSE, user.battler, move.move)
|
next !target.battler.pbCanRaiseStatStage?(:DEFENSE, user.battler, move.move)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -1226,10 +1226,10 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("UserTargetSwapAtkSpAtkSt
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
next Battle::AI::MOVE_USELESS_SCORE if raises.length == 0 # No stat raises
|
next Battle::AI::MOVE_USELESS_SCORE if raises.length == 0 # No stat raises
|
||||||
score += ai.get_score_for_target_stat_raise(score, user, raises, false, true) if raises.length > 0
|
score = ai.get_score_for_target_stat_raise(score, user, raises, false, true) if raises.length > 0
|
||||||
score += ai.get_score_for_target_stat_drop(score, target, raises, false, true) if raises.length > 0
|
score = ai.get_score_for_target_stat_drop(score, target, raises, false, true) if raises.length > 0
|
||||||
score += ai.get_score_for_target_stat_drop(score, user, drops, false, true) if drops.length > 0
|
score = ai.get_score_for_target_stat_drop(score, user, drops, false, true) if drops.length > 0
|
||||||
score += ai.get_score_for_target_stat_raise(score, target, drops, false, true) if drops.length > 0
|
score = ai.get_score_for_target_stat_raise(score, target, drops, false, true) if drops.length > 0
|
||||||
next score
|
next score
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -1252,10 +1252,10 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("UserTargetSwapDefSpDefSt
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
next Battle::AI::MOVE_USELESS_SCORE if raises.length == 0 # No stat raises
|
next Battle::AI::MOVE_USELESS_SCORE if raises.length == 0 # No stat raises
|
||||||
score += ai.get_score_for_target_stat_raise(score, user, raises, false, true) if raises.length > 0
|
score = ai.get_score_for_target_stat_raise(score, user, raises, false, true) if raises.length > 0
|
||||||
score += ai.get_score_for_target_stat_drop(score, target, raises, false, true) if raises.length > 0
|
score = ai.get_score_for_target_stat_drop(score, target, raises, false, true) if raises.length > 0
|
||||||
score += ai.get_score_for_target_stat_drop(score, user, drops, false, true) if drops.length > 0
|
score = ai.get_score_for_target_stat_drop(score, user, drops, false, true) if drops.length > 0
|
||||||
score += ai.get_score_for_target_stat_raise(score, target, drops, false, true) if drops.length > 0
|
score = ai.get_score_for_target_stat_raise(score, target, drops, false, true) if drops.length > 0
|
||||||
next score
|
next score
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -1278,10 +1278,10 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("UserTargetSwapStatStages
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
next Battle::AI::MOVE_USELESS_SCORE if raises.length == 0 # No stat raises
|
next Battle::AI::MOVE_USELESS_SCORE if raises.length == 0 # No stat raises
|
||||||
score += ai.get_score_for_target_stat_raise(score, user, raises, false, true) if raises.length > 0
|
score = ai.get_score_for_target_stat_raise(score, user, raises, false, true) if raises.length > 0
|
||||||
score += ai.get_score_for_target_stat_drop(score, target, raises, false, true) if raises.length > 0
|
score = ai.get_score_for_target_stat_drop(score, target, raises, false, true) if raises.length > 0
|
||||||
score += ai.get_score_for_target_stat_drop(score, user, drops, false, true) if drops.length > 0
|
score = ai.get_score_for_target_stat_drop(score, user, drops, false, true) if drops.length > 0
|
||||||
score += ai.get_score_for_target_stat_raise(score, target, drops, false, true) if drops.length > 0
|
score = ai.get_score_for_target_stat_raise(score, target, drops, false, true) if drops.length > 0
|
||||||
next score
|
next score
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -1304,8 +1304,8 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("UserCopyTargetStatStages
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
next Battle::AI::MOVE_USELESS_SCORE if raises.length == 0 # No stat raises
|
next Battle::AI::MOVE_USELESS_SCORE if raises.length == 0 # No stat raises
|
||||||
score += ai.get_score_for_target_stat_raise(score, user, raises, false, true) if raises.length > 0
|
score = ai.get_score_for_target_stat_raise(score, user, raises, false, true) if raises.length > 0
|
||||||
score += ai.get_score_for_target_stat_drop(score, user, drops, false, true) if drops.length > 0
|
score = ai.get_score_for_target_stat_drop(score, user, drops, false, true) if drops.length > 0
|
||||||
if Settings::NEW_CRITICAL_HIT_RATE_MECHANICS
|
if Settings::NEW_CRITICAL_HIT_RATE_MECHANICS
|
||||||
if user.effects[PBEffects::FocusEnergy] > 0 && target.effects[PBEffects::FocusEnergy] == 0
|
if user.effects[PBEffects::FocusEnergy] > 0 && target.effects[PBEffects::FocusEnergy] == 0
|
||||||
score -= 4
|
score -= 4
|
||||||
@@ -1337,8 +1337,8 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("UserStealTargetPositiveS
|
|||||||
raises.push(target.stages[s.id])
|
raises.push(target.stages[s.id])
|
||||||
end
|
end
|
||||||
if raises.length > 0
|
if raises.length > 0
|
||||||
score += ai.get_score_for_target_stat_raise(score, user, raises, false)
|
score = ai.get_score_for_target_stat_raise(score, user, raises, false)
|
||||||
score += ai.get_score_for_target_stat_drop(score, target, raises, false, true)
|
score = ai.get_score_for_target_stat_drop(score, target, raises, false, true)
|
||||||
end
|
end
|
||||||
next score
|
next score
|
||||||
}
|
}
|
||||||
@@ -1366,8 +1366,8 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("InvertTargetStatStages",
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
next Battle::AI::MOVE_USELESS_SCORE if drops.length == 0 # No stats will drop
|
next Battle::AI::MOVE_USELESS_SCORE if drops.length == 0 # No stats will drop
|
||||||
score += ai.get_score_for_target_stat_raise(score, target, raises, false, true) if raises.length > 0
|
score = ai.get_score_for_target_stat_raise(score, target, raises, false, true) if raises.length > 0
|
||||||
score += ai.get_score_for_target_stat_drop(score, target, drops, false, true) if drops.length > 0
|
score = ai.get_score_for_target_stat_drop(score, target, drops, false, true) if drops.length > 0
|
||||||
next score
|
next score
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -1388,8 +1388,8 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("ResetTargetStatStages",
|
|||||||
raises.push(target.stages[s.id])
|
raises.push(target.stages[s.id])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
score += ai.get_score_for_target_stat_raise(score, target, raises, false, true) if raises.length > 0
|
score = ai.get_score_for_target_stat_raise(score, target, raises, false, true) if raises.length > 0
|
||||||
score += ai.get_score_for_target_stat_drop(score, target, drops, false, true) if drops.length > 0
|
score = ai.get_score_for_target_stat_drop(score, target, drops, false, true) if drops.length > 0
|
||||||
next score
|
next score
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -1416,8 +1416,8 @@ Battle::AI::Handlers::MoveEffectScore.add("ResetAllBattlersStatStages",
|
|||||||
raises.push(b.stages[s.id])
|
raises.push(b.stages[s.id])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
score += ai.get_score_for_target_stat_raise(score, b, raises, false, true) if raises.length > 0
|
score = ai.get_score_for_target_stat_raise(score, b, raises, false, true) if raises.length > 0
|
||||||
score += ai.get_score_for_target_stat_drop(score, b, drops, false, true) if drops.length > 0
|
score = ai.get_score_for_target_stat_drop(score, b, drops, false, true) if drops.length > 0
|
||||||
end
|
end
|
||||||
next score
|
next score
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -783,7 +783,7 @@ Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("SetUserTypesToTargetTyp
|
|||||||
next true if !user.battler.canChangeType?
|
next true if !user.battler.canChangeType?
|
||||||
next true if target.battler.pbTypes(true).empty?
|
next true if target.battler.pbTypes(true).empty?
|
||||||
next true if user.battler.pbTypes == target.battler.pbTypes &&
|
next true if user.battler.pbTypes == target.battler.pbTypes &&
|
||||||
user.effects[PBEffects::Type3] == target.effects[PBEffects::Type3]
|
user.effects[PBEffects::ExtraType] == target.effects[PBEffects::ExtraType]
|
||||||
next false
|
next false
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -157,7 +157,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("HealUserByTargetAttackLo
|
|||||||
proc { |score, move, user, target, ai, battle|
|
proc { |score, move, user, target, ai, battle|
|
||||||
# Check whether lowering the target's Attack will have any impact
|
# Check whether lowering the target's Attack will have any impact
|
||||||
if ai.trainer.medium_skill?
|
if ai.trainer.medium_skill?
|
||||||
score = ai.get_score_for_target_stat_drop(score, target, [:ATTACK, 1])
|
score = ai.get_score_for_target_stat_drop(score, target, move.move.statDown)
|
||||||
end
|
end
|
||||||
# Consider how much HP will be restored
|
# Consider how much HP will be restored
|
||||||
heal_amt = target.rough_stat(:ATTACK)
|
heal_amt = target.rough_stat(:ATTACK)
|
||||||
|
|||||||
@@ -506,21 +506,24 @@ Battle::AI::Handlers::MoveFailureCheck.add("UseRandomUserMoveIfAsleep",
|
|||||||
#===============================================================================
|
#===============================================================================
|
||||||
#
|
#
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
|
Battle::AI::Handlers::MoveFailureCheck.add("ReplaceMoveThisBattleWithTargetLastMoveUsed",
|
||||||
|
proc { |move, user, ai, battle|
|
||||||
|
next user.effects[PBEffects::Transform] || !user.battler.pbHasMove?(move.id)
|
||||||
|
}
|
||||||
|
)
|
||||||
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("ReplaceMoveThisBattleWithTargetLastMoveUsed",
|
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("ReplaceMoveThisBattleWithTargetLastMoveUsed",
|
||||||
proc { |move, user, target, ai, battle|
|
proc { |move, user, target, ai, battle|
|
||||||
next true if user.effects[PBEffects::Transform] || !user.battler.pbHasMove?(move.id)
|
next false if !user.faster_than?(target)
|
||||||
if user.faster_than?(target)
|
last_move_data = GameData::Move.try_get(target.battler.lastRegularMoveUsed)
|
||||||
last_move_data = GameData::Move.try_get(target.battler.lastRegularMoveUsed)
|
next true if !last_move_data ||
|
||||||
next true if !last_move_data ||
|
user.battler.pbHasMove?(target.battler.lastRegularMoveUsed) ||
|
||||||
user.battler.pbHasMove?(target.battler.lastRegularMoveUsed) ||
|
move.move.moveBlacklist.include?(last_move_data.function_code) ||
|
||||||
move.move.moveBlacklist.include?(last_move_data.function_code) ||
|
last_move_data.type == :SHADOW
|
||||||
last_move_data.type == :SHADOW
|
|
||||||
end
|
|
||||||
next false
|
next false
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
Battle::AI::Handlers::MoveEffectScore.add("ReplaceMoveThisBattleWithTargetLastMoveUsed",
|
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("ReplaceMoveThisBattleWithTargetLastMoveUsed",
|
||||||
proc { |score, move, user, ai, battle|
|
proc { |score, move, user, target, ai, battle|
|
||||||
# Generally don't prefer, as this wastes the user's turn just to gain a move
|
# Generally don't prefer, as this wastes the user's turn just to gain a move
|
||||||
# of unknown utility
|
# of unknown utility
|
||||||
score -= 8
|
score -= 8
|
||||||
|
|||||||
@@ -28,7 +28,10 @@
|
|||||||
#===============================================================================
|
#===============================================================================
|
||||||
Battle::AI::Handlers::GeneralMoveAgainstTargetScore.add(:shiny_target,
|
Battle::AI::Handlers::GeneralMoveAgainstTargetScore.add(:shiny_target,
|
||||||
proc { |score, move, user, target, ai, battle|
|
proc { |score, move, user, target, ai, battle|
|
||||||
score -= 40 if target.wild? && target.battler.shiny?
|
if target.wild? && target.battler.shiny?
|
||||||
|
PBDebug.log_score_change(-40, "avoid attacking a shiny wild Pokémon")
|
||||||
|
score -= 40
|
||||||
|
end
|
||||||
next score
|
next score
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -47,10 +50,16 @@ Battle::AI::Handlers::GeneralMoveAgainstTargetScore.add(:add_predicted_damage,
|
|||||||
proc { |score, move, user, target, ai, battle|
|
proc { |score, move, user, target, ai, battle|
|
||||||
if move.damagingMove?
|
if move.damagingMove?
|
||||||
dmg = move.rough_damage
|
dmg = move.rough_damage
|
||||||
score += [20.0 * dmg / target.hp, 25].min
|
old_score = score
|
||||||
score += 10 if dmg > target.hp * 1.1 # Predicted to KO the target
|
score += ([30.0 * dmg / target.hp, 35].min).to_i
|
||||||
|
PBDebug.log_score_change(score - old_score, "damaging move (predicted damage #{dmg} = #{100 * dmg / target.hp}% of target's HP)")
|
||||||
|
if dmg > target.hp * 1.1 # Predicted to KO the target
|
||||||
|
old_score = score
|
||||||
|
score += 10
|
||||||
|
PBDebug.log_score_change(score - old_score, "predicted to KO the target")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
next score.to_i
|
next score
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -60,7 +69,13 @@ Battle::AI::Handlers::GeneralMoveAgainstTargetScore.add(:add_predicted_damage,
|
|||||||
#===============================================================================
|
#===============================================================================
|
||||||
Battle::AI::Handlers::GeneralMoveAgainstTargetScore.add(:move_accuracy,
|
Battle::AI::Handlers::GeneralMoveAgainstTargetScore.add(:move_accuracy,
|
||||||
proc { |score, move, user, target, ai, battle|
|
proc { |score, move, user, target, ai, battle|
|
||||||
next score * move.rough_accuracy / 100.0
|
acc = move.rough_accuracy.to_i
|
||||||
|
if acc < 90
|
||||||
|
old_score = score
|
||||||
|
score -= (0.2 * (100 - acc)).to_i # -2 (89%) to -19 (1%)
|
||||||
|
PBDebug.log_score_change(score - old_score, "accuracy (predicted #{acc}%)")
|
||||||
|
end
|
||||||
|
next score
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -89,7 +104,11 @@ Battle::AI::Handlers::GeneralMoveAgainstTargetScore.add(:target_semi_invulnerabl
|
|||||||
miss = false if move.move.hitsDivingTargets?
|
miss = false if move.move.hitsDivingTargets?
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
next Battle::AI::MOVE_USELESS_SCORE if miss
|
if miss
|
||||||
|
old_score = score
|
||||||
|
score = Battle::AI::MOVE_USELESS_SCORE
|
||||||
|
PBDebug.log_score_change(score - old_score, "target is semi-invulnerable")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
next score
|
next score
|
||||||
}
|
}
|
||||||
@@ -109,7 +128,9 @@ Battle::AI::Handlers::GeneralMoveAgainstTargetScore.add(:thawing_move_against_fr
|
|||||||
proc { |score, move, user, target, ai, battle|
|
proc { |score, move, user, target, ai, battle|
|
||||||
if ai.trainer.medium_skill? && target.status == :FROZEN
|
if ai.trainer.medium_skill? && target.status == :FROZEN
|
||||||
if move.rough_type == :FIRE || (Settings::MECHANICS_GENERATION >= 6 && move.move.thawsUser?)
|
if move.rough_type == :FIRE || (Settings::MECHANICS_GENERATION >= 6 && move.move.thawsUser?)
|
||||||
score -= 30
|
old_score = score
|
||||||
|
score -= 15
|
||||||
|
PBDebug.log_score_change(score - old_score, "thaws the target")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
next score
|
next score
|
||||||
@@ -137,7 +158,9 @@ Battle::AI::Handlers::GeneralMoveAgainstTargetScore.add(:flinching_effects,
|
|||||||
(move.damagingMove? &&
|
(move.damagingMove? &&
|
||||||
(user.has_active_item?([:KINGSROCK, :RAZORFANG]) ||
|
(user.has_active_item?([:KINGSROCK, :RAZORFANG]) ||
|
||||||
user.has_active_ability?(:STENCH)))
|
user.has_active_ability?(:STENCH)))
|
||||||
score += 20
|
old_score = score
|
||||||
|
score += 8
|
||||||
|
PBDebug.log_score_change(score - old_score, "flinching")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -166,7 +189,11 @@ Battle::AI::Handlers::GeneralMoveAgainstTargetScore.add(:flinching_effects,
|
|||||||
#===============================================================================
|
#===============================================================================
|
||||||
Battle::AI::Handlers::GeneralMoveAgainstTargetScore.add(:dance_move_against_dancer,
|
Battle::AI::Handlers::GeneralMoveAgainstTargetScore.add(:dance_move_against_dancer,
|
||||||
proc { |score, move, user, target, ai, battle|
|
proc { |score, move, user, target, ai, battle|
|
||||||
score /= 2 if move.move.danceMove? && target.has_active_ability?(:DANCER)
|
if move.move.danceMove? && target.has_active_ability?(:DANCER)
|
||||||
|
old_score = score
|
||||||
|
score -= 12
|
||||||
|
PBDebug.log_score_change(score - old_score, "don't want to use a dance move on a target with Dancer")
|
||||||
|
end
|
||||||
next score
|
next score
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -199,8 +226,10 @@ Battle::AI::Handlers::GeneralMoveAgainstTargetScore.add(:avoid_knocking_out_dest
|
|||||||
if ai.trainer.medium_skill? && move.damagingMove? && target.effects[PBEffects::DestinyBond]
|
if ai.trainer.medium_skill? && move.damagingMove? && target.effects[PBEffects::DestinyBond]
|
||||||
dmg = move.rough_damage
|
dmg = move.rough_damage
|
||||||
if dmg > target.hp * 1.05 # Predicted to KO the target
|
if dmg > target.hp * 1.05 # Predicted to KO the target
|
||||||
score -= 25
|
old_score = score
|
||||||
score -= 20 if battle.pbAbleNonActiveCount(user.idxOwnSide) == 0
|
score -= 15
|
||||||
|
score -= 10 if battle.pbAbleNonActiveCount(user.idxOwnSide) == 0
|
||||||
|
PBDebug.log_score_change(score - old_score, "don't want to KO the Destiny Bonding target")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
next score
|
next score
|
||||||
@@ -243,14 +272,13 @@ Battle::AI::Handlers::GeneralMoveAgainstTargetScore.add(:avoid_knocking_out_dest
|
|||||||
Battle::AI::Handlers::GeneralMoveScore.add(:thawing_move_when_frozen,
|
Battle::AI::Handlers::GeneralMoveScore.add(:thawing_move_when_frozen,
|
||||||
proc { |score, move, user, ai, battle|
|
proc { |score, move, user, ai, battle|
|
||||||
if ai.trainer.medium_skill? && user.status == :FROZEN
|
if ai.trainer.medium_skill? && user.status == :FROZEN
|
||||||
|
old_score = score
|
||||||
if move.move.thawsUser?
|
if move.move.thawsUser?
|
||||||
score += 30
|
score += 30
|
||||||
else
|
PBDebug.log_score_change(score - old_score, "move will thaw the user")
|
||||||
user.battler.eachMove do |m|
|
elsif user.check_for_move { |m| m.thawsUser? }
|
||||||
next unless m.thawsUser?
|
score -= 30 # Don't prefer this move if user knows another move that thaws
|
||||||
score -= 30 # Don't prefer this move if user knows another move that thaws
|
PBDebug.log_score_change(score - old_score, "user knows another move will thaw it")
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
next score
|
next score
|
||||||
@@ -267,7 +295,11 @@ Battle::AI::Handlers::GeneralMoveScore.add(:good_move_for_choice_item,
|
|||||||
if user.has_active_item?([:CHOICEBAND, :CHOICESPECS, :CHOICESCARF]) ||
|
if user.has_active_item?([:CHOICEBAND, :CHOICESPECS, :CHOICESCARF]) ||
|
||||||
user.has_active_ability?(:GORILLATACTICS)
|
user.has_active_ability?(: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"
|
if move.statusMove? && move.function != "UserTargetSwapItems"
|
||||||
|
old_score = score
|
||||||
|
score -= 25
|
||||||
|
PBDebug.log_score_change(score - old_score, "move is not suitable to be Choiced into")
|
||||||
|
end
|
||||||
# Don't prefer moves of certain types
|
# Don't prefer moves of certain types
|
||||||
move_type = move.rough_type
|
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
|
||||||
@@ -280,11 +312,13 @@ Battle::AI::Handlers::GeneralMoveScore.add(:good_move_for_choice_item,
|
|||||||
# very effective against Dragon.
|
# very effective against Dragon.
|
||||||
unpreferred_types = [:NORMAL, :FIGHTING, :POISON, :GROUND, :GHOST,
|
unpreferred_types = [:NORMAL, :FIGHTING, :POISON, :GROUND, :GHOST,
|
||||||
:FIRE, :WATER, :GRASS, :ELECTRIC, :PSYCHIC, :DRAGON]
|
:FIRE, :WATER, :GRASS, :ELECTRIC, :PSYCHIC, :DRAGON]
|
||||||
score *= 0.95 if unpreferred_types.include?(move_type)
|
old_score = score
|
||||||
|
score -= 5 if unpreferred_types.include?(move_type)
|
||||||
# Don't prefer moves with lower accuracy
|
# Don't prefer moves with lower accuracy
|
||||||
score *= move.accuracy / 100.0 if move.accuracy > 0
|
score = score * move.accuracy / 100 if move.accuracy > 0
|
||||||
# Don't prefer moves with low PP
|
# Don't prefer moves with low PP
|
||||||
score *= 0.9 if move.move.pp < 6
|
score -= 10 if move.move.pp < 6
|
||||||
|
PBDebug.log_score_change(score - old_score, "move is less suitable to be Choiced into")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
next score
|
next score
|
||||||
@@ -305,10 +339,13 @@ Battle::AI::Handlers::GeneralMoveScore.add(:prefer_damaging_moves_if_last_pokemo
|
|||||||
# Don't mess with scores just because a move is damaging; need to play well
|
# Don't mess with scores just because a move is damaging; need to play well
|
||||||
next score if ai.trainer.high_skill? && foes > reserves # AI is outnumbered
|
next score if ai.trainer.high_skill? && foes > reserves # AI is outnumbered
|
||||||
# Prefer damaging moves depending on remaining Pokémon
|
# Prefer damaging moves depending on remaining Pokémon
|
||||||
|
old_score = score
|
||||||
if foes == 0 # Foe is down to their last Pokémon
|
if foes == 0 # Foe is down to their last Pokémon
|
||||||
score *= 1.1 # => Go for the kill
|
score += 10 # => Go for the kill
|
||||||
|
PBDebug.log_score_change(score - old_score, "prefer damaging moves (no foe party Pokémon left)")
|
||||||
elsif reserves == 0 # AI is down to its last Pokémon, foe has reserves
|
elsif reserves == 0 # AI is down to its last Pokémon, foe has reserves
|
||||||
score *= 1.05 # => Go out with a bang
|
score += 5 # => Go out with a bang
|
||||||
|
PBDebug.log_score_change(score - old_score, "prefer damaging moves (no ally party Pokémon left)")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
next score
|
next score
|
||||||
|
|||||||
@@ -40,6 +40,10 @@ class Battle::AI::AIBattler
|
|||||||
return @ai.battle.wildBattle? && opposes?
|
return @ai.battle.wildBattle? && opposes?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def name
|
||||||
|
return sprintf("%s (%d)", @battler.name, @index)
|
||||||
|
end
|
||||||
|
|
||||||
def opposes?(other = nil)
|
def opposes?(other = nil)
|
||||||
return @side == 1 if other.nil?
|
return @side == 1 if other.nil?
|
||||||
return other.side != @side
|
return other.side != @side
|
||||||
@@ -184,7 +188,7 @@ class Battle::AI::AIBattler
|
|||||||
#=============================================================================
|
#=============================================================================
|
||||||
|
|
||||||
def types; return @battler.types; end
|
def types; return @battler.types; end
|
||||||
def pbTypes(withType3 = false); return @battler.pbTypes(withType3); end
|
def pbTypes(withExtraType = false); return @battler.pbTypes(withExtraType); end
|
||||||
|
|
||||||
def has_type?(type)
|
def has_type?(type)
|
||||||
return false if !type
|
return false if !type
|
||||||
@@ -208,7 +212,7 @@ class Battle::AI::AIBattler
|
|||||||
# TODO: Need to check the move's pbCalcTypeModSingle.
|
# TODO: Need to check the move's pbCalcTypeModSingle.
|
||||||
ret *= effectiveness_of_type_against_single_battler_type(type, defend_type, user)
|
ret *= effectiveness_of_type_against_single_battler_type(type, defend_type, user)
|
||||||
end
|
end
|
||||||
ret *= 2 if target.effects[PBEffects::TarShot] && type == :FIRE
|
ret *= 2 if @battler.effects[PBEffects::TarShot] && type == :FIRE
|
||||||
end
|
end
|
||||||
return ret
|
return ret
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -396,7 +396,7 @@ class Battle::AI::AIMove
|
|||||||
# OHKO move accuracy
|
# OHKO move accuracy
|
||||||
if @move.is_a?(Battle::Move::OHKO)
|
if @move.is_a?(Battle::Move::OHKO)
|
||||||
ret = self.accuracy + user.level - target.level
|
ret = self.accuracy + user.level - target.level
|
||||||
ret -= 10 if function == "OHKOIce" && !user.pbHasType?(:ICE)
|
ret -= 10 if function == "OHKOIce" && !user.has_type?(:ICE)
|
||||||
return [ret, 0].max
|
return [ret, 0].max
|
||||||
end
|
end
|
||||||
# "Always hit" effects and "always hit" accuracy
|
# "Always hit" effects and "always hit" accuracy
|
||||||
|
|||||||
@@ -1,3 +1,11 @@
|
|||||||
|
# TODO: Better randomisation of moves, including tracking of how many times each
|
||||||
|
# function code has been tested (note that some Pokémon may not be used in
|
||||||
|
# battle, so their moves won't be score).
|
||||||
|
# TODO: Add held items.
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
def debug_set_up_trainer
|
def debug_set_up_trainer
|
||||||
# Values to return
|
# Values to return
|
||||||
trainer_array = []
|
trainer_array = []
|
||||||
@@ -6,7 +14,7 @@ def debug_set_up_trainer
|
|||||||
party_starts = [0]
|
party_starts = [0]
|
||||||
|
|
||||||
# Choose random trainer type and trainer name
|
# Choose random trainer type and trainer name
|
||||||
trainer_type = GameData::TrainerType.keys.sample
|
trainer_type = :CHAMPION # GameData::TrainerType.keys.sample
|
||||||
trainer_name = ["Alpha", "Bravo", "Charlie", "Delta", "Echo",
|
trainer_name = ["Alpha", "Bravo", "Charlie", "Delta", "Echo",
|
||||||
"Foxtrot", "Golf", "Hotel", "India", "Juliette",
|
"Foxtrot", "Golf", "Hotel", "India", "Juliette",
|
||||||
"Kilo", "Lima", "Mike", "November", "Oscar",
|
"Kilo", "Lima", "Mike", "November", "Oscar",
|
||||||
@@ -24,8 +32,12 @@ def debug_set_up_trainer
|
|||||||
GameData::Species.each_species { |sp| valid_species.push(sp.species) }
|
GameData::Species.each_species { |sp| valid_species.push(sp.species) }
|
||||||
Settings::MAX_PARTY_SIZE.times do |i|
|
Settings::MAX_PARTY_SIZE.times do |i|
|
||||||
this_species = valid_species.sample
|
this_species = valid_species.sample
|
||||||
this_level = rand(1, Settings::MAXIMUM_LEVEL)
|
this_level = 100 # rand(1, Settings::MAXIMUM_LEVEL)
|
||||||
pkmn = Pokemon.new(this_species, this_level, trainer)
|
pkmn = Pokemon.new(this_species, this_level, trainer, false)
|
||||||
|
all_moves = pkmn.getMoveList.map { |m| m[1] }
|
||||||
|
all_moves.uniq!
|
||||||
|
moves = all_moves.sample(4)
|
||||||
|
moves.each { |m| pkmn.learn_move(m) }
|
||||||
trainer.party.push(pkmn)
|
trainer.party.push(pkmn)
|
||||||
pokemon_array.push(pkmn)
|
pokemon_array.push(pkmn)
|
||||||
end
|
end
|
||||||
@@ -37,7 +49,7 @@ end
|
|||||||
def debug_test_auto_battle(logging = false)
|
def debug_test_auto_battle(logging = false)
|
||||||
old_internal = $INTERNAL
|
old_internal = $INTERNAL
|
||||||
$INTERNAL = logging
|
$INTERNAL = logging
|
||||||
echoln "Start of testing auto battle."
|
echoln "Start of testing auto-battle."
|
||||||
echoln "" if !$INTERNAL
|
echoln "" if !$INTERNAL
|
||||||
PBDebug.log("")
|
PBDebug.log("")
|
||||||
PBDebug.log("================================================================")
|
PBDebug.log("================================================================")
|
||||||
@@ -51,7 +63,7 @@ def debug_test_auto_battle(logging = false)
|
|||||||
trainer_txt = "[Trainer #{index}] #{trainer.full_name} [skill: #{trainer.skill_level}]"
|
trainer_txt = "[Trainer #{index}] #{trainer.full_name} [skill: #{trainer.skill_level}]"
|
||||||
($INTERNAL) ? PBDebug.log_header(trainer_txt) : echoln(trainer_txt)
|
($INTERNAL) ? PBDebug.log_header(trainer_txt) : echoln(trainer_txt)
|
||||||
party.each do |pkmn|
|
party.each do |pkmn|
|
||||||
pkmn_txt = "* #{pkmn.name}, Lv.#{pkmn.level}"
|
pkmn_txt = "#{pkmn.name}, Lv.#{pkmn.level}"
|
||||||
pkmn_txt += " [Ability: #{pkmn.ability&.name || "---"}]"
|
pkmn_txt += " [Ability: #{pkmn.ability&.name || "---"}]"
|
||||||
pkmn_txt += " [Item: #{pkmn.item&.name || "---"}]"
|
pkmn_txt += " [Item: #{pkmn.item&.name || "---"}]"
|
||||||
($INTERNAL) ? PBDebug.log(pkmn_txt) : echoln(pkmn_txt)
|
($INTERNAL) ? PBDebug.log(pkmn_txt) : echoln(pkmn_txt)
|
||||||
@@ -85,18 +97,19 @@ def debug_test_auto_battle(logging = false)
|
|||||||
# Perform the battle itself
|
# Perform the battle itself
|
||||||
outcome = battle.pbStartBattle
|
outcome = battle.pbStartBattle
|
||||||
# End
|
# End
|
||||||
echoln ["Undecided",
|
text = ["Undecided",
|
||||||
"Trainer 1 #{player_trainers[0].name} won",
|
"Trainer 1 #{player_trainers[0].name} won",
|
||||||
"Trainer 2 #{foe_trainers[0].name} won",
|
"Trainer 2 #{foe_trainers[0].name} won",
|
||||||
"Ran/forfeited",
|
"Ran/forfeited",
|
||||||
"Wild Pokémon caught",
|
"Wild Pokémon caught",
|
||||||
"Draw"][outcome]
|
"Draw"][outcome]
|
||||||
|
echoln sprintf("%s after %d rounds", text, battle.turnCount + 1)
|
||||||
echoln ""
|
echoln ""
|
||||||
$INTERNAL = old_internal
|
$INTERNAL = old_internal
|
||||||
end
|
end
|
||||||
|
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
# Add to Debug menu
|
# Add to Debug menu.
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
MenuHandlers.add(:debug_menu, :test_auto_battle, {
|
MenuHandlers.add(:debug_menu, :test_auto_battle, {
|
||||||
"name" => _INTL("Test Auto Battle"),
|
"name" => _INTL("Test Auto Battle"),
|
||||||
@@ -115,5 +128,6 @@ MenuHandlers.add(:debug_menu, :test_auto_battle_logging, {
|
|||||||
"always_show" => false,
|
"always_show" => false,
|
||||||
"effect" => proc {
|
"effect" => proc {
|
||||||
debug_test_auto_battle(true)
|
debug_test_auto_battle(true)
|
||||||
|
pbMessage(_INTL("Battle transcript was logged in Data/debuglog.txt."))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
Reference in New Issue
Block a user