mirror of
https://github.com/infinitefusion/infinitefusion-e18.git
synced 2025-12-08 13:44:59 +00:00
Added script to make two random AI trainers battle, tweaked battle messages when logged, fixed typos
This commit is contained in:
@@ -7,7 +7,9 @@ module PBDebug
|
|||||||
rescue
|
rescue
|
||||||
PBDebug.log("")
|
PBDebug.log("")
|
||||||
PBDebug.log("**Exception: #{$!.message}")
|
PBDebug.log("**Exception: #{$!.message}")
|
||||||
PBDebug.log($!.backtrace.inspect.to_s)
|
backtrace = ""
|
||||||
|
$!.backtrace.each { |line| backtrace += line + "\r\n" }
|
||||||
|
PBDebug.log(backtrace)
|
||||||
PBDebug.log("")
|
PBDebug.log("")
|
||||||
pbPrintException($!) # if $INTERNAL
|
pbPrintException($!) # if $INTERNAL
|
||||||
PBDebug.flush
|
PBDebug.flush
|
||||||
@@ -23,7 +25,15 @@ module PBDebug
|
|||||||
|
|
||||||
def self.log(msg)
|
def self.log(msg)
|
||||||
if $DEBUG && $INTERNAL
|
if $DEBUG && $INTERNAL
|
||||||
echoln msg
|
echoln msg.gsub("%", "%%")
|
||||||
|
@@log.push(msg + "\r\n")
|
||||||
|
PBDebug.flush # if @@log.length > 1024
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.log_header(msg)
|
||||||
|
if $DEBUG && $INTERNAL
|
||||||
|
echoln Console.markup_style(msg.gsub("%", "%%"), text: :light_purple)
|
||||||
@@log.push(msg + "\r\n")
|
@@log.push(msg + "\r\n")
|
||||||
PBDebug.flush # if @@log.length > 1024
|
PBDebug.flush # if @@log.length > 1024
|
||||||
end
|
end
|
||||||
@@ -32,7 +42,7 @@ module PBDebug
|
|||||||
def self.log_message(msg)
|
def self.log_message(msg)
|
||||||
if $DEBUG && $INTERNAL
|
if $DEBUG && $INTERNAL
|
||||||
msg = "\"" + msg + "\""
|
msg = "\"" + msg + "\""
|
||||||
echoln Console.markup_style(msg, text: :dark_gray)
|
echoln Console.markup_style(msg.gsub("%", "%%"), text: :dark_gray)
|
||||||
@@log.push(msg + "\r\n")
|
@@log.push(msg + "\r\n")
|
||||||
PBDebug.flush # if @@log.length > 1024
|
PBDebug.flush # if @@log.length > 1024
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -246,7 +246,8 @@ class Battle
|
|||||||
#=============================================================================
|
#=============================================================================
|
||||||
def pbStartBattle
|
def pbStartBattle
|
||||||
PBDebug.log("")
|
PBDebug.log("")
|
||||||
PBDebug.log("******************************************")
|
PBDebug.log("================================================================")
|
||||||
|
PBDebug.log("")
|
||||||
logMsg = "[Started battle] "
|
logMsg = "[Started battle] "
|
||||||
if @sideSizes[0] == 1 && @sideSizes[1] == 1
|
if @sideSizes[0] == 1 && @sideSizes[1] == 1
|
||||||
logMsg += "Single "
|
logMsg += "Single "
|
||||||
@@ -322,7 +323,7 @@ class Battle
|
|||||||
@turnCount = 0
|
@turnCount = 0
|
||||||
loop do # Now begin the battle loop
|
loop do # Now begin the battle loop
|
||||||
PBDebug.log("")
|
PBDebug.log("")
|
||||||
PBDebug.log("***Round #{@turnCount + 1}***")
|
PBDebug.log_header("===== Round #{@turnCount + 1} =====")
|
||||||
if @debug && @turnCount >= 100
|
if @debug && @turnCount >= 100
|
||||||
@decision = pbDecisionOnTime
|
@decision = pbDecisionOnTime
|
||||||
PBDebug.log("")
|
PBDebug.log("")
|
||||||
@@ -408,7 +409,8 @@ class Battle
|
|||||||
##### WIN #####
|
##### WIN #####
|
||||||
when 1
|
when 1
|
||||||
PBDebug.log("")
|
PBDebug.log("")
|
||||||
PBDebug.log("***Player won***")
|
PBDebug.log_header("===== Player won =====")
|
||||||
|
PBDebug.log("")
|
||||||
if trainerBattle?
|
if trainerBattle?
|
||||||
@scene.pbTrainerBattleSuccess
|
@scene.pbTrainerBattleSuccess
|
||||||
case @opponent.length
|
case @opponent.length
|
||||||
@@ -427,6 +429,7 @@ class Battle
|
|||||||
msg = "..." if !msg || msg.empty?
|
msg = "..." if !msg || msg.empty?
|
||||||
pbDisplayPaused(msg.gsub(/\\[Pp][Nn]/, pbPlayer.name))
|
pbDisplayPaused(msg.gsub(/\\[Pp][Nn]/, pbPlayer.name))
|
||||||
end
|
end
|
||||||
|
PBDebug.log("")
|
||||||
end
|
end
|
||||||
# Gain money from winning a trainer battle, and from Pay Day
|
# Gain money from winning a trainer battle, and from Pay Day
|
||||||
pbGainMoney if @decision != 4
|
pbGainMoney if @decision != 4
|
||||||
@@ -435,8 +438,9 @@ class Battle
|
|||||||
##### LOSE, DRAW #####
|
##### LOSE, DRAW #####
|
||||||
when 2, 5
|
when 2, 5
|
||||||
PBDebug.log("")
|
PBDebug.log("")
|
||||||
PBDebug.log("***Player lost***") if @decision == 2
|
PBDebug.log_header("===== Player lost =====") if @decision == 2
|
||||||
PBDebug.log("***Player drew with opponent***") if @decision == 5
|
PBDebug.log_header("===== Player drew with opponent =====") if @decision == 5
|
||||||
|
PBDebug.log("")
|
||||||
if @internalBattle
|
if @internalBattle
|
||||||
pbDisplayPaused(_INTL("You have no more Pokémon that can fight!"))
|
pbDisplayPaused(_INTL("You have no more Pokémon that can fight!"))
|
||||||
if trainerBattle?
|
if trainerBattle?
|
||||||
@@ -462,10 +466,14 @@ class Battle
|
|||||||
msg = "..." if !msg || msg.empty?
|
msg = "..." if !msg || msg.empty?
|
||||||
pbDisplayPaused(msg.gsub(/\\[Pp][Nn]/, pbPlayer.name))
|
pbDisplayPaused(msg.gsub(/\\[Pp][Nn]/, pbPlayer.name))
|
||||||
end
|
end
|
||||||
|
PBDebug.log("")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
##### CAUGHT WILD POKÉMON #####
|
##### CAUGHT WILD POKÉMON #####
|
||||||
when 4
|
when 4
|
||||||
|
PBDebug.log("")
|
||||||
|
PBDebug.log_header("===== Pokémon caught =====")
|
||||||
|
PBDebug.log("")
|
||||||
@scene.pbWildBattleSuccess if !Settings::GAIN_EXP_FOR_CAPTURE
|
@scene.pbWildBattleSuccess if !Settings::GAIN_EXP_FOR_CAPTURE
|
||||||
end
|
end
|
||||||
# Register captured Pokémon in the Pokédex, and store them
|
# Register captured Pokémon in the Pokédex, and store them
|
||||||
|
|||||||
@@ -243,16 +243,16 @@ class Battle
|
|||||||
end
|
end
|
||||||
}
|
}
|
||||||
# Write the priority order to the debug log
|
# Write the priority order to the debug log
|
||||||
logMsg = (fullCalc) ? "[Round order] " : "[Round order recalculated] "
|
if fullCalc && $INTERNAL
|
||||||
comma = false
|
logMsg = "[Round order] "
|
||||||
@priority.each do |entry|
|
@priority.each_with_index do |entry, i|
|
||||||
logMsg += ", " if comma
|
logMsg += ", " if i > 0
|
||||||
logMsg += "#{entry[0].pbThis(comma)} (#{entry[0].index})"
|
logMsg += "#{entry[0].pbThis(i > 0)} (#{entry[0].index})"
|
||||||
comma = true
|
|
||||||
end
|
end
|
||||||
PBDebug.log(logMsg)
|
PBDebug.log(logMsg)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def pbPriority(onlySpeedSort = false)
|
def pbPriority(onlySpeedSort = false)
|
||||||
ret = []
|
ret = []
|
||||||
|
|||||||
@@ -200,8 +200,11 @@ class Battle
|
|||||||
idxBattler += 1
|
idxBattler += 1
|
||||||
break if idxBattler >= @battlers.length
|
break if idxBattler >= @battlers.length
|
||||||
next if !@battlers[idxBattler] || pbOwnedByPlayer?(idxBattler) != isPlayer
|
next if !@battlers[idxBattler] || pbOwnedByPlayer?(idxBattler) != isPlayer
|
||||||
next if @choices[idxBattler][0] != :None # Action is forced, can't choose one
|
if @choices[idxBattler][0] != :None || !pbCanShowCommands?(idxBattler)
|
||||||
next if !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")
|
||||||
|
next
|
||||||
|
end
|
||||||
# AI controls this battler
|
# AI controls this battler
|
||||||
if @controlPlayer || !pbOwnedByPlayer?(idxBattler)
|
if @controlPlayer || !pbOwnedByPlayer?(idxBattler)
|
||||||
@battleAI.pbDefaultChooseEnemyCommand(idxBattler)
|
@battleAI.pbDefaultChooseEnemyCommand(idxBattler)
|
||||||
|
|||||||
@@ -186,9 +186,10 @@ class Battle
|
|||||||
end
|
end
|
||||||
b.effects[PBEffects::Rage] = false if !pbChoseMoveFunctionCode?(i, "StartRaiseUserAtk1WhenDamaged")
|
b.effects[PBEffects::Rage] = false if !pbChoseMoveFunctionCode?(i, "StartRaiseUserAtk1WhenDamaged")
|
||||||
end
|
end
|
||||||
PBDebug.log("")
|
|
||||||
# Calculate move order for this round
|
# Calculate move order for this round
|
||||||
|
PBDebug.log("")
|
||||||
pbCalculatePriority(true)
|
pbCalculatePriority(true)
|
||||||
|
PBDebug.log("")
|
||||||
# Perform actions
|
# Perform actions
|
||||||
pbAttackPhasePriorityChangeMessages
|
pbAttackPhasePriorityChangeMessages
|
||||||
pbAttackPhaseCall
|
pbAttackPhaseCall
|
||||||
|
|||||||
@@ -596,7 +596,7 @@ class Battle
|
|||||||
#=============================================================================
|
#=============================================================================
|
||||||
def pbEndOfRoundPhase
|
def pbEndOfRoundPhase
|
||||||
PBDebug.log("")
|
PBDebug.log("")
|
||||||
PBDebug.log("[End of round]")
|
PBDebug.log("[End of round #{@turnCount + 1}]")
|
||||||
@endOfRound = true
|
@endOfRound = true
|
||||||
@scene.pbBeginEndOfRoundPhase
|
@scene.pbBeginEndOfRoundPhase
|
||||||
pbCalculatePriority # recalculate speeds
|
pbCalculatePriority # recalculate speeds
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ class Battle::Battler
|
|||||||
amt = 1 if amt < 1 && !fainted?
|
amt = 1 if amt < 1 && !fainted?
|
||||||
oldHP = @hp
|
oldHP = @hp
|
||||||
self.hp -= amt
|
self.hp -= amt
|
||||||
PBDebug.log("[HP change] #{pbThis} lost #{amt} HP (#{oldHP}=>#{@hp})") if amt > 0
|
PBDebug.log("[HP change] #{pbThis} lost #{amt} HP (#{oldHP} -> #{@hp})") if amt > 0
|
||||||
raise _INTL("HP less than 0") if @hp < 0
|
raise _INTL("HP less than 0") if @hp < 0
|
||||||
raise _INTL("HP greater than total HP") if @hp > @totalhp
|
raise _INTL("HP greater than total HP") if @hp > @totalhp
|
||||||
@battle.scene.pbHPChanged(self, oldHP, anim) if anyAnim && amt > 0
|
@battle.scene.pbHPChanged(self, oldHP, anim) if anyAnim && amt > 0
|
||||||
@@ -26,7 +26,7 @@ class Battle::Battler
|
|||||||
amt = 1 if amt < 1 && @hp < @totalhp
|
amt = 1 if amt < 1 && @hp < @totalhp
|
||||||
oldHP = @hp
|
oldHP = @hp
|
||||||
self.hp += amt
|
self.hp += amt
|
||||||
PBDebug.log("[HP change] #{pbThis} gained #{amt} HP (#{oldHP}=>#{@hp})") if amt > 0
|
PBDebug.log("[HP change] #{pbThis} gained #{amt} HP (#{oldHP} -> #{@hp})") if amt > 0
|
||||||
raise _INTL("HP less than 0") if @hp < 0
|
raise _INTL("HP less than 0") if @hp < 0
|
||||||
raise _INTL("HP greater than total HP") if @hp > @totalhp
|
raise _INTL("HP greater than total HP") if @hp > @totalhp
|
||||||
@battle.scene.pbHPChanged(self, oldHP, anim) if anyAnim && amt > 0
|
@battle.scene.pbHPChanged(self, oldHP, anim) if anyAnim && amt > 0
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ class Battle::Battler
|
|||||||
if increment > 0
|
if increment > 0
|
||||||
stat_name = GameData::Stat.get(stat).name
|
stat_name = GameData::Stat.get(stat).name
|
||||||
new = @stages[stat] + increment
|
new = @stages[stat] + increment
|
||||||
PBDebug.log("[Stat change] #{pbThis}'s #{stat_name}: #{@stages[stat]} -> #{new} (+#{increment})")
|
PBDebug.log("[Stat change] #{pbThis}'s #{stat_name} changed by +#{increment} (#{@stages[stat]} -> #{new})")
|
||||||
@stages[stat] += increment
|
@stages[stat] += increment
|
||||||
@statsRaisedThisRound = true
|
@statsRaisedThisRound = true
|
||||||
end
|
end
|
||||||
@@ -187,7 +187,7 @@ class Battle::Battler
|
|||||||
if increment > 0
|
if increment > 0
|
||||||
stat_name = GameData::Stat.get(stat).name
|
stat_name = GameData::Stat.get(stat).name
|
||||||
new = @stages[stat] - increment
|
new = @stages[stat] - increment
|
||||||
PBDebug.log("[Stat change] #{pbThis}'s #{stat_name}: #{@stages[stat]} -> #{new} (-#{increment})")
|
PBDebug.log("[Stat change] #{pbThis}'s #{stat_name} changed by -#{increment} (#{@stages[stat]} -> #{new})")
|
||||||
@stages[stat] -= increment
|
@stages[stat] -= increment
|
||||||
@statsLoweredThisRound = true
|
@statsLoweredThisRound = true
|
||||||
@statsDropped = true
|
@statsDropped = true
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ class Battle::Battler
|
|||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
# Use the move
|
# Use the move
|
||||||
PBDebug.log("[Move usage] #{pbThis} started using #{choice[2].name}")
|
PBDebug.log("[Use move] #{pbThis} (#{@index}) used #{choice[2].name}")
|
||||||
PBDebug.logonerr {
|
PBDebug.logonerr {
|
||||||
pbUseMove(choice, choice[2] == @battle.struggle)
|
pbUseMove(choice, choice[2] == @battle.struggle)
|
||||||
}
|
}
|
||||||
@@ -146,7 +146,7 @@ class Battle::Battler
|
|||||||
choice[2].pp = -1
|
choice[2].pp = -1
|
||||||
end
|
end
|
||||||
choice[3] = target # Target (-1 means no target yet)
|
choice[3] = target # Target (-1 means no target yet)
|
||||||
PBDebug.log("[Move usage] #{pbThis} started using the called/simple move #{choice[2].name}")
|
PBDebug.log("[Use move] #{pbThis} used the called/simple move #{choice[2].name}")
|
||||||
pbUseMove(choice, specialUsage)
|
pbUseMove(choice, specialUsage)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -192,10 +192,12 @@ class Battle::Battler
|
|||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
if @effects[PBEffects::HyperBeam] > 0 # Intentionally before Truant
|
if @effects[PBEffects::HyperBeam] > 0 # Intentionally before Truant
|
||||||
|
PBDebug.log("[Move failed] #{pbThis} is recharging after using #{move.name}")
|
||||||
@battle.pbDisplay(_INTL("{1} must recharge!", pbThis))
|
@battle.pbDisplay(_INTL("{1} must recharge!", pbThis))
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
if choice[1] == -2 # Battle Palace
|
if choice[1] == -2 # Battle Palace
|
||||||
|
PBDebug.log("[Move failed] #{pbThis} can't act in the Battle Palace somehow")
|
||||||
@battle.pbDisplay(_INTL("{1} appears incapable of using its power!", pbThis))
|
@battle.pbDisplay(_INTL("{1} appears incapable of using its power!", pbThis))
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
@@ -210,6 +212,7 @@ class Battle::Battler
|
|||||||
else
|
else
|
||||||
pbContinueStatus
|
pbContinueStatus
|
||||||
if !move.usableWhenAsleep? # Snore/Sleep Talk
|
if !move.usableWhenAsleep? # Snore/Sleep Talk
|
||||||
|
PBDebug.log("[Move failed] #{pbThis} is asleep")
|
||||||
@lastMoveFailed = true
|
@lastMoveFailed = true
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
@@ -220,6 +223,7 @@ class Battle::Battler
|
|||||||
pbCureStatus
|
pbCureStatus
|
||||||
else
|
else
|
||||||
pbContinueStatus
|
pbContinueStatus
|
||||||
|
PBDebug.log("[Move failed] #{pbThis} is frozen")
|
||||||
@lastMoveFailed = true
|
@lastMoveFailed = true
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
@@ -235,12 +239,14 @@ class Battle::Battler
|
|||||||
@battle.pbDisplay(_INTL("{1} is loafing around!", pbThis))
|
@battle.pbDisplay(_INTL("{1} is loafing around!", pbThis))
|
||||||
@lastMoveFailed = true
|
@lastMoveFailed = true
|
||||||
@battle.pbHideAbilitySplash(self)
|
@battle.pbHideAbilitySplash(self)
|
||||||
|
PBDebug.log("[Move failed] #{pbThis} can't act because of #{abilityName}")
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
# Flinching
|
# Flinching
|
||||||
if @effects[PBEffects::Flinch]
|
if @effects[PBEffects::Flinch]
|
||||||
@battle.pbDisplay(_INTL("{1} flinched and couldn't move!", pbThis))
|
@battle.pbDisplay(_INTL("{1} flinched and couldn't move!", pbThis))
|
||||||
|
PBDebug.log("[Move failed] #{pbThis} flinched")
|
||||||
if abilityActive?
|
if abilityActive?
|
||||||
Battle::AbilityEffects.triggerOnFlinch(self.ability, self, @battle)
|
Battle::AbilityEffects.triggerOnFlinch(self.ability, self, @battle)
|
||||||
end
|
end
|
||||||
@@ -259,6 +265,7 @@ class Battle::Battler
|
|||||||
threshold = (Settings::MECHANICS_GENERATION >= 7) ? 33 : 50 # % chance
|
threshold = (Settings::MECHANICS_GENERATION >= 7) ? 33 : 50 # % chance
|
||||||
if @battle.pbRandom(100) < threshold
|
if @battle.pbRandom(100) < threshold
|
||||||
pbConfusionDamage(_INTL("It hurt itself in its confusion!"))
|
pbConfusionDamage(_INTL("It hurt itself in its confusion!"))
|
||||||
|
PBDebug.log("[Move failed] #{pbThis} hurt itself in its confusion")
|
||||||
@lastMoveFailed = true
|
@lastMoveFailed = true
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
@@ -267,6 +274,7 @@ class Battle::Battler
|
|||||||
# Paralysis
|
# Paralysis
|
||||||
if @status == :PARALYSIS && @battle.pbRandom(100) < 25
|
if @status == :PARALYSIS && @battle.pbRandom(100) < 25
|
||||||
pbContinueStatus
|
pbContinueStatus
|
||||||
|
PBDebug.log("[Move failed] #{pbThis} is paralyzed")
|
||||||
@lastMoveFailed = true
|
@lastMoveFailed = true
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
@@ -277,6 +285,7 @@ class Battle::Battler
|
|||||||
@battle.battlers[@effects[PBEffects::Attract]].pbThis(true)))
|
@battle.battlers[@effects[PBEffects::Attract]].pbThis(true)))
|
||||||
if @battle.pbRandom(100) < 50
|
if @battle.pbRandom(100) < 50
|
||||||
@battle.pbDisplay(_INTL("{1} is immobilized by love!", pbThis))
|
@battle.pbDisplay(_INTL("{1} is immobilized by love!", pbThis))
|
||||||
|
PBDebug.log("[Move failed] #{pbThis} is immobilized by love")
|
||||||
@lastMoveFailed = true
|
@lastMoveFailed = true
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
@@ -295,7 +304,10 @@ class Battle::Battler
|
|||||||
# Two-turn attacks can't fail here in the charging turn
|
# Two-turn attacks can't fail here in the charging turn
|
||||||
return true if user.effects[PBEffects::TwoTurnAttack]
|
return true if user.effects[PBEffects::TwoTurnAttack]
|
||||||
# Move-specific failures
|
# Move-specific failures
|
||||||
return false if move.pbFailsAgainstTarget?(user, target, show_message)
|
if move.pbFailsAgainstTarget?(user, target, show_message)
|
||||||
|
PBDebug.log(sprintf("[Move failed] In function code %s's def pbFailsAgainstTarget?", move.function))
|
||||||
|
return false
|
||||||
|
end
|
||||||
# Immunity to priority moves because of Psychic Terrain
|
# Immunity to priority moves because of Psychic Terrain
|
||||||
if @battle.field.terrain == :Psychic && target.affectedByTerrain? && target.opposes?(user) &&
|
if @battle.field.terrain == :Psychic && target.affectedByTerrain? && target.opposes?(user) &&
|
||||||
@battle.choices[user.index][4] > 0 # Move priority saved from pbCalculatePriority
|
@battle.choices[user.index][4] > 0 # Move priority saved from pbCalculatePriority
|
||||||
@@ -551,15 +563,17 @@ class Battle::Battler
|
|||||||
miss = true
|
miss = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
target.damageState.invulnerable = true if miss
|
if miss
|
||||||
if !miss
|
target.damageState.invulnerable = true
|
||||||
|
PBDebug.log("[Move failed] Target is semi-invulnerable")
|
||||||
|
else
|
||||||
# Called by another move
|
# Called by another move
|
||||||
return true if skipAccuracyCheck
|
return true if skipAccuracyCheck
|
||||||
# Accuracy check
|
# Accuracy check
|
||||||
return true if move.pbAccuracyCheck(user, target) # Includes Counter/Mirror Coat
|
return true if move.pbAccuracyCheck(user, target) # Includes Counter/Mirror Coat
|
||||||
|
PBDebug.log("[Move failed] Failed pbAccuracyCheck")
|
||||||
end
|
end
|
||||||
# Missed
|
# Missed
|
||||||
PBDebug.log("[Move failed] Failed pbAccuracyCheck or target is semi-invulnerable")
|
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -248,10 +248,9 @@ class Battle::Move
|
|||||||
oldHP = b.hp
|
oldHP = b.hp
|
||||||
if b.damageState.substitute
|
if b.damageState.substitute
|
||||||
old_sub_hp = b.effects[PBEffects::Substitute] + b.damageState.hpLost
|
old_sub_hp = b.effects[PBEffects::Substitute] + b.damageState.hpLost
|
||||||
PBDebug.log("[Move damage] #{b.pbThis}'s substitute lost #{b.damageState.hpLost} HP (#{old_sub_hp}=>#{b.effects[PBEffects::Substitute]})")
|
PBDebug.log("[Substitute HP change] #{b.pbThis}'s substitute lost #{b.damageState.hpLost} HP (#{old_sub_hp} -> #{b.effects[PBEffects::Substitute]})")
|
||||||
else
|
else
|
||||||
oldHP += b.damageState.hpLost
|
oldHP += b.damageState.hpLost
|
||||||
PBDebug.log("[Move damage] #{b.pbThis} lost #{b.damageState.hpLost} HP (#{oldHP}=>#{b.hp})")
|
|
||||||
end
|
end
|
||||||
effectiveness = 0
|
effectiveness = 0
|
||||||
if Effectiveness.resistant?(b.damageState.typeMod)
|
if Effectiveness.resistant?(b.damageState.typeMod)
|
||||||
|
|||||||
@@ -23,10 +23,17 @@ end
|
|||||||
# (Fell Stinger (Gen 6-))
|
# (Fell Stinger (Gen 6-))
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
class Battle::Move::RaiseUserAttack2IfTargetFaints < Battle::Move
|
class Battle::Move::RaiseUserAttack2IfTargetFaints < Battle::Move
|
||||||
|
attr_reader :statUp
|
||||||
|
|
||||||
|
def initialize(battle, move)
|
||||||
|
super
|
||||||
|
@statUp = [:ATTACK, 2]
|
||||||
|
end
|
||||||
|
|
||||||
def pbEffectAfterAllHits(user, target)
|
def pbEffectAfterAllHits(user, target)
|
||||||
return if !target.damageState.fainted
|
return if !target.damageState.fainted
|
||||||
return if !user.pbCanRaiseStatStage?(:ATTACK, user, self)
|
return if !user.pbCanRaiseStatStage?(@statUp[0], user, self)
|
||||||
user.pbRaiseStatStage(:ATTACK, 2, user)
|
user.pbRaiseStatStage(@statUp[0], @statUp[1], user)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -45,10 +52,17 @@ end
|
|||||||
# (Fell Stinger (Gen 7+))
|
# (Fell Stinger (Gen 7+))
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
class Battle::Move::RaiseUserAttack3IfTargetFaints < Battle::Move
|
class Battle::Move::RaiseUserAttack3IfTargetFaints < Battle::Move
|
||||||
|
attr_reader :statUp
|
||||||
|
|
||||||
|
def initialize(battle, move)
|
||||||
|
super
|
||||||
|
@statUp = [:ATTACK, 3]
|
||||||
|
end
|
||||||
|
|
||||||
def pbEffectAfterAllHits(user, target)
|
def pbEffectAfterAllHits(user, target)
|
||||||
return if !target.damageState.fainted
|
return if !target.damageState.fainted
|
||||||
return if !user.pbCanRaiseStatStage?(:ATTACK, user, self)
|
return if !user.pbCanRaiseStatStage?(@statUp[0], user, self)
|
||||||
user.pbRaiseStatStage(:ATTACK, 3, user)
|
user.pbRaiseStatStage(@statUp[0], @statUp[1], user)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
#===============================================================================
|
#===============================================================================
|
||||||
# Used when generating new trainers for battle challenges
|
# Used when generating new trainers for battle challenges
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
class Battle::DebugSceneNoLogging
|
class Battle::DebugSceneNoVisuals
|
||||||
def initialize
|
def initialize(log_messages = false)
|
||||||
@battle = nil
|
@battle = nil
|
||||||
@lastCmd = [0, 0, 0, 0]
|
@lastCmd = [0, 0, 0, 0]
|
||||||
@lastMove = [0, 0, 0, 0]
|
@lastMove = [0, 0, 0, 0]
|
||||||
|
@log_messages = log_messages
|
||||||
end
|
end
|
||||||
|
|
||||||
# Called whenever the battle begins.
|
# Called whenever the battle begins.
|
||||||
@@ -42,11 +43,24 @@ class Battle::DebugSceneNoLogging
|
|||||||
def pbRefresh; end
|
def pbRefresh; end
|
||||||
def pbRefreshOne(idxBattler); end
|
def pbRefreshOne(idxBattler); end
|
||||||
|
|
||||||
def pbDisplayMessage(msg, brief = false); end
|
def pbDisplayMessage(msg, brief = false)
|
||||||
|
PBDebug.log_message(msg) if @log_messages
|
||||||
|
end
|
||||||
alias pbDisplay pbDisplayMessage
|
alias pbDisplay pbDisplayMessage
|
||||||
def pbDisplayPausedMessage(msg); end
|
|
||||||
def pbDisplayConfirmMessage(msg); return true; end
|
def pbDisplayPausedMessage(msg)
|
||||||
def pbShowCommands(msg, commands, defaultValue); return 0; end
|
PBDebug.log_message(msg) if @log_messages
|
||||||
|
end
|
||||||
|
|
||||||
|
def pbDisplayConfirmMessage(msg)
|
||||||
|
PBDebug.log_message(msg) if @log_messages
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
def pbShowCommands(msg, commands, defaultValue)
|
||||||
|
PBDebug.log_message(msg) if @log_messages
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
|
||||||
def pbSendOutBattlers(sendOuts, startBattle = false); end
|
def pbSendOutBattlers(sendOuts, startBattle = false); end
|
||||||
def pbRecall(idxBattler); end
|
def pbRecall(idxBattler); end
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ class Battle::AI
|
|||||||
@trainer = @trainers[(opposes) ? 1 : 0][trainer_index]
|
@trainer = @trainers[(opposes) ? 1 : 0][trainer_index]
|
||||||
# Find the AI battler for which the action is being chosen
|
# Find the AI battler for which the action is being chosen
|
||||||
@user = @battlers[idxBattler]
|
@user = @battlers[idxBattler]
|
||||||
@user.refresh_battler
|
@battlers.each { |b| b.refresh_battler if b }
|
||||||
end
|
end
|
||||||
|
|
||||||
# Choose an action.
|
# Choose an action.
|
||||||
|
|||||||
@@ -11,16 +11,18 @@ class Battle::AI
|
|||||||
shouldSwitch = forceSwitch
|
shouldSwitch = forceSwitch
|
||||||
battler = @user.battler
|
battler = @user.battler
|
||||||
batonPass = -1
|
batonPass = -1
|
||||||
|
foe = nil
|
||||||
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 && battler.turnCount > 0 && @trainer.high_skill?
|
if !shouldSwitch && battler.turnCount > 0 && @trainer.high_skill?
|
||||||
target = battler.pbDirectOpposing(true)
|
target = battler.pbDirectOpposing(true)
|
||||||
|
foe = @battlers[target.index]
|
||||||
if !target.fainted? && target.lastMoveUsed &&
|
if !target.fainted? && target.lastMoveUsed &&
|
||||||
(target.level - battler.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 = battler.effectiveness_of_type_against_battler(moveType, target)
|
typeMod = @user.effectiveness_of_type_against_battler(moveType, foe)
|
||||||
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)
|
||||||
@@ -106,7 +108,7 @@ 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?(battler.effectiveness_of_type_against_battler(moveType))
|
if moveType && Effectiveness.ineffective?(@user.effectiveness_of_type_against_battler(moveType, foe))
|
||||||
weight = 65
|
weight = 65
|
||||||
typeMod = pbCalcTypeModPokemon(pkmn, battler.pbDirectOpposing(true))
|
typeMod = pbCalcTypeModPokemon(pkmn, battler.pbDirectOpposing(true))
|
||||||
if Effectiveness.super_effective?(typeMod)
|
if Effectiveness.super_effective?(typeMod)
|
||||||
@@ -114,7 +116,7 @@ class Battle::AI
|
|||||||
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?(battler.effectiveness_of_type_against_battler(moveType))
|
elsif moveType && Effectiveness.resistant?(@user.effectiveness_of_type_against_battler(moveType, foe))
|
||||||
weight = 40
|
weight = 40
|
||||||
typeMod = pbCalcTypeModPokemon(pkmn, battler.pbDirectOpposing(true))
|
typeMod = pbCalcTypeModPokemon(pkmn, battler.pbDirectOpposing(true))
|
||||||
if Effectiveness.super_effective?(typeMod)
|
if Effectiveness.super_effective?(typeMod)
|
||||||
|
|||||||
@@ -11,20 +11,17 @@ class Battle::AI
|
|||||||
# (which are based on the predicted damages). Multi-target moves could
|
# (which are based on the predicted damages). Multi-target moves could
|
||||||
# be fiddly since damages should be calculated for each target but
|
# be fiddly since damages should be calculated for each target but
|
||||||
# they're all related.
|
# they're all related.
|
||||||
battler.eachMoveWithIndex do |_m, i|
|
battler.eachMoveWithIndex do |m, i|
|
||||||
next if !@battle.pbCanChooseMove?(battler.index, i, false) # Unchoosable moves aren't considered
|
if !@battle.pbCanChooseMove?(battler.index, i, false) # Unchoosable moves aren't considered
|
||||||
|
if m.pp == 0 && m.total_pp > 0
|
||||||
|
PBDebug.log("[AI] #{battler.pbThis} (#{battler.index}) cannot use move #{m.name} as it has no PP left")
|
||||||
|
else
|
||||||
|
PBDebug.log("[AI] #{battler.pbThis} (#{battler.index}) cannot choose to use #{m.name}")
|
||||||
|
end
|
||||||
|
next
|
||||||
|
end
|
||||||
pbAddMoveWithScoreToChoices(i, choices)
|
pbAddMoveWithScoreToChoices(i, choices)
|
||||||
end
|
end
|
||||||
# Log the available choices
|
|
||||||
if $INTERNAL
|
|
||||||
logMsg = "[AI] Move choices for #{battler.pbThis(true)} (#{battler.index}): "
|
|
||||||
choices.each_with_index do |c, i|
|
|
||||||
logMsg += "#{battler.moves[c[0]].name}=#{c[1]}"
|
|
||||||
logMsg += " (target #{c[2]})" if c[2] >= 0
|
|
||||||
logMsg += ", " if i < choices.length - 1
|
|
||||||
end
|
|
||||||
PBDebug.log(logMsg)
|
|
||||||
end
|
|
||||||
@battle.moldBreaker = false
|
@battle.moldBreaker = false
|
||||||
return choices
|
return choices
|
||||||
end
|
end
|
||||||
@@ -159,7 +156,7 @@ class Battle::AI
|
|||||||
target_battler = @target.battler
|
target_battler = @target.battler
|
||||||
|
|
||||||
# Predict whether the move will fail
|
# Predict whether the move will fail
|
||||||
return 50 if pbPredictMoveFailure
|
return 25 if pbPredictMoveFailure
|
||||||
|
|
||||||
# Get the base score for the move
|
# Get the base score for the move
|
||||||
if @move.damagingMove?
|
if @move.damagingMove?
|
||||||
@@ -188,21 +185,12 @@ class Battle::AI
|
|||||||
def pbChooseMove(choices)
|
def pbChooseMove(choices)
|
||||||
user_battler = @user.battler
|
user_battler = @user.battler
|
||||||
|
|
||||||
# If there are no calculated choices, pick one at random
|
# If no moves can be chosen, auto-choose a move or Struggle
|
||||||
if choices.length == 0
|
if choices.length == 0
|
||||||
# NOTE: Can only get here if no moves can be chosen, i.e. will auto-use a
|
|
||||||
# move or struggle.
|
|
||||||
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)
|
@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_battler.pbThis} (#{user_battler.index}) will auto-use a move or Struggle")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
PBDebug.log("[AI] #{user_battler.pbThis} (#{user_battler.index}) doesn't want to use any moves; picking one at random")
|
|
||||||
end
|
|
||||||
|
|
||||||
# Figure out useful information about the choices
|
# Figure out useful information about the choices
|
||||||
max_score = 0
|
max_score = 0
|
||||||
@@ -211,31 +199,45 @@ class Battle::AI
|
|||||||
# Decide whether all choices are bad, and if so, try switching instead
|
# Decide whether all choices are bad, and if so, try switching instead
|
||||||
if @trainer.high_skill? && @user.can_switch_lax?
|
if @trainer.high_skill? && @user.can_switch_lax?
|
||||||
badMoves = false
|
badMoves = false
|
||||||
if (max_score <= 20 && user_battler.turnCount > 2) ||
|
if (max_score <= 25 && user_battler.turnCount > 2) ||
|
||||||
(max_score <= 40 && user_battler.turnCount > 5)
|
(max_score <= 50 && user_battler.turnCount > 5)
|
||||||
badMoves = true if pbAIRandom(100) < 80
|
badMoves = true if pbAIRandom(100) < 80
|
||||||
end
|
end
|
||||||
if !badMoves && max_score < 60 && user_battler.turnCount > 1
|
if !badMoves && max_score < 50 && user_battler.turnCount >= 1
|
||||||
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 && pbEnemyShouldWithdrawEx?(true)
|
||||||
if $INTERNAL
|
|
||||||
PBDebug.log("[AI] #{user_battler.pbThis} (#{user_battler.index}) will switch due to terrible moves")
|
PBDebug.log("[AI] #{user_battler.pbThis} (#{user_battler.index}) will switch due to terrible moves")
|
||||||
end
|
|
||||||
return
|
return
|
||||||
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
|
||||||
threshold = (max_score * 0.85).floor
|
threshold = (max_score * 0.85).floor
|
||||||
choices.each { |c| c[1] = [c[1] - threshold, 0].max }
|
choices.each { |c| c[3] = [c[1] - threshold, 0].max }
|
||||||
total_score = choices.sum { |c| c[1] }
|
total_score = choices.sum { |c| c[3] }
|
||||||
|
|
||||||
|
# Log the available choices
|
||||||
|
if $INTERNAL
|
||||||
|
PBDebug.log("[AI] Move choices for #{user_battler.pbThis(true)} (#{user_battler.index}):")
|
||||||
|
choices.each_with_index do |c, i|
|
||||||
|
chance = "0"
|
||||||
|
chance = sprintf("%.1f", 100.0 * c[3] / total_score) if c[3] > 0
|
||||||
|
while chance.length < 5
|
||||||
|
chance = " " + chance
|
||||||
|
end
|
||||||
|
log_msg = " * #{chance}% chance: #{user_battler.moves[c[0]].name}"
|
||||||
|
log_msg += " (against target #{c[2]})" if c[2] >= 0
|
||||||
|
log_msg += " = score #{c[1]}"
|
||||||
|
PBDebug.log(log_msg)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# Pick a move randomly from choices weighted by their scores
|
# Pick a move randomly from choices weighted by their scores
|
||||||
randNum = pbAIRandom(total_score)
|
randNum = pbAIRandom(total_score)
|
||||||
choices.each do |c|
|
choices.each do |c|
|
||||||
randNum -= c[1]
|
randNum -= c[3]
|
||||||
next if randNum >= 0
|
next if randNum >= 0
|
||||||
@battle.pbRegisterMove(user_battler.index, c[0], false)
|
@battle.pbRegisterMove(user_battler.index, c[0], false)
|
||||||
@battle.pbRegisterTarget(user_battler.index, c[2]) if c[2] >= 0
|
@battle.pbRegisterTarget(user_battler.index, c[2]) if c[2] >= 0
|
||||||
@@ -244,7 +246,7 @@ class Battle::AI
|
|||||||
|
|
||||||
# Log the result
|
# Log the result
|
||||||
if @battle.choices[user_battler.index][2]
|
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}")
|
PBDebug.log(" => will use #{@battle.choices[user_battler.index][2].name}")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -62,22 +62,22 @@ class Battle::AI
|
|||||||
# TODO: Exception if user knows Baton Pass/Stored Power?
|
# TODO: Exception if user knows Baton Pass/Stored Power?
|
||||||
case stat
|
case stat
|
||||||
when :ATTACK
|
when :ATTACK
|
||||||
return false if !@user.check_for_move { |move| move.physicalMove?(move.type) &&
|
return false if !@user.check_for_move { |m| m.physicalMove?(move.type) &&
|
||||||
move.function != "UseUserBaseDefenseInsteadOfUserBaseAttack" &&
|
m.function != "UseUserBaseDefenseInsteadOfUserBaseAttack" &&
|
||||||
move.function != "UseTargetAttackInsteadOfUserAttack" }
|
m.function != "UseTargetAttackInsteadOfUserAttack" }
|
||||||
when :DEFENSE
|
when :DEFENSE
|
||||||
each_foe_battler(@user.side) do |b, i|
|
each_foe_battler(@user.side) do |b, i|
|
||||||
next if !b.check_for_move { |move| move.physicalMove?(move.type) ||
|
next if !b.check_for_move { |m| m.physicalMove?(m.type) ||
|
||||||
move.function == "UseTargetDefenseInsteadOfTargetSpDef" }
|
m.function == "UseTargetDefenseInsteadOfTargetSpDef" }
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
return false
|
return false
|
||||||
when :SPECIAL_ATTACK
|
when :SPECIAL_ATTACK
|
||||||
return false if !@user.check_for_move { |move| move.specialMove?(move.rough_type) }
|
return false if !@user.check_for_move { |m| m.specialMove?(m.type) }
|
||||||
when :SPECIAL_DEFENSE
|
when :SPECIAL_DEFENSE
|
||||||
each_foe_battler(@user.side) do |b, i|
|
each_foe_battler(@user.side) do |b, i|
|
||||||
next if !b.check_for_move { |move| move.specialMove?(move.type) &&
|
next if !b.check_for_move { |m| m.specialMove?(m.type) &&
|
||||||
move.function != "UseTargetDefenseInsteadOfTargetSpDef" }
|
m.function != "UseTargetDefenseInsteadOfTargetSpDef" }
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
return false
|
return false
|
||||||
@@ -86,7 +86,7 @@ class Battle::AI
|
|||||||
"PowerHigherWithUserFasterThanTarget",
|
"PowerHigherWithUserFasterThanTarget",
|
||||||
"PowerHigherWithUserPositiveStatStages"
|
"PowerHigherWithUserPositiveStatStages"
|
||||||
]
|
]
|
||||||
if !@user.check_for_move { |move| moves_that_prefer_high_speed.include?(move.function) }
|
if !@user.check_for_move { |m| moves_that_prefer_high_speed.include?(m.function) }
|
||||||
each_foe_battler(@user.side) do |b, i|
|
each_foe_battler(@user.side) do |b, i|
|
||||||
return true if b.faster_than?(@user)
|
return true if b.faster_than?(@user)
|
||||||
end
|
end
|
||||||
@@ -241,7 +241,7 @@ class Battle::AI
|
|||||||
if @user.stages[stat] >= 3
|
if @user.stages[stat] >= 3
|
||||||
score -= 20
|
score -= 20
|
||||||
else
|
else
|
||||||
has_special_moves = @user.check_for_move { |move| move.specialMove?(move.rough_type) }
|
has_special_moves = @user.check_for_move { |m| m.specialMove?(m.type) }
|
||||||
inc = (has_special_moves) ? 5 : 10
|
inc = (has_special_moves) ? 5 : 10
|
||||||
score += inc * (3 - @user.stages[stat]) * increment # 5 to 45
|
score += inc * (3 - @user.stages[stat]) * increment # 5 to 45
|
||||||
score += 5 * increment if @user.hp == @user.totalhp
|
score += 5 * increment if @user.hp == @user.totalhp
|
||||||
@@ -262,9 +262,9 @@ class Battle::AI
|
|||||||
if @user.stages[stat] >= 3
|
if @user.stages[stat] >= 3
|
||||||
score -= 20
|
score -= 20
|
||||||
else
|
else
|
||||||
has_physical_moves = @user.check_for_move { |move| move.physicalMove?(move.type) &&
|
has_physical_moves = @user.check_for_move { |m| m.physicalMove?(m.type) &&
|
||||||
move.function != "UseUserBaseDefenseInsteadOfUserBaseAttack" &&
|
m.function != "UseUserBaseDefenseInsteadOfUserBaseAttack" &&
|
||||||
move.function != "UseTargetAttackInsteadOfUserAttack" }
|
m.function != "UseTargetAttackInsteadOfUserAttack" }
|
||||||
inc = (has_physical_moves) ? 5 : 10
|
inc = (has_physical_moves) ? 5 : 10
|
||||||
score += inc * (3 - @user.stages[stat]) * increment # 5 to 45
|
score += inc * (3 - @user.stages[stat]) * increment # 5 to 45
|
||||||
score += 5 * increment if @user.hp == @user.totalhp
|
score += 5 * increment if @user.hp == @user.totalhp
|
||||||
@@ -288,7 +288,7 @@ class Battle::AI
|
|||||||
end
|
end
|
||||||
# Don't prefer if any foe has Gyro Ball
|
# Don't prefer if any foe has Gyro Ball
|
||||||
each_foe_battler(@user.side) do |b, i|
|
each_foe_battler(@user.side) do |b, i|
|
||||||
next if !b.check_for_move { |move| move.function == "PowerHigherWithTargetFasterThanUser" }
|
next if !b.check_for_move { |m| m.function == "PowerHigherWithTargetFasterThanUser" }
|
||||||
score -= 10 * increment
|
score -= 10 * increment
|
||||||
end
|
end
|
||||||
# Don't prefer if user has Speed Boost (will be gaining Speed anyway)
|
# Don't prefer if user has Speed Boost (will be gaining Speed anyway)
|
||||||
@@ -336,12 +336,12 @@ class Battle::AI
|
|||||||
pos_change = [@user.stages[stat] + increment, increment].min
|
pos_change = [@user.stages[stat] + increment, increment].min
|
||||||
if pos_change > 0
|
if pos_change > 0
|
||||||
# Prefer if user has Stored Power
|
# Prefer if user has Stored Power
|
||||||
if @user.check_for_move { |move| move.function == "PowerHigherWithUserPositiveStatStages" }
|
if @user.check_for_move { |m| m.function == "PowerHigherWithUserPositiveStatStages" }
|
||||||
score += 10 * pos_change
|
score += 10 * pos_change
|
||||||
end
|
end
|
||||||
# Don't prefer if any foe has Punishment
|
# Don't prefer if any foe has Punishment
|
||||||
each_foe_battler(@user.side) do |b, i|
|
each_foe_battler(@user.side) do |b, i|
|
||||||
next if !b.check_for_move { |move| move.function == "PowerHigherWithTargetPositiveStatStages" }
|
next if !b.check_for_move { |m| m.function == "PowerHigherWithTargetPositiveStatStages" }
|
||||||
score -= 10 * pos_change
|
score -= 10 * pos_change
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -355,7 +355,7 @@ class Battle::AI
|
|||||||
when :ATTACK
|
when :ATTACK
|
||||||
# TODO: Don't prefer if target has previously used a move that benefits
|
# TODO: Don't prefer if target has previously used a move that benefits
|
||||||
# from user's Attack being boosted.
|
# from user's Attack being boosted.
|
||||||
# mini_score *= 0.3 if @target.check_for_move { |move| move.function == "UseTargetAttackInsteadOfUserAttack" } # Foul Play
|
# mini_score *= 0.3 if @target.check_for_move { |m| m.function == "UseTargetAttackInsteadOfUserAttack" } # Foul Play
|
||||||
# Prefer if user can definitely survive a hit no matter how powerful, and
|
# Prefer if user can definitely survive a hit no matter how powerful, and
|
||||||
# it won't be hurt by weather
|
# it won't be hurt by weather
|
||||||
# if @user.hp == @user.totalhp &&
|
# if @user.hp == @user.totalhp &&
|
||||||
@@ -393,7 +393,7 @@ class Battle::AI
|
|||||||
# (@user.hasActiveItem?(:BLACKSLUDGE) && @user.pbHasType?(:POISON))
|
# (@user.hasActiveItem?(:BLACKSLUDGE) && @user.pbHasType?(:POISON))
|
||||||
# Prefer if user knows any healing moves
|
# Prefer if user knows any healing moves
|
||||||
# # TODO: Is 1.2x for RaiseUserAtkDefAcc1 Coil (+Atk, +Def, +acc).
|
# # TODO: Is 1.2x for RaiseUserAtkDefAcc1 Coil (+Atk, +Def, +acc).
|
||||||
# mini_score *= 1.3 if check_for_move(@user) { |move| move.healingMove? }
|
# mini_score *= 1.3 if check_for_move(@user) { |m| m.healingMove? }
|
||||||
# Prefer if user knows Pain Split or Leech Seed
|
# Prefer if user knows Pain Split or Leech Seed
|
||||||
# # TODO: Leech Seed is 1.2x for RaiseUserAtkDefAcc1 Coil (+Atk, +Def, +acc).
|
# # TODO: Leech Seed is 1.2x for RaiseUserAtkDefAcc1 Coil (+Atk, +Def, +acc).
|
||||||
# mini_score *= 1.2 if @user.pbHasMoveFunction?("UserTargetAverageHP") # Pain Split
|
# mini_score *= 1.2 if @user.pbHasMoveFunction?("UserTargetAverageHP") # Pain Split
|
||||||
@@ -483,7 +483,7 @@ class Battle::AI
|
|||||||
# mini_score *= 1.2 if @user.hasActiveItem?(:LEFTOVERS) ||
|
# mini_score *= 1.2 if @user.hasActiveItem?(:LEFTOVERS) ||
|
||||||
# (@user.hasActiveItem?(:BLACKSLUDGE) && @user.pbHasType?(:POISON))
|
# (@user.hasActiveItem?(:BLACKSLUDGE) && @user.pbHasType?(:POISON))
|
||||||
# Prefer if user knows any healing moves
|
# Prefer if user knows any healing moves
|
||||||
# mini_score *= 1.3 if check_for_move(@user) { |move| move.healingMove? }
|
# mini_score *= 1.3 if check_for_move(@user) { |m| m.healingMove? }
|
||||||
# Prefer if user knows Pain Split or Leech Seed
|
# Prefer if user knows Pain Split or Leech Seed
|
||||||
# mini_score *= 1.2 if @user.pbHasMoveFunction?("UserTargetAverageHP") # Pain Split
|
# mini_score *= 1.2 if @user.pbHasMoveFunction?("UserTargetAverageHP") # Pain Split
|
||||||
# mini_score *= 1.3 if @user.pbHasMoveFunction?("StartLeechSeedTarget") # Leech Seed
|
# mini_score *= 1.3 if @user.pbHasMoveFunction?("StartLeechSeedTarget") # Leech Seed
|
||||||
@@ -495,7 +495,7 @@ class Battle::AI
|
|||||||
|
|
||||||
when :ACCURACY
|
when :ACCURACY
|
||||||
# Prefer if user knows any weaker moves
|
# Prefer if user knows any weaker moves
|
||||||
mini_score *= 1.1 if check_for_move(@user) { |move| move.damagingMove? && move.basedamage < 95 }
|
mini_score *= 1.1 if check_for_move(@user) { |m| m.damagingMove? && m.basedamage < 95 }
|
||||||
# Prefer if target has a raised evasion
|
# Prefer if target has a raised evasion
|
||||||
sum_stages = @target.stages[:EVASION]
|
sum_stages = @target.stages[:EVASION]
|
||||||
mini_score *= 1 + sum_stages * 0.05 if sum_stages > 0
|
mini_score *= 1 + sum_stages * 0.05 if sum_stages > 0
|
||||||
@@ -521,7 +521,7 @@ class Battle::AI
|
|||||||
mini_score *= 1.3
|
mini_score *= 1.3
|
||||||
end
|
end
|
||||||
# Prefer if user knows any healing moves
|
# Prefer if user knows any healing moves
|
||||||
mini_score *= 1.3 if check_for_move(@user) { |move| move.healingMove? }
|
mini_score *= 1.3 if check_for_move(@user) { |m| move.healingMove? }
|
||||||
# Prefer if user knows Pain Split or Leech Seed
|
# Prefer if user knows Pain Split or Leech Seed
|
||||||
mini_score *= 1.2 if @user.pbHasMoveFunction?("UserTargetAverageHP") # Pain Split
|
mini_score *= 1.2 if @user.pbHasMoveFunction?("UserTargetAverageHP") # Pain Split
|
||||||
mini_score *= 1.3 if @user.pbHasMoveFunction?("StartLeechSeedTarget") # Leech Seed
|
mini_score *= 1.3 if @user.pbHasMoveFunction?("StartLeechSeedTarget") # Leech Seed
|
||||||
@@ -537,8 +537,8 @@ class Battle::AI
|
|||||||
|
|
||||||
# TODO: Don't prefer if any foe has previously used a stat stage-clearing
|
# TODO: Don't prefer if any foe has previously used a stat stage-clearing
|
||||||
# move (Clear Smog/Haze).
|
# move (Clear Smog/Haze).
|
||||||
mini_score *= 0.3 if check_for_move(@target) { |move|
|
mini_score *= 0.3 if check_for_move(@target) { |m|
|
||||||
["ResetTargetStatStages", "ResetAllBattlersStatStages"].include?(move.function)
|
["ResetTargetStatStages", "ResetAllBattlersStatStages"].include?(m.function)
|
||||||
} # Clear Smog, Haze
|
} # Clear Smog, Haze
|
||||||
|
|
||||||
# TODO: Prefer if user is faster than the target.
|
# TODO: Prefer if user is faster than the target.
|
||||||
@@ -561,8 +561,8 @@ class Battle::AI
|
|||||||
def get_score_for_terrain(terrain, move_user)
|
def get_score_for_terrain(terrain, move_user)
|
||||||
ret = 0
|
ret = 0
|
||||||
# Inherent effects of terrain
|
# Inherent effects of terrain
|
||||||
@battlers.each do |b|
|
each_battler do |b, i|
|
||||||
next if !b || b.battler.fainted? || !b.battler.affectedByTerrain?
|
next if !b.battler.affectedByTerrain?
|
||||||
case terrain
|
case terrain
|
||||||
when :Electric
|
when :Electric
|
||||||
# Immunity to sleep
|
# Immunity to sleep
|
||||||
@@ -574,14 +574,14 @@ class Battle::AI
|
|||||||
ret += (b.opposes?(move_user)) ? -10 : 10
|
ret += (b.opposes?(move_user)) ? -10 : 10
|
||||||
end
|
end
|
||||||
# Check for Electric moves
|
# Check for Electric moves
|
||||||
if b.check_for_move { |move| move.type == :ELECTRIC && move.damagingMove? }
|
if b.check_for_move { |m| m.type == :ELECTRIC && m.damagingMove? }
|
||||||
ret += (b.opposes?(move_user)) ? -15 : 15
|
ret += (b.opposes?(move_user)) ? -15 : 15
|
||||||
end
|
end
|
||||||
when :Grassy
|
when :Grassy
|
||||||
# End of round healing
|
# End of round healing
|
||||||
ret += (b.opposes?(move_user)) ? -10 : 10
|
ret += (b.opposes?(move_user)) ? -10 : 10
|
||||||
# Check for Grass moves
|
# Check for Grass moves
|
||||||
if b.check_for_move { |move| move.type == :GRASS && move.damagingMove? }
|
if b.check_for_move { |m| m.type == :GRASS && m.damagingMove? }
|
||||||
ret += (b.opposes?(move_user)) ? -15 : 15
|
ret += (b.opposes?(move_user)) ? -15 : 15
|
||||||
end
|
end
|
||||||
when :Misty
|
when :Misty
|
||||||
@@ -592,16 +592,16 @@ class Battle::AI
|
|||||||
ret += (b.opposes?(move_user)) ? -5 : 5
|
ret += (b.opposes?(move_user)) ? -5 : 5
|
||||||
end
|
end
|
||||||
# Check for Dragon moves
|
# Check for Dragon moves
|
||||||
if b.check_for_move { |move| move.type == :DRAGON && move.damagingMove? }
|
if b.check_for_move { |m| m.type == :DRAGON && m.damagingMove? }
|
||||||
ret += (b.opposes?(move_user)) ? 15 : -15
|
ret += (b.opposes?(move_user)) ? 15 : -15
|
||||||
end
|
end
|
||||||
when :Psychic
|
when :Psychic
|
||||||
# Check for priority moves
|
# Check for priority moves
|
||||||
if b.check_for_move { |move| move.priority > 0 && move.pbTarget&.can_target_one_foe? }
|
if b.check_for_move { |m| m.priority > 0 && m.pbTarget&.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
|
||||||
if b.check_for_move { |move| move.type == :PSYCHIC && move.damagingMove? }
|
if b.check_for_move { |m| m.type == :PSYCHIC && m.damagingMove? }
|
||||||
ret += (b.opposes?(move_user)) ? -15 : 15
|
ret += (b.opposes?(move_user)) ? -15 : 15
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -613,8 +613,7 @@ class Battle::AI
|
|||||||
:Misty => :MISTYSEED,
|
:Misty => :MISTYSEED,
|
||||||
:Psychic => :PSYCHICSEED
|
:Psychic => :PSYCHICSEED
|
||||||
}[terrain]
|
}[terrain]
|
||||||
ai.battlers.each do |b|
|
each_battler do |b, i|
|
||||||
next if !b || b.battler.fainted?
|
|
||||||
if b.has_active_item?(:TERRAINEXTENDER)
|
if b.has_active_item?(:TERRAINEXTENDER)
|
||||||
ret += (b.opposes?(move_user)) ? -15 : 15
|
ret += (b.opposes?(move_user)) ? -15 : 15
|
||||||
elsif seed && b.has_active_item?(seed)
|
elsif seed && b.has_active_item?(seed)
|
||||||
@@ -622,7 +621,7 @@ class Battle::AI
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
# Check for abilities/moves affected by the terrain
|
# Check for abilities/moves affected by the terrain
|
||||||
if ai.trainer.medium_skill?
|
if @trainer.medium_skill?
|
||||||
abils = {
|
abils = {
|
||||||
:Electric => :SURGESURFER,
|
:Electric => :SURGESURFER,
|
||||||
:Grassy => :GRASSPELT,
|
:Grassy => :GRASSPELT,
|
||||||
@@ -644,8 +643,8 @@ class Battle::AI
|
|||||||
:Misty => nil,
|
:Misty => nil,
|
||||||
:Psychic => nil
|
:Psychic => nil
|
||||||
}[terrain]
|
}[terrain]
|
||||||
ai.battlers.each do |b|
|
each_battler do |b, i|
|
||||||
next if !b || b.battler.fainted? || !b.battler.affectedByTerrain?
|
next if !b.battler.affectedByTerrain?
|
||||||
# Abilities
|
# Abilities
|
||||||
if b.has_active_ability?(:MIMICRY)
|
if b.has_active_ability?(:MIMICRY)
|
||||||
ret += (b.opposes?(move_user)) ? -5 : 5
|
ret += (b.opposes?(move_user)) ? -5 : 5
|
||||||
@@ -654,16 +653,16 @@ class Battle::AI
|
|||||||
ret += (b.opposes?(move_user)) ? -15 : 15
|
ret += (b.opposes?(move_user)) ? -15 : 15
|
||||||
end
|
end
|
||||||
# Moves
|
# Moves
|
||||||
if b.check_for_move { |move| ["EffectDependsOnEnvironment",
|
if b.check_for_move { |m| ["EffectDependsOnEnvironment",
|
||||||
"SetUserTypesBasedOnEnvironment",
|
"SetUserTypesBasedOnEnvironment",
|
||||||
"TypeAndPowerDependOnTerrain",
|
"TypeAndPowerDependOnTerrain",
|
||||||
"UseMoveDependingOnEnvironment"].include?(move.function) }
|
"UseMoveDependingOnEnvironment"].include?(m.function) }
|
||||||
ret += (b.opposes?(move_user)) ? -10 : 10
|
ret += (b.opposes?(move_user)) ? -10 : 10
|
||||||
end
|
end
|
||||||
if good_moves && b.check_for_move { |move| good_moves.include?(move.function) }
|
if good_moves && b.check_for_move { |m| good_moves.include?(m.function) }
|
||||||
ret += (b.opposes?(move_user)) ? -10 : 10
|
ret += (b.opposes?(move_user)) ? -10 : 10
|
||||||
end
|
end
|
||||||
if bad_moves && b.check_for_move { |move| bad_moves.include?(move.function) }
|
if bad_moves && b.check_for_move { |m| bad_moves.include?(m.function) }
|
||||||
ret += (b.opposes?(move_user)) ? 10 : -10
|
ret += (b.opposes?(move_user)) ? 10 : -10
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -129,12 +129,12 @@ Battle::AI::Handlers::MoveEffectScore.add("FailsIfUserDamagedThisTurn",
|
|||||||
if target.effects[PBEffects::HyperBeam] > 0 ||
|
if target.effects[PBEffects::HyperBeam] > 0 ||
|
||||||
target.effects[PBEffects::Truant] ||
|
target.effects[PBEffects::Truant] ||
|
||||||
(target.battler.asleep? && target.statusCount > 1) ||
|
(target.battler.asleep? && target.statusCount > 1) ||
|
||||||
target.frozen?
|
target.battler.frozen?
|
||||||
score += 20
|
score += 20
|
||||||
elsif target.effects[PBEffects::Confusion] > 1 ||
|
elsif target.effects[PBEffects::Confusion] > 1 ||
|
||||||
target.effects[PBEffects::Attract] == user.index
|
target.effects[PBEffects::Attract] == user.index
|
||||||
score += 10
|
score += 10
|
||||||
elsif target.paralyzed?
|
elsif target.battler.paralyzed?
|
||||||
score += 5
|
score += 5
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -167,7 +167,7 @@ Battle::AI::Handlers::MoveEffectScore.add("FailsIfTargetActed",
|
|||||||
#===============================================================================
|
#===============================================================================
|
||||||
Battle::AI::Handlers::MoveEffectScore.add("CrashDamageIfFailsUnusableInGravity",
|
Battle::AI::Handlers::MoveEffectScore.add("CrashDamageIfFailsUnusableInGravity",
|
||||||
proc { |score, move, user, target, ai, battle|
|
proc { |score, move, user, target, ai, battle|
|
||||||
next score - (100 - move.rough_accuracy) if user.takesIndirectDamage?
|
next score - (100 - move.rough_accuracy) if user.battler.takesIndirectDamage?
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -448,7 +448,7 @@ Battle::AI::Handlers::MoveEffectScore.add("AddSpikesToFoeSide",
|
|||||||
inBattleIndices = battle.allSameSideBattlers(user.idxOpposingSide).map { |b| b.pokemonIndex }
|
inBattleIndices = battle.allSameSideBattlers(user.idxOpposingSide).map { |b| b.pokemonIndex }
|
||||||
foe_reserves = []
|
foe_reserves = []
|
||||||
battle.pbParty(user.idxOpposingSide).each_with_index do |pkmn, idxParty|
|
battle.pbParty(user.idxOpposingSide).each_with_index do |pkmn, idxParty|
|
||||||
next if !pkmn || !pkmn.able? || inBattleIndices.include(idxParty)
|
next if !pkmn || !pkmn.able? || inBattleIndices.include?(idxParty)
|
||||||
if ai.trainer.medium_skill?
|
if ai.trainer.medium_skill?
|
||||||
# Check affected by entry hazard
|
# Check affected by entry hazard
|
||||||
next if pkmn.hasItem?(:HEAVYDUTYBOOTS)
|
next if pkmn.hasItem?(:HEAVYDUTYBOOTS)
|
||||||
@@ -484,7 +484,7 @@ Battle::AI::Handlers::MoveEffectScore.add("AddToxicSpikesToFoeSide",
|
|||||||
inBattleIndices = battle.allSameSideBattlers(user.idxOpposingSide).map { |b| b.pokemonIndex }
|
inBattleIndices = battle.allSameSideBattlers(user.idxOpposingSide).map { |b| b.pokemonIndex }
|
||||||
foe_reserves = []
|
foe_reserves = []
|
||||||
battle.pbParty(user.idxOpposingSide).each_with_index do |pkmn, idxParty|
|
battle.pbParty(user.idxOpposingSide).each_with_index do |pkmn, idxParty|
|
||||||
next if !pkmn || !pkmn.able? || inBattleIndices.include(idxParty)
|
next if !pkmn || !pkmn.able? || inBattleIndices.include?(idxParty)
|
||||||
if ai.trainer.medium_skill?
|
if ai.trainer.medium_skill?
|
||||||
# Check affected by entry hazard
|
# Check affected by entry hazard
|
||||||
next if pkmn.hasItem?(:HEAVYDUTYBOOTS)
|
next if pkmn.hasItem?(:HEAVYDUTYBOOTS)
|
||||||
@@ -522,7 +522,7 @@ Battle::AI::Handlers::MoveEffectScore.add("AddStealthRocksToFoeSide",
|
|||||||
inBattleIndices = battle.allSameSideBattlers(user.idxOpposingSide).map { |b| b.pokemonIndex }
|
inBattleIndices = battle.allSameSideBattlers(user.idxOpposingSide).map { |b| b.pokemonIndex }
|
||||||
foe_reserves = []
|
foe_reserves = []
|
||||||
battle.pbParty(user.idxOpposingSide).each_with_index do |pkmn, idxParty|
|
battle.pbParty(user.idxOpposingSide).each_with_index do |pkmn, idxParty|
|
||||||
next if !pkmn || !pkmn.able? || inBattleIndices.include(idxParty)
|
next if !pkmn || !pkmn.able? || inBattleIndices.include?(idxParty)
|
||||||
if ai.trainer.medium_skill?
|
if ai.trainer.medium_skill?
|
||||||
# Check affected by entry hazard
|
# Check affected by entry hazard
|
||||||
next if pkmn.hasItem?(:HEAVYDUTYBOOTS)
|
next if pkmn.hasItem?(:HEAVYDUTYBOOTS)
|
||||||
@@ -549,7 +549,7 @@ Battle::AI::Handlers::MoveEffectScore.add("AddStickyWebToFoeSide",
|
|||||||
inBattleIndices = battle.allSameSideBattlers(user.idxOpposingSide).map { |b| b.pokemonIndex }
|
inBattleIndices = battle.allSameSideBattlers(user.idxOpposingSide).map { |b| b.pokemonIndex }
|
||||||
foe_reserves = []
|
foe_reserves = []
|
||||||
battle.pbParty(user.idxOpposingSide).each_with_index do |pkmn, idxParty|
|
battle.pbParty(user.idxOpposingSide).each_with_index do |pkmn, idxParty|
|
||||||
next if !pkmn || !pkmn.able? || inBattleIndices.include(idxParty)
|
next if !pkmn || !pkmn.able? || inBattleIndices.include?(idxParty)
|
||||||
if ai.trainer.medium_skill?
|
if ai.trainer.medium_skill?
|
||||||
# Check affected by entry hazard
|
# Check affected by entry hazard
|
||||||
next if pkmn.hasItem?(:HEAVYDUTYBOOTS)
|
next if pkmn.hasItem?(:HEAVYDUTYBOOTS)
|
||||||
|
|||||||
@@ -393,7 +393,7 @@ Battle::AI::Handlers::MoveEffectScore.add("FlinchTarget",
|
|||||||
#===============================================================================
|
#===============================================================================
|
||||||
Battle::AI::Handlers::MoveFailureCheck.add("FlinchTargetFailsIfUserNotAsleep",
|
Battle::AI::Handlers::MoveFailureCheck.add("FlinchTargetFailsIfUserNotAsleep",
|
||||||
proc { |move, user, target, ai, battle|
|
proc { |move, user, target, ai, battle|
|
||||||
next true if !user.asleep?
|
next true if !user.battler.asleep?
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
Battle::AI::Handlers::MoveEffectScore.add("FlinchTargetFailsIfUserNotAsleep",
|
Battle::AI::Handlers::MoveEffectScore.add("FlinchTargetFailsIfUserNotAsleep",
|
||||||
@@ -649,7 +649,7 @@ Battle::AI::Handlers::MoveFailureCheck.add("SetTargetAbilityToInsomnia",
|
|||||||
#===============================================================================
|
#===============================================================================
|
||||||
Battle::AI::Handlers::MoveFailureCheck.add("SetUserAbilityToTargetAbility",
|
Battle::AI::Handlers::MoveFailureCheck.add("SetUserAbilityToTargetAbility",
|
||||||
proc { |move, user, target, ai, battle|
|
proc { |move, user, target, ai, battle|
|
||||||
next true if user.battle.unstoppableAbility?
|
next true if user.battler.unstoppableAbility?
|
||||||
next true if !target.ability || user.ability_id == target.ability_id
|
next true if !target.ability || user.ability_id == target.ability_id
|
||||||
next true if target.battler.ungainableAbility? ||
|
next true if target.battler.ungainableAbility? ||
|
||||||
[:POWEROFALCHEMY, :RECEIVER, :TRACE, :WONDERGUARD].include?(target.ability_id)
|
[:POWEROFALCHEMY, :RECEIVER, :TRACE, :WONDERGUARD].include?(target.ability_id)
|
||||||
@@ -673,7 +673,7 @@ Battle::AI::Handlers::MoveFailureCheck.add("SetTargetAbilityToUserAbility",
|
|||||||
next true if !user.ability || user.ability_id == target.ability_id
|
next true if !user.ability || user.ability_id == target.ability_id
|
||||||
next true if user.battler.ungainableAbility? ||
|
next true if user.battler.ungainableAbility? ||
|
||||||
[:POWEROFALCHEMY, :RECEIVER, :TRACE].include?(user.ability_id)
|
[:POWEROFALCHEMY, :RECEIVER, :TRACE].include?(user.ability_id)
|
||||||
next true if target.battle.unstoppableAbility? || target.ability_id == :TRUANT
|
next true if target.battler.unstoppableAbility? || target.ability_id == :TRUANT
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
Battle::AI::Handlers::MoveEffectScore.add("SetTargetAbilityToUserAbility",
|
Battle::AI::Handlers::MoveEffectScore.add("SetTargetAbilityToUserAbility",
|
||||||
@@ -693,9 +693,9 @@ Battle::AI::Handlers::MoveFailureCheck.add("UserTargetSwapAbilities",
|
|||||||
proc { |move, user, target, ai, battle|
|
proc { |move, user, target, ai, battle|
|
||||||
next true if !user.ability || !target.ability
|
next true if !user.ability || !target.ability
|
||||||
next true if Settings::MECHANICS_GENERATION <= 5 && user.ability_id == target.ability_id
|
next true if Settings::MECHANICS_GENERATION <= 5 && user.ability_id == target.ability_id
|
||||||
next true if user.battle.unstoppableAbility? || user.battler.ungainableAbility? ||
|
next true if user.battler.unstoppableAbility? || user.battler.ungainableAbility? ||
|
||||||
user.ability_id == :WONDERGUARD
|
user.ability_id == :WONDERGUARD
|
||||||
next true if target.battle.unstoppableAbility? || target.battler.ungainableAbility? ||
|
next true if target.battler.unstoppableAbility? || target.battler.ungainableAbility? ||
|
||||||
target.ability_id == :WONDERGUARD
|
target.ability_id == :WONDERGUARD
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -714,7 +714,7 @@ Battle::AI::Handlers::MoveEffectScore.add("UserTargetSwapAbilities",
|
|||||||
#===============================================================================
|
#===============================================================================
|
||||||
Battle::AI::Handlers::MoveFailureCheck.add("NegateTargetAbility",
|
Battle::AI::Handlers::MoveFailureCheck.add("NegateTargetAbility",
|
||||||
proc { |move, user, target, ai, battle|
|
proc { |move, user, target, ai, battle|
|
||||||
next true if target.unstoppableAbility? ||
|
next true if target.battler.unstoppableAbility? ||
|
||||||
target.effects[PBEffects::GastroAcid]
|
target.effects[PBEffects::GastroAcid]
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -422,7 +422,7 @@ Battle::AI::Handlers::MoveEffectScore.add("StartLeechSeedTarget",
|
|||||||
if !user.check_for_move { |move| move.damagingMove? }
|
if !user.check_for_move { |move| move.damagingMove? }
|
||||||
score += 20
|
score += 20
|
||||||
end
|
end
|
||||||
score -= 20 if target.has_active_ability?([:LIQUIDOOZE]) || !target.takesIndirectDamage?
|
score -= 20 if target.has_active_ability?([:LIQUIDOOZE]) || !target.battler.takesIndirectDamage?
|
||||||
end
|
end
|
||||||
if ai.trainer.high_skill?
|
if ai.trainer.high_skill?
|
||||||
if user.check_for_move { |move| move.is_a?(Battle::Move::ProtectMove) }
|
if user.check_for_move { |move| move.is_a?(Battle::Move::ProtectMove) }
|
||||||
|
|||||||
@@ -315,8 +315,8 @@ Battle::AI::Handlers::MoveFailureCheck.add("UseLastMoveUsed",
|
|||||||
#===============================================================================
|
#===============================================================================
|
||||||
Battle::AI::Handlers::MoveFailureCheck.add("UseLastMoveUsedByTarget",
|
Battle::AI::Handlers::MoveFailureCheck.add("UseLastMoveUsedByTarget",
|
||||||
proc { |move, user, target, ai, battle|
|
proc { |move, user, target, ai, battle|
|
||||||
next true if !target.battle.lastRegularMoveUsed
|
next true if !target.battler.lastRegularMoveUsed
|
||||||
next true if GameData::Move.get(target.battle.lastRegularMoveUsed).flags.none? { |f| f[/^CanMirrorMove$/i] }
|
next true if GameData::Move.get(target.battler.lastRegularMoveUsed).flags.none? { |f| f[/^CanMirrorMove$/i] }
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
Battle::AI::Handlers::MoveEffectScore.add("UseLastMoveUsedByTarget",
|
Battle::AI::Handlers::MoveEffectScore.add("UseLastMoveUsedByTarget",
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ Battle::AI::Handlers::GeneralMoveScore.add(:damaging_moves_if_last_pokemon,
|
|||||||
if ai.trainer.medium_skill? && battle.pbAbleNonActiveCount(user.idxOwnSide) == 0 &&
|
if ai.trainer.medium_skill? && battle.pbAbleNonActiveCount(user.idxOwnSide) == 0 &&
|
||||||
!(ai.trainer.high_skill? && target && battle.pbAbleNonActiveCount(target.idxOwnSide) > 0)
|
!(ai.trainer.high_skill? && target && battle.pbAbleNonActiveCount(target.idxOwnSide) > 0)
|
||||||
next score * 0.9 if move.statusMove?
|
next score * 0.9 if move.statusMove?
|
||||||
next score * 1.1 if target_battler.hp <= target_battler.totalhp / 2
|
next score * 1.1 if target && target.battler.hp <= target.battler.totalhp / 2
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -213,7 +213,7 @@ Battle::AI::Handlers::GeneralMoveScore.add(:thawing_move_against_frozen_target,
|
|||||||
#===============================================================================
|
#===============================================================================
|
||||||
Battle::AI::Handlers::GeneralMoveScore.add(:shiny_target,
|
Battle::AI::Handlers::GeneralMoveScore.add(:shiny_target,
|
||||||
proc { |score, move, user, target, ai, battle|
|
proc { |score, move, user, target, ai, battle|
|
||||||
next score - 40 if target&.wild? && target&.battler.shiny?
|
next score - 40 if target && target.wild? && target.battler.shiny?
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -260,7 +260,7 @@ Battle::AI::Handlers::GeneralMoveScore.add(:flinching_effects,
|
|||||||
#===============================================================================
|
#===============================================================================
|
||||||
Battle::AI::Handlers::GeneralMoveScore.add(:add_predicted_damage,
|
Battle::AI::Handlers::GeneralMoveScore.add(:add_predicted_damage,
|
||||||
proc { |score, move, user, target, ai, battle|
|
proc { |score, move, user, target, ai, battle|
|
||||||
if move.damagingMove?
|
if move.damagingMove? && target
|
||||||
dmg = move.rough_damage
|
dmg = move.rough_damage
|
||||||
score += [15.0 * dmg / target.hp, 20].min
|
score += [15.0 * dmg / target.hp, 20].min
|
||||||
score += 10 if dmg > target.hp * 1.1 # Predicted to KO the target
|
score += 10 if dmg > target.hp * 1.1 # Predicted to KO the target
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ class Battle::AI::AIBattler
|
|||||||
# Trapping damage
|
# Trapping damage
|
||||||
if self.effects[PBEffects::Trapping] > 1 && @battler.takesIndirectDamage?
|
if self.effects[PBEffects::Trapping] > 1 && @battler.takesIndirectDamage?
|
||||||
amt = (Settings::MECHANICS_GENERATION >= 6) ? self.totalhp / 8 : self.totalhp / 16
|
amt = (Settings::MECHANICS_GENERATION >= 6) ? self.totalhp / 8 : self.totalhp / 16
|
||||||
if @battlers[self.effects[PBEffects::TrappingUser]].has_active_item?(:BINDINGBAND)
|
if @ai.battlers[self.effects[PBEffects::TrappingUser]].has_active_item?(:BINDINGBAND)
|
||||||
amt = (Settings::MECHANICS_GENERATION >= 6) ? self.totalhp / 6 : self.totalhp / 8
|
amt = (Settings::MECHANICS_GENERATION >= 6) ? self.totalhp / 6 : self.totalhp / 8
|
||||||
end
|
end
|
||||||
ret += [amt, 1].max
|
ret += [amt, 1].max
|
||||||
|
|||||||
@@ -371,17 +371,17 @@ class Battle::AI::AIMove
|
|||||||
end
|
end
|
||||||
|
|
||||||
def rough_accuracy
|
def rough_accuracy
|
||||||
|
# Determine user and target
|
||||||
|
user = @ai.user
|
||||||
|
user_battler = user.battler
|
||||||
|
target = @ai.target
|
||||||
|
target_battler = target.battler
|
||||||
# "Always hit" effects and "always hit" accuracy
|
# "Always hit" effects and "always hit" accuracy
|
||||||
if @ai.trainer.medium_skill?
|
if @ai.trainer.medium_skill?
|
||||||
return 100 if target.effects[PBEffects::Telekinesis] > 0
|
return 100 if target.effects[PBEffects::Telekinesis] > 0
|
||||||
return 100 if target.effects[PBEffects::Minimize] && @move.tramplesMinimize? &&
|
return 100 if target.effects[PBEffects::Minimize] && @move.tramplesMinimize? &&
|
||||||
Settings::MECHANICS_GENERATION >= 6
|
Settings::MECHANICS_GENERATION >= 6
|
||||||
end
|
end
|
||||||
# Determine user and target
|
|
||||||
user = @ai.user
|
|
||||||
user_battler = user.battler
|
|
||||||
target = @ai.target
|
|
||||||
target_battler = target.battler
|
|
||||||
# Get base accuracy
|
# Get base accuracy
|
||||||
baseAcc = self.accuracy
|
baseAcc = self.accuracy
|
||||||
return 100 if baseAcc == 0
|
return 100 if baseAcc == 0
|
||||||
@@ -486,7 +486,7 @@ class Battle::AI::AIMove
|
|||||||
case function
|
case function
|
||||||
when "BadPoisonTarget"
|
when "BadPoisonTarget"
|
||||||
modifiers[:base_accuracy] = 0 if Settings::MORE_TYPE_EFFECTS &&
|
modifiers[:base_accuracy] = 0 if Settings::MORE_TYPE_EFFECTS &&
|
||||||
@move.statusMove? && @user.has_type?(:POISON)
|
@move.statusMove? && user.has_type?(:POISON)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1207,7 +1207,7 @@ Battle::AbilityEffects::DamageCalcFromUser.add(:ANALYTIC,
|
|||||||
# are being used), so I'm choosing to ignore it. The effect is thus:
|
# are being used), so I'm choosing to ignore it. The effect is thus:
|
||||||
# "power up the move if all other battlers on the field right now have
|
# "power up the move if all other battlers on the field right now have
|
||||||
# already moved".
|
# already moved".
|
||||||
if move.move.pbMoveFailedLastInRound?(user, false)
|
if move.pbMoveFailedLastInRound?(user, false)
|
||||||
mults[:base_damage_multiplier] *= 1.3
|
mults[:base_damage_multiplier] *= 1.3
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
@@ -1528,7 +1528,7 @@ Battle::AbilityEffects::DamageCalcFromTarget.add(:FLOWERGIFT,
|
|||||||
Battle::AbilityEffects::DamageCalcFromTarget.add(:FLUFFY,
|
Battle::AbilityEffects::DamageCalcFromTarget.add(:FLUFFY,
|
||||||
proc { |ability, user, target, move, mults, baseDmg, type|
|
proc { |ability, user, target, move, mults, baseDmg, type|
|
||||||
mults[:final_damage_multiplier] *= 2 if move.calcType == :FIRE
|
mults[:final_damage_multiplier] *= 2 if move.calcType == :FIRE
|
||||||
mults[:final_damage_multiplier] /= 2 if move.move.pbContactMove?(user)
|
mults[:final_damage_multiplier] /= 2 if move.pbContactMove?(user)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -398,7 +398,7 @@ def pbRuledBattle(team1, team2, rule)
|
|||||||
items2[i] = p.item_id
|
items2[i] = p.item_id
|
||||||
trainer2.party.push(p)
|
trainer2.party.push(p)
|
||||||
end
|
end
|
||||||
scene = Battle::DebugSceneNoLogging.new
|
scene = Battle::DebugSceneNoVisuals.new
|
||||||
battle = rule.createBattle(scene, trainer1, trainer2)
|
battle = rule.createBattle(scene, trainer1, trainer2)
|
||||||
battle.debug = true
|
battle.debug = true
|
||||||
battle.controlPlayer = true
|
battle.controlPlayer = true
|
||||||
|
|||||||
115
Data/Scripts/999_Main/002_debug battle test.rb
Normal file
115
Data/Scripts/999_Main/002_debug battle test.rb
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
def debug_set_up_trainer
|
||||||
|
# Values to return
|
||||||
|
trainer_array = []
|
||||||
|
foe_items = [] # Intentionally left blank (for now)
|
||||||
|
pokemon_array = []
|
||||||
|
party_starts = [0]
|
||||||
|
|
||||||
|
# Choose random trainer type and trainer name
|
||||||
|
trainer_type = GameData::TrainerType.keys.sample
|
||||||
|
trainer_name = ["Alpha", "Bravo", "Charlie", "Delta", "Echo",
|
||||||
|
"Foxtrot", "Golf", "Hotel", "India", "Juliette",
|
||||||
|
"Kilo", "Lima", "Mike", "November", "Oscar",
|
||||||
|
"Papa", "Quebec", "Romeo", "Sierra", "Tango",
|
||||||
|
"Uniform", "Victor", "Whiskey", "X-ray", "Yankee", "Zulu"].sample
|
||||||
|
|
||||||
|
# Generate trainer
|
||||||
|
trainer = NPCTrainer.new(trainer_name, trainer_type)
|
||||||
|
trainer.id = $player.make_foreign_ID
|
||||||
|
trainer.lose_text = "I lost."
|
||||||
|
trainer_array.push(trainer)
|
||||||
|
|
||||||
|
# Generate party
|
||||||
|
valid_species = []
|
||||||
|
GameData::Species.each_species { |sp| valid_species.push(sp.species) }
|
||||||
|
Settings::MAX_PARTY_SIZE.times do |i|
|
||||||
|
this_species = valid_species.sample
|
||||||
|
this_level = rand(1, Settings::MAXIMUM_LEVEL)
|
||||||
|
pkmn = Pokemon.new(this_species, this_level, trainer)
|
||||||
|
trainer.party.push(pkmn)
|
||||||
|
pokemon_array.push(pkmn)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Return values
|
||||||
|
return trainer_array, foe_items, pokemon_array, party_starts
|
||||||
|
end
|
||||||
|
|
||||||
|
def debug_test_auto_battle(logging = false)
|
||||||
|
old_internal = $INTERNAL
|
||||||
|
$INTERNAL = logging
|
||||||
|
echoln "Start of testing auto battle."
|
||||||
|
echoln "" if !$INTERNAL
|
||||||
|
PBDebug.log("")
|
||||||
|
PBDebug.log("================================================================")
|
||||||
|
PBDebug.log("")
|
||||||
|
# Generate information for the foes
|
||||||
|
foe_trainers, foe_items, foe_party, foe_party_starts = debug_set_up_trainer
|
||||||
|
# Generate information for the player and partner trainer(s)
|
||||||
|
player_trainers, ally_items, player_party, player_party_starts = debug_set_up_trainer
|
||||||
|
# Log the combatants
|
||||||
|
echo_participant = lambda do |trainer, party, index|
|
||||||
|
trainer_txt = "Trainer #{index}: #{trainer.full_name}"
|
||||||
|
($INTERNAL) ? PBDebug.log_header(trainer_txt) : echoln(trainer_txt)
|
||||||
|
party.each do |pkmn|
|
||||||
|
pkmn_txt = " #{pkmn.name}, Lv.#{pkmn.level}\r\n"
|
||||||
|
pkmn_txt += " Ability: #{pkmn.ability&.name || "---"}\r\n"
|
||||||
|
pkmn_txt += " Held item: #{pkmn.item&.name || "---"}"
|
||||||
|
($INTERNAL) ? PBDebug.log(pkmn_txt) : echoln(pkmn_txt)
|
||||||
|
moves_msg = " Moves: "
|
||||||
|
pkmn.moves.each_with_index do |move, i|
|
||||||
|
moves_msg += ", " if i > 0
|
||||||
|
moves_msg += move.name
|
||||||
|
end
|
||||||
|
($INTERNAL) ? PBDebug.log(moves_msg) : echoln(moves_msg)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
echo_participant.call(player_trainers[0], player_party, 1)
|
||||||
|
echo_participant.call(foe_trainers[0], foe_party, 2)
|
||||||
|
echoln "" if !$INTERNAL
|
||||||
|
# Create the battle scene (the visual side of it)
|
||||||
|
scene = Battle::DebugSceneNoVisuals.new(logging)
|
||||||
|
# Create the battle class (the mechanics side of it)
|
||||||
|
battle = Battle.new(scene, player_party, foe_party, player_trainers, foe_trainers)
|
||||||
|
battle.party1starts = player_party_starts
|
||||||
|
battle.party2starts = foe_party_starts
|
||||||
|
battle.ally_items = ally_items
|
||||||
|
battle.items = foe_items
|
||||||
|
|
||||||
|
battle.debug = true
|
||||||
|
battle.internalBattle = false
|
||||||
|
battle.controlPlayer = true
|
||||||
|
# Set various other properties in the battle class
|
||||||
|
BattleCreationHelperMethods.prepare_battle(battle)
|
||||||
|
# Perform the battle itself
|
||||||
|
outcome = battle.pbStartBattle
|
||||||
|
# End
|
||||||
|
echoln ["Undecided",
|
||||||
|
"Trainer 1 #{player_trainers[0].name} won",
|
||||||
|
"Trainer 2 #{foe_trainers[0].name} won",
|
||||||
|
"Ran/forfeited",
|
||||||
|
"Wild Pokémon caught",
|
||||||
|
"Draw"][outcome]
|
||||||
|
echoln ""
|
||||||
|
$INTERNAL = old_internal
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
# Add to Debug menu
|
||||||
|
#===============================================================================
|
||||||
|
MenuHandlers.add(:debug_menu, :test_auto_battle, {
|
||||||
|
"name" => _INTL("Test Auto Battle"),
|
||||||
|
"parent" => :main,
|
||||||
|
"description" => _INTL("Runs an AI-controlled battle with no visuals."),
|
||||||
|
"effect" => proc {
|
||||||
|
debug_test_auto_battle
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
MenuHandlers.add(:debug_menu, :test_auto_battle_logging, {
|
||||||
|
"name" => _INTL("Test Auto Battle with Logging"),
|
||||||
|
"parent" => :main,
|
||||||
|
"description" => _INTL("Runs an AI-controlled battle with no visuals. Logs messages."),
|
||||||
|
"effect" => proc {
|
||||||
|
debug_test_auto_battle(true)
|
||||||
|
}
|
||||||
|
})
|
||||||
Reference in New Issue
Block a user