diff --git a/Data/Scripts/001_Technical/001_Debugging/001_PBDebug.rb b/Data/Scripts/001_Technical/001_Debugging/001_PBDebug.rb index 81360266d..8b3b1ea54 100644 --- a/Data/Scripts/001_Technical/001_Debugging/001_PBDebug.rb +++ b/Data/Scripts/001_Technical/001_Debugging/001_PBDebug.rb @@ -16,14 +16,24 @@ module PBDebug def self.flush if $DEBUG && $INTERNAL && @@log.length > 0 - File.open("Data/debuglog.txt", "a+b") { |f| f.write(@@log.to_s) } + File.open("Data/debuglog.txt", "a+b") { |f| f.write(@@log.join) } end @@log.clear end def self.log(msg) if $DEBUG && $INTERNAL - @@log.push("#{msg}\r\n") + echoln msg + @@log.push(msg + "\r\n") + PBDebug.flush # if @@log.length > 1024 + end + end + + def self.log_message(msg) + if $DEBUG && $INTERNAL + msg = "\"" + msg + "\"" + echoln Console.markup_style(msg, text: :dark_gray) + @@log.push(msg + "\r\n") PBDebug.flush # if @@log.length > 1024 end end diff --git a/Data/Scripts/011_Battle/001_Battle/002_Battle_StartAndEnd.rb b/Data/Scripts/011_Battle/001_Battle/002_Battle_StartAndEnd.rb index 73d285044..6899a731c 100644 --- a/Data/Scripts/011_Battle/001_Battle/002_Battle_StartAndEnd.rb +++ b/Data/Scripts/011_Battle/001_Battle/002_Battle_StartAndEnd.rb @@ -278,6 +278,7 @@ class Battle def pbStartBattleCore # Set up the battlers on each side sendOuts = pbSetUpSides + @battleAI.create_ai_objects # Create all the sprites and play the battle intro animation @scene.pbStartBattle(self) # Show trainers on both sides sending out Pokémon diff --git a/Data/Scripts/011_Battle/004_Scene/001_Battle_Scene.rb b/Data/Scripts/011_Battle/004_Scene/001_Battle_Scene.rb index 6d2c93921..5ab4157db 100644 --- a/Data/Scripts/011_Battle/004_Scene/001_Battle_Scene.rb +++ b/Data/Scripts/011_Battle/004_Scene/001_Battle_Scene.rb @@ -189,7 +189,7 @@ class Battle::Scene pbShowWindow(MESSAGE_BOX) cw = @sprites["messageWindow"] cw.setText(msg) - PBDebug.log(msg) + PBDebug.log_message(msg) yielded = false timer = 0.0 loop do @@ -235,7 +235,7 @@ class Battle::Scene pbShowWindow(MESSAGE_BOX) cw = @sprites["messageWindow"] cw.text = _INTL("{1}\1", msg) - PBDebug.log(msg) + PBDebug.log_message(msg) yielded = false timer = 0.0 loop do @@ -283,7 +283,7 @@ class Battle::Scene cw.z = dw.z + 1 cw.index = 0 cw.viewport = @viewport - PBDebug.log(msg) + PBDebug.log_message(msg) loop do cw.visible = (!dw.busy?) pbUpdate(cw) diff --git a/Data/Scripts/011_Battle/005_AI/001_Battle_AI.rb b/Data/Scripts/011_Battle/005_AI/001_Battle_AI.rb index 25edfb07c..04f9037d3 100644 --- a/Data/Scripts/011_Battle/005_AI/001_Battle_AI.rb +++ b/Data/Scripts/011_Battle/005_AI/001_Battle_AI.rb @@ -2,93 +2,61 @@ # #=============================================================================== class Battle::AI - # AI skill levels: - # 0: Wild Pokémon - # 1-31: Basic trainer (young/inexperienced) - # 32-47: Some skill - # 48-99: High skill - # 100+: Best trainers (Gym Leaders, Elite Four, Champion) - # NOTE: A trainer's skill value can range from 0-255, but by default only four - # distinct skill levels exist. The skill value is typically the same as - # the trainer's base money value. - module AILevel - # Minimum skill level to be in each AI skill bracket. - def self.minimum; return 1; end - def self.medium; return 32; end - def self.high; return 48; end - def self.best; return 100; end - end + attr_reader :battle + attr_reader :trainer + attr_reader :user, :target, :move - #============================================================================= - # - #============================================================================= def initialize(battle) - @battle = battle - @skill = 0 - @user = nil - @wildBattler = @battle.wildBattle? # Whether AI is choosing for a wild Pokémon - @roles = [Array.new(@battle.pbParty(0).length) { |i| determine_roles(0, i) }, - Array.new(@battle.pbParty(1).length) { |i| determine_roles(1, i) }] + @battle = battle + + # TODO: Move this elsewhere? + @roles = [Array.new(@battle.pbParty(0).length) { |i| determine_roles(0, i) }, + Array.new(@battle.pbParty(1).length) { |i| determine_roles(1, i) }] end - def pbAIRandom(x); return rand(x); end - - def pbStdDev(choices) - sum = 0 - n = 0 - choices.each do |c| - sum += c[1] - n += 1 + def create_ai_objects + # Initialize AI trainers + @trainers = [[], []] + @battle.player.each_with_index do |trainer, i| + @trainers[0][i] = AITrainer.new(self, 0, i, trainer) end - return 0 if n < 2 - mean = sum.to_f / n - varianceTimesN = 0 - choices.each do |c| - next if c[1] <= 0 - deviation = c[1].to_f - mean - varianceTimesN += deviation * deviation + if @battle.wildBattle? + @trainers[1][0] = AITrainer.new(self, 1, 0, nil) + else + @battle.opponent.each_with_index do |trainer, i| + @trainers[1][i] = AITrainer.new(self, 1, i, trainer) + end end - # Using population standard deviation - # [(n-1) makes it a sample std dev, would be 0 with only 1 sample] - return Math.sqrt(varianceTimesN / n) + # Initialize AI battlers + @battlers = [] + @battle.battlers.each_with_index do |battler, i| + @battlers[i] = AIBattler.new(self, i) if battler + end + # Initialize AI move object + @move = AIMove.new(self) end - # Decide whether the opponent should Mega Evolve their Pokémon. - def pbEnemyShouldMegaEvolve? - if @battle.pbCanMegaEvolve?(@user.index) # Simple "always should if possible" - PBDebug.log("[AI] #{@user.pbThis} (#{@user.index}) will Mega Evolve") - return true - end - return false + # Set some class variables for the Pokémon whose action is being chosen + def set_up(idxBattler) + # Find the AI trainer choosing the action + opposes = @battle.opposes?(idxBattler) + trainer_index = @battle.pbGetOwnerIndexFromBattlerIndex(idxBattler) + @trainer = @trainers[(opposes) ? 1 : 0][trainer_index] + # Find the AI battler for which the action is being chosen + @user = @battlers[idxBattler] + @user.refresh_battler end # Choose an action. def pbDefaultChooseEnemyCommand(idxBattler) set_up(idxBattler) - choices = pbGetMoveScores - return if pbEnemyShouldUseItem? return if pbEnemyShouldWithdraw? + return if pbEnemyShouldUseItem? return if @battle.pbAutoFightMenu(idxBattler) @battle.pbRegisterMegaEvolution(idxBattler) if pbEnemyShouldMegaEvolve? + choices = pbGetMoveScores pbChooseMove(choices) end - - # Set some class variables for the Pokémon whose action is being chosen - def set_up(idxBattler) - # TODO: Where relevant, pretend the user is Mega Evolved if it isn't but can - # be. - @user = @battle.battlers[idxBattler] - @wildBattler = (@battle.wildBattle? && @user.opposes?) - @skill = 0 - if !@wildBattler - @skill = @battle.pbGetOwnerFromBattlerIndex(@user.index).skill_level || 0 - @skill = AILevel.minimum if @skill < AILevel.minimum - end - end - - def skill_check(threshold) - return @skill >= threshold - end end #=============================================================================== diff --git a/Data/Scripts/011_Battle/005_AI/002_AI_Item.rb b/Data/Scripts/011_Battle/005_AI/002_AI_Item.rb index 11ad1c9df..740bcef1e 100644 --- a/Data/Scripts/011_Battle/005_AI/002_AI_Item.rb +++ b/Data/Scripts/011_Battle/005_AI/002_AI_Item.rb @@ -24,7 +24,7 @@ class Battle::AI return nil if !items || items.length == 0 # Determine target of item (always the Pokémon choosing the action) idxTarget = @user.index # Battler using the item - battler = @battle.battlers[idxTarget] + battler = @user.battler pkmn = battler.pokemon # Item categories hpItems = { diff --git a/Data/Scripts/011_Battle/005_AI/003_AI_Switch.rb b/Data/Scripts/011_Battle/005_AI/003_AI_Switch.rb index bb8be850a..b96eae728 100644 --- a/Data/Scripts/011_Battle/005_AI/003_AI_Switch.rb +++ b/Data/Scripts/011_Battle/005_AI/003_AI_Switch.rb @@ -7,19 +7,20 @@ class Battle::AI end def pbEnemyShouldWithdrawEx?(forceSwitch) - return false if @wildBattler + return false if @user.wild? shouldSwitch = forceSwitch + battler = @user.battler batonPass = -1 moveType = nil # If Pokémon is within 6 levels of the foe, and foe's last move was # super-effective and powerful - if !shouldSwitch && @user.turnCount > 0 && skill_check(AILevel.high) - target = @user.pbDirectOpposing(true) + if !shouldSwitch && battler.turnCount > 0 && @trainer.high_skill? + target = battler.pbDirectOpposing(true) if !target.fainted? && target.lastMoveUsed && - (target.level - @user.level).abs <= 6 + (target.level - battler.level).abs <= 6 moveData = GameData::Move.get(target.lastMoveUsed) moveType = moveData.type - typeMod = pbCalcTypeMod(moveType, target, @user) + typeMod = battler.effectiveness_of_type_against_battler(moveType, target) if Effectiveness.super_effective?(typeMod) && moveData.base_damage > 50 switchChance = (moveData.base_damage > 70) ? 30 : 20 shouldSwitch = (pbAIRandom(100) < switchChance) @@ -27,36 +28,36 @@ class Battle::AI end end # Pokémon can't do anything (must have been in battle for at least 5 rounds) - if !@battle.pbCanChooseAnyMove?(@user.index) && - @user.turnCount && @user.turnCount >= 5 + if !shouldSwitch && !@battle.pbCanChooseAnyMove?(battler.index) && + battler.turnCount && battler.turnCount >= 5 shouldSwitch = true end # Pokémon is Perish Songed and has Baton Pass - if skill_check(AILevel.high) && @user.effects[PBEffects::PerishSong] == 1 - @user.eachMoveWithIndex do |m, i| + if @trainer.high_skill? && battler.effects[PBEffects::PerishSong] == 1 + battler.eachMoveWithIndex do |m, i| next if m.function != "SwitchOutUserPassOnEffects" # Baton Pass - next if !@battle.pbCanChooseMove?(@user.index, i, false) + next if !@battle.pbCanChooseMove?(battler.index, i, false) batonPass = i break end end # Pokémon will faint because of bad poisoning at the end of this round, but # would survive at least one more round if it were regular poisoning instead - if @user.status == :POISON && @user.statusCount > 0 && skill_check(AILevel.high) - toxicHP = @user.totalhp / 16 - nextToxicHP = toxicHP * (@user.effects[PBEffects::Toxic] + 1) - if @user.hp <= nextToxicHP && @user.hp > toxicHP * 2 + if !shouldSwitch && battler.status == :POISON && battler.statusCount > 0 && @trainer.high_skill? + toxicHP = battler.totalhp / 16 + nextToxicHP = toxicHP * (battler.effects[PBEffects::Toxic] + 1) + if battler.hp <= nextToxicHP && battler.hp > toxicHP * 2 shouldSwitch = true if pbAIRandom(100) < 80 end end # Pokémon is Encored into an unfavourable move - if @user.effects[PBEffects::Encore] > 0 && skill_check(AILevel.medium) - idxEncoredMove = @user.pbEncoredMoveIndex + if !shouldSwitch && battler.effects[PBEffects::Encore] > 0 && @trainer.medium_skill? + idxEncoredMove = battler.pbEncoredMoveIndex if idxEncoredMove >= 0 scoreSum = 0 scoreCount = 0 - @user.allOpposing.each do |b| - scoreSum += pbGetMoveScore(@user.moves[idxEncoredMove], b) + battler.allOpposing.each do |b| + scoreSum += pbGetMoveScore(battler.moves[idxEncoredMove], b) scoreCount += 1 end if scoreCount > 0 && scoreSum / scoreCount <= 20 @@ -66,37 +67,37 @@ class Battle::AI end # If there is a single foe and it is resting after Hyper Beam or is # Truanting (i.e. free turn) - if @battle.pbSideSize(@user.index + 1) == 1 && - !@user.pbDirectOpposing.fainted? && skill_check(AILevel.high) - opp = @user.pbDirectOpposing + if shouldSwitch && @battle.pbSideSize(battler.index + 1) == 1 && + !battler.pbDirectOpposing.fainted? && @trainer.high_skill? + opp = battler.pbDirectOpposing if (opp.effects[PBEffects::HyperBeam] > 0 || (opp.hasActiveAbility?(:TRUANT) && opp.effects[PBEffects::Truant])) shouldSwitch = false if pbAIRandom(100) < 80 end end # Sudden Death rule - I'm not sure what this means - if @battle.rules["suddendeath"] && @user.turnCount > 0 - if @user.hp <= @user.totalhp / 4 && pbAIRandom(100) < 30 + if !shouldSwitch && @battle.rules["suddendeath"] && battler.turnCount > 0 + if battler.hp <= battler.totalhp / 4 && pbAIRandom(100) < 30 shouldSwitch = true - elsif @user.hp <= @user.totalhp / 2 && pbAIRandom(100) < 80 + elsif battler.hp <= battler.totalhp / 2 && pbAIRandom(100) < 80 shouldSwitch = true end end # Pokémon is about to faint because of Perish Song - if @user.effects[PBEffects::PerishSong] == 1 + if !shouldSwitch && battler.effects[PBEffects::PerishSong] == 1 shouldSwitch = true end if shouldSwitch list = [] - idxPartyStart, idxPartyEnd = @battle.pbTeamIndexRangeFromBattlerIndex(@user.index) - @battle.pbParty(@user.index).each_with_index do |pkmn, i| + idxPartyStart, idxPartyEnd = @battle.pbTeamIndexRangeFromBattlerIndex(battler.index) + @battle.pbParty(battler.index).each_with_index do |pkmn, i| next if i == idxPartyEnd - 1 # Don't choose to switch in ace - next if !@battle.pbCanSwitch?(@user.index, i) + next if !@battle.pbCanSwitch?(battler.index, i) # If perish count is 1, it may be worth it to switch # even with Spikes, since Perish Song's effect will end - if @user.effects[PBEffects::PerishSong] != 1 + if battler.effects[PBEffects::PerishSong] != 1 # Will contain effects that recommend against switching - spikes = @user.pbOwnSide.effects[PBEffects::Spikes] + spikes = battler.pbOwnSide.effects[PBEffects::Spikes] # Don't switch to this if too little HP if spikes > 0 spikesDmg = [8, 6, 4][spikes - 1] @@ -105,17 +106,17 @@ class Battle::AI end end # moveType is the type of the target's last used move - if moveType && Effectiveness.ineffective?(pbCalcTypeMod(moveType, @user, @user)) + if moveType && Effectiveness.ineffective?(battler.effectiveness_of_type_against_battler(moveType)) weight = 65 - typeMod = pbCalcTypeModPokemon(pkmn, @user.pbDirectOpposing(true)) + typeMod = pbCalcTypeModPokemon(pkmn, battler.pbDirectOpposing(true)) if Effectiveness.super_effective?(typeMod) # Greater weight if new Pokemon's type is effective against target weight = 85 end list.unshift(i) if pbAIRandom(100) < weight # Put this Pokemon first - elsif moveType && Effectiveness.resistant?(pbCalcTypeMod(moveType, @user, @user)) + elsif moveType && Effectiveness.resistant?(battler.effectiveness_of_type_against_battler(moveType)) weight = 40 - typeMod = pbCalcTypeModPokemon(pkmn, @user.pbDirectOpposing(true)) + typeMod = pbCalcTypeModPokemon(pkmn, battler.pbDirectOpposing(true)) if Effectiveness.super_effective?(typeMod) # Greater weight if new Pokemon's type is effective against target weight = 60 @@ -126,13 +127,13 @@ class Battle::AI end end if list.length > 0 - if batonPass >= 0 && @battle.pbRegisterMove(@user.index, batonPass, false) - PBDebug.log("[AI] #{@user.pbThis} (#{@user.index}) will use Baton Pass to avoid Perish Song") + if batonPass >= 0 && @battle.pbRegisterMove(battler.index, batonPass, false) + PBDebug.log("[AI] #{battler.pbThis} (#{battler.index}) will use Baton Pass to avoid Perish Song") return true end - if @battle.pbRegisterSwitch(@user.index, list[0]) - PBDebug.log("[AI] #{@user.pbThis} (#{@user.index}) will switch with " + - @battle.pbParty(@user.index)[list[0]].name) + if @battle.pbRegisterSwitch(battler.index, list[0]) + PBDebug.log("[AI] #{battler.pbThis} (#{battler.index}) will switch with " + + @battle.pbParty(battler.index)[list[0]].name) return true end end diff --git a/Data/Scripts/011_Battle/005_AI/004_AI_Move.rb b/Data/Scripts/011_Battle/005_AI/004_AI_Move.rb index 03f760295..3d223b382 100644 --- a/Data/Scripts/011_Battle/005_AI/004_AI_Move.rb +++ b/Data/Scripts/011_Battle/005_AI/004_AI_Move.rb @@ -1,93 +1,10 @@ class Battle::AI - #============================================================================= - # Main move-choosing method (moves with higher scores are more likely to be - # chosen) - #============================================================================= - def pbChooseMove(choices) - # Figure out useful information about the choices - totalScore = 0 - maxScore = 0 - choices.each do |c| - totalScore += c[1] - maxScore = c[1] if maxScore < c[1] - end - - # Find any preferred moves and just choose from them - if skill_check(AILevel.high) && maxScore > 100 - stDev = pbStdDev(choices) - if stDev >= 40 && pbAIRandom(100) < 90 - preferredMoves = [] - choices.each do |c| - next if c[1] < 200 && c[1] < maxScore * 0.8 - preferredMoves.push(c) - preferredMoves.push(c) if c[1] == maxScore # Doubly prefer the best move - end - if preferredMoves.length > 0 - m = preferredMoves[pbAIRandom(preferredMoves.length)] - PBDebug.log("[AI] #{@user.pbThis} (#{@user.index}) prefers #{@user.moves[m[0]].name}") - @battle.pbRegisterMove(@user.index, m[0], false) - @battle.pbRegisterTarget(@user.index, m[2]) if m[2] >= 0 - return - end - end - end - - # Decide whether all choices are bad, and if so, try switching instead - if !@wildBattler && skill_check(AILevel.high) - badMoves = false - if (maxScore <= 20 && @user.turnCount > 2) || - (maxScore <= 40 && @user.turnCount > 5) - badMoves = true if pbAIRandom(100) < 80 - end - if !badMoves && totalScore < 100 && @user.turnCount > 1 - badMoves = true - choices.each do |c| - next if !@user.moves[c[0]].damagingMove? - badMoves = false - break - end - badMoves = false if badMoves && pbAIRandom(100) < 10 - end - if badMoves && pbEnemyShouldWithdrawEx?(true) - if $INTERNAL - PBDebug.log("[AI] #{@user.pbThis} (#{@user.index}) will switch due to terrible moves") - end - return - end - end - - # If there are no calculated choices, pick one at random - if choices.length == 0 - PBDebug.log("[AI] #{@user.pbThis} (#{@user.index}) doesn't want to use any moves; picking one at random") - @user.eachMoveWithIndex do |_m, i| - next if !@battle.pbCanChooseMove?(@user.index, i, false) - choices.push([i, 100, -1]) # Move index, score, target - end - if choices.length == 0 # No moves are physically possible to use; use Struggle - @battle.pbAutoChooseMove(@user.index) - end - end - - # Randomly choose a move from the choices and register it - randNum = pbAIRandom(totalScore) - choices.each do |c| - randNum -= c[1] - next if randNum >= 0 - @battle.pbRegisterMove(@user.index, c[0], false) - @battle.pbRegisterTarget(@user.index, c[2]) if c[2] >= 0 - break - end - # Log the result - if @battle.choices[@user.index][2] - PBDebug.log("[AI] #{@user.pbThis} (#{@user.index}) will use #{@battle.choices[@user.index][2].name}") - end - end - #============================================================================= # Get scores for the user's moves (done before any action is assessed) # NOTE: A move is only added to the choices array if it has a non-zero score. #============================================================================= def pbGetMoveScores + battler = @user.battler # Get scores and targets for each move choices = [] # TODO: Split this into two, the first part being the calculation of all @@ -98,9 +15,9 @@ class Battle::AI # whittled down to one per move which are chosen from. Multi-target # moves could be fiddly since damages should be calculated for each # target but they're all related. - @user.eachMoveWithIndex do |_m, i| - next if !@battle.pbCanChooseMove?(@user.index, i, false) - if @wildBattler + battler.eachMoveWithIndex do |_m, i| + next if !@battle.pbCanChooseMove?(battler.index, i, false) + if @user.wild? pbRegisterMoveWild(i, choices) else pbRegisterMoveTrainer(i, choices) @@ -108,9 +25,9 @@ class Battle::AI end # Log the available choices if $INTERNAL - logMsg = "[AI] Move choices for #{@user.pbThis(true)} (#{@user.index}): " + logMsg = "[AI] Move choices for #{battler.pbThis(true)} (#{battler.index}): " choices.each_with_index do |c, i| - logMsg += "#{@user.moves[c[0]].name}=#{c[1]}" + logMsg += "#{battler.moves[c[0]].name}=#{c[1]}" logMsg += " (target #{c[2]})" if c[2] >= 0 logMsg += ", " if i < choices.length-1 end @@ -124,40 +41,42 @@ class Battle::AI #============================================================================= # Wild Pokémon choose their moves randomly. def pbRegisterMoveWild(idxMove, choices) + battler = @user.battler score = 100 # Doubly prefer one of the user's moves (the choice is random but consistent # and does not correlate to any other property of the user) - score *= 2 if @user.pokemon.personalID % @user.moves.length == idxMove + score *= 2 if battler.pokemon.personalID % battler.moves.length == idxMove choices.push([idxMove, 100, -1]) # Move index, score, target end # Trainer Pokémon calculate how much they want to use each of their moves. def pbRegisterMoveTrainer(idxMove, choices) - move = @user.moves[idxMove] - target_data = move.pbTarget(@user) + battler = @user.battler + move = battler.moves[idxMove] + target_data = move.pbTarget(battler) # TODO: Alter target_data if user has Protean and move is Curse. if [:UserAndAllies, :AllAllies, :AllBattlers].include?(target_data.id) || target_data.num_targets == 0 # If move has no targets, affects the user, a side or the whole field, or # specially affects multiple Pokémon and the AI calculates an overall # score at once instead of per target - score = pbGetMoveScore(move, @user) + score = pbGetMoveScore(move) choices.push([idxMove, score, -1]) if score > 0 elsif target_data.num_targets > 1 # If move affects multiple battlers and you don't choose a particular one totalScore = 0 @battle.allBattlers.each do |b| - next if !@battle.pbMoveCanTarget?(@user.index, b.index, target_data) + next if !@battle.pbMoveCanTarget?(battler.index, b.index, target_data) score = pbGetMoveScore(move, b) - totalScore += ((@user.opposes?(b)) ? score : -score) + totalScore += ((battler.opposes?(b)) ? score : -score) end choices.push([idxMove, totalScore, -1]) if totalScore > 0 else # If move affects one battler and you have to choose which one scoresAndTargets = [] @battle.allBattlers.each do |b| - next if !@battle.pbMoveCanTarget?(@user.index, b.index, target_data) - next if target_data.targets_foe && !@user.opposes?(b) + next if !@battle.pbMoveCanTarget?(battler.index, b.index, target_data) + next if target_data.targets_foe && !battler.opposes?(b) score = pbGetMoveScore(move, b) scoresAndTargets.push([score, b.index]) if score > 0 end @@ -170,21 +89,15 @@ class Battle::AI end #============================================================================= - # Set some class variables for the move being assessed + # Set some extra class variables for the move/target combo being assessed #============================================================================= def set_up_move_check(move, target) - @move = move - @target = target - # TODO: Calculate pbRoughType once here. + @move.set_up(move, @user) + @target = (target) ? @battlers[target.index] : @user + @target&.refresh_battler # Determine whether user or target is faster, and store that result so it # doesn't need recalculating - if @target - user_speed = pbRoughStat(@user, :SPEED) - target_speed = pbRoughStat(@target, :SPEED) - @user_faster = (user_speed > target_speed) ^ (@battle.field.effects[PBEffects::TrickRoom] > 0) - else - @user_faster = false # Won't be used if there is no target - end + @user_faster = @user.faster_than?(@target) end #============================================================================= @@ -192,9 +105,11 @@ class Battle::AI #============================================================================= def pbGetMoveScore(move, target = nil) set_up_move_check(move, target) + user_battler = @user.battler + target_battler = @target.battler # Get the base score for the move - if @move.damagingMove? + if @move.move.damagingMove? # Is also the predicted damage amount as a percentage of target's current HP score = pbGetDamagingMoveBaseScore else # Status moves @@ -202,8 +117,8 @@ class Battle::AI score = pbGetStatusMoveBaseScore end # Modify the score according to the move's effect - score = Battle::AI::Handlers.apply_move_effect_score(move.function, - score, move, @user, target, @skill, self, @battle) + score = Battle::AI::Handlers.apply_move_effect_score(@move.move.function, + score, @move.move, user_battler, target_battler, self, @battle) # A score of 0 here means it absolutely should not be used return 0 if score <= 0 @@ -230,7 +145,7 @@ class Battle::AI # Don't prefer a dancing move if the target has the Dancer ability # TODO: Check all battlers, not just the target. - if skill_check(AILevel.high) && @move.danceMove? && @target.hasActiveAbility?(:DANCER) + if @move.move.danceMove? && @target.has_active_ability?(:DANCER) score /= 2 end @@ -275,47 +190,46 @@ class Battle::AI # => If target has previously used a move that will hurt the user by 30% of # its current HP or more, moreso don't prefer a status move. - if skill_check(AILevel.medium) + # Prefer damaging moves if AI has no more Pokémon or AI is less clever + if @trainer.medium_skill? && @battle.pbAbleNonActiveCount(user_battler.idxOwnSide) == 0 && + !(@trainer.high_skill? && @battle.pbAbleNonActiveCount(target_battler.idxOwnSide) > 0) + if @move.move.statusMove? + score *= 0.9 + elsif target_battler.hp <= target_battler.totalhp / 2 + score *= 1.1 + end + end - # Prefer damaging moves if AI has no more Pokémon or AI is less clever - if @battle.pbAbleNonActiveCount(@user.idxOwnSide) == 0 && - !(skill_check(AILevel.high) && @battle.pbAbleNonActiveCount(@target.idxOwnSide) > 0) - if @move.statusMove? - score *= 0.9 - elsif @target.hp <= @target.totalhp / 2 - score *= 1.1 + # Don't prefer attacking the target if they'd be semi-invulnerable + if @move.accuracy > 0 && @user_faster && + (target_battler.semiInvulnerable? || target_battler.effects[PBEffects::SkyDrop] >= 0) + miss = true + miss = false if @user.has_active_ability?(:NOGUARD) + miss = false if @trainer.best_skill? && @target.has_active_ability?(:NOGUARD) + if @trainer.best_skill? && miss + # Knows what can get past semi-invulnerability + if target_battler.effects[PBEffects::SkyDrop] >= 0 || + target_battler.inTwoTurnAttack?("TwoTurnAttackInvulnerableInSky", + "TwoTurnAttackInvulnerableInSkyParalyzeTarget", + "TwoTurnAttackInvulnerableInSkyTargetCannotAct") + miss = false if move.hitsFlyingTargets? + elsif target.inTwoTurnAttack?("TwoTurnAttackInvulnerableUnderground") + miss = false if move.hitsDiggingTargets? + elsif target.inTwoTurnAttack?("TwoTurnAttackInvulnerableUnderwater") + miss = false if move.hitsDivingTargets? end end + score = 10 if miss + end - # Don't prefer attacking the target if they'd be semi-invulnerable - if skill_check(AILevel.high) && @move.accuracy > 0 && @user_faster && - (@target.semiInvulnerable? || @target.effects[PBEffects::SkyDrop] >= 0) - miss = true - miss = false if @user.hasActiveAbility?(:NOGUARD) - miss = false if skill_check(AILevel.best) && @target.hasActiveAbility?(:NOGUARD) - if skill_check(AILevel.best) && miss - # Knows what can get past semi-invulnerability - if @target.effects[PBEffects::SkyDrop] >= 0 || - @target.inTwoTurnAttack?("TwoTurnAttackInvulnerableInSky", - "TwoTurnAttackInvulnerableInSkyParalyzeTarget", - "TwoTurnAttackInvulnerableInSkyTargetCannotAct") - miss = false if move.hitsFlyingTargets? - elsif target.inTwoTurnAttack?("TwoTurnAttackInvulnerableUnderground") - miss = false if move.hitsDiggingTargets? - elsif target.inTwoTurnAttack?("TwoTurnAttackInvulnerableUnderwater") - miss = false if move.hitsDivingTargets? - end - end - score = 0 if miss - end - - # Pick a good move for the Choice items - if @user.hasActiveItem?([:CHOICEBAND, :CHOICESPECS, :CHOICESCARF]) || - @user.hasActiveAbility?(:GORILLATACTICS) + # Pick a good move for the Choice items + if @trainer.medium_skill? + if @user.has_active_item?([:CHOICEBAND, :CHOICESPECS, :CHOICESCARF]) || + @user.has_active_ability?(:GORILLATACTICS) # Really don't prefer status moves (except Trick) - score *= 0.1 if @move.statusMove? && @move.function != "UserTargetSwapItems" + score *= 0.1 if @move.move.statusMove? && @move.move.function != "UserTargetSwapItems" # Don't prefer moves of certain types - move_type = pbRoughType(@move) + move_type = @move.rough_type # Most unpreferred types are 0x effective against another type, except # Fire/Water/Grass # TODO: Actually check through the types for 0x instead of hardcoding @@ -330,38 +244,38 @@ class Battle::AI # Don't prefer moves with lower accuracy score *= @move.accuracy / 100.0 if @move.accuracy > 0 # Don't prefer moves with low PP - score *= 0.9 if @move.pp < 6 + score *= 0.9 if @move.move.pp < 6 end + end - # If user is asleep, don't prefer moves that can't be used while asleep - if skill_check(AILevel.medium) && @user.asleep? && @user.statusCount > 1 && - !@move.usableWhenAsleep? - score *= 0.2 - end + # If user is asleep, don't prefer moves that can't be used while asleep + if @trainer.medium_skill? && user_battler.asleep? && user_battler.statusCount > 1 && + !@move.move.usableWhenAsleep? + score *= 0.2 + end - # If user is frozen, prefer a move that can thaw the user - if skill_check(AILevel.medium) && @user.status == :FROZEN - if @move.thawsUser? - score += 30 - else - @user.eachMove do |m| - next unless m.thawsUser? - score = 0 # Discard this move if user knows another move that thaws - break - end - end - end - - # If target is frozen, don't prefer moves that could thaw them - if @target.status == :FROZEN - if pbRoughType(@move) == :FIRE || (Settings::MECHANICS_GENERATION >= 6 && @move.thawsUser?) - score *= 0.1 + # If user is frozen, prefer a move that can thaw the user + if @trainer.medium_skill? && user_battler.status == :FROZEN + if @move.move.thawsUser? + score += 30 + else + user_battler.eachMove do |m| + next unless m.thawsUser? + score = 0 # Discard this move if user knows another move that thaws + break end end end + # If target is frozen, don't prefer moves that could thaw them + if @trainer.medium_skill? && target_battler.status == :FROZEN + if @move.rough_type == :FIRE || (Settings::MECHANICS_GENERATION >= 6 && @move.move.thawsUser?) + score *= 0.1 + end + end + # Don't prefer hitting a wild shiny Pokémon - if @battle.wildBattle? && @target.opposes? && @target.shiny? + if @target.wild? && target_battler.shiny? score *= 0.15 end @@ -369,18 +283,18 @@ class Battle::AI # Bounce. # Account for accuracy of move - accuracy = pbRoughAccuracy(@move, @target) + accuracy = @move.rough_accuracy score *= accuracy / 100.0 # Prefer flinching external effects (note that move effects which cause # flinching are dealt with in the function code part of score calculation) - if skill_check(AILevel.medium) - if !@target.hasActiveAbility?([:INNERFOCUS, :SHIELDDUST]) && - @target.effects[PBEffects::Substitute] == 0 - if @move.flinchingMove? || - (@move.damagingMove? && - (@user.hasActiveItem?([:KINGSROCK, :RAZORFANG]) || - @user.hasActiveAbility?(:STENCH))) + if @trainer.medium_skill? + if !@target.has_active_ability?([:INNERFOCUS, :SHIELDDUST]) && + target_battler.effects[PBEffects::Substitute] == 0 + if @move.move.flinchingMove? || + (@move.move.damagingMove? && + (@user.has_active_item?([:KINGSROCK, :RAZORFANG]) || + @user.has_active_ability?(:STENCH))) score *= 1.3 end end @@ -388,14 +302,14 @@ class Battle::AI # # Adjust score based on how much damage it can deal # if move.damagingMove? - # score = pbGetMoveScoreDamage(score, move, @user, @target, @skill) + # score = pbGetMoveScoreDamage(score, move, @user, @target, @trainer.skill) # else # Status moves # # Don't prefer attacks which don't deal damage # score -= 10 # # Account for accuracy of move # accuracy = pbRoughAccuracy(move, target) # score *= accuracy / 100.0 - # score = 0 if score <= 10 && skill_check(AILevel.high) + # score = 0 if score <= 10 && @trainer.high_skill? # end score = score.to_i score = 0 if score < 0 @@ -408,21 +322,23 @@ class Battle::AI #============================================================================= def pbGetDamagingMoveBaseScore # Don't prefer moves that are ineffective because of abilities or effects - return 0 if pbCheckMoveImmunity(@move, @target) + return 0 if @target.immune_to_move? + user_battler = @user.battler + target_battler = @target.battler # Calculate how much damage the move will do (roughly) - base_damage = pbMoveBaseDamage(@move, @target) + base_damage = @move.base_power calc_damage = pbRoughDamage(@move, @target, base_damage) # TODO: Maybe move this check elsewhere? Note that Reborn's base score does # not include this halving, but the predicted damage does. # Two-turn attacks waste 2 turns to deal one lot of damage - calc_damage /= 2 if @move.chargingTurnMove? + calc_damage /= 2 if @move.move.chargingTurnMove? # TODO: Maybe move this check elsewhere? # Increased critical hit rate - if skill_check(AILevel.medium) - crit_stage = pbRoughCriticalHitStage(@move, @target) + if @trainer.medium_skill? + crit_stage = @move.rough_critical_hit_stage if crit_stage >= 0 crit_fraction = (crit_stage > 50) ? 1 : Battle::Move::CRITICAL_HIT_RATIOS[crit_stage] crit_mult = (Settings::NEW_CRITICAL_HIT_RATE_MECHANICS) ? 0.5 : 1 @@ -431,13 +347,13 @@ class Battle::AI end # Convert damage to percentage of target's remaining HP - damage_percentage = calc_damage * 100.0 / @target.hp + damage_percentage = calc_damage * 100.0 / target_battler.hp # Don't prefer weak attacks # damage_percentage /= 2 if damage_percentage < 20 # Prefer damaging attack if level difference is significantly high -# damage_percentage *= 1.2 if @user.level - 10 > @target.level +# damage_percentage *= 1.2 if user_battler.level - 10 > target_battler.level # Adjust score damage_percentage = 110 if damage_percentage > 110 # Treat all lethal moves the same @@ -447,7 +363,7 @@ class Battle::AI end def pbGetStatusMoveBaseScore - # TODO: Call pbCheckMoveImmunity here too, not just for damaging moves + # TODO: Call @target.immune_to_move? here too, not just for damaging moves # (only if this status move will be affected). # TODO: Make sure all status moves are accounted for. @@ -465,7 +381,7 @@ class Battle::AI # "LowerTargetAttack2" - Charm (10), Feather Dance (15) # "LowerTargetSpeed2" - String Shot (10), Cotton Spore (15), Scary Face (15) # "LowerTargetSpDef2" - Metal Sound (10), Fake Tears (15) - case @move.function + case @move.move.function when "ConfuseTarget", "LowerTargetAccuracy1", "LowerTargetEvasion1RemoveSideEffects", @@ -690,4 +606,90 @@ class Battle::AI # "ProtectUserSideFromStatusMoves" return 0 end + + #============================================================================= + # Make the final choice of which move to use depending on the calculated + # scores for each move. Moves with higher scores are more likely to be chosen. + #============================================================================= + def pbChooseMove(choices) + user_battler = @user.battler + + # Figure out useful information about the choices + totalScore = 0 + maxScore = 0 + choices.each do |c| + totalScore += c[1] + maxScore = c[1] if maxScore < c[1] + end + + # Find any preferred moves and just choose from them + if @trainer.high_skill? && maxScore > 100 + stDev = pbStdDev(choices) + if stDev >= 40 && pbAIRandom(100) < 90 + preferredMoves = [] + choices.each do |c| + next if c[1] < 200 && c[1] < maxScore * 0.8 + preferredMoves.push(c) + preferredMoves.push(c) if c[1] == maxScore # Doubly prefer the best move + end + if preferredMoves.length > 0 + m = preferredMoves[pbAIRandom(preferredMoves.length)] + PBDebug.log("[AI] #{user_battler.pbThis} (#{user_battler.index}) prefers #{user_battler.moves[m[0]].name}") + @battle.pbRegisterMove(user_battler.index, m[0], false) + @battle.pbRegisterTarget(user_battler.index, m[2]) if m[2] >= 0 + return + end + end + end + + # Decide whether all choices are bad, and if so, try switching instead + if @trainer.high_skill? && @user.can_switch_lax? + badMoves = false + if (maxScore <= 20 && user_battler.turnCount > 2) || + (maxScore <= 40 && user_battler.turnCount > 5) + badMoves = true if pbAIRandom(100) < 80 + end + if !badMoves && totalScore < 100 && user_battler.turnCount > 1 + badMoves = true + choices.each do |c| + next if !user_battler.moves[c[0]].damagingMove? + badMoves = false + break + end + badMoves = false if badMoves && pbAIRandom(100) < 10 + end + if badMoves && pbEnemyShouldWithdrawEx?(true) + if $INTERNAL + PBDebug.log("[AI] #{user_battler.pbThis} (#{user_battler.index}) will switch due to terrible moves") + end + return + end + end + + # If there are no calculated choices, pick one at random + if choices.length == 0 + PBDebug.log("[AI] #{user_battler.pbThis} (#{user_battler.index}) doesn't want to use any moves; picking one at random") + user_battler.eachMoveWithIndex do |_m, i| + next if !@battle.pbCanChooseMove?(user_battler.index, i, false) + choices.push([i, 100, -1]) # Move index, score, target + end + if choices.length == 0 # No moves are physically possible to use; use Struggle + @battle.pbAutoChooseMove(user_battler.index) + end + end + + # Randomly choose a move from the choices and register it + randNum = pbAIRandom(totalScore) + choices.each do |c| + randNum -= c[1] + next if randNum >= 0 + @battle.pbRegisterMove(user_battler.index, c[0], false) + @battle.pbRegisterTarget(user_battler.index, c[2]) if c[2] >= 0 + break + end + # Log the result + if @battle.choices[user_battler.index][2] + PBDebug.log("[AI] #{user_battler.pbThis} (#{user_battler.index}) will use #{@battle.choices[user_battler.index][2].name}") + end + end end diff --git a/Data/Scripts/011_Battle/005_AI/005_AI_MegaEvolve.rb b/Data/Scripts/011_Battle/005_AI/005_AI_MegaEvolve.rb new file mode 100644 index 000000000..6909ee008 --- /dev/null +++ b/Data/Scripts/011_Battle/005_AI/005_AI_MegaEvolve.rb @@ -0,0 +1,14 @@ +class Battle::AI + #============================================================================= + # Decide whether the opponent should Mega Evolve. + #============================================================================= + # TODO: Where relevant, pretend the user is Mega Evolved if it isn't but can + # be. + def pbEnemyShouldMegaEvolve? + if @battle.pbCanMegaEvolve?(@user.index) # Simple "always should if possible" + PBDebug.log("[AI] #{@user.pbThis} (#{@user.index}) will Mega Evolve") + return true + end + return false + end +end diff --git a/Data/Scripts/011_Battle/005_AI/008_AI_Move_Utilities.rb b/Data/Scripts/011_Battle/005_AI/008_AI_Move_Utilities.rb index f9ecceebe..a10eab79e 100644 --- a/Data/Scripts/011_Battle/005_AI/008_AI_Move_Utilities.rb +++ b/Data/Scripts/011_Battle/005_AI/008_AI_Move_Utilities.rb @@ -1,326 +1,72 @@ class Battle::AI - #============================================================================= - # - #============================================================================= - def pbTargetsMultiple?(move) - target_data = move.pbTarget(@user) - return false if target_data.num_targets <= 1 - num_targets = 0 - case target_data.id - when :AllAllies - @battle.allSameSideBattlers(@user).each { |b| num_targets += 1 if b.index != @user.index } - when :UserAndAllies - @battle.allSameSideBattlers(@user).each { |_b| num_targets += 1 } - when :AllNearFoes - @battle.allOtherSideBattlers(@user).each { |b| num_targets += 1 if b.near?(@user) } - when :AllFoes - @battle.allOtherSideBattlers(@user).each { |_b| num_targets += 1 } - when :AllNearOthers - @battle.allBattlers.each { |b| num_targets += 1 if b.near?(@user) } - when :AllBattlers - @battle.allBattlers.each { |_b| num_targets += 1 } + def pbAIRandom(x); return rand(x); end + + def pbStdDev(choices) + sum = 0 + n = 0 + choices.each do |c| + sum += c[1] + n += 1 end - return num_targets > 1 + return 0 if n < 2 + mean = sum.to_f / n + varianceTimesN = 0 + choices.each do |c| + next if c[1] <= 0 + deviation = c[1].to_f - mean + varianceTimesN += deviation * deviation + end + # Using population standard deviation + # [(n-1) makes it a sample std dev, would be 0 with only 1 sample] + return Math.sqrt(varianceTimesN / n) end #============================================================================= # Move's type effectiveness #============================================================================= - def pbCalcTypeModSingle(moveType, defType, user, target) - ret = Effectiveness.calculate_one(moveType, defType) - if Effectiveness.ineffective_type?(moveType, defType) - # Ring Target - if target.hasActiveItem?(:RINGTARGET) - ret = Effectiveness::NORMAL_EFFECTIVE_ONE - end - # Foresight - if (user.hasActiveAbility?(:SCRAPPY) || target.effects[PBEffects::Foresight]) && - defType == :GHOST - ret = Effectiveness::NORMAL_EFFECTIVE_ONE - end - # Miracle Eye - if target.effects[PBEffects::MiracleEye] && defType == :DARK - ret = Effectiveness::NORMAL_EFFECTIVE_ONE - end - elsif Effectiveness.super_effective_type?(moveType, defType) - # Delta Stream's weather - if target.effectiveWeather == :StrongWinds && defType == :FLYING - ret = Effectiveness::NORMAL_EFFECTIVE_ONE - end - end - # Grounded Flying-type Pokémon become susceptible to Ground moves - if !target.airborne? && defType == :FLYING && moveType == :GROUND - ret = Effectiveness::NORMAL_EFFECTIVE_ONE - end - return ret - end - - def pbCalcTypeMod(moveType, user, target) - return Effectiveness::NORMAL_EFFECTIVE if !moveType - return Effectiveness::NORMAL_EFFECTIVE if moveType == :GROUND && - target.pbHasType?(:FLYING) && - target.hasActiveItem?(:IRONBALL) - # Determine types - tTypes = target.pbTypes(true) - # Get effectivenesses - typeMods = [Effectiveness::NORMAL_EFFECTIVE_ONE] * 3 # 3 types max - if moveType == :SHADOW - if target.shadowPokemon? - typeMods[0] = Effectiveness::NOT_VERY_EFFECTIVE_ONE - else - typeMods[0] = Effectiveness::SUPER_EFFECTIVE_ONE - end - else - tTypes.each_with_index do |type, i| - typeMods[i] = pbCalcTypeModSingle(moveType, type, user, target) - end - end - # Multiply all effectivenesses together - ret = 1 - typeMods.each { |m| ret *= m } - return ret - end - # For switching. Determines the effectiveness of a potential switch-in against # an opposing battler. - def pbCalcTypeModPokemon(pkmn, target) - mod1 = Effectiveness.calculate(pkmn.types[0], target.types[0], target.types[1]) + def pbCalcTypeModPokemon(pkmn, target_battler) + mod1 = Effectiveness.calculate(pkmn.types[0], target_battler.types[0], target_battler.types[1]) mod2 = Effectiveness::NORMAL_EFFECTIVE if pkmn.types.length > 1 - mod2 = Effectiveness.calculate(pkmn.types[1], target.types[0], target.types[1]) + mod2 = Effectiveness.calculate(pkmn.types[1], target_battler.types[0], target_battler.types[1]) mod2 = mod2.to_f / Effectivenesss::NORMAL_EFFECTIVE end return mod1 * mod2 end - #============================================================================= - # Immunity to a move because of the target's ability, item or other effects - #============================================================================= - def pbCheckMoveImmunity(move, target) - # TODO: Add consideration of user's Mold Breaker. - move_type = pbRoughType(move) - typeMod = pbCalcTypeMod(move_type, @user, target) - # Type effectiveness - return true if move.damagingMove? && Effectiveness.ineffective?(typeMod) - # Immunity due to ability/item/other effects - if skill_check(AILevel.medium) - case move_type - when :GROUND - # TODO: Split target.airborne? into separate parts to allow different - # skill levels to apply to each part. - return true if target.airborne? && !move.hitsFlyingTargets? - when :FIRE - return true if target.hasActiveAbility?(:FLASHFIRE) - when :WATER - return true if target.hasActiveAbility?([:DRYSKIN, :STORMDRAIN, :WATERABSORB]) - when :GRASS - return true if target.hasActiveAbility?(:SAPSIPPER) - when :ELECTRIC - return true if target.hasActiveAbility?([:LIGHTNINGROD, :MOTORDRIVE, :VOLTABSORB]) - end - return true if move.damagingMove? && Effectiveness.not_very_effective?(typeMod) && - target.hasActiveAbility?(:WONDERGUARD) - return true if move.damagingMove? && @user.index != target.index && !target.opposes?(@user) && - target.hasActiveAbility?(:TELEPATHY) - return true if move.statusMove? && move.canMagicCoat? && target.hasActiveAbility?(:MAGICBOUNCE) && - target.opposes?(@user) - return true if move.soundMove? && target.hasActiveAbility?(:SOUNDPROOF) - return true if move.bombMove? && target.hasActiveAbility?(:BULLETPROOF) - if move.powderMove? - return true if target.pbHasType?(:GRASS) - return true if skill_check(AILevel.best) && target.hasActiveAbility?(:OVERCOAT) - return true if skill_check(AILevel.high) && target.hasActiveItem?(:SAFETYGOGGLES) - end - return true if move.statusMove? && target.effects[PBEffects::Substitute] > 0 && - !move.ignoresSubstitute?(@user) && @user.index != target.index - return true if move.statusMove? && Settings::MECHANICS_GENERATION >= 7 && - @user.hasActiveAbility?(:PRANKSTER) && target.pbHasType?(:DARK) && - target.opposes?(@user) - return true if move.priority > 0 && @battle.field.terrain == :Psychic && - target.affectedByTerrain? && target.opposes?(@user) - # TODO: Dazzling/Queenly Majesty go here. - end - return false - end - - #============================================================================= - # Get approximate properties for a battler - #============================================================================= - def pbRoughType(move) - ret = move.type - ret = move.pbCalcType(@user) if skill_check(AILevel.high) - return ret - end - - def pbRoughStat(battler, stat) - return battler.pbSpeed if skill_check(AILevel.high) && stat == :SPEED - stageMul = [2, 2, 2, 2, 2, 2, 2, 3, 4, 5, 6, 7, 8] - stageDiv = [8, 7, 6, 5, 4, 3, 2, 2, 2, 2, 2, 2, 2] - stage = battler.stages[stat] + 6 - value = 0 - case stat - when :ATTACK then value = battler.attack - when :DEFENSE then value = battler.defense - when :SPECIAL_ATTACK then value = battler.spatk - when :SPECIAL_DEFENSE then value = battler.spdef - when :SPEED then value = battler.speed - end - return (value.to_f * stageMul[stage] / stageDiv[stage]).floor - end - - #============================================================================= - # Get a better move's base damage value - #============================================================================= - def pbMoveBaseDamage(move, target) - baseDmg = move.baseDamage - baseDmg = 60 if baseDmg == 1 - return baseDmg if !skill_check(AILevel.medium) - # Covers all function codes which have their own def pbBaseDamage - case move.function - # Sonic Boom, Dragon Rage, Super Fang, Night Shade, Endeavor - when "FixedDamage20", "FixedDamage40", "FixedDamageHalfTargetHP", - "FixedDamageUserLevel", "LowerTargetHPToUserHP" - baseDmg = move.pbFixedDamage(@user, target) - when "FixedDamageUserLevelRandom" # Psywave - baseDmg = @user.level - when "OHKO", "OHKOIce", "OHKOHitsUndergroundTarget" - baseDmg = 200 - when "CounterPhysicalDamage", "CounterSpecialDamage", "CounterDamagePlusHalf" - baseDmg = 60 - when "DoublePowerIfTargetUnderwater", "DoublePowerIfTargetUnderground", - "BindTargetDoublePowerIfTargetUnderwater" - baseDmg = move.pbModifyDamage(baseDmg, @user, target) - # Gust, Twister, Venoshock, Smelling Salts, Wake-Up Slap, Facade, Hex, Brine, - # Retaliate, Weather Ball, Return, Frustration, Eruption, Crush Grip, - # Stored Power, Punishment, Hidden Power, Fury Cutter, Echoed Voice, - # Trump Card, Flail, Electro Ball, Low Kick, Fling, Spit Up - when "DoublePowerIfTargetInSky", - "FlinchTargetDoublePowerIfTargetInSky", - "DoublePowerIfTargetPoisoned", - "DoublePowerIfTargetParalyzedCureTarget", - "DoublePowerIfTargetAsleepCureTarget", - "DoublePowerIfUserPoisonedBurnedParalyzed", - "DoublePowerIfTargetStatusProblem", - "DoublePowerIfTargetHPLessThanHalf", - "DoublePowerIfAllyFaintedLastTurn", - "TypeAndPowerDependOnWeather", - "PowerHigherWithUserHappiness", - "PowerLowerWithUserHappiness", - "PowerHigherWithUserHP", - "PowerHigherWithTargetHP", - "PowerHigherWithUserPositiveStatStages", - "PowerHigherWithTargetPositiveStatStages", - "TypeDependsOnUserIVs", - "PowerHigherWithConsecutiveUse", - "PowerHigherWithConsecutiveUseOnUserSide", - "PowerHigherWithLessPP", - "PowerLowerWithUserHP", - "PowerHigherWithUserFasterThanTarget", - "PowerHigherWithTargetWeight", - "ThrowUserItemAtTarget", - "PowerDependsOnUserStockpile" - baseDmg = move.pbBaseDamage(baseDmg, @user, target) - when "DoublePowerIfUserHasNoItem" # Acrobatics - baseDmg *= 2 if !@user.item || @user.hasActiveItem?(:FLYINGGEM) - when "PowerHigherWithTargetFasterThanUser" # Gyro Ball - targetSpeed = pbRoughStat(target, :SPEED) - userSpeed = pbRoughStat(@user, :SPEED) - baseDmg = [[(25 * targetSpeed / userSpeed).floor, 150].min, 1].max - when "RandomlyDamageOrHealTarget" # Present - baseDmg = 50 - when "RandomPowerDoublePowerIfTargetUnderground" # Magnitude - baseDmg = 71 - baseDmg *= 2 if target.inTwoTurnAttack?("TwoTurnAttackInvulnerableUnderground") # Dig - when "TypeAndPowerDependOnUserBerry" # Natural Gift - baseDmg = move.pbNaturalGiftBaseDamage(@user.item_id) - when "PowerHigherWithUserHeavierThanTarget" # Heavy Slam - baseDmg = move.pbBaseDamage(baseDmg, @user, target) - baseDmg *= 2 if Settings::MECHANICS_GENERATION >= 7 && skill_check(AILevel.medium) && - target.effects[PBEffects::Minimize] - when "AlwaysCriticalHit", "HitTwoTimes", "HitTwoTimesPoisonTarget" # Frost Breath, Double Kick, Twineedle - baseDmg *= 2 - when "HitThreeTimesPowersUpWithEachHit" # Triple Kick - baseDmg *= 6 # Hits do x1, x2, x3 baseDmg in turn, for x6 in total - when "HitTwoToFiveTimes" # Fury Attack - if @user.hasActiveAbility?(:SKILLLINK) - baseDmg *= 5 - else - baseDmg = (baseDmg * 31 / 10).floor # Average damage dealt - end - when "HitTwoToFiveTimesOrThreeForAshGreninja" - if @user.isSpecies?(:GRENINJA) && @user.form == 2 - baseDmg *= 4 # 3 hits at 20 power = 4 hits at 15 power - elsif @user.hasActiveAbility?(:SKILLLINK) - baseDmg *= 5 - else - baseDmg = (baseDmg * 31 / 10).floor # Average damage dealt - end - when "HitOncePerUserTeamMember" # Beat Up - mult = 0 - @battle.eachInTeamFromBattlerIndex(@user.index) do |pkmn, _i| - mult += 1 if pkmn&.able? && pkmn.status == :NONE - end - baseDmg *= mult - when "TwoTurnAttackOneTurnInSun" # Solar Beam - baseDmg = move.pbBaseDamageMultiplier(baseDmg, @user, target) - when "MultiTurnAttackPowersUpEachTurn" # Rollout - baseDmg *= 2 if @user.effects[PBEffects::DefenseCurl] - when "MultiTurnAttackBideThenReturnDoubleDamage" # Bide - baseDmg = 40 - when "UserFaintsFixedDamageUserHP" # Final Gambit - baseDmg = @user.hp - when "EffectivenessIncludesFlyingType" # Flying Press - if GameData::Type.exists?(:FLYING) - if skill_check(AILevel.high) - targetTypes = target.pbTypes(true) - mult = Effectiveness.calculate( - :FLYING, targetTypes[0], targetTypes[1], targetTypes[2] - ) - else - mult = Effectiveness.calculate( - :FLYING, target.types[0], target.types[1], target.effects[PBEffects::Type3] - ) - end - baseDmg = (baseDmg.to_f * mult / Effectiveness::NORMAL_EFFECTIVE).round - end - baseDmg *= 2 if skill_check(AILevel.medium) && target.effects[PBEffects::Minimize] - when "DoublePowerIfUserLastMoveFailed" # Stomping Tantrum - baseDmg *= 2 if @user.lastRoundMoveFailed - when "HitTwoTimesFlinchTarget" # Double Iron Bash - baseDmg *= 2 - baseDmg *= 2 if skill_check(AILevel.medium) && target.effects[PBEffects::Minimize] - end - return baseDmg - end - #============================================================================= # Damage calculation #============================================================================= def pbRoughDamage(move, target, baseDmg) # Fixed damage moves - return baseDmg if move.is_a?(Battle::Move::FixedDamageMove) + return baseDmg if move.move.is_a?(Battle::Move::FixedDamageMove) + + user_battler = @user.battler + target_battler = target.battler # Get the move's type - type = pbRoughType(move) + type = move.rough_type ##### Calculate user's attack stat ##### - atk = pbRoughStat(@user, :ATTACK) - if move.function == "UseTargetAttackInsteadOfUserAttack" # Foul Play - atk = pbRoughStat(target, :ATTACK) - elsif move.function == "UseUserBaseDefenseInsteadOfUserBaseAttack" # Body Press - atk = pbRoughStat(@user, :DEFENSE) - elsif move.specialMove?(type) - if move.function == "UseTargetAttackInsteadOfUserAttack" # Foul Play - atk = pbRoughStat(target, :SPECIAL_ATTACK) + atk = @user.rough_stat(:ATTACK) + if move.move.function == "UseTargetAttackInsteadOfUserAttack" # Foul Play + atk = target.rough_stat(:ATTACK) + elsif move.move.function == "UseUserBaseDefenseInsteadOfUserBaseAttack" # Body Press + atk = @user.rough_stat(:DEFENSE) + elsif move.move.specialMove?(type) + if move.move.function == "UseTargetAttackInsteadOfUserAttack" # Foul Play + atk = target.rough_stat(:SPECIAL_ATTACK) else - atk = pbRoughStat(@user, :SPECIAL_ATTACK) + atk = @user.rough_stat(:SPECIAL_ATTACK) end end ##### Calculate target's defense stat ##### - defense = pbRoughStat(target, :DEFENSE) - if move.specialMove?(type) && move.function != "UseTargetDefenseInsteadOfTargetSpDef" # Psyshock - defense = pbRoughStat(target, :SPECIAL_DEFENSE) + defense = target.rough_stat(:DEFENSE) + if move.move.specialMove?(type) && move.move.function != "UseTargetDefenseInsteadOfTargetSpDef" # Psyshock + defense = target.rough_stat(:SPECIAL_DEFENSE) end ##### Calculate all multiplier effects ##### @@ -331,56 +77,56 @@ class Battle::AI :final_damage_multiplier => 1.0 } # Ability effects that alter damage - moldBreaker = skill_check(AILevel.high) && target.hasMoldBreaker? + moldBreaker = @trainer.high_skill? && target_battler.hasMoldBreaker? - if skill_check(AILevel.medium) && @user.abilityActive? + if @user.ability_active? # NOTE: These abilities aren't suitable for checking at the start of the # round. abilityBlacklist = [:ANALYTIC, :SNIPER, :TINTEDLENS, :AERILATE, :PIXILATE, :REFRIGERATE] canCheck = true abilityBlacklist.each do |m| - next if move.id != m + next if move.move.id != m canCheck = false break end if canCheck Battle::AbilityEffects.triggerDamageCalcFromUser( - @user.ability, @user, target, move, multipliers, baseDmg, type + user_battler.ability, user_battler, target_battler, move.move, multipliers, baseDmg, type ) end end - if skill_check(AILevel.medium) && !moldBreaker - @user.allAllies.each do |b| + if @trainer.medium_skill? && !moldBreaker + user_battler.allAllies.each do |b| next if !b.abilityActive? Battle::AbilityEffects.triggerDamageCalcFromAlly( - b.ability, @user, target, move, multipliers, baseDmg, type + b.ability, user_battler, target_battler, move.move, multipliers, baseDmg, type ) end end - if skill_check(AILevel.best) && !moldBreaker && target.abilityActive? + if !moldBreaker && target.ability_active? # NOTE: These abilities aren't suitable for checking at the start of the # round. abilityBlacklist = [:FILTER, :SOLIDROCK] canCheck = true abilityBlacklist.each do |m| - next if move.id != m + next if move.move.id != m canCheck = false break end if canCheck Battle::AbilityEffects.triggerDamageCalcFromTarget( - target.ability, @user, target, move, multipliers, baseDmg, type + target_battler.ability, user_battler, target_battler, move.move, multipliers, baseDmg, type ) end end - if skill_check(AILevel.best) && !moldBreaker - target.allAllies.each do |b| + if @trainer.high_skill? && !moldBreaker + target_battler.allAllies.each do |b| next if !b.abilityActive? Battle::AbilityEffects.triggerDamageCalcFromTargetAlly( - b.ability, @user, target, move, multipliers, baseDmg, type + b.ability, user_battler, target_battler, move.move, multipliers, baseDmg, type ) end end @@ -388,28 +134,27 @@ class Battle::AI # Item effects that alter damage # NOTE: Type-boosting gems aren't suitable for checking at the start of the # round. - if skill_check(AILevel.medium) && @user.itemActive? + if @user.item_active? # NOTE: These items aren't suitable for checking at the start of the # round. itemBlacklist = [:EXPERTBELT, :LIFEORB] - if !itemBlacklist.include?(@user.item_id) + if !itemBlacklist.include?(user_battler.item_id) Battle::ItemEffects.triggerDamageCalcFromUser( - @user.item, @user, target, move, multipliers, baseDmg, type + user_battler.item, user_battler, target_battler, move.move, multipliers, baseDmg, type ) - @user.effects[PBEffects::GemConsumed] = nil # Untrigger consuming of Gems + user_battler.effects[PBEffects::GemConsumed] = nil # Untrigger consuming of Gems end # TODO: Prefer (1.5x?) if item will be consumed and user has Unburden. end - if skill_check(AILevel.best) && - target.itemActive? && target.item && !target.item.is_berry? + if target.item_active? && target_battler.item && !target_battler.item.is_berry? Battle::ItemEffects.triggerDamageCalcFromTarget( - target.item, @user, target, move, multipliers, baseDmg, type + target_battler.item, user_battler, target_battler, move.move, multipliers, baseDmg, type ) end # Global abilities - if skill_check(AILevel.medium) && + if @trainer.medium_skill? && ((@battle.pbCheckGlobalAbility(:DARKAURA) && type == :DARK) || (@battle.pbCheckGlobalAbility(:FAIRYAURA) && type == :FAIRY)) if @battle.pbCheckGlobalAbility(:AURABREAK) @@ -420,7 +165,7 @@ class Battle::AI end # Parental Bond - if skill_check(AILevel.medium) && @user.hasActiveAbility?(:PARENTALBOND) + if @user.has_active_ability?(:PARENTALBOND) multipliers[:base_damage_multiplier] *= 1.25 end @@ -430,13 +175,13 @@ class Battle::AI # Helping Hand - n/a # Charge - if skill_check(AILevel.medium) && - @user.effects[PBEffects::Charge] > 0 && type == :ELECTRIC + if @trainer.medium_skill? && + user_battler.effects[PBEffects::Charge] > 0 && type == :ELECTRIC multipliers[:base_damage_multiplier] *= 2 end # Mud Sport and Water Sport - if skill_check(AILevel.medium) + if @trainer.medium_skill? if type == :ELECTRIC if @battle.allBattlers.any? { |b| b.effects[PBEffects::MudSport] } multipliers[:base_damage_multiplier] /= 3 @@ -456,38 +201,38 @@ class Battle::AI end # Terrain moves - if skill_check(AILevel.medium) + if @trainer.medium_skill? case @battle.field.terrain when :Electric - multipliers[:base_damage_multiplier] *= 1.5 if type == :ELECTRIC && @user.affectedByTerrain? + multipliers[:base_damage_multiplier] *= 1.5 if type == :ELECTRIC && user_battler.affectedByTerrain? when :Grassy - multipliers[:base_damage_multiplier] *= 1.5 if type == :GRASS && @user.affectedByTerrain? + multipliers[:base_damage_multiplier] *= 1.5 if type == :GRASS && user_battler.affectedByTerrain? when :Psychic - multipliers[:base_damage_multiplier] *= 1.5 if type == :PSYCHIC && @user.affectedByTerrain? + multipliers[:base_damage_multiplier] *= 1.5 if type == :PSYCHIC && user_battler.affectedByTerrain? when :Misty - multipliers[:base_damage_multiplier] /= 2 if type == :DRAGON && target.affectedByTerrain? + multipliers[:base_damage_multiplier] /= 2 if type == :DRAGON && target_battler.affectedByTerrain? end end # Badge multipliers - if skill_check(AILevel.high) && @battle.internalBattle && target.pbOwnedByPlayer? + if @trainer.high_skill? && @battle.internalBattle && target_battler.pbOwnedByPlayer? # Don't need to check the Atk/Sp Atk-boosting badges because the AI # won't control the player's Pokémon. - if move.physicalMove?(type) && @battle.pbPlayer.badge_count >= Settings::NUM_BADGES_BOOST_DEFENSE + if move.move.physicalMove?(type) && @battle.pbPlayer.badge_count >= Settings::NUM_BADGES_BOOST_DEFENSE multipliers[:defense_multiplier] *= 1.1 - elsif move.specialMove?(type) && @battle.pbPlayer.badge_count >= Settings::NUM_BADGES_BOOST_SPDEF + elsif move.move.specialMove?(type) && @battle.pbPlayer.badge_count >= Settings::NUM_BADGES_BOOST_SPDEF multipliers[:defense_multiplier] *= 1.1 end end # Multi-targeting attacks - if skill_check(AILevel.high) && pbTargetsMultiple?(move) + if @trainer.high_skill? && move.targets_multiple_battlers? multipliers[:final_damage_multiplier] *= 0.75 end # Weather - if skill_check(AILevel.medium) - case @user.effectiveWeather + if @trainer.medium_skill? + case user_battler.effectiveWeather when :Sun, :HarshSun case type when :FIRE @@ -503,8 +248,8 @@ class Battle::AI multipliers[:final_damage_multiplier] *= 1.5 end when :Sandstorm - if target.pbHasType?(:ROCK) && move.specialMove?(type) && - move.function != "UseTargetDefenseInsteadOfTargetSpDef" # Psyshock + if target.has_type?(:ROCK) && move.move.specialMove?(type) && + move.move.function != "UseTargetDefenseInsteadOfTargetSpDef" # Psyshock multipliers[:defense_multiplier] *= 1.5 end end @@ -515,8 +260,8 @@ class Battle::AI # Random variance - n/a # STAB - if skill_check(AILevel.medium) && type && @user.pbHasType?(type) - if @user.hasActiveAbility?(:ADAPTABILITY) + if type && @user.has_type?(type) + if @user.has_active_ability?(:ADAPTABILITY) multipliers[:final_damage_multiplier] *= 2 else multipliers[:final_damage_multiplier] *= 1.5 @@ -524,35 +269,33 @@ class Battle::AI end # Type effectiveness - if skill_check(AILevel.medium) - typemod = pbCalcTypeMod(type, @user, target) - multipliers[:final_damage_multiplier] *= typemod.to_f / Effectiveness::NORMAL_EFFECTIVE - end + typemod = target.effectiveness_of_type_against_battler(type, @user) + multipliers[:final_damage_multiplier] *= typemod.to_f / Effectiveness::NORMAL_EFFECTIVE # Burn - if skill_check(AILevel.high) && move.physicalMove?(type) && - @user.status == :BURN && !@user.hasActiveAbility?(:GUTS) && + if @trainer.high_skill? && move.move.physicalMove?(type) && + user_battler.status == :BURN && !@user.has_active_ability?(:GUTS) && !(Settings::MECHANICS_GENERATION >= 6 && - move.function == "DoublePowerIfUserPoisonedBurnedParalyzed") # Facade + move.move.function == "DoublePowerIfUserPoisonedBurnedParalyzed") # Facade multipliers[:final_damage_multiplier] /= 2 end # Aurora Veil, Reflect, Light Screen - if skill_check(AILevel.high) && !move.ignoresReflect? && !@user.hasActiveAbility?(:INFILTRATOR) - if target.pbOwnSide.effects[PBEffects::AuroraVeil] > 0 - if @battle.pbSideBattlerCount(target) > 1 + if @trainer.medium_skill? && !move.move.ignoresReflect? && !@user.has_active_ability?(:INFILTRATOR) + if target_battler.pbOwnSide.effects[PBEffects::AuroraVeil] > 0 + if @battle.pbSideBattlerCount(target_battler) > 1 multipliers[:final_damage_multiplier] *= 2 / 3.0 else multipliers[:final_damage_multiplier] /= 2 end - elsif target.pbOwnSide.effects[PBEffects::Reflect] > 0 && move.physicalMove?(type) - if @battle.pbSideBattlerCount(target) > 1 + elsif target_battler.pbOwnSide.effects[PBEffects::Reflect] > 0 && move.move.physicalMove?(type) + if @battle.pbSideBattlerCount(target_battler) > 1 multipliers[:final_damage_multiplier] *= 2 / 3.0 else multipliers[:final_damage_multiplier] /= 2 end - elsif target.pbOwnSide.effects[PBEffects::LightScreen] > 0 && move.specialMove?(type) - if @battle.pbSideBattlerCount(target) > 1 + elsif target_battler.pbOwnSide.effects[PBEffects::LightScreen] > 0 && move.move.specialMove?(type) + if @battle.pbSideBattlerCount(target_battler) > 1 multipliers[:final_damage_multiplier] *= 2 / 3.0 else multipliers[:final_damage_multiplier] /= 2 @@ -561,7 +304,7 @@ class Battle::AI end # Minimize - if skill_check(AILevel.high) && target.effects[PBEffects::Minimize] && move.tramplesMinimize? + if @trainer.medium_skill? && target_battler.effects[PBEffects::Minimize] && move.move.tramplesMinimize? multipliers[:final_damage_multiplier] *= 2 end @@ -575,156 +318,11 @@ class Battle::AI baseDmg = [(baseDmg * multipliers[:base_damage_multiplier]).round, 1].max atk = [(atk * multipliers[:attack_multiplier]).round, 1].max defense = [(defense * multipliers[:defense_multiplier]).round, 1].max - damage = ((((2.0 * @user.level / 5) + 2).floor * baseDmg * atk / defense).floor / 50).floor + 2 + damage = ((((2.0 * user_battler.level / 5) + 2).floor * baseDmg * atk / defense).floor / 50).floor + 2 damage = [(damage * multipliers[:final_damage_multiplier]).round, 1].max return damage.floor end - #============================================================================= - # Critical hit rate calculation - #============================================================================= - def pbRoughCriticalHitStage(move, target) - return -1 if target.pbOwnSide.effects[PBEffects::LuckyChant] > 0 - mold_breaker = (skill_check(AILevel.medium) && @user.hasMoldBreaker?) - crit_stage = 0 - # Ability effects that alter critical hit rate - if skill_check(AILevel.medium) && @user.abilityActive? - crit_stage = BattleHandlers.triggerCriticalCalcUserAbility(@user.ability, @user, target, crit_stage) - return -1 if crit_stage < 0 - end - if skill_check(AILevel.best) && !mold_breaker && target.abilityActive? - crit_stage = BattleHandlers.triggerCriticalCalcTargetAbility(target.ability, @user, target, crit_stage) - return -1 if crit_stage < 0 - end - # Item effects that alter critical hit rate - if skill_check(AILevel.medium) && @user.itemActive? - crit_stage = BattleHandlers.triggerCriticalCalcUserItem(@user.item, @user, target, crit_stage) - return -1 if crit_stage < 0 - end - if skill_check(AILevel.high) && target.itemActive? - crit_stage = BattleHandlers.triggerCriticalCalcTargetItem(target.item, @user, target, crit_stage) - return -1 if crit_stage < 0 - end - # Other effects - case move.pbCritialOverride(@user, target) - when 1 then return 99 - when -1 then return -1 - end - return 99 if crit_stage > 50 # Merciless - return 99 if @user.effects[PBEffects::LaserFocus] > 0 - crit_stage += 1 if move.highCriticalRate? - crit_stage += @user.effects[PBEffects::FocusEnergy] - crit_stage += 1 if @user.inHyperMode? && move.type == :SHADOW - crit_stage = [crit_stage, Battle::Move::CRITICAL_HIT_RATIOS.length - 1].min - return crit_stage - end - - #============================================================================= - # Accuracy calculation - #============================================================================= - def pbRoughAccuracy(move, target) - # "Always hit" effects and "always hit" accuracy - if skill_check(AILevel.medium) - return 100 if target.effects[PBEffects::Minimize] && move.tramplesMinimize? && - Settings::MECHANICS_GENERATION >= 6 - return 100 if target.effects[PBEffects::Telekinesis] > 0 - end - # Get base accuracy - baseAcc = move.accuracy - baseAcc = move.pbBaseAccuracy(@user, target) if skill_check(AILevel.medium) - return 100 if baseAcc == 0 && skill_check(AILevel.medium) - # Get the move's type - type = pbRoughType(move) - # Calculate all modifier effects - modifiers = {} - modifiers[:base_accuracy] = baseAcc - modifiers[:accuracy_stage] = @user.stages[:ACCURACY] - modifiers[:evasion_stage] = target.stages[:EVASION] - modifiers[:accuracy_multiplier] = 1.0 - modifiers[:evasion_multiplier] = 1.0 - pbCalcAccuracyModifiers(target, modifiers, move, type) - # Check if move certainly misses/can't miss - return 0 if modifiers[:base_accuracy] < 0 - return 100 if modifiers[:base_accuracy] == 0 - # Calculation - accStage = [[modifiers[:accuracy_stage], -6].max, 6].min + 6 - evaStage = [[modifiers[:evasion_stage], -6].max, 6].min + 6 - stageMul = [3, 3, 3, 3, 3, 3, 3, 4, 5, 6, 7, 8, 9] - stageDiv = [9, 8, 7, 6, 5, 4, 3, 3, 3, 3, 3, 3, 3] - accuracy = 100.0 * stageMul[accStage] / stageDiv[accStage] - evasion = 100.0 * stageMul[evaStage] / stageDiv[evaStage] - accuracy = (accuracy * modifiers[:accuracy_multiplier]).round - evasion = (evasion * modifiers[:evasion_multiplier]).round - evasion = 1 if evasion < 1 - return modifiers[:base_accuracy] * accuracy / evasion - end - - def pbCalcAccuracyModifiers(target, modifiers, move, type) - moldBreaker = (skill_check(AILevel.medium) && target.hasMoldBreaker?) - # Ability effects that alter accuracy calculation - if skill_check(AILevel.medium) && @user.abilityActive? - Battle::AbilityEffects.triggerAccuracyCalcFromUser( - @user.ability, modifiers, @user, target, move, type - ) - end - if skill_check(AILevel.high) - @user.allAllies.each do |b| - next if !b.abilityActive? - Battle::AbilityEffects.triggerAccuracyCalcFromAlly( - b.ability, modifiers, @user, target, move, type - ) - end - end - if skill_check(AILevel.best) && target.abilityActive? && !moldBreaker - Battle::AbilityEffects.triggerAccuracyCalcFromTarget( - target.ability, modifiers, @user, target, move, type - ) - end - # Item effects that alter accuracy calculation - if skill_check(AILevel.medium) && @user.itemActive? - # TODO: Zoom Lens needs to be checked differently (compare speeds of - # user and target). - Battle::ItemEffects.triggerAccuracyCalcFromUser( - @user.item, modifiers, @user, target, move, type - ) - end - if skill_check(AILevel.high) && target.itemActive? - Battle::ItemEffects.triggerAccuracyCalcFromTarget( - target.item, modifiers, @user, target, move, type - ) - end - # Other effects, inc. ones that set accuracy_multiplier or evasion_stage to specific values - if @battle.field.effects[PBEffects::Gravity] > 0 - modifiers[:accuracy_multiplier] *= 5 / 3.0 - end - if skill_check(AILevel.medium) - if @user.effects[PBEffects::MicleBerry] - modifiers[:accuracy_multiplier] *= 1.2 - end - modifiers[:evasion_stage] = 0 if target.effects[PBEffects::Foresight] && modifiers[:evasion_stage] > 0 - modifiers[:evasion_stage] = 0 if target.effects[PBEffects::MiracleEye] && modifiers[:evasion_stage] > 0 - end - # "AI-specific calculations below" - modifiers[:evasion_stage] = 0 if move.function == "IgnoreTargetDefSpDefEvaStatStages" # Chip Away - if skill_check(AILevel.medium) - modifiers[:base_accuracy] = 0 if @user.effects[PBEffects::LockOn] > 0 && - @user.effects[PBEffects::LockOnPos] == target.index - end - if skill_check(AILevel.medium) - if move.function == "BadPoisonTarget" && # Toxic - Settings::MORE_TYPE_EFFECTS && move.statusMove? && @user.pbHasType?(:POISON) - modifiers[:base_accuracy] = 0 - end - if ["OHKO", "OHKOIce", "OHKOHitsUndergroundTarget"].include?(move.function) - modifiers[:base_accuracy] = move.accuracy + @user.level - target.level - modifiers[:accuracy_multiplier] = 0 if target.level > @user.level - if skill_check(AILevel.best) && target.hasActiveAbility?(:STURDY) - modifiers[:accuracy_multiplier] = 0 - end - end - end - end - #============================================================================= # Check if battler has a move that meets the criteria in the block provided #============================================================================= diff --git a/Data/Scripts/011_Battle/005_AI/020_AI_MoveEffectScores_Generic.rb b/Data/Scripts/011_Battle/005_AI/020_AI_MoveEffectScores_Generic.rb index 2f7532e5d..0ba940523 100644 --- a/Data/Scripts/011_Battle/005_AI/020_AI_MoveEffectScores_Generic.rb +++ b/Data/Scripts/011_Battle/005_AI/020_AI_MoveEffectScores_Generic.rb @@ -112,7 +112,7 @@ class Battle::AI # instead if the move raises evasion. Note this comes after the # dissociation of Bulk Up from sweeping_stat. - if skill_check(AILevel.medium) + if @trainer.medium_skill? # TODO: Prefer if the maximum damage the target has dealt wouldn't hurt # the user much. end diff --git a/Data/Scripts/011_Battle/005_AI/051_AI_MoveHandlers_Misc.rb b/Data/Scripts/011_Battle/005_AI/051_AI_MoveHandlers_Misc.rb index b7a064393..53a17c500 100644 --- a/Data/Scripts/011_Battle/005_AI/051_AI_MoveHandlers_Misc.rb +++ b/Data/Scripts/011_Battle/005_AI/051_AI_MoveHandlers_Misc.rb @@ -6,8 +6,8 @@ # None Battle::AI::Handlers::MoveEffectScore.add("DoesNothingCongratulations", - proc { |score, move, user, target, skill, ai, battle| - next 0 if ai.skill_check(Battle::AI::AILevel.high) + proc { |score, move, user, target, ai, battle| + next 0 if ai.trainer.high_skill? next score - 95 } ) @@ -20,7 +20,7 @@ Battle::AI::Handlers::MoveEffectScore.copy("DoesNothingCongratulations", # AddMoneyGainedFromBattle Battle::AI::Handlers::MoveEffectScore.add("FailsIfNotUserFirstTurn", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| next score - 90 if user.turnCount > 0 } ) @@ -28,31 +28,31 @@ Battle::AI::Handlers::MoveEffectScore.add("FailsIfNotUserFirstTurn", # FailsIfUserHasUnusedMove Battle::AI::Handlers::MoveEffectScore.add("FailsIfUserNotConsumedBerry", - proc { |score, move, user, target, skill, ai, battle| - next score - 90 if !user.belched? + proc { |score, move, user, target, ai, battle| + next score - 90 if !user.battler.belched? } ) Battle::AI::Handlers::MoveEffectScore.add("FailsIfTargetHasNoItem", - proc { |score, move, user, target, skill, ai, battle| - if ai.skill_check(Battle::AI::AILevel.medium) - next score - 90 if !target.item || !target.itemActive? + proc { |score, move, user, target, ai, battle| + if ai.trainer.medium_skill? + next score - 90 if !target.item || !target.item_active? next score + 50 end } ) Battle::AI::Handlers::MoveEffectScore.add("FailsUnlessTargetSharesTypeWithUser", - proc { |score, move, user, target, skill, ai, battle| - if !(user.types[0] && target.pbHasType?(user.types[0])) && - !(user.types[1] && target.pbHasType?(user.types[1])) + proc { |score, move, user, target, ai, battle| + if !(user.types[0] && target.has_type?(user.types[0])) && + !(user.types[1] && target.has_type?(user.types[1])) next score - 90 end } ) Battle::AI::Handlers::MoveEffectScore.add("FailsIfUserDamagedThisTurn", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| score += 50 if target.effects[PBEffects::HyperBeam] > 0 score -= 35 if target.hp <= target.totalhp / 2 # If target is weak, no score -= 70 if target.hp <= target.totalhp / 4 # need to risk this move @@ -63,20 +63,20 @@ Battle::AI::Handlers::MoveEffectScore.add("FailsIfUserDamagedThisTurn", # FailsIfTargetActed Battle::AI::Handlers::MoveEffectScore.add("CrashDamageIfFailsUnusableInGravity", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| next score + 10 * (user.stages[:ACCURACY] - target.stages[:EVASION]) } ) Battle::AI::Handlers::MoveEffectScore.add("StartSunWeather", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if battle.pbCheckGlobalAbility(:AIRLOCK) || battle.pbCheckGlobalAbility(:CLOUDNINE) next score - 90 elsif battle.field.weather == :Sun next score - 90 else - user.eachMove do |m| + user.battler.eachMove do |m| next if !m.damagingMove? || m.type != :FIRE score += 20 end @@ -86,14 +86,14 @@ Battle::AI::Handlers::MoveEffectScore.add("StartSunWeather", ) Battle::AI::Handlers::MoveEffectScore.add("StartRainWeather", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if battle.pbCheckGlobalAbility(:AIRLOCK) || battle.pbCheckGlobalAbility(:CLOUDNINE) next score - 90 elsif battle.field.weather == :Rain next score - 90 else - user.eachMove do |m| + user.battler.eachMove do |m| next if !m.damagingMove? || m.type != :WATER score += 20 end @@ -103,7 +103,7 @@ Battle::AI::Handlers::MoveEffectScore.add("StartRainWeather", ) Battle::AI::Handlers::MoveEffectScore.add("StartSandstormWeather", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if battle.pbCheckGlobalAbility(:AIRLOCK) || battle.pbCheckGlobalAbility(:CLOUDNINE) next score - 90 @@ -114,7 +114,7 @@ Battle::AI::Handlers::MoveEffectScore.add("StartSandstormWeather", ) Battle::AI::Handlers::MoveEffectScore.add("StartHailWeather", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if battle.pbCheckGlobalAbility(:AIRLOCK) || battle.pbCheckGlobalAbility(:CLOUDNINE) next score - 90 @@ -133,16 +133,16 @@ Battle::AI::Handlers::MoveEffectScore.add("StartHailWeather", # StartPsychicTerrain Battle::AI::Handlers::MoveEffectScore.add("RemoveTerrain", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| next 0 if battle.field.terrain == :None } ) Battle::AI::Handlers::MoveEffectScore.add("AddSpikesToFoeSide", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if user.pbOpposingSide.effects[PBEffects::Spikes] >= 3 next score - 90 - elsif user.allOpposing.none? { |b| battle.pbCanChooseNonActive?(b.index) } + elsif user.battler.allOpposing.none? { |b| battle.pbCanChooseNonActive?(b.index) } next score - 90 # Opponent can't switch in any Pokemon else score += 10 * battle.pbAbleNonActiveCount(user.idxOpposingSide) @@ -153,10 +153,10 @@ Battle::AI::Handlers::MoveEffectScore.add("AddSpikesToFoeSide", ) Battle::AI::Handlers::MoveEffectScore.add("AddToxicSpikesToFoeSide", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if user.pbOpposingSide.effects[PBEffects::ToxicSpikes] >= 2 next score - 90 - elsif user.allOpposing.none? { |b| battle.pbCanChooseNonActive?(b.index) } + elsif user.battler.allOpposing.none? { |b| battle.pbCanChooseNonActive?(b.index) } next score - 90 # Opponent can't switch in any Pokemon else score += 8 * battle.pbAbleNonActiveCount(user.idxOpposingSide) @@ -167,10 +167,10 @@ Battle::AI::Handlers::MoveEffectScore.add("AddToxicSpikesToFoeSide", ) Battle::AI::Handlers::MoveEffectScore.add("AddStealthRocksToFoeSide", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if user.pbOpposingSide.effects[PBEffects::StealthRock] next score - 90 - elsif user.allOpposing.none? { |b| battle.pbCanChooseNonActive?(b.index) } + elsif user.battler.allOpposing.none? { |b| battle.pbCanChooseNonActive?(b.index) } next score - 90 # Opponent can't switch in any Pokemon else next score + 10 * battle.pbAbleNonActiveCount(user.idxOpposingSide) @@ -179,14 +179,14 @@ Battle::AI::Handlers::MoveEffectScore.add("AddStealthRocksToFoeSide", ) Battle::AI::Handlers::MoveEffectScore.add("AddStickyWebToFoeSide", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| next score - 95 if user.pbOpposingSide.effects[PBEffects::StickyWeb] } ) Battle::AI::Handlers::MoveEffectScore.add("SwapSideEffects", - proc { |score, move, user, target, skill, ai, battle| - if ai.skill_check(Battle::AI::AILevel.medium) + proc { |score, move, user, target, ai, battle| + if ai.trainer.medium_skill? good_effects = [:Reflect, :LightScreen, :AuroraVeil, :SeaOfFire, :Swamp, :Rainbow, :Mist, :Safeguard, :Tailwind].map! { |e| PBEffects.const_get(e) } @@ -195,7 +195,7 @@ Battle::AI::Handlers::MoveEffectScore.add("SwapSideEffects", score += 10 if ![0, false, nil].include?(user.pbOwnSide.effects[e]) score -= 10 if ![0, 1, false, nil].include?(user.pbOpposingSide.effects[e]) end - if ai.skill_check(Battle::AI::AILevel.high) + if ai.trainer.high_skill? good_effects.each do |e| score += 10 if ![0, 1, false, nil].include?(user.pbOpposingSide.effects[e]) score -= 10 if ![0, false, nil].include?(user.pbOwnSide.effects[e]) @@ -207,7 +207,7 @@ Battle::AI::Handlers::MoveEffectScore.add("SwapSideEffects", ) Battle::AI::Handlers::MoveEffectScore.add("UserMakeSubstitute", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if user.effects[PBEffects::Substitute] > 0 next score - 90 elsif user.hp <= user.totalhp / 4 @@ -217,7 +217,7 @@ Battle::AI::Handlers::MoveEffectScore.add("UserMakeSubstitute", ) Battle::AI::Handlers::MoveEffectScore.add("RemoveUserBindingAndEntryHazards", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| score += 30 if user.effects[PBEffects::Trapping] > 0 score += 30 if user.effects[PBEffects::LeechSeed] >= 0 if battle.pbAbleNonActiveCount(user.idxOwnSide) > 0 @@ -230,7 +230,7 @@ Battle::AI::Handlers::MoveEffectScore.add("RemoveUserBindingAndEntryHazards", ) Battle::AI::Handlers::MoveEffectScore.add("AttackTwoTurnsLater", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if battle.positions[target.index].effects[PBEffects::FutureSightCounter] > 0 next 0 elsif battle.pbAbleNonActiveCount(user.idxOwnSide) == 0 @@ -243,7 +243,7 @@ Battle::AI::Handlers::MoveEffectScore.add("AttackTwoTurnsLater", # UserSwapsPositionsWithAlly Battle::AI::Handlers::MoveEffectScore.add("BurnAttackerBeforeUserActs", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| next score + 20 # Because of possible burning } ) diff --git a/Data/Scripts/011_Battle/005_AI/052_AI_MoveHandlers_BattlerStats.rb b/Data/Scripts/011_Battle/005_AI/052_AI_MoveHandlers_BattlerStats.rb index 689b9d28e..2e2fcf352 100644 --- a/Data/Scripts/011_Battle/005_AI/052_AI_MoveHandlers_BattlerStats.rb +++ b/Data/Scripts/011_Battle/005_AI/052_AI_MoveHandlers_BattlerStats.rb @@ -2,28 +2,28 @@ # #=============================================================================== Battle::AI::Handlers::MoveEffectScore.add("RaiseUserAttack1", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if move.statusMove? next score - 90 if user.statStageAtMax?(:ATTACK) score -= user.stages[:ATTACK] * 20 - if ai.skill_check(Battle::AI::AILevel.medium) + if ai.trainer.medium_skill? hasPhysicalAttack = false - user.eachMove do |m| + user.battler.eachMove do |m| next if !m.physicalMove?(m.type) hasPhysicalAttack = true break end if hasPhysicalAttack score += 20 - elsif ai.skill_check(Battle::AI::AILevel.high) + elsif ai.trainer.high_skill? score -= 90 end end else score += 20 if user.stages[:ATTACK] < 0 - if ai.skill_check(Battle::AI::AILevel.medium) + if ai.trainer.medium_skill? hasPhysicalAttack = false - user.eachMove do |m| + user.battler.eachMove do |m| next if !m.physicalMove?(m.type) hasPhysicalAttack = true break @@ -36,30 +36,30 @@ Battle::AI::Handlers::MoveEffectScore.add("RaiseUserAttack1", ) Battle::AI::Handlers::MoveEffectScore.add("RaiseUserAttack2", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if move.statusMove? next score - 90 if user.statStageAtMax?(:ATTACK) score += 40 if user.turnCount == 0 score -= user.stages[:ATTACK] * 20 - if ai.skill_check(Battle::AI::AILevel.medium) + if ai.trainer.medium_skill? hasPhysicalAttack = false - user.eachMove do |m| + user.battler.eachMove do |m| next if !m.physicalMove?(m.type) hasPhysicalAttack = true break end if hasPhysicalAttack score += 20 - elsif ai.skill_check(Battle::AI::AILevel.high) + elsif ai.trainer.high_skill? score -= 90 end end else score += 10 if user.turnCount == 0 score += 20 if user.stages[:ATTACK] < 0 - if ai.skill_check(Battle::AI::AILevel.medium) + if ai.trainer.medium_skill? hasPhysicalAttack = false - user.eachMove do |m| + user.battler.eachMove do |m| next if !m.physicalMove?(m.type) hasPhysicalAttack = true break @@ -77,19 +77,19 @@ Battle::AI::Handlers::MoveEffectScore.copy("RaiseUserAttack2", "RaiseUserAttack3IfTargetFaints") Battle::AI::Handlers::MoveEffectScore.add("MaxUserAttackLoseHalfOfTotalHP", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| next 0 if user.statStageAtMax?(:ATTACK) || user.hp <= user.totalhp / 2 score += (6 - user.stages[:ATTACK]) * 10 - if ai.skill_check(Battle::AI::AILevel.medium) + if ai.trainer.medium_skill? hasPhysicalAttack = false - user.eachMove do |m| + user.battler.eachMove do |m| next if !m.physicalMove?(m.type) hasPhysicalAttack = true break end if hasPhysicalAttack score += 40 - elsif ai.skill_check(Battle::AI::AILevel.high) + elsif ai.trainer.high_skill? score -= 90 end end @@ -98,7 +98,7 @@ Battle::AI::Handlers::MoveEffectScore.add("MaxUserAttackLoseHalfOfTotalHP", ) Battle::AI::Handlers::MoveEffectScore.add("RaiseUserDefense1", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if move.statusMove? next 0 if user.statStageAtMax?(:DEFENSE) next score - user.stages[:DEFENSE] * 20 @@ -112,7 +112,7 @@ Battle::AI::Handlers::MoveEffectScore.copy("RaiseUserDefense1", "RaiseUserDefense1CurlUpUser") Battle::AI::Handlers::MoveEffectScore.add("RaiseUserDefense2", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if move.statusMove? next 0 if user.statStageAtMax?(:DEFENSE) score += 40 if user.turnCount == 0 @@ -126,7 +126,7 @@ Battle::AI::Handlers::MoveEffectScore.add("RaiseUserDefense2", ) Battle::AI::Handlers::MoveEffectScore.add("RaiseUserDefense3", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if move.statusMove? next 0 if user.statStageAtMax?(:DEFENSE) score += 40 if user.turnCount == 0 @@ -140,28 +140,28 @@ Battle::AI::Handlers::MoveEffectScore.add("RaiseUserDefense3", ) Battle::AI::Handlers::MoveEffectScore.add("RaiseUserSpAtk1", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if move.statusMove? next 0 if user.statStageAtMax?(:SPECIAL_ATTACK) score -= user.stages[:SPECIAL_ATTACK] * 20 - if ai.skill_check(Battle::AI::AILevel.medium) + if ai.trainer.medium_skill? hasSpecicalAttack = false - user.eachMove do |m| + user.battler.eachMove do |m| next if !m.specialMove?(m.type) hasSpecicalAttack = true break end if hasSpecicalAttack score += 20 - elsif ai.skill_check(Battle::AI::AILevel.high) + elsif ai.trainer.high_skill? score -= 90 end end else score += 20 if user.stages[:SPECIAL_ATTACK] < 0 - if ai.skill_check(Battle::AI::AILevel.medium) + if ai.trainer.medium_skill? hasSpecicalAttack = false - user.eachMove do |m| + user.battler.eachMove do |m| next if !m.specialMove?(m.type) hasSpecicalAttack = true break @@ -174,30 +174,30 @@ Battle::AI::Handlers::MoveEffectScore.add("RaiseUserSpAtk1", ) Battle::AI::Handlers::MoveEffectScore.add("RaiseUserSpAtk2", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if move.statusMove? next 0 if user.statStageAtMax?(:SPECIAL_ATTACK) score += 40 if user.turnCount == 0 score -= user.stages[:SPECIAL_ATTACK] * 20 - if ai.skill_check(Battle::AI::AILevel.medium) + if ai.trainer.medium_skill? hasSpecicalAttack = false - user.eachMove do |m| + user.battler.eachMove do |m| next if !m.specialMove?(m.type) hasSpecicalAttack = true break end if hasSpecicalAttack score += 20 - elsif ai.skill_check(Battle::AI::AILevel.high) + elsif ai.trainer.high_skill? score -= 90 end end else score += 10 if user.turnCount == 0 score += 20 if user.stages[:SPECIAL_ATTACK] < 0 - if ai.skill_check(Battle::AI::AILevel.medium) + if ai.trainer.medium_skill? hasSpecicalAttack = false - user.eachMove do |m| + user.battler.eachMove do |m| next if !m.specialMove?(m.type) hasSpecicalAttack = true break @@ -210,30 +210,30 @@ Battle::AI::Handlers::MoveEffectScore.add("RaiseUserSpAtk2", ) Battle::AI::Handlers::MoveEffectScore.add("RaiseUserSpAtk3", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if move.statusMove? next 0 if user.statStageAtMax?(:SPECIAL_ATTACK) score += 40 if user.turnCount == 0 score -= user.stages[:SPECIAL_ATTACK] * 30 - if ai.skill_check(Battle::AI::AILevel.medium) + if ai.trainer.medium_skill? hasSpecicalAttack = false - user.eachMove do |m| + user.battler.eachMove do |m| next if !m.specialMove?(m.type) hasSpecicalAttack = true break end if hasSpecicalAttack score += 30 - elsif ai.skill_check(Battle::AI::AILevel.high) + elsif ai.trainer.high_skill? score -= 90 end end else score += 10 if user.turnCount == 0 score += 30 if user.stages[:SPECIAL_ATTACK] < 0 - if ai.skill_check(Battle::AI::AILevel.medium) + if ai.trainer.medium_skill? hasSpecicalAttack = false - user.eachMove do |m| + user.battler.eachMove do |m| next if !m.specialMove?(m.type) hasSpecicalAttack = true break @@ -246,7 +246,7 @@ Battle::AI::Handlers::MoveEffectScore.add("RaiseUserSpAtk3", ) Battle::AI::Handlers::MoveEffectScore.add("RaiseUserSpDef1", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if move.statusMove? next 0 if user.statStageAtMax?(:SPECIAL_DEFENSE) score += 40 if user.turnCount == 0 @@ -264,9 +264,9 @@ Battle::AI::Handlers::MoveEffectScore.copy("RaiseUserSpDef1", "RaiseUserSpDef3") Battle::AI::Handlers::MoveEffectScore.add("RaiseUserSpDef1PowerUpElectricMove", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| foundMove = false - user.eachMove do |m| + user.battler.eachMove do |m| next if m.type != :ELECTRIC || !m.damagingMove? foundMove = true break @@ -286,13 +286,13 @@ Battle::AI::Handlers::MoveEffectScore.add("RaiseUserSpDef1PowerUpElectricMove", ) Battle::AI::Handlers::MoveEffectScore.add("RaiseUserSpeed1", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if move.statusMove? next 0 if user.statStageAtMax?(:SPEED) score -= user.stages[:SPEED] * 10 - if ai.skill_check(Battle::AI::AILevel.high) - aspeed = pbRoughStat(user, :SPEED) - ospeed = pbRoughStat(target, :SPEED) + if ai.trainer.high_skill? + aspeed = user.rough_stat(:SPEED) + ospeed = target.rough_stat(:SPEED) score += 30 if aspeed < ospeed && aspeed * 2 > ospeed end elsif user.stages[:SPEED] < 0 @@ -303,14 +303,14 @@ Battle::AI::Handlers::MoveEffectScore.add("RaiseUserSpeed1", ) Battle::AI::Handlers::MoveEffectScore.add("RaiseUserSpeed2", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if move.statusMove? next 0 if user.statStageAtMax?(:SPEED) score += 20 if user.turnCount == 0 score -= user.stages[:SPEED] * 10 - if ai.skill_check(Battle::AI::AILevel.high) - aspeed = pbRoughStat(user, :SPEED) - ospeed = pbRoughStat(target, :SPEED) + if ai.trainer.high_skill? + aspeed = user.rough_stat(:SPEED) + ospeed = target.rough_stat(:SPEED) score += 30 if aspeed < ospeed && aspeed * 2 > ospeed end else @@ -326,7 +326,7 @@ Battle::AI::Handlers::MoveEffectScore.copy("RaiseUserSpeed2", "RaiseUserSpeed3") Battle::AI::Handlers::MoveEffectScore.add("RaiseUserAccuracy1", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if move.statusMove? next 0 if user.statStageAtMax?(:ACCURACY) score += 40 if user.turnCount == 0 @@ -344,7 +344,7 @@ Battle::AI::Handlers::MoveEffectScore.copy("RaiseUserAccuracy1", "RaiseUserAccuracy3") Battle::AI::Handlers::MoveEffectScore.add("RaiseUserEvasion1", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if move.statusMove? next 0 if user.statStageAtMax?(:EVASION) score -= user.stages[:EVASION] * 10 @@ -356,7 +356,7 @@ Battle::AI::Handlers::MoveEffectScore.add("RaiseUserEvasion1", ) Battle::AI::Handlers::MoveEffectScore.add("RaiseUserEvasion2", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if move.statusMove? next 0 if user.statStageAtMax?(:EVASION) score += 40 if user.turnCount == 0 @@ -374,7 +374,7 @@ Battle::AI::Handlers::MoveEffectScore.copy("RaiseUserEvasion2", "RaiseUserEvasion3") Battle::AI::Handlers::MoveEffectScore.add("RaiseUserCriticalHitRate2", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if move.statusMove? next 0 if user.effects[PBEffects::FocusEnergy] >= 2 next score + 30 @@ -385,23 +385,21 @@ Battle::AI::Handlers::MoveEffectScore.add("RaiseUserCriticalHitRate2", ) Battle::AI::Handlers::MoveEffectScore.add("RaiseUserAtkDef1", - proc { |score, move, user, target, skill, ai, battle| - if user.statStageAtMax?(:ATTACK) && - user.statStageAtMax?(:DEFENSE) - next score - 90 - end + proc { |score, move, user, target, ai, battle| + next score - 90 if user.statStageAtMax?(:ATTACK) && + user.statStageAtMax?(:DEFENSE) score -= user.stages[:ATTACK] * 10 score -= user.stages[:DEFENSE] * 10 - if ai.skill_check(Battle::AI::AILevel.medium) + if ai.trainer.medium_skill? hasPhysicalAttack = false - user.eachMove do |m| + user.battler.eachMove do |m| next if !m.physicalMove?(m.type) hasPhysicalAttack = true break end if hasPhysicalAttack score += 20 - elsif ai.skill_check(Battle::AI::AILevel.high) + elsif ai.trainer.high_skill? score -= 90 end end @@ -410,25 +408,23 @@ Battle::AI::Handlers::MoveEffectScore.add("RaiseUserAtkDef1", ) Battle::AI::Handlers::MoveEffectScore.add("RaiseUserAtkDefAcc1", - proc { |score, move, user, target, skill, ai, battle| - if user.statStageAtMax?(:ATTACK) && - user.statStageAtMax?(:DEFENSE) && - user.statStageAtMax?(:ACCURACY) - next score - 90 - end + proc { |score, move, user, target, ai, battle| + next score - 90 if user.statStageAtMax?(:ATTACK) && + user.statStageAtMax?(:DEFENSE) && + user.statStageAtMax?(:ACCURACY) score -= user.stages[:ATTACK] * 10 score -= user.stages[:DEFENSE] * 10 score -= user.stages[:ACCURACY] * 10 - if ai.skill_check(Battle::AI::AILevel.medium) + if ai.trainer.medium_skill? hasPhysicalAttack = false - user.eachMove do |m| + user.battler.eachMove do |m| next if !m.physicalMove?(m.type) hasPhysicalAttack = true break end if hasPhysicalAttack score += 20 - elsif ai.skill_check(Battle::AI::AILevel.high) + elsif ai.trainer.high_skill? score -= 90 end end @@ -437,28 +433,26 @@ Battle::AI::Handlers::MoveEffectScore.add("RaiseUserAtkDefAcc1", ) Battle::AI::Handlers::MoveEffectScore.add("RaiseUserAtkDefAcc1", - proc { |score, move, user, target, skill, ai, battle| - if user.statStageAtMax?(:ATTACK) && - user.statStageAtMax?(:SPECIAL_ATTACK) - next score - 90 - end + proc { |score, move, user, target, ai, battle| + next score - 90 if user.statStageAtMax?(:ATTACK) && + user.statStageAtMax?(:SPECIAL_ATTACK) score -= user.stages[:ATTACK] * 10 score -= user.stages[:SPECIAL_ATTACK] * 10 - if ai.skill_check(Battle::AI::AILevel.medium) + if ai.trainer.medium_skill? hasDamagingAttack = false - user.eachMove do |m| + user.battler.eachMove do |m| next if !m.damagingMove? hasDamagingAttack = true break end if hasDamagingAttack score += 20 - elsif ai.skill_check(Battle::AI::AILevel.high) + elsif ai.trainer.high_skill? score -= 90 end end if move.function == "RaiseUserAtkSpAtk1Or2InSun" # Growth - score += 20 if [:Sun, :HarshSun].include?(user.effectiveWeather) + score += 20 if [:Sun, :HarshSun].include?(user.battler.effectiveWeather) end next score } @@ -468,15 +462,15 @@ Battle::AI::Handlers::MoveEffectScore.copy("RaiseUserAtkSpAtk1", "RaiseUserAtkSpAtk1Or2InSun") Battle::AI::Handlers::MoveEffectScore.add("LowerUserDefSpDef1RaiseUserAtkSpAtkSpd2", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| score -= user.stages[:ATTACK] * 20 score -= user.stages[:SPEED] * 20 score -= user.stages[:SPECIAL_ATTACK] * 20 score += user.stages[:DEFENSE] * 10 score += user.stages[:SPECIAL_DEFENSE] * 10 - if ai.skill_check(Battle::AI::AILevel.medium) + if ai.trainer.medium_skill? hasDamagingAttack = false - user.eachMove do |m| + user.battler.eachMove do |m| next if !m.damagingMove? hasDamagingAttack = true break @@ -488,30 +482,28 @@ Battle::AI::Handlers::MoveEffectScore.add("LowerUserDefSpDef1RaiseUserAtkSpAtkSp ) Battle::AI::Handlers::MoveEffectScore.add("RaiseUserAtkSpd1", - proc { |score, move, user, target, skill, ai, battle| - if user.statStageAtMax?(:ATTACK) && - user.statStageAtMax?(:SPEED) - next score - 90 - end + proc { |score, move, user, target, ai, battle| + next score - 90 if user.statStageAtMax?(:ATTACK) && + user.statStageAtMax?(:SPEED) score += 40 if user.turnCount == 0 # Dragon Dance tends to be popular score -= user.stages[:ATTACK] * 10 score -= user.stages[:SPEED] * 10 - if ai.skill_check(Battle::AI::AILevel.medium) + if ai.trainer.medium_skill? hasPhysicalAttack = false - user.eachMove do |m| + user.battler.eachMove do |m| next if !m.physicalMove?(m.type) hasPhysicalAttack = true break end if hasPhysicalAttack score += 20 - elsif ai.skill_check(Battle::AI::AILevel.high) + elsif ai.trainer.high_skill? score -= 90 end end - if ai.skill_check(Battle::AI::AILevel.high) - aspeed = pbRoughStat(user, :SPEED) - ospeed = pbRoughStat(target, :SPEED) + if ai.trainer.high_skill? + aspeed = user.rough_stat(:SPEED) + ospeed = target.rough_stat(:SPEED) score += 20 if aspeed < ospeed && aspeed * 2 > ospeed end next score @@ -519,29 +511,27 @@ Battle::AI::Handlers::MoveEffectScore.add("RaiseUserAtkSpd1", ) Battle::AI::Handlers::MoveEffectScore.add("RaiseUserAtk1Spd2", - proc { |score, move, user, target, skill, ai, battle| - if user.statStageAtMax?(:ATTACK) && - user.statStageAtMax?(:SPEED) - next score - 90 - end + proc { |score, move, user, target, ai, battle| + next score - 90 if user.statStageAtMax?(:ATTACK) && + user.statStageAtMax?(:SPEED) score -= user.stages[:ATTACK] * 10 score -= user.stages[:SPEED] * 10 - if ai.skill_check(Battle::AI::AILevel.medium) + if ai.trainer.medium_skill? hasPhysicalAttack = false - user.eachMove do |m| + user.battler.eachMove do |m| next if !m.physicalMove?(m.type) hasPhysicalAttack = true break end if hasPhysicalAttack score += 20 - elsif ai.skill_check(Battle::AI::AILevel.high) + elsif ai.trainer.high_skill? score -= 90 end end - if ai.skill_check(Battle::AI::AILevel.high) - aspeed = pbRoughStat(user, :SPEED) - ospeed = pbRoughStat(target, :SPEED) + if ai.trainer.high_skill? + aspeed = user.rough_stat(:SPEED) + ospeed = target.rough_stat(:SPEED) score += 30 if aspeed < ospeed && aspeed * 2 > ospeed end next score @@ -549,23 +539,21 @@ Battle::AI::Handlers::MoveEffectScore.add("RaiseUserAtk1Spd2", ) Battle::AI::Handlers::MoveEffectScore.add("RaiseUserAtkAcc1", - proc { |score, move, user, target, skill, ai, battle| - if user.statStageAtMax?(:ATTACK) && - user.statStageAtMax?(:ACCURACY) - next score - 90 - end + proc { |score, move, user, target, ai, battle| + next score - 90 if user.statStageAtMax?(:ATTACK) && + user.statStageAtMax?(:ACCURACY) score -= user.stages[:ATTACK] * 10 score -= user.stages[:ACCURACY] * 10 - if ai.skill_check(Battle::AI::AILevel.medium) + if ai.trainer.medium_skill? hasPhysicalAttack = false - user.eachMove do |m| + user.battler.eachMove do |m| next if !m.physicalMove?(m.type) hasPhysicalAttack = true break end if hasPhysicalAttack score += 20 - elsif ai.skill_check(Battle::AI::AILevel.high) + elsif ai.trainer.high_skill? score -= 90 end end @@ -574,11 +562,9 @@ Battle::AI::Handlers::MoveEffectScore.add("RaiseUserAtkAcc1", ) Battle::AI::Handlers::MoveEffectScore.add("RaiseUserDefSpDef1", - proc { |score, move, user, target, skill, ai, battle| - if user.statStageAtMax?(:DEFENSE) && - user.statStageAtMax?(:SPECIAL_DEFENSE) - next score - 90 - end + proc { |score, move, user, target, ai, battle| + next score - 90 if user.statStageAtMax?(:DEFENSE) && + user.statStageAtMax?(:SPECIAL_DEFENSE) score -= user.stages[:DEFENSE] * 10 score -= user.stages[:SPECIAL_DEFENSE] * 10 next score @@ -586,24 +572,22 @@ Battle::AI::Handlers::MoveEffectScore.add("RaiseUserDefSpDef1", ) Battle::AI::Handlers::MoveEffectScore.add("RaiseUserSpAtkSpDef1", - proc { |score, move, user, target, skill, ai, battle| - if user.statStageAtMax?(:SPECIAL_ATTACK) && - user.statStageAtMax?(:SPECIAL_DEFENSE) - next score - 90 - end + proc { |score, move, user, target, ai, battle| + next score - 90 if user.statStageAtMax?(:SPECIAL_ATTACK) && + user.statStageAtMax?(:SPECIAL_DEFENSE) score += 40 if user.turnCount == 0 # Calm Mind tends to be popular score -= user.stages[:SPECIAL_ATTACK] * 10 score -= user.stages[:SPECIAL_DEFENSE] * 10 - if ai.skill_check(Battle::AI::AILevel.medium) + if ai.trainer.medium_skill? hasSpecicalAttack = false - user.eachMove do |m| + user.battler.eachMove do |m| next if !m.specialMove?(m.type) hasSpecicalAttack = true break end if hasSpecicalAttack score += 20 - elsif ai.skill_check(Battle::AI::AILevel.high) + elsif ai.trainer.high_skill? score -= 90 end end @@ -612,46 +596,42 @@ Battle::AI::Handlers::MoveEffectScore.add("RaiseUserSpAtkSpDef1", ) Battle::AI::Handlers::MoveEffectScore.add("RaiseUserSpAtkSpDefSpd1", - proc { |score, move, user, target, skill, ai, battle| - if user.statStageAtMax?(:SPECIAL_ATTACK) && - user.statStageAtMax?(:SPECIAL_DEFENSE) && - user.statStageAtMax?(:SPEED) - next score - 90 - end + proc { |score, move, user, target, ai, battle| + next score - 90 if user.statStageAtMax?(:SPECIAL_ATTACK) && + user.statStageAtMax?(:SPECIAL_DEFENSE) && + user.statStageAtMax?(:SPEED) score += 40 if user.turnCount == 0 # Calm Mind tends to be popular score -= user.stages[:SPECIAL_ATTACK] * 10 score -= user.stages[:SPECIAL_DEFENSE] * 10 score -= user.stages[:SPEED] * 10 - if ai.skill_check(Battle::AI::AILevel.medium) + if ai.trainer.medium_skill? hasSpecicalAttack = false - user.eachMove do |m| + user.battler.eachMove do |m| next if !m.specialMove?(m.type) hasSpecicalAttack = true break end if hasSpecicalAttack score += 20 - elsif ai.skill_check(Battle::AI::AILevel.high) + elsif ai.trainer.high_skill? score -= 90 end end - if ai.skill_check(Battle::AI::AILevel.high) - aspeed = pbRoughStat(user, :SPEED) - ospeed = pbRoughStat(target, :SPEED) - if aspeed < ospeed && aspeed * 2 > ospeed - score += 20 - end + if ai.trainer.high_skill? + aspeed = user.rough_stat(:SPEED) + ospeed = target.rough_stat(:SPEED) + score += 20 if aspeed < ospeed && aspeed * 2 > ospeed end next score } ) Battle::AI::Handlers::MoveEffectScore.add("RaiseUserMainStats1", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| GameData::Stat.each_main_battle { |s| score += 10 if user.stages[s.id] < 0 } - if ai.skill_check(Battle::AI::AILevel.medium) + if ai.trainer.medium_skill? hasDamagingAttack = false - user.eachMove do |m| + user.battler.eachMove do |m| next if !m.damagingMove? hasDamagingAttack = true break @@ -663,9 +643,9 @@ Battle::AI::Handlers::MoveEffectScore.add("RaiseUserMainStats1", ) Battle::AI::Handlers::MoveEffectScore.add("RaiseUserMainStats1LoseThirdOfTotalHP", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| next 0 if user.hp <= user.totalhp / 2 - next 0 if user.hasActiveAbility?(:CONTRARY) + next 0 if user.has_active_ability?(:CONTRARY) stats_maxed = true GameData::Stat.each_main_battle do |s| next if user.statStageAtMax?(s.id) @@ -673,12 +653,10 @@ Battle::AI::Handlers::MoveEffectScore.add("RaiseUserMainStats1LoseThirdOfTotalHP break end next 0 if stats_maxed - if ai.skill_check(Battle::AI::AILevel.high) && user.hp >= user.totalhp * 0.75 - score += 30 - end + score += 30 if ai.trainer.high_skill? && user.hp >= user.totalhp * 0.75 GameData::Stat.each_main_battle { |s| score += 10 if user.stages[s.id] <= 0 } - if ai.skill_check(Battle::AI::AILevel.medium) - hasDamagingAttack = user.moves.any? { |m| next m&.damagingMove? } + if ai.trainer.medium_skill? + hasDamagingAttack = user.battler.moves.any? { |m| next m&.damagingMove? } score += 20 if hasDamagingAttack end next score @@ -686,9 +664,9 @@ Battle::AI::Handlers::MoveEffectScore.add("RaiseUserMainStats1LoseThirdOfTotalHP ) Battle::AI::Handlers::MoveEffectScore.add("RaiseUserMainStats1TrapUserInBattle", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| next 0 if user.effects[PBEffects::NoRetreat] - next 0 if user.hasActiveAbility?(:CONTRARY) + next 0 if user.has_active_ability?(:CONTRARY) stats_maxed = true GameData::Stat.each_main_battle do |s| next if user.statStageAtMax?(s.id) @@ -696,13 +674,13 @@ Battle::AI::Handlers::MoveEffectScore.add("RaiseUserMainStats1TrapUserInBattle", break end next 0 if stats_maxed - if ai.skill_check(Battle::AI::AILevel.high) + if ai.trainer.high_skill? score -= 50 if user.hp <= user.totalhp / 2 - score += 30 if user.trappedInBattle? + score += 30 if user.battler.trappedInBattle? end GameData::Stat.each_main_battle { |s| score += 10 if user.stages[s.id] <= 0 } - if ai.skill_check(Battle::AI::AILevel.medium) - hasDamagingAttack = user.moves.any? { |m| next m&.damagingMove? } + if ai.trainer.medium_skill? + hasDamagingAttack = user.battler.moves.any? { |m| next m&.damagingMove? } score += 20 if hasDamagingAttack end next score @@ -710,13 +688,13 @@ Battle::AI::Handlers::MoveEffectScore.add("RaiseUserMainStats1TrapUserInBattle", ) Battle::AI::Handlers::MoveEffectScore.add("StartRaiseUserAtk1WhenDamaged", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| next score + 25 if user.effects[PBEffects::Rage] } ) Battle::AI::Handlers::MoveEffectScore.add("LowerUserAttack1", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| next score + user.stages[:ATTACK] * 10 } ) @@ -725,7 +703,7 @@ Battle::AI::Handlers::MoveEffectScore.copy("LowerUserAttack1", "LowerUserAttack2") Battle::AI::Handlers::MoveEffectScore.add("LowerUserDefense1", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| next score + user.stages[:DEFENSE] * 10 } ) @@ -734,7 +712,7 @@ Battle::AI::Handlers::MoveEffectScore.copy("LowerUserDefense1", "LowerUserDefense2") Battle::AI::Handlers::MoveEffectScore.add("LowerUserSpAtk1", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| next score + user.stages[:SPECIAL_ATTACK] * 10 } ) @@ -743,7 +721,7 @@ Battle::AI::Handlers::MoveEffectScore.copy("LowerUserSpAtk1", "LowerUserSpAtk2") Battle::AI::Handlers::MoveEffectScore.add("LowerUserSpDef1", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| next score + user.stages[:SPECIAL_DEFENSE] * 10 } ) @@ -752,7 +730,7 @@ Battle::AI::Handlers::MoveEffectScore.copy("LowerUserSpDef1", "LowerUserSpDef2") Battle::AI::Handlers::MoveEffectScore.add("LowerUserSpeed1", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| next score + user.stages[:SPECIAL_DEFENSE] * 10 } ) @@ -761,7 +739,7 @@ Battle::AI::Handlers::MoveEffectScore.copy("LowerUserSpeed1", "LowerUserSpeed2") Battle::AI::Handlers::MoveEffectScore.add("LowerUserAtkDef1", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| avg = user.stages[:ATTACK] * 10 avg += user.stages[:DEFENSE] * 10 next score + avg / 2 @@ -769,7 +747,7 @@ Battle::AI::Handlers::MoveEffectScore.add("LowerUserAtkDef1", ) Battle::AI::Handlers::MoveEffectScore.add("LowerUserDefSpDef1", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| avg = user.stages[:DEFENSE] * 10 avg += user.stages[:SPECIAL_DEFENSE] * 10 next score + avg / 2 @@ -777,7 +755,7 @@ Battle::AI::Handlers::MoveEffectScore.add("LowerUserDefSpDef1", ) Battle::AI::Handlers::MoveEffectScore.add("LowerUserDefSpDefSpd1", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| avg = user.stages[:DEFENSE] * 10 avg += user.stages[:SPEED] * 10 avg += user.stages[:SPECIAL_DEFENSE] * 10 @@ -788,28 +766,28 @@ Battle::AI::Handlers::MoveEffectScore.add("LowerUserDefSpDefSpd1", # RaiseTargetAttack1 Battle::AI::Handlers::MoveEffectScore.add("RaiseTargetAttack2ConfuseTarget", - proc { |score, move, user, target, skill, ai, battle| - next score - 90 if !target.pbCanConfuse?(user, false) + proc { |score, move, user, target, ai, battle| + next score - 90 if !target.battler.pbCanConfuse?(user.battler, false) next score + 30 if target.stages[:ATTACK] < 0 } ) Battle::AI::Handlers::MoveEffectScore.add("RaiseTargetSpAtk1ConfuseTarget", - proc { |score, move, user, target, skill, ai, battle| - next score - 90 if !target.pbCanConfuse?(user, false) + proc { |score, move, user, target, ai, battle| + next score - 90 if !target.battler.pbCanConfuse?(user.battler, false) next score + 30 if target.stages[:SPECIAL_ATTACK] < 0 } ) Battle::AI::Handlers::MoveEffectScore.add("RaiseTargetSpDef1", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| next score + 30 if target.statStageAtMax?(:SPECIAL_DEFENSE) next score - target.stages[:SPECIAL_DEFENSE] * 10 } ) Battle::AI::Handlers::MoveEffectScore.add("RaiseTargetRandomStat2", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| avgStat = 0 canChangeStat = false GameData::Stat.each_battle do |s| @@ -827,9 +805,9 @@ Battle::AI::Handlers::MoveEffectScore.add("RaiseTargetRandomStat2", ) Battle::AI::Handlers::MoveEffectScore.add("RaiseTargetAtkSpAtk2", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| next 0 if target.opposes?(user) - next score - 90 if ai.skill_check(Battle::AI::AILevel.medium) && target.hasActiveAbility?(:CONTRARY) + next score - 90 if target.has_active_ability?(:CONTRARY) score -= target.stages[:ATTACK] * 20 score -= target.stages[:SPECIAL_ATTACK] * 20 next score @@ -837,28 +815,28 @@ Battle::AI::Handlers::MoveEffectScore.add("RaiseTargetAtkSpAtk2", ) Battle::AI::Handlers::MoveEffectScore.add("LowerTargetAttack1", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if move.statusMove? - next 0 if !target.pbCanLowerStatStage?(:ATTACK, user) + next 0 if !target.battler.pbCanLowerStatStage?(:ATTACK, user.battler) score += target.stages[:ATTACK] * 20 - if ai.skill_check(Battle::AI::AILevel.medium) + if ai.trainer.medium_skill? hasPhysicalAttack = false - target.eachMove do |m| + target.battler.eachMove do |m| next if !m.physicalMove?(m.type) hasPhysicalAttack = true break end if hasPhysicalAttack score += 20 - elsif ai.skill_check(Battle::AI::AILevel.high) + elsif ai.trainer.high_skill? score -= 90 end end else score += 20 if target.stages[:ATTACK] > 0 - if ai.skill_check(Battle::AI::AILevel.medium) + if ai.trainer.medium_skill? hasPhysicalAttack = false - target.eachMove do |m| + target.battler.eachMove do |m| next if !m.physicalMove?(m.type) hasPhysicalAttack = true break @@ -871,19 +849,19 @@ Battle::AI::Handlers::MoveEffectScore.add("LowerTargetAttack1", ) Battle::AI::Handlers::MoveEffectScore.add("LowerTargetAttack1BypassSubstitute", - proc { |score, move, user, target, skill, ai, battle| - next 0 if !target.pbCanLowerStatStage?(:ATTACK, user) + proc { |score, move, user, target, ai, battle| + next 0 if !target.battler.pbCanLowerStatStage?(:ATTACK, user.battler) score += target.stages[:ATTACK] * 20 - if ai.skill_check(Battle::AI::AILevel.medium) + if ai.trainer.medium_skill? hasPhysicalAttack = false - target.eachMove do |m| + target.battler.eachMove do |m| next if !m.physicalMove?(m.type) hasPhysicalAttack = true break end if hasPhysicalAttack score += 20 - elsif ai.skill_check(Battle::AI::AILevel.high) + elsif ai.trainer.high_skill? score -= 90 end end @@ -892,30 +870,30 @@ Battle::AI::Handlers::MoveEffectScore.add("LowerTargetAttack1BypassSubstitute", ) Battle::AI::Handlers::MoveEffectScore.add("LowerTargetAttack2", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if move.statusMove? - next 0 if !target.pbCanLowerStatStage?(:ATTACK, user) + next 0 if !target.battler.pbCanLowerStatStage?(:ATTACK, user.battler) score += 40 if user.turnCount == 0 score += target.stages[:ATTACK] * 20 - if ai.skill_check(Battle::AI::AILevel.medium) + if ai.trainer.medium_skill? hasPhysicalAttack = false - target.eachMove do |m| + target.battler.eachMove do |m| next if !m.physicalMove?(m.type) hasPhysicalAttack = true break end if hasPhysicalAttack score += 20 - elsif ai.skill_check(Battle::AI::AILevel.high) + elsif ai.trainer.high_skill? score -= 90 end end else score += 10 if user.turnCount == 0 score += 20 if target.stages[:ATTACK] > 0 - if ai.skill_check(Battle::AI::AILevel.medium) + if ai.trainer.medium_skill? hasPhysicalAttack = false - target.eachMove do |m| + target.battler.eachMove do |m| next if !m.physicalMove?(m.type) hasPhysicalAttack = true break @@ -931,9 +909,9 @@ Battle::AI::Handlers::MoveEffectScore.copy("LowerTargetAttack2", "LowerTargetAttack3") Battle::AI::Handlers::MoveEffectScore.add("LowerTargetDefense1", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if move.statusMove? - next 0 if !target.pbCanLowerStatStage?(:DEFENSE, user) + next 0 if !target.battler.pbCanLowerStatStage?(:DEFENSE, user.battler) score += target.stages[:DEFENSE] * 20 elsif target.stages[:DEFENSE] > 0 score += 20 @@ -943,9 +921,9 @@ Battle::AI::Handlers::MoveEffectScore.add("LowerTargetDefense1", ) Battle::AI::Handlers::MoveEffectScore.add("LowerTargetDefense1PowersUpInGravity", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if move.statusMove? - next 0 if !target.pbCanLowerStatStage?(:DEFENSE, user) + next 0 if !target.battler.pbCanLowerStatStage?(:DEFENSE, user.battler) score += target.stages[:DEFENSE] * 20 elsif target.stages[:DEFENSE] > 0 score += 20 @@ -956,9 +934,9 @@ Battle::AI::Handlers::MoveEffectScore.add("LowerTargetDefense1PowersUpInGravity" ) Battle::AI::Handlers::MoveEffectScore.add("LowerTargetDefense2", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if move.statusMove? - next 0 if !target.pbCanLowerStatStage?(:DEFENSE, user) + next 0 if !target.battler.pbCanLowerStatStage?(:DEFENSE, user.battler) score += 40 if user.turnCount == 0 score += target.stages[:DEFENSE] * 20 else @@ -973,28 +951,28 @@ Battle::AI::Handlers::MoveEffectScore.copy("LowerTargetDefense2", "LowerTargetDefense3") Battle::AI::Handlers::MoveEffectScore.add("LowerTargetSpAtk1", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if move.statusMove? - next 0 if !target.pbCanLowerStatStage?(:SPECIAL_ATTACK, user) + next 0 if !target.battler.pbCanLowerStatStage?(:SPECIAL_ATTACK, user.battler) score += user.stages[:SPECIAL_ATTACK] * 20 - if ai.skill_check(Battle::AI::AILevel.medium) + if ai.trainer.medium_skill? hasSpecicalAttack = false - target.eachMove do |m| + target.battler.eachMove do |m| next if !m.specialMove?(m.type) hasSpecicalAttack = true break end if hasSpecicalAttack score += 20 - elsif ai.skill_check(Battle::AI::AILevel.high) + elsif ai.trainer.high_skill? score -= 90 end end else score += 20 if user.stages[:SPECIAL_ATTACK] > 0 - if ai.skill_check(Battle::AI::AILevel.medium) + if ai.trainer.medium_skill? hasSpecicalAttack = false - target.eachMove do |m| + target.battler.eachMove do |m| next if !m.specialMove?(m.type) hasSpecicalAttack = true break @@ -1007,8 +985,8 @@ Battle::AI::Handlers::MoveEffectScore.add("LowerTargetSpAtk1", ) Battle::AI::Handlers::MoveEffectScore.add("LowerTargetSpAtk2", - proc { |score, move, user, target, skill, ai, battle| - next 0 if !target.pbCanLowerStatStage?(:SPECIAL_ATTACK, user) + proc { |score, move, user, target, ai, battle| + next 0 if !target.battler.pbCanLowerStatStage?(:SPECIAL_ATTACK, user.battler) score += 40 if user.turnCount == 0 score += target.stages[:SPECIAL_ATTACK] * 20 next score @@ -1016,32 +994,32 @@ Battle::AI::Handlers::MoveEffectScore.add("LowerTargetSpAtk2", ) Battle::AI::Handlers::MoveEffectScore.add("LowerTargetSpAtk2IfCanAttract", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| next 0 if user.gender == 2 || target.gender == 2 || - user.gender == target.gender || target.hasActiveAbility?(:OBLIVIOUS) + user.gender == target.gender || target.has_active_ability?(:OBLIVIOUS) if move.statusMove? - next 0 if !target.pbCanLowerStatStage?(:SPECIAL_ATTACK, user) + next 0 if !target.battler.pbCanLowerStatStage?(:SPECIAL_ATTACK, user.battler) score += 40 if user.turnCount == 0 score += target.stages[:SPECIAL_ATTACK] * 20 - if ai.skill_check(Battle::AI::AILevel.medium) + if ai.trainer.medium_skill? hasSpecicalAttack = false - target.eachMove do |m| + target.battler.eachMove do |m| next if !m.specialMove?(m.type) hasSpecicalAttack = true break end if hasSpecicalAttack score += 20 - elsif ai.skill_check(Battle::AI::AILevel.high) + elsif ai.trainer.high_skill? score -= 90 end end else score += 10 if user.turnCount == 0 score += 20 if target.stages[:SPECIAL_ATTACK] > 0 - if ai.skill_check(Battle::AI::AILevel.medium) + if ai.trainer.medium_skill? hasSpecicalAttack = false - target.eachMove do |m| + target.battler.eachMove do |m| next if !m.specialMove?(m.type) hasSpecicalAttack = true break @@ -1054,8 +1032,8 @@ Battle::AI::Handlers::MoveEffectScore.add("LowerTargetSpAtk2IfCanAttract", ) Battle::AI::Handlers::MoveEffectScore.add("LowerTargetSpAtk2", - proc { |score, move, user, target, skill, ai, battle| - next 0 if !target.pbCanLowerStatStage?(:SPECIAL_ATTACK, user) + proc { |score, move, user, target, ai, battle| + next 0 if !target.battler.pbCanLowerStatStage?(:SPECIAL_ATTACK, user.battler) score += 40 if user.turnCount == 0 score += target.stages[:SPECIAL_ATTACK] * 20 next score @@ -1063,9 +1041,9 @@ Battle::AI::Handlers::MoveEffectScore.add("LowerTargetSpAtk2", ) Battle::AI::Handlers::MoveEffectScore.add("LowerTargetSpDef1", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if move.statusMove? - next 0 if !target.pbCanLowerStatStage?(:SPECIAL_DEFENSE, user) + next 0 if !target.battler.pbCanLowerStatStage?(:SPECIAL_DEFENSE, user.battler) score += target.stages[:SPECIAL_DEFENSE] * 20 elsif target.stages[:SPECIAL_DEFENSE] > 0 score += 20 @@ -1075,9 +1053,9 @@ Battle::AI::Handlers::MoveEffectScore.add("LowerTargetSpDef1", ) Battle::AI::Handlers::MoveEffectScore.add("LowerTargetSpDef2", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if move.statusMove? - next 0 if !target.pbCanLowerStatStage?(:SPECIAL_DEFENSE, user) + next 0 if !target.battler.pbCanLowerStatStage?(:SPECIAL_DEFENSE, user.battler) score += 40 if user.turnCount == 0 score += target.stages[:SPECIAL_DEFENSE] * 20 else @@ -1092,13 +1070,13 @@ Battle::AI::Handlers::MoveEffectScore.copy("LowerTargetSpDef2", "LowerTargetSpDef3") Battle::AI::Handlers::MoveEffectScore.add("LowerTargetSpeed1", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if move.statusMove? - next 0 if !target.pbCanLowerStatStage?(:SPEED, user) + next 0 if !target.battler.pbCanLowerStatStage?(:SPEED, user.battler) score += target.stages[:SPEED] * 10 - if ai.skill_check(Battle::AI::AILevel.high) - aspeed = pbRoughStat(user, :SPEED) - ospeed = pbRoughStat(target, :SPEED) + if ai.trainer.high_skill? + aspeed = user.rough_stat(:SPEED) + ospeed = target.rough_stat(:SPEED) score += 30 if aspeed < ospeed && aspeed * 2 > ospeed end elsif user.stages[:SPEED] > 0 @@ -1112,28 +1090,29 @@ Battle::AI::Handlers::MoveEffectScore.copy("LowerTargetSpeed1", "LowerTargetSpeed1WeakerInGrassyTerrain") Battle::AI::Handlers::MoveEffectScore.add("LowerTargetSpeed1MakeTargetWeakerToFire", - proc { |score, move, user, target, skill, ai, battle| - next 0 if !target.pbCanLowerStatStage?(:SPEED, user) && target.effects[PBEffects::TarShot] + proc { |score, move, user, target, ai, battle| + next 0 if !target.battler.pbCanLowerStatStage?(:SPEED, user.battler) && + target.effects[PBEffects::TarShot] score += target.stages[:SPEED] * 10 - if ai.skill_check(Battle::AI::AILevel.high) - aspeed = pbRoughStat(user, :SPEED) - ospeed = pbRoughStat(target, :SPEED) + if ai.trainer.high_skill? + aspeed = user.rough_stat(:SPEED) + ospeed = target.rough_stat(:SPEED) score += 50 if aspeed < ospeed && aspeed * 2 > ospeed end - score += 20 if user.moves.any? { |m| m.damagingMove? && m.pbCalcType(user) == :FIRE } + score += 20 if user.battler.moves.any? { |m| m.damagingMove? && m.pbCalcType(user.battler) == :FIRE } next score } ) Battle::AI::Handlers::MoveEffectScore.add("LowerTargetSpeed2", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if move.statusMove? - next 0 if !target.pbCanLowerStatStage?(:SPEED, user) + next 0 if !target.battler.pbCanLowerStatStage?(:SPEED, user.battler) score += 20 if user.turnCount == 0 score += target.stages[:SPEED] * 20 - if ai.skill_check(Battle::AI::AILevel.high) - aspeed = pbRoughStat(user, :SPEED) - ospeed = pbRoughStat(target, :SPEED) + if ai.trainer.high_skill? + aspeed = user.rough_stat(:SPEED) + ospeed = target.rough_stat(:SPEED) score += 30 if aspeed < ospeed && aspeed * 2 > ospeed end else @@ -1148,9 +1127,9 @@ Battle::AI::Handlers::MoveEffectScore.copy("LowerTargetSpeed2", "LowerTargetSpeed3") Battle::AI::Handlers::MoveEffectScore.add("LowerTargetAccuracy1", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if move.statusMove? - return 0 if !target.pbCanLowerStatStage?(:ACCURACY, user) + return 0 if !target.battler.pbCanLowerStatStage?(:ACCURACY, user.battler) score += target.stages[:ACCURACY] * 10 elsif target.stages[:ACCURACY] > 0 score += 20 @@ -1164,9 +1143,9 @@ Battle::AI::Handlers::MoveEffectScore.copy("LowerTargetAccuracy1", "LowerTargetAccuracy3") Battle::AI::Handlers::MoveEffectScore.add("LowerTargetEvasion1", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if move.statusMove? - return 0 if !target.pbCanLowerStatStage?(:EVASION, user) + return 0 if !target.battler.pbCanLowerStatStage?(:EVASION, user.battler) score += target.stages[:EVASION] * 10 elsif target.stages[:EVASION] > 0 score += 20 @@ -1176,9 +1155,9 @@ Battle::AI::Handlers::MoveEffectScore.add("LowerTargetEvasion1", ) Battle::AI::Handlers::MoveEffectScore.add("LowerTargetEvasion1RemoveSideEffects", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if move.statusMove? - next 0 if !target.pbCanLowerStatStage?(:EVASION, user) + next 0 if !target.battler.pbCanLowerStatStage?(:EVASION, user.battler) score += target.stages[:EVASION] * 10 elsif target.stages[:EVASION] > 0 score += 20 @@ -1196,9 +1175,9 @@ Battle::AI::Handlers::MoveEffectScore.add("LowerTargetEvasion1RemoveSideEffects" ) Battle::AI::Handlers::MoveEffectScore.add("LowerTargetEvasion2", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if move.statusMove? - return 0 if !target.pbCanLowerStatStage?(:EVASION, user) + return 0 if !target.battler.pbCanLowerStatStage?(:EVASION, user.battler) score += target.stages[:EVASION] * 10 elsif target.stages[:EVASION] > 0 score += 20 @@ -1211,7 +1190,7 @@ Battle::AI::Handlers::MoveEffectScore.copy("LowerTargetEvasion2", "LowerTargetEvasion3") Battle::AI::Handlers::MoveEffectScore.add("LowerTargetAtkDef1", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| avg = target.stages[:ATTACK] * 10 avg += target.stages[:DEFENSE] * 10 next score + avg / 2 @@ -1219,7 +1198,7 @@ Battle::AI::Handlers::MoveEffectScore.add("LowerTargetAtkDef1", ) Battle::AI::Handlers::MoveEffectScore.add("LowerTargetAtkSpAtk1", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| avg = target.stages[:ATTACK] * 10 avg += target.stages[:SPECIAL_ATTACK] * 10 next score + avg / 2 @@ -1227,7 +1206,7 @@ Battle::AI::Handlers::MoveEffectScore.add("LowerTargetAtkSpAtk1", ) Battle::AI::Handlers::MoveEffectScore.add("LowerPoisonedTargetAtkSpAtkSpd1", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| count = 0 battle.allBattlers.each do |b| if b.poisoned? && @@ -1235,7 +1214,7 @@ Battle::AI::Handlers::MoveEffectScore.add("LowerPoisonedTargetAtkSpAtkSpd1", !b.statStageAtMin?(:SPECIAL_ATTACK) || !b.statStageAtMin?(:SPEED)) count += 1 - if user.opposes?(b) + if user.battler.opposes?(b) score += user.stages[:ATTACK] * 10 score += user.stages[:SPECIAL_ATTACK] * 10 score += user.stages[:SPEED] * 10 @@ -1250,13 +1229,13 @@ Battle::AI::Handlers::MoveEffectScore.add("LowerPoisonedTargetAtkSpAtkSpd1", ) Battle::AI::Handlers::MoveEffectScore.add("RaiseUserAndAlliesAtkDef1", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| has_ally = false - user.allAllies.each do |b| - next if !b.pbCanLowerStatStage?(:ATTACK, user) && - !b.pbCanLowerStatStage?(:SPECIAL_ATTACK, user) + user.battler.allAllies.each do |b| + next if !b.pbCanLowerStatStage?(:ATTACK, user.battler) && + !b.pbCanLowerStatStage?(:SPECIAL_ATTACK, user.battler) has_ally = true - if ai.skill_check(Battle::AI::AILevel.medium) && b.hasActiveAbility?(:CONTRARY) + if b.hasActiveAbility?(:CONTRARY) score -= 90 else score += 40 @@ -1270,10 +1249,10 @@ Battle::AI::Handlers::MoveEffectScore.add("RaiseUserAndAlliesAtkDef1", ) Battle::AI::Handlers::MoveEffectScore.add("RaisePlusMinusUserAndAlliesAtkSpAtk1", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| hasEffect = user.statStageAtMax?(:ATTACK) && user.statStageAtMax?(:SPECIAL_ATTACK) - user.allAllies.each do |b| + user.battler.allAllies.each do |b| next if b.statStageAtMax?(:ATTACK) && b.statStageAtMax?(:SPECIAL_ATTACK) hasEffect = true score -= b.stages[:ATTACK] * 10 @@ -1287,10 +1266,10 @@ Battle::AI::Handlers::MoveEffectScore.add("RaisePlusMinusUserAndAlliesAtkSpAtk1" ) Battle::AI::Handlers::MoveEffectScore.add("RaisePlusMinusUserAndAlliesDefSpDef1", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| hasEffect = user.statStageAtMax?(:DEFENSE) && user.statStageAtMax?(:SPECIAL_DEFENSE) - user.allAllies.each do |b| + user.battler.allAllies.each do |b| next if b.statStageAtMax?(:DEFENSE) && b.statStageAtMax?(:SPECIAL_DEFENSE) hasEffect = true score -= b.stages[:DEFENSE] * 10 @@ -1304,18 +1283,18 @@ Battle::AI::Handlers::MoveEffectScore.add("RaisePlusMinusUserAndAlliesDefSpDef1" ) Battle::AI::Handlers::MoveEffectScore.add("RaiseGroundedGrassBattlersAtkSpAtk1", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| count = 0 battle.allBattlers.each do |b| - if b.pbHasType?(:GRASS) && !b.airborne? && - (!b.statStageAtMax?(:ATTACK) || !b.statStageAtMax?(:SPECIAL_ATTACK)) - count += 1 - if user.opposes?(b) - score -= 20 - else - score -= user.stages[:ATTACK] * 10 - score -= user.stages[:SPECIAL_ATTACK] * 10 - end + next if !b.pbHasType?(:GRASS) + next if b.airborne? + next if b.statStageAtMax?(:ATTACK) && b.statStageAtMax?(:SPECIAL_ATTACK) + count += 1 + if user.battler.opposes?(b) + score -= 20 + else + score -= user.stages[:ATTACK] * 10 + score -= user.stages[:SPECIAL_ATTACK] * 10 end end next 0 if count == 0 @@ -1324,12 +1303,12 @@ Battle::AI::Handlers::MoveEffectScore.add("RaiseGroundedGrassBattlersAtkSpAtk1", ) Battle::AI::Handlers::MoveEffectScore.add("RaiseGrassBattlersDef1", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| count = 0 battle.allBattlers.each do |b| if b.pbHasType?(:GRASS) && !b.statStageAtMax?(:DEFENSE) count += 1 - if user.opposes?(b) + if user.battler.opposes?(b) score -= 20 else score -= user.stages[:DEFENSE] * 10 @@ -1342,8 +1321,8 @@ Battle::AI::Handlers::MoveEffectScore.add("RaiseGrassBattlersDef1", ) Battle::AI::Handlers::MoveEffectScore.add("UserTargetSwapAtkSpAtkStages", - proc { |score, move, user, target, skill, ai, battle| - if ai.skill_check(Battle::AI::AILevel.medium) + proc { |score, move, user, target, ai, battle| + if ai.trainer.medium_skill? aatk = user.stages[:ATTACK] aspa = user.stages[:SPECIAL_ATTACK] oatk = target.stages[:ATTACK] @@ -1362,8 +1341,8 @@ Battle::AI::Handlers::MoveEffectScore.add("UserTargetSwapAtkSpAtkStages", ) Battle::AI::Handlers::MoveEffectScore.add("UserTargetSwapDefSpDefStages", - proc { |score, move, user, target, skill, ai, battle| - if ai.skill_check(Battle::AI::AILevel.medium) + proc { |score, move, user, target, ai, battle| + if ai.trainer.medium_skill? adef = user.stages[:DEFENSE] aspd = user.stages[:SPECIAL_DEFENSE] odef = target.stages[:DEFENSE] @@ -1382,8 +1361,8 @@ Battle::AI::Handlers::MoveEffectScore.add("UserTargetSwapDefSpDefStages", ) Battle::AI::Handlers::MoveEffectScore.add("UserTargetSwapStatStages", - proc { |score, move, user, target, skill, ai, battle| - if ai.skill_check(Battle::AI::AILevel.medium) + proc { |score, move, user, target, ai, battle| + if ai.trainer.medium_skill? userStages = 0 targetStages = 0 GameData::Stat.each_battle do |s| @@ -1399,8 +1378,8 @@ Battle::AI::Handlers::MoveEffectScore.add("UserTargetSwapStatStages", ) Battle::AI::Handlers::MoveEffectScore.add("UserCopyTargetStatStages", - proc { |score, move, user, target, skill, ai, battle| - if ai.skill_check(Battle::AI::AILevel.medium) + proc { |score, move, user, target, ai, battle| + if ai.trainer.medium_skill? equal = true GameData::Stat.each_battle do |s| stagediff = target.stages[s.id] - user.stages[s.id] @@ -1416,7 +1395,7 @@ Battle::AI::Handlers::MoveEffectScore.add("UserCopyTargetStatStages", ) Battle::AI::Handlers::MoveEffectScore.add("UserStealTargetPositiveStatStages", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| numStages = 0 GameData::Stat.each_battle do |s| next if target.stages[s.id] <= 0 @@ -1427,7 +1406,7 @@ Battle::AI::Handlers::MoveEffectScore.add("UserStealTargetPositiveStatStages", ) Battle::AI::Handlers::MoveEffectScore.add("InvertTargetStatStages", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| next 0 if target.effects[PBEffects::Substitute] > 0 numpos = 0 numneg = 0 @@ -1441,7 +1420,7 @@ Battle::AI::Handlers::MoveEffectScore.add("InvertTargetStatStages", ) Battle::AI::Handlers::MoveEffectScore.add("ResetTargetStatStages", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| next 0 if target.effects[PBEffects::Substitute] > 0 avg = 0 anyChange = false @@ -1456,13 +1435,13 @@ Battle::AI::Handlers::MoveEffectScore.add("ResetTargetStatStages", ) Battle::AI::Handlers::MoveEffectScore.add("ResetAllBattlersStatStages", - proc { |score, move, user, target, skill, ai, battle| - if ai.skill_check(Battle::AI::AILevel.medium) + proc { |score, move, user, target, ai, battle| + if ai.trainer.medium_skill? stages = 0 battle.allBattlers.each do |b| totalStages = 0 GameData::Stat.each_battle { |s| totalStages += b.stages[s.id] } - if b.opposes?(user) + if b.opposes?(user.battler) stages += totalStages else stages -= totalStages @@ -1474,16 +1453,16 @@ Battle::AI::Handlers::MoveEffectScore.add("ResetAllBattlersStatStages", ) Battle::AI::Handlers::MoveEffectScore.add("StartUserSideImmunityToStatStageLowering", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| next score - 80 if user.pbOwnSide.effects[PBEffects::Mist] > 0 } ) Battle::AI::Handlers::MoveEffectScore.add("UserSwapBaseAtkDef", - proc { |score, move, user, target, skill, ai, battle| - if ai.skill_check(Battle::AI::AILevel.medium) - aatk = pbRoughStat(user, :ATTACK) - adef = pbRoughStat(user, :DEFENSE) + proc { |score, move, user, target, ai, battle| + if ai.trainer.medium_skill? + aatk = user.rough_stat(:ATTACK) + adef = user.rough_stat(:DEFENSE) if aatk == adef || user.effects[PBEffects::PowerTrick] # No flip-flopping score -= 90 @@ -1500,8 +1479,8 @@ Battle::AI::Handlers::MoveEffectScore.add("UserSwapBaseAtkDef", ) Battle::AI::Handlers::MoveEffectScore.add("UserTargetSwapBaseSpeed", - proc { |score, move, user, target, skill, ai, battle| - if ai.skill_check(Battle::AI::AILevel.medium) + proc { |score, move, user, target, ai, battle| + if ai.trainer.medium_skill? if user.speed > target.speed score += 50 else @@ -1513,12 +1492,12 @@ Battle::AI::Handlers::MoveEffectScore.add("UserTargetSwapBaseSpeed", ) Battle::AI::Handlers::MoveEffectScore.add("UserTargetAverageBaseAtkSpAtk", - proc { |score, move, user, target, skill, ai, battle| - if ai.skill_check(Battle::AI::AILevel.medium) - aatk = pbRoughStat(user, :ATTACK) - aspatk = pbRoughStat(user, :SPECIAL_ATTACK) - oatk = pbRoughStat(target, :ATTACK) - ospatk = pbRoughStat(target, :SPECIAL_ATTACK) + proc { |score, move, user, target, ai, battle| + if ai.trainer.medium_skill? + aatk = user.rough_stat(:ATTACK) + aspatk = user.rough_stat(:SPECIAL_ATTACK) + oatk = target.rough_stat(:ATTACK) + ospatk = target.rough_stat(:SPECIAL_ATTACK) if aatk < oatk && aspatk < ospatk score += 50 elsif aatk + aspatk < oatk + ospatk @@ -1534,12 +1513,12 @@ Battle::AI::Handlers::MoveEffectScore.add("UserTargetAverageBaseAtkSpAtk", ) Battle::AI::Handlers::MoveEffectScore.add("UserTargetAverageBaseDefSpDef", - proc { |score, move, user, target, skill, ai, battle| - if ai.skill_check(Battle::AI::AILevel.medium) - adef = pbRoughStat(user, :DEFENSE) - aspdef = pbRoughStat(user, :SPECIAL_DEFENSE) - odef = pbRoughStat(target, :DEFENSE) - ospdef = pbRoughStat(target, :SPECIAL_DEFENSE) + proc { |score, move, user, target, ai, battle| + if ai.trainer.medium_skill? + adef = user.rough_stat(:DEFENSE) + aspdef = user.rough_stat(:SPECIAL_DEFENSE) + odef = target.rough_stat(:DEFENSE) + ospdef = target.rough_stat(:SPECIAL_DEFENSE) if adef < odef && aspdef < ospdef score += 50 elsif adef + aspdef < odef + ospdef @@ -1555,7 +1534,7 @@ Battle::AI::Handlers::MoveEffectScore.add("UserTargetAverageBaseDefSpDef", ) Battle::AI::Handlers::MoveEffectScore.add("UserTargetAverageHP", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if target.effects[PBEffects::Substitute] > 0 score -= 90 elsif user.hp >= (user.hp + target.hp) / 2 @@ -1568,7 +1547,7 @@ Battle::AI::Handlers::MoveEffectScore.add("UserTargetAverageHP", ) Battle::AI::Handlers::MoveEffectScore.add("StartUserSideDoubleSpeed", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| next score - 90 if user.pbOwnSide.effects[PBEffects::Tailwind] > 0 } ) diff --git a/Data/Scripts/011_Battle/005_AI/053_AI_MoveHandlers_BattlerOther.rb b/Data/Scripts/011_Battle/005_AI/053_AI_MoveHandlers_BattlerOther.rb index 1c4ee1184..1fe7f8b8e 100644 --- a/Data/Scripts/011_Battle/005_AI/053_AI_MoveHandlers_BattlerOther.rb +++ b/Data/Scripts/011_Battle/005_AI/053_AI_MoveHandlers_BattlerOther.rb @@ -2,18 +2,16 @@ # #=============================================================================== Battle::AI::Handlers::MoveEffectScore.add("SleepTarget", - proc { |score, move, user, target, skill, ai, battle| - if target.pbCanSleep?(user, false) + proc { |score, move, user, target, ai, battle| + if target.battler.pbCanSleep?(user.battler, false) score += 30 - if ai.skill_check(Battle::AI::AILevel.medium) + if ai.trainer.medium_skill? score -= 30 if target.effects[PBEffects::Yawn] > 0 end - if ai.skill_check(Battle::AI::AILevel.high) - score -= 30 if target.hasActiveAbility?(:MARVELSCALE) - end - if ai.skill_check(Battle::AI::AILevel.best) - if target.pbHasMoveFunction?("FlinchTargetFailsIfUserNotAsleep", - "UseRandomUserMoveIfAsleep") # Snore, Sleep Talk + score -= 30 if target.has_active_ability?(:MARVELSCALE) + if ai.trainer.best_skill? + if target.battler.pbHasMoveFunction?("FlinchTargetFailsIfUserNotAsleep", + "UseRandomUserMoveIfAsleep") # Snore, Sleep Talk score -= 50 end end @@ -29,15 +27,14 @@ Battle::AI::Handlers::MoveEffectScore.copy("SleepTarget", "SleepTargetChangeUserMeloettaForm") Battle::AI::Handlers::MoveEffectScore.add("SleepTargetNextTurn", - proc { |score, move, user, target, skill, ai, battle| - next 0 if target.effects[PBEffects::Yawn] > 0 || !target.pbCanSleep?(user, false) + proc { |score, move, user, target, ai, battle| + next 0 if target.effects[PBEffects::Yawn] > 0 || + !target.battler.pbCanSleep?(user.battler, false) score += 30 - if ai.skill_check(Battle::AI::AILevel.high) - score -= 30 if target.hasActiveAbility?(:MARVELSCALE) - end - if ai.skill_check(Battle::AI::AILevel.best) - if target.pbHasMoveFunction?("FlinchTargetFailsIfUserNotAsleep", - "UseRandomUserMoveIfAsleep") # Snore, Sleep Talk + score -= 30 if target.has_active_ability?(:MARVELSCALE) + if ai.trainer.best_skill? + if target.battler.pbHasMoveFunction?("FlinchTargetFailsIfUserNotAsleep", + "UseRandomUserMoveIfAsleep") # Snore, Sleep Talk score -= 50 end end @@ -46,19 +43,19 @@ Battle::AI::Handlers::MoveEffectScore.add("SleepTargetNextTurn", ) Battle::AI::Handlers::MoveEffectScore.add("PoisonTarget", - proc { |score, move, user, target, skill, ai, battle| - if target.pbCanPoison?(user, false) + proc { |score, move, user, target, ai, battle| + if target.battler.pbCanPoison?(user.battler, false) score += 30 - if ai.skill_check(Battle::AI::AILevel.medium) + if ai.trainer.medium_skill? score += 30 if target.hp <= target.totalhp / 4 score += 50 if target.hp <= target.totalhp / 8 score -= 40 if target.effects[PBEffects::Yawn] > 0 end - if ai.skill_check(Battle::AI::AILevel.high) - score += 10 if pbRoughStat(target, :DEFENSE) > 100 - score += 10 if pbRoughStat(target, :SPECIAL_DEFENSE) > 100 - score -= 40 if target.hasActiveAbility?([:GUTS, :MARVELSCALE, :TOXICBOOST]) + if ai.trainer.high_skill? + score += 10 if target.rough_stat(:DEFENSE) > 100 + score += 10 if target.rough_stat(:SPECIAL_DEFENSE) > 100 end + score -= 40 if target.has_active_ability?([:GUTS, :MARVELSCALE, :TOXICBOOST]) else next 0 if move.statusMove? end @@ -67,26 +64,27 @@ Battle::AI::Handlers::MoveEffectScore.add("PoisonTarget", ) Battle::AI::Handlers::MoveEffectScore.add("PoisonTargetLowerTargetSpeed1", - proc { |score, move, user, target, skill, ai, battle| - next 0 if !target.pbCanPoison?(user, false) && !target.pbCanLowerStatStage?(:SPEED, user) - if target.pbCanPoison?(user, false) + proc { |score, move, user, target, ai, battle| + next 0 if !target.battler.pbCanPoison?(user.battler, false) && + !target.battler.pbCanLowerStatStage?(:SPEED, user.battler) + if target.battler.pbCanPoison?(user.battler, false) score += 30 - if ai.skill_check(Battle::AI::AILevel.medium) + if ai.trainer.medium_skill? score += 30 if target.hp <= target.totalhp / 4 score += 50 if target.hp <= target.totalhp / 8 score -= 40 if target.effects[PBEffects::Yawn] > 0 end - if ai.skill_check(Battle::AI::AILevel.high) - score += 10 if pbRoughStat(target, :DEFENSE) > 100 - score += 10 if pbRoughStat(target, :SPECIAL_DEFENSE) > 100 - score -= 40 if target.hasActiveAbility?([:GUTS, :MARVELSCALE, :TOXICBOOST]) + if ai.trainer.high_skill? + score += 10 if target.rough_stat(:DEFENSE) > 100 + score += 10 if target.rough_stat(:SPECIAL_DEFENSE) > 100 end + score -= 40 if target.has_active_ability?([:GUTS, :MARVELSCALE, :TOXICBOOST]) end - if target.pbCanLowerStatStage?(:SPEED, user) + if target.battler.pbCanLowerStatStage?(:SPEED, user.battler) score += target.stages[:SPEED] * 10 - if ai.skill_check(Battle::AI::AILevel.high) - aspeed = pbRoughStat(user, :SPEED) - ospeed = pbRoughStat(target, :SPEED) + if ai.trainer.high_skill? + aspeed = user.rough_stat(:SPEED) + ospeed = target.rough_stat(:SPEED) score += 30 if aspeed < ospeed && aspeed * 2 > ospeed end end @@ -95,19 +93,19 @@ Battle::AI::Handlers::MoveEffectScore.add("PoisonTargetLowerTargetSpeed1", ) Battle::AI::Handlers::MoveEffectScore.add("BadPoisonTarget", - proc { |score, move, user, target, skill, ai, battle| - if target.pbCanPoison?(user, false) + proc { |score, move, user, target, ai, battle| + if target.battler.pbCanPoison?(user.battler, false) score += 30 - if ai.skill_check(Battle::AI::AILevel.medium) + if ai.trainer.medium_skill? score += 30 if target.hp <= target.totalhp / 4 score += 50 if target.hp <= target.totalhp / 8 score -= 40 if target.effects[PBEffects::Yawn] > 0 end - if ai.skill_check(Battle::AI::AILevel.high) - score += 10 if pbRoughStat(target, :DEFENSE) > 100 - score += 10 if pbRoughStat(target, :SPECIAL_DEFENSE) > 100 - score -= 40 if target.hasActiveAbility?([:GUTS, :MARVELSCALE, :TOXICBOOST]) + if ai.trainer.high_skill? + score += 10 if target.rough_stat(:DEFENSE) > 100 + score += 10 if target.rough_stat(:SPECIAL_DEFENSE) > 100 end + score -= 40 if target.has_active_ability?([:GUTS, :MARVELSCALE, :TOXICBOOST]) else score -= 90 if move.statusMove? end @@ -116,24 +114,22 @@ Battle::AI::Handlers::MoveEffectScore.add("BadPoisonTarget", ) Battle::AI::Handlers::MoveEffectScore.add("ParalyzeTarget", - proc { |score, move, user, target, skill, ai, battle| - if target.pbCanParalyze?(user, false) && - !(ai.skill_check(Battle::AI::AILevel.medium) && + proc { |score, move, user, target, ai, battle| + if target.battler.pbCanParalyze?(user.battler, false) && + !(ai.trainer.medium_skill? && move.id == :THUNDERWAVE && - Effectiveness.ineffective?(pbCalcTypeMod(move.type, user, target))) + Effectiveness.ineffective?(target.effectiveness_of_type_against_battler(move.type, user))) score += 30 - if ai.skill_check(Battle::AI::AILevel.medium) - aspeed = pbRoughStat(user, :SPEED) - ospeed = pbRoughStat(target, :SPEED) + if ai.trainer.medium_skill? + aspeed = user.rough_stat(:SPEED) + ospeed = target.rough_stat(:SPEED) if aspeed < ospeed score += 30 elsif aspeed > ospeed score -= 40 end end - if ai.skill_check(Battle::AI::AILevel.high) - score -= 40 if target.hasActiveAbility?([:GUTS, :MARVELSCALE, :QUICKFEET]) - end + score -= 40 if target.has_active_ability?([:GUTS, :MARVELSCALE, :QUICKFEET]) else score -= 90 if move.statusMove? end @@ -147,12 +143,10 @@ Battle::AI::Handlers::MoveEffectScore.copy("ParalyzeTarget", "ParalyzeFlinchTarget") Battle::AI::Handlers::MoveEffectScore.add("BurnTarget", - proc { |score, move, user, target, skill, ai, battle| - if target.pbCanBurn?(user, false) + proc { |score, move, user, target, ai, battle| + if target.battler.pbCanBurn?(user.battler, false) score += 30 - if ai.skill_check(Battle::AI::AILevel.high) - score -= 40 if target.hasActiveAbility?([:GUTS, :MARVELSCALE, :QUICKFEET, :FLAREBOOST]) - end + score -= 40 if target.has_active_ability?([:GUTS, :MARVELSCALE, :QUICKFEET, :FLAREBOOST]) else score -= 90 if move.statusMove? end @@ -165,12 +159,10 @@ Battle::AI::Handlers::MoveEffectScore.copy("BurnTarget", "BurnFlinchTarget") Battle::AI::Handlers::MoveEffectScore.add("FreezeTarget", - proc { |score, move, user, target, skill, ai, battle| - if target.pbCanFreeze?(user, false) + proc { |score, move, user, target, ai, battle| + if target.battler.pbCanFreeze?(user.battler, false) score += 30 - if ai.skill_check(Battle::AI::AILevel.high) - score -= 20 if target.hasActiveAbility?(:MARVELSCALE) - end + score -= 20 if target.has_active_ability?(:MARVELSCALE) else score -= 90 if move.statusMove? end @@ -179,24 +171,20 @@ Battle::AI::Handlers::MoveEffectScore.add("FreezeTarget", ) Battle::AI::Handlers::MoveEffectScore.add("FreezeTargetSuperEffectiveAgainstWater", - proc { |score, move, user, target, skill, ai, battle| - if target.pbCanFreeze?(user, false) + proc { |score, move, user, target, ai, battle| + if target.battler.pbCanFreeze?(user.battler, false) score += 30 - if ai.skill_check(Battle::AI::AILevel.high) - score -= 20 if target.hasActiveAbility?(:MARVELSCALE) - end + score -= 20 if target.has_active_ability?(:MARVELSCALE) end next score } ) Battle::AI::Handlers::MoveEffectScore.add("FreezeTargetAlwaysHitsInHail", - proc { |score, move, user, target, skill, ai, battle| - if target.pbCanFreeze?(user, false) + proc { |score, move, user, target, ai, battle| + if target.battler.pbCanFreeze?(user.battler, false) score += 30 - if ai.skill_check(Battle::AI::AILevel.high) - score -= 20 if target.hasActiveAbility?(:MARVELSCALE) - end + score -= 20 if target.has_active_ability?(:MARVELSCALE) else score -= 90 if move.statusMove? end @@ -208,27 +196,27 @@ Battle::AI::Handlers::MoveEffectScore.copy("FreezeTargetAlwaysHitsInHail", "FreezeFlinchTarget") Battle::AI::Handlers::MoveEffectScore.add("ParalyzeBurnOrFreezeTarget", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| next score + 30 if target.status == :NONE } ) Battle::AI::Handlers::MoveEffectScore.add("GiveUserStatusToTarget", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| next 0 if user.status == :NONE next score + 40 } ) Battle::AI::Handlers::MoveEffectScore.add("CureUserBurnPoisonParalysis", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| case user.status when :POISON score += 40 - if ai.skill_check(Battle::AI::AILevel.medium) + if ai.trainer.medium_skill? if user.hp < user.totalhp / 8 score += 60 - elsif ai.skill_check(Battle::AI::AILevel.high) && + elsif ai.trainer.high_skill? && user.hp < (user.effects[PBEffects::Toxic] + 1) * user.totalhp / 16 score += 60 end @@ -243,7 +231,7 @@ Battle::AI::Handlers::MoveEffectScore.add("CureUserBurnPoisonParalysis", ) Battle::AI::Handlers::MoveEffectScore.add("CureUserPartyStatus", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| statuses = 0 battle.pbParty(user.index).each do |pkmn| statuses += 1 if pkmn && pkmn.status != :NONE @@ -258,7 +246,7 @@ Battle::AI::Handlers::MoveEffectScore.add("CureUserPartyStatus", ) Battle::AI::Handlers::MoveEffectScore.add("CureTargetBurn", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if target.opposes?(user) score -= 40 if target.status == :BURN elsif target.status == :BURN @@ -269,7 +257,7 @@ Battle::AI::Handlers::MoveEffectScore.add("CureTargetBurn", ) Battle::AI::Handlers::MoveEffectScore.add("StartUserSideImmunityToInflictedStatus", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if user.pbOwnSide.effects[PBEffects::Safeguard] > 0 score -= 80 elsif user.status != :NONE @@ -282,52 +270,44 @@ Battle::AI::Handlers::MoveEffectScore.add("StartUserSideImmunityToInflictedStatu ) Battle::AI::Handlers::MoveEffectScore.add("FlinchTarget", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| score += 30 - if ai.skill_check(Battle::AI::AILevel.high) - score += 30 if !target.hasActiveAbility?(:INNERFOCUS) && - target.effects[PBEffects::Substitute] == 0 - end + score += 30 if !target.has_active_ability?(:INNERFOCUS) && + target.effects[PBEffects::Substitute] == 0 next score } ) Battle::AI::Handlers::MoveEffectScore.add("FlinchTargetFailsIfUserNotAsleep", - proc { |score, move, user, target, skill, ai, battle| - next 0 if !user.asleep? + proc { |score, move, user, target, ai, battle| + next 0 if !user.battler.asleep? score += 100 # Because it can only be used while asleep - if ai.skill_check(Battle::AI::AILevel.high) - score += 30 if !target.hasActiveAbility?(:INNERFOCUS) && - target.effects[PBEffects::Substitute] == 0 - end + score += 30 if !target.has_active_ability?(:INNERFOCUS) && + target.effects[PBEffects::Substitute] == 0 next score } ) Battle::AI::Handlers::MoveEffectScore.add("FlinchTargetFailsIfNotUserFirstTurn", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| next 0 if user.turnCount != 0 - if ai.skill_check(Battle::AI::AILevel.high) - score += 30 if !target.hasActiveAbility?(:INNERFOCUS) && - target.effects[PBEffects::Substitute] == 0 - end + score += 30 if !target.has_active_ability?(:INNERFOCUS) && + target.effects[PBEffects::Substitute] == 0 next score } ) Battle::AI::Handlers::MoveEffectScore.add("FlinchTargetDoublePowerIfTargetInSky", - proc { |score, move, user, target, skill, ai, battle| - if ai.skill_check(Battle::AI::AILevel.high) - score += 30 if !target.hasActiveAbility?(:INNERFOCUS) && - target.effects[PBEffects::Substitute] == 0 - end + proc { |score, move, user, target, ai, battle| + score += 30 if !target.has_active_ability?(:INNERFOCUS) && + target.effects[PBEffects::Substitute] == 0 next score } ) Battle::AI::Handlers::MoveEffectScore.add("ConfuseTarget", - proc { |score, move, user, target, skill, ai, battle| - next 0 if !target.pbCanConfuse?(user, false) + proc { |score, move, user, target, ai, battle| + next 0 if !target.battler.pbCanConfuse?(user.battler, false) next score + 30 } ) @@ -336,7 +316,7 @@ Battle::AI::Handlers::MoveEffectScore.copy("ConfuseTarget", "ConfuseTargetAlwaysHitsInRainHitsTargetInSky") Battle::AI::Handlers::MoveEffectScore.add("AttractTarget", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| canattract = true agender = user.gender ogender = target.gender @@ -346,25 +326,23 @@ Battle::AI::Handlers::MoveEffectScore.add("AttractTarget", elsif target.effects[PBEffects::Attract] >= 0 score -= 80 canattract = false - elsif ai.skill_check(Battle::AI::AILevel.best) && target.hasActiveAbility?(:OBLIVIOUS) + elsif target.has_active_ability?(:OBLIVIOUS) score -= 80 canattract = false end - if ai.skill_check(Battle::AI::AILevel.high) - if canattract && target.hasActiveItem?(:DESTINYKNOT) && - user.pbCanAttract?(target, false) - score -= 30 - end + if canattract && target.has_active_item?(:DESTINYKNOT) && + user.battler.pbCanAttract?(target.battler, false) + score -= 30 end next score } ) Battle::AI::Handlers::MoveEffectScore.add("SetUserTypesBasedOnEnvironment", - proc { |score, move, user, target, skill, ai, battle| - if !user.canChangeType? + proc { |score, move, user, target, ai, battle| + if !user.battler.canChangeType? score -= 90 - elsif ai.skill_check(Battle::AI::AILevel.medium) + elsif ai.trainer.medium_skill? new_type = nil case battle.field.terrain when :Electric @@ -402,28 +380,28 @@ Battle::AI::Handlers::MoveEffectScore.add("SetUserTypesBasedOnEnvironment", new_type = nil if !GameData::Type.exists?(new_type) new_type ||= :NORMAL end - score -= 90 if !user.pbHasOtherType?(new_type) + score -= 90 if !user.battler.pbHasOtherType?(new_type) end next score } ) Battle::AI::Handlers::MoveEffectScore.add("SetUserTypesToResistLastAttack", - proc { |score, move, user, target, skill, ai, battle| - next 0 if !user.canChangeType? - next 0 if !target.lastMoveUsed || !target.lastMoveUsedType || - GameData::Type.get(target.lastMoveUsedType).pseudo_type + proc { |score, move, user, target, ai, battle| + next 0 if !user.battler.canChangeType? + next 0 if !target.battler.lastMoveUsed || !target.battler.lastMoveUsedType || + GameData::Type.get(target.battler.lastMoveUsedType).pseudo_type aType = nil - target.eachMove do |m| - next if m.id != target.lastMoveUsed - aType = m.pbCalcType(user) + target.battler.eachMove do |m| + next if m.id != target.battler.lastMoveUsed + aType = m.pbCalcType(user.battler) break end next 0 if !aType has_possible_type = false GameData::Type.each do |t| - next if t.pseudo_type || user.pbHasType?(t.id) || - !Effectiveness.resistant_type?(target.lastMoveUsedType, t.id) + next if t.pseudo_type || user.has_type?(t.id) || + !Effectiveness.resistant_type?(target.battler.lastMoveUsedType, t.id) has_possible_type = true break end @@ -432,21 +410,21 @@ Battle::AI::Handlers::MoveEffectScore.add("SetUserTypesToResistLastAttack", ) Battle::AI::Handlers::MoveEffectScore.add("SetUserTypesToTargetTypes", - proc { |score, move, user, target, skill, ai, battle| - next 0 if !user.canChangeType? || target.pbTypes(true).length == 0 - next 0 if user.pbTypes == target.pbTypes && + proc { |score, move, user, target, ai, battle| + next 0 if !user.battler.canChangeType? || target.battler.pbTypes(true).length == 0 + next 0 if user.battler.pbTypes == target.battler.pbTypes && user.effects[PBEffects::Type3] == target.effects[PBEffects::Type3] } ) Battle::AI::Handlers::MoveEffectScore.add("SetUserTypesToUserMoveType", - proc { |score, move, user, target, skill, ai, battle| - next 0 if !user.canChangeType? + proc { |score, move, user, target, ai, battle| + next 0 if !user.battler.canChangeType? has_possible_type = false - user.eachMoveWithIndex do |m, i| + user.battler.eachMoveWithIndex do |m, i| break if Settings::MECHANICS_GENERATION >= 6 && i > 0 next if GameData::Type.get(m.type).pseudo_type - next if user.pbHasType?(m.type) + next if user.has_type?(m.type) has_possible_type = true break end @@ -455,10 +433,10 @@ Battle::AI::Handlers::MoveEffectScore.add("SetUserTypesToUserMoveType", ) Battle::AI::Handlers::MoveEffectScore.add("SetTargetTypesToPsychic", - proc { |score, move, user, target, skill, ai, battle| - if target.pbHasOtherType?(:PSYCHIC) + proc { |score, move, user, target, ai, battle| + if !target.battler.canChangeType? score -= 90 - elsif !target.canChangeType? + elsif !target.battler.pbHasOtherType?(:PSYCHIC) score -= 90 end next score @@ -466,10 +444,10 @@ Battle::AI::Handlers::MoveEffectScore.add("SetTargetTypesToPsychic", ) Battle::AI::Handlers::MoveEffectScore.add("SetTargetTypesToWater", - proc { |score, move, user, target, skill, ai, battle| - if target.effects[PBEffects::Substitute] > 0 || !target.canChangeType? + proc { |score, move, user, target, ai, battle| + if !target.battler.canChangeType? || target.effects[PBEffects::Substitute] > 0 score -= 90 - elsif !target.pbHasOtherType?(:WATER) + elsif !target.battler.pbHasOtherType?(:WATER) score -= 90 end next score @@ -477,47 +455,47 @@ Battle::AI::Handlers::MoveEffectScore.add("SetTargetTypesToWater", ) Battle::AI::Handlers::MoveEffectScore.add("AddGhostTypeToTarget", - proc { |score, move, user, target, skill, ai, battle| - next 0 if target.pbHasType?(:GHOST) + proc { |score, move, user, target, ai, battle| + next 0 if target.has_type?(:GHOST) } ) Battle::AI::Handlers::MoveEffectScore.add("AddGrassTypeToTarget", - proc { |score, move, user, target, skill, ai, battle| - next 0 if target.pbHasType?(:GRASS) + proc { |score, move, user, target, ai, battle| + next 0 if target.has_type?(:GRASS) } ) Battle::AI::Handlers::MoveEffectScore.add("UserLosesFireType", - proc { |score, move, user, target, skill, ai, battle| - next 0 if !user.pbHasType?(:FIRE) + proc { |score, move, user, target, ai, battle| + next 0 if !user.has_type?(:FIRE) } ) Battle::AI::Handlers::MoveEffectScore.add("SetTargetAbilityToSimple", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| next 0 if target.effects[PBEffects::Substitute] > 0 - if ai.skill_check(Battle::AI::AILevel.medium) - next 0 if target.unstoppableAbility? || + if ai.trainer.medium_skill? + next 0 if target.battler.unstoppableAbility? || [:TRUANT, :SIMPLE].include?(target.ability) end } ) Battle::AI::Handlers::MoveEffectScore.add("SetTargetAbilityToInsomnia", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| next 0 if target.effects[PBEffects::Substitute] > 0 - if ai.skill_check(Battle::AI::AILevel.medium) - next 0 if target.unstoppableAbility? || + if ai.trainer.medium_skill? + next 0 if target.battler.unstoppableAbility? || [:TRUANT, :INSOMNIA].include?(target.ability) end } ) Battle::AI::Handlers::MoveEffectScore.add("SetUserAbilityToTargetAbility", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| score -= 40 # don't prefer this move - if ai.skill_check(Battle::AI::AILevel.medium) + if ai.trainer.medium_skill? if !target.ability || user.ability == target.ability || [:MULTITYPE, :RKSSYSTEM].include?(user.ability_id) || [:FLOWERGIFT, :FORECAST, :ILLUSION, :IMPOSTER, :MULTITYPE, :RKSSYSTEM, @@ -525,7 +503,7 @@ Battle::AI::Handlers::MoveEffectScore.add("SetUserAbilityToTargetAbility", score -= 90 end end - if ai.skill_check(Battle::AI::AILevel.high) + if ai.trainer.high_skill? if target.ability == :TRUANT && user.opposes?(target) score -= 90 elsif target.ability == :SLOWSTART && user.opposes?(target) @@ -537,18 +515,18 @@ Battle::AI::Handlers::MoveEffectScore.add("SetUserAbilityToTargetAbility", ) Battle::AI::Handlers::MoveEffectScore.add("SetTargetAbilityToUserAbility", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| score -= 40 # don't prefer this move if target.effects[PBEffects::Substitute] > 0 score -= 90 - elsif ai.skill_check(Battle::AI::AILevel.medium) + elsif ai.trainer.medium_skill? if !user.ability || user.ability == target.ability || [:MULTITYPE, :RKSSYSTEM, :TRUANT].include?(target.ability_id) || [:FLOWERGIFT, :FORECAST, :ILLUSION, :IMPOSTER, :MULTITYPE, :RKSSYSTEM, :TRACE, :ZENMODE].include?(user.ability_id) score -= 90 end - if ai.skill_check(Battle::AI::AILevel.high) + if ai.trainer.high_skill? if user.ability == :TRUANT && user.opposes?(target) score += 90 elsif user.ability == :SLOWSTART && user.opposes?(target) @@ -561,9 +539,9 @@ Battle::AI::Handlers::MoveEffectScore.add("SetTargetAbilityToUserAbility", ) Battle::AI::Handlers::MoveEffectScore.add("UserTargetSwapAbilities", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| score -= 40 # don't prefer this move - if ai.skill_check(Battle::AI::AILevel.medium) + if ai.trainer.medium_skill? if (!user.ability && !target.ability) || user.ability == target.ability || [:ILLUSION, :MULTITYPE, :RKSSYSTEM, :WONDERGUARD].include?(user.ability_id) || @@ -571,7 +549,7 @@ Battle::AI::Handlers::MoveEffectScore.add("UserTargetSwapAbilities", score -= 90 end end - if ai.skill_check(Battle::AI::AILevel.high) + if ai.trainer.high_skill? if target.ability == :TRUANT && user.opposes?(target) score -= 90 elsif target.ability == :SLOWSTART && user.opposes?(target) @@ -583,11 +561,11 @@ Battle::AI::Handlers::MoveEffectScore.add("UserTargetSwapAbilities", ) Battle::AI::Handlers::MoveEffectScore.add("NegateTargetAbility", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if target.effects[PBEffects::Substitute] > 0 || target.effects[PBEffects::GastroAcid] score -= 90 - elsif ai.skill_check(Battle::AI::AILevel.high) + elsif ai.trainer.high_skill? score -= 90 if [:MULTITYPE, :RKSSYSTEM, :SLOWSTART, :TRUANT].include?(target.ability_id) end next score @@ -595,13 +573,9 @@ Battle::AI::Handlers::MoveEffectScore.add("NegateTargetAbility", ) Battle::AI::Handlers::MoveEffectScore.add("NegateTargetAbilityIfTargetActed", - proc { |score, move, user, target, skill, ai, battle| - if ai.skill_check(Battle::AI::AILevel.medium) - userSpeed = pbRoughStat(user, :SPEED) - targetSpeed = pbRoughStat(target, :SPEED) - if userSpeed < targetSpeed - score += 30 - end + proc { |score, move, user, target, ai, battle| + if ai.trainer.medium_skill? + score += 30 if target.faster_than?(user) else score += 30 end @@ -612,7 +586,7 @@ Battle::AI::Handlers::MoveEffectScore.add("NegateTargetAbilityIfTargetActed", # IgnoreTargetAbility Battle::AI::Handlers::MoveEffectScore.add("StartUserAirborne", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if user.effects[PBEffects::MagnetRise] > 0 || user.effects[PBEffects::Ingrain] || user.effects[PBEffects::SmackDown] @@ -623,7 +597,7 @@ Battle::AI::Handlers::MoveEffectScore.add("StartUserAirborne", ) Battle::AI::Handlers::MoveEffectScore.add("StartTargetAirborneAndAlwaysHitByMoves", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if target.effects[PBEffects::Telekinesis] > 0 || target.effects[PBEffects::Ingrain] || target.effects[PBEffects::SmackDown] @@ -636,48 +610,48 @@ Battle::AI::Handlers::MoveEffectScore.add("StartTargetAirborneAndAlwaysHitByMove # HitsTargetInSky Battle::AI::Handlers::MoveEffectScore.add("HitsTargetInSkyGroundsTarget", - proc { |score, move, user, target, skill, ai, battle| - if ai.skill_check(Battle::AI::AILevel.medium) + proc { |score, move, user, target, ai, battle| + if ai.trainer.medium_skill? score += 20 if target.effects[PBEffects::MagnetRise] > 0 score += 20 if target.effects[PBEffects::Telekinesis] > 0 - score += 20 if target.inTwoTurnAttack?("TwoTurnAttackInvulnerableInSky", - "TwoTurnAttackInvulnerableInSkyParalyzeTarget") - score += 20 if target.pbHasType?(:FLYING) - score += 20 if target.hasActiveAbility?(:LEVITATE) - score += 20 if target.hasActiveItem?(:AIRBALLOON) + score += 20 if target.battler.inTwoTurnAttack?("TwoTurnAttackInvulnerableInSky", + "TwoTurnAttackInvulnerableInSkyParalyzeTarget") + score += 20 if target.has_type?(:FLYING) + score += 20 if target.has_active_ability?(:LEVITATE) + score += 20 if target.has_active_item?(:AIRBALLOON) end next score } ) Battle::AI::Handlers::MoveEffectScore.add("StartGravity", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if battle.field.effects[PBEffects::Gravity] > 0 score -= 90 - elsif ai.skill_check(Battle::AI::AILevel.medium) + elsif ai.trainer.medium_skill? score -= 30 score -= 20 if user.effects[PBEffects::SkyDrop] >= 0 score -= 20 if user.effects[PBEffects::MagnetRise] > 0 score -= 20 if user.effects[PBEffects::Telekinesis] > 0 - score -= 20 if user.pbHasType?(:FLYING) - score -= 20 if user.hasActiveAbility?(:LEVITATE) - score -= 20 if user.hasActiveItem?(:AIRBALLOON) + score -= 20 if user.has_type?(:FLYING) + score -= 20 if user.has_active_ability?(:LEVITATE) + score -= 20 if user.has_active_item?(:AIRBALLOON) score += 20 if target.effects[PBEffects::SkyDrop] >= 0 score += 20 if target.effects[PBEffects::MagnetRise] > 0 score += 20 if target.effects[PBEffects::Telekinesis] > 0 - score += 20 if target.inTwoTurnAttack?("TwoTurnAttackInvulnerableInSky", - "TwoTurnAttackInvulnerableInSkyParalyzeTarget", - "TwoTurnAttackInvulnerableInSkyTargetCannotAct") - score += 20 if target.pbHasType?(:FLYING) - score += 20 if target.hasActiveAbility?(:LEVITATE) - score += 20 if target.hasActiveItem?(:AIRBALLOON) + score += 20 if target.battler.inTwoTurnAttack?("TwoTurnAttackInvulnerableInSky", + "TwoTurnAttackInvulnerableInSkyParalyzeTarget", + "TwoTurnAttackInvulnerableInSkyTargetCannotAct") + score += 20 if target.has_type?(:FLYING) + score += 20 if target.has_active_ability?(:LEVITATE) + score += 20 if target.has_active_item?(:AIRBALLOON) end next score } ) Battle::AI::Handlers::MoveEffectScore.add("TransformUserIntoTarget", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| next score - 70 } ) diff --git a/Data/Scripts/011_Battle/005_AI/054_AI_MoveHandlers_MoveAttributes.rb b/Data/Scripts/011_Battle/005_AI/054_AI_MoveHandlers_MoveAttributes.rb index 0ebf64d73..bf24b7a08 100644 --- a/Data/Scripts/011_Battle/005_AI/054_AI_MoveHandlers_MoveAttributes.rb +++ b/Data/Scripts/011_Battle/005_AI/054_AI_MoveHandlers_MoveAttributes.rb @@ -2,7 +2,7 @@ # #=============================================================================== Battle::AI::Handlers::MoveEffectScore.add("FixedDamage20", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if target.hp <= 20 score += 80 elsif target.level >= 25 @@ -13,32 +13,32 @@ Battle::AI::Handlers::MoveEffectScore.add("FixedDamage20", ) Battle::AI::Handlers::MoveEffectScore.add("FixedDamage40", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| next score + 80 if target.hp <= 40 } ) Battle::AI::Handlers::MoveEffectScore.add("FixedDamageHalfTargetHP", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| score -= 50 next score + target.hp * 100 / target.totalhp } ) Battle::AI::Handlers::MoveEffectScore.add("FixedDamageUserLevel", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| next score + 80 if target.hp <= user.level } ) Battle::AI::Handlers::MoveEffectScore.add("FixedDamageUserLevelRandom", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| next score + 30 if target.hp <= user.level } ) Battle::AI::Handlers::MoveEffectScore.add("LowerTargetHPToUserHP", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if user.hp >= target.hp score -= 90 elsif user.hp < target.hp / 2 @@ -49,8 +49,8 @@ Battle::AI::Handlers::MoveEffectScore.add("LowerTargetHPToUserHP", ) Battle::AI::Handlers::MoveEffectScore.add("OHKO", - proc { |score, move, user, target, skill, ai, battle| - next 0 if target.hasActiveAbility?(:STURDY) + proc { |score, move, user, target, ai, battle| + next 0 if target.has_active_ability?(:STURDY) next 0 if target.level > user.level } ) @@ -60,9 +60,9 @@ Battle::AI::Handlers::MoveEffectScore.copy("OHKO", "OHKOHitsUndergroundTarget") Battle::AI::Handlers::MoveEffectScore.add("DamageTargetAlly", - proc { |score, move, user, target, skill, ai, battle| - target.allAllies.each do |b| - next if !b.near?(target) + proc { |score, move, user, target, ai, battle| + target.battler.allAllies.each do |b| + next if !b.near?(target.battler) score += 10 end next score @@ -104,7 +104,7 @@ Battle::AI::Handlers::MoveEffectScore.add("DamageTargetAlly", # DoublePowerIfUserPoisonedBurnedParalyzed Battle::AI::Handlers::MoveEffectScore.add("DoublePowerIfTargetAsleepCureTarget", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| next score - 20 if target.status == :SLEEP && # Will cure status target.statusCount > 1 } @@ -113,7 +113,7 @@ Battle::AI::Handlers::MoveEffectScore.add("DoublePowerIfTargetAsleepCureTarget", # DoublePowerIfTargetPoisoned Battle::AI::Handlers::MoveEffectScore.add("DoublePowerIfTargetParalyzedCureTarget", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| next score - 20 if target.status == :PARALYSIS # Will cure status } ) @@ -129,8 +129,8 @@ Battle::AI::Handlers::MoveEffectScore.add("DoublePowerIfTargetParalyzedCureTarge # DoublePowerIfTargetInSky Battle::AI::Handlers::MoveEffectScore.add("DoublePowerInElectricTerrain", - proc { |score, move, user, target, skill, ai, battle| - next score + 40 if battle.field.terrain == :Electric && target.affectedByTerrain? + proc { |score, move, user, target, ai, battle| + next score + 40 if battle.field.terrain == :Electric && target.battler.affectedByTerrain? } ) @@ -139,26 +139,22 @@ Battle::AI::Handlers::MoveEffectScore.add("DoublePowerInElectricTerrain", # DoublePowerIfAllyFaintedLastTurn Battle::AI::Handlers::MoveEffectScore.add("DoublePowerIfUserLostHPThisTurn", - proc { |score, move, user, target, skill, ai, battle| - attspeed = pbRoughStat(user, :SPEED) - oppspeed = pbRoughStat(target, :SPEED) - next score + 30 if oppspeed > attspeed + proc { |score, move, user, target, ai, battle| + next score + 30 if target.faster_than?(user) } ) Battle::AI::Handlers::MoveEffectScore.add("DoublePowerIfTargetLostHPThisTurn", - proc { |score, move, user, target, skill, ai, battle| - next score + 20 if battle.pbOpposingBattlerCount(user) > 1 + proc { |score, move, user, target, ai, battle| + next score + 20 if battle.pbOpposingBattlerCount(user.battler) > 1 } ) # DoublePowerIfUserStatsLoweredThisTurn Battle::AI::Handlers::MoveEffectScore.add("DoublePowerIfTargetActed", - proc { |score, move, user, target, skill, ai, battle| - attspeed = pbRoughStat(user, :SPEED) - oppspeed = pbRoughStat(target, :SPEED) - next score + 30 if oppspeed > attspeed + proc { |score, move, user, target, ai, battle| + next score + 30 if target.faster_than?(user) } ) @@ -167,7 +163,7 @@ Battle::AI::Handlers::MoveEffectScore.add("DoublePowerIfTargetActed", # AlwaysCriticalHit Battle::AI::Handlers::MoveEffectScore.add("EnsureNextCriticalHit", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if user.effects[PBEffects::LaserFocus] > 0 score -= 90 else @@ -178,13 +174,13 @@ Battle::AI::Handlers::MoveEffectScore.add("EnsureNextCriticalHit", ) Battle::AI::Handlers::MoveEffectScore.add("EnsureNextCriticalHit", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| next 0 if user.pbOwnSide.effects[PBEffects::LuckyChant] > 0 } ) Battle::AI::Handlers::MoveEffectScore.add("CannotMakeTargetFaint", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| next 0 if target.hp == 1 if target.hp <= target.totalhp / 8 score -= 60 @@ -196,9 +192,9 @@ Battle::AI::Handlers::MoveEffectScore.add("CannotMakeTargetFaint", ) Battle::AI::Handlers::MoveEffectScore.add("UserEnduresFaintingThisTurn", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| score -= 25 if user.hp > user.totalhp / 2 - if ai.skill_check(Battle::AI::AILevel.medium) + if ai.trainer.medium_skill? score -= 90 if user.effects[PBEffects::ProtectRate] > 1 score -= 90 if target.effects[PBEffects::HyperBeam] > 0 else @@ -209,38 +205,39 @@ Battle::AI::Handlers::MoveEffectScore.add("UserEnduresFaintingThisTurn", ) Battle::AI::Handlers::MoveEffectScore.add("StartWeakenElectricMoves", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| next 0 if user.effects[PBEffects::MudSport] } ) Battle::AI::Handlers::MoveEffectScore.add("StartWeakenFireMoves", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| next 0 if user.effects[PBEffects::WaterSport] } ) Battle::AI::Handlers::MoveEffectScore.add("StartWeakenPhysicalDamageAgainstUserSide", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| next 0 if user.pbOwnSide.effects[PBEffects::Reflect] > 0 } ) Battle::AI::Handlers::MoveEffectScore.add("StartWeakenSpecialDamageAgainstUserSide", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| next 0 if user.pbOwnSide.effects[PBEffects::LightScreen] > 0 } ) Battle::AI::Handlers::MoveEffectScore.add("StartWeakenDamageAgainstUserSideIfHail", - proc { |score, move, user, target, skill, ai, battle| - next 0 if user.pbOwnSide.effects[PBEffects::AuroraVeil] > 0 || user.effectiveWeather != :Hail + proc { |score, move, user, target, ai, battle| + next 0 if user.pbOwnSide.effects[PBEffects::AuroraVeil] > 0 || + user.battler.effectiveWeather != :Hail next score + 40 } ) Battle::AI::Handlers::MoveEffectScore.add("RemoveScreens", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| score += 20 if user.pbOpposingSide.effects[PBEffects::AuroraVeil] > 0 score += 20 if user.pbOpposingSide.effects[PBEffects::Reflect] > 0 score += 20 if user.pbOpposingSide.effects[PBEffects::LightScreen] > 0 @@ -249,12 +246,12 @@ Battle::AI::Handlers::MoveEffectScore.add("RemoveScreens", ) Battle::AI::Handlers::MoveEffectScore.add("ProtectUser", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if user.effects[PBEffects::ProtectRate] > 1 || target.effects[PBEffects::HyperBeam] > 0 score -= 90 else - if ai.skill_check(Battle::AI::AILevel.medium) + if ai.trainer.medium_skill? score -= user.effects[PBEffects::ProtectRate] * 40 end score += 50 if user.turnCount == 0 @@ -265,12 +262,12 @@ Battle::AI::Handlers::MoveEffectScore.add("ProtectUser", ) Battle::AI::Handlers::MoveEffectScore.add("ProtectUserBanefulBunker", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if user.effects[PBEffects::ProtectRate] > 1 || target.effects[PBEffects::HyperBeam] > 0 score -= 90 else - if ai.skill_check(Battle::AI::AILevel.medium) + if ai.trainer.medium_skill? score -= user.effects[PBEffects::ProtectRate] * 40 end score += 50 if user.turnCount == 0 @@ -282,12 +279,12 @@ Battle::AI::Handlers::MoveEffectScore.add("ProtectUserBanefulBunker", ) Battle::AI::Handlers::MoveEffectScore.add("ProtectUserFromDamagingMovesKingsShield", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if user.effects[PBEffects::ProtectRate] > 1 || target.effects[PBEffects::HyperBeam] > 0 score -= 90 else - if ai.skill_check(Battle::AI::AILevel.medium) + if ai.trainer.medium_skill? score -= user.effects[PBEffects::ProtectRate] * 40 end score += 50 if user.turnCount == 0 @@ -298,12 +295,12 @@ Battle::AI::Handlers::MoveEffectScore.add("ProtectUserFromDamagingMovesKingsShie ) Battle::AI::Handlers::MoveEffectScore.add("ProtectUserFromDamagingMovesObstruct", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if user.effects[PBEffects::ProtectRate] > 1 || target.effects[PBEffects::HyperBeam] > 0 score -= 90 else - if ai.skill_check(Battle::AI::AILevel.medium) + if ai.trainer.medium_skill? score -= user.effects[PBEffects::ProtectRate] * 40 end score += 50 if user.turnCount == 0 @@ -314,12 +311,12 @@ Battle::AI::Handlers::MoveEffectScore.add("ProtectUserFromDamagingMovesObstruct" ) Battle::AI::Handlers::MoveEffectScore.add("ProtectUserFromTargetingMovesSpikyShield", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if user.effects[PBEffects::ProtectRate] > 1 || target.effects[PBEffects::HyperBeam] > 0 score -= 90 else - if ai.skill_check(Battle::AI::AILevel.medium) + if ai.trainer.medium_skill? score -= user.effects[PBEffects::ProtectRate] * 40 end score += 50 if user.turnCount == 0 @@ -330,7 +327,7 @@ Battle::AI::Handlers::MoveEffectScore.add("ProtectUserFromTargetingMovesSpikyShi ) Battle::AI::Handlers::MoveEffectScore.add("ProtectUserSideFromDamagingMovesIfUserFirstTurn", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| next 0 if user.turnCount != 0 next score + 30 } @@ -347,55 +344,51 @@ Battle::AI::Handlers::MoveEffectScore.add("ProtectUserSideFromDamagingMovesIfUse # RemoveProtectionsBypassSubstitute Battle::AI::Handlers::MoveEffectScore.add("HoopaRemoveProtectionsBypassSubstituteLowerUserDef1", - proc { |score, move, user, target, skill, ai, battle| - next 0 if !user.isSpecies?(:HOOPA) || user.form != 1 + proc { |score, move, user, target, ai, battle| + next 0 if !user.battler.isSpecies?(:HOOPA) || user.battler.form != 1 next score + 20 if target.stages[:DEFENSE] > 0 } ) Battle::AI::Handlers::MoveEffectScore.add("RecoilQuarterOfDamageDealt", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| next score - 25 } ) Battle::AI::Handlers::MoveEffectScore.add("RecoilThirdOfDamageDealtParalyzeTarget", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| score -= 30 - if target.pbCanParalyze?(user, false) + if target.battler.pbCanParalyze?(user.battler, false) score += 30 - if ai.skill_check(Battle::AI::AILevel.medium) - aspeed = pbRoughStat(user, :SPEED) - ospeed = pbRoughStat(target, :SPEED) + if ai.trainer.medium_skill? + aspeed = user.rough_stat(:SPEED) + ospeed = target.rough_stat(:SPEED) if aspeed < ospeed score += 30 elsif aspeed > ospeed score -= 40 end end - if ai.skill_check(Battle::AI::AILevel.high) - score -= 40 if target.hasActiveAbility?([:GUTS, :MARVELSCALE, :QUICKFEET]) - end + score -= 40 if target.has_active_ability?([:GUTS, :MARVELSCALE, :QUICKFEET]) end next score } ) Battle::AI::Handlers::MoveEffectScore.add("RecoilThirdOfDamageDealtBurnTarget", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| score -= 30 - if target.pbCanBurn?(user, false) + if target.battler.pbCanBurn?(user.battler, false) score += 30 - if ai.skill_check(Battle::AI::AILevel.high) - score -= 40 if target.hasActiveAbility?([:GUTS, :MARVELSCALE, :QUICKFEET, :FLAREBOOST]) - end + score -= 40 if target.has_active_ability?([:GUTS, :MARVELSCALE, :QUICKFEET, :FLAREBOOST]) end next score } ) Battle::AI::Handlers::MoveEffectScore.add("RecoilHalfOfDamageDealt", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| next score - 40 } ) @@ -403,8 +396,8 @@ Battle::AI::Handlers::MoveEffectScore.add("RecoilHalfOfDamageDealt", # EffectivenessIncludesFlyingType Battle::AI::Handlers::MoveEffectScore.add("CategoryDependsOnHigherDamagePoisonTarget", - proc { |score, move, user, target, skill, ai, battle| - next score + 5 if target.pbCanPoison?(user, false) + proc { |score, move, user, target, ai, battle| + next score + 5 if target.battler.pbCanPoison?(user.battler, false) } ) @@ -417,17 +410,17 @@ Battle::AI::Handlers::MoveEffectScore.add("CategoryDependsOnHigherDamagePoisonTa # UseTargetDefenseInsteadOfTargetSpDef Battle::AI::Handlers::MoveEffectScore.add("EnsureNextMoveAlwaysHits", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| next 0 if target.effects[PBEffects::Substitute] > 0 next 0 if user.effects[PBEffects::LockOn] > 0 } ) Battle::AI::Handlers::MoveEffectScore.add("StartNegateTargetEvasionStatStageAndGhostImmunity", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if target.effects[PBEffects::Foresight] score -= 90 - elsif target.pbHasType?(:GHOST) + elsif target.has_type?(:GHOST) score += 70 elsif target.stages[:EVASION] <= 0 score -= 60 @@ -437,10 +430,10 @@ Battle::AI::Handlers::MoveEffectScore.add("StartNegateTargetEvasionStatStageAndG ) Battle::AI::Handlers::MoveEffectScore.add("StartNegateTargetEvasionStatStageAndDarkImmunity", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if target.effects[PBEffects::MiracleEye] score -= 90 - elsif target.pbHasType?(:DARK) + elsif target.has_type?(:DARK) score += 70 elsif target.stages[:EVASION] <= 0 score -= 60 @@ -456,8 +449,8 @@ Battle::AI::Handlers::MoveEffectScore.add("StartNegateTargetEvasionStatStageAndD # TypeDependsOnUserIVs Battle::AI::Handlers::MoveEffectScore.add("TypeAndPowerDependOnUserBerry", - proc { |score, move, user, target, skill, ai, battle| - next 0 if !user.item || !user.item.is_berry? || !user.itemActive? + proc { |score, move, user, target, ai, battle| + next 0 if !user.item || !user.item.is_berry? || !user.item_active? } ) @@ -468,7 +461,7 @@ Battle::AI::Handlers::MoveEffectScore.add("TypeAndPowerDependOnUserBerry", # TypeDependsOnUserDrive Battle::AI::Handlers::MoveEffectScore.add("TypeDependsOnUserMorpekoFormRaiseUserSpeed1", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| next score + 20 if user.stages[:SPEED] <= 0 } ) @@ -476,16 +469,14 @@ Battle::AI::Handlers::MoveEffectScore.add("TypeDependsOnUserMorpekoFormRaiseUser # TypeAndPowerDependOnWeather Battle::AI::Handlers::MoveEffectScore.add("TypeAndPowerDependOnTerrain", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| next score + 40 if battle.field.terrain != :None } ) Battle::AI::Handlers::MoveEffectScore.add("TargetMovesBecomeElectric", - proc { |score, move, user, target, skill, ai, battle| - aspeed = pbRoughStat(user, :SPEED) - ospeed = pbRoughStat(target, :SPEED) - next 0 if aspeed > ospeed + proc { |score, move, user, target, ai, battle| + next 0 if user.faster_than?(target) } ) diff --git a/Data/Scripts/011_Battle/005_AI/055_AI_MoveHandlers_MultiHit.rb b/Data/Scripts/011_Battle/005_AI/055_AI_MoveHandlers_MultiHit.rb index 6105c4d11..1b57f276e 100644 --- a/Data/Scripts/011_Battle/005_AI/055_AI_MoveHandlers_MultiHit.rb +++ b/Data/Scripts/011_Battle/005_AI/055_AI_MoveHandlers_MultiHit.rb @@ -5,25 +5,25 @@ # HitTwoTimes Battle::AI::Handlers::MoveEffectScore.add("HitTwoTimesPoisonTarget", - proc { |score, move, user, target, skill, ai, battle| - next 0 if !target.pbCanPoison?(user, false) + proc { |score, move, user, target, ai, battle| + next 0 if !target.battler.pbCanPoison?(user.battler, false) score += 30 - if ai.skill_check(Battle::AI::AILevel.medium) + if ai.trainer.medium_skill? score += 30 if target.hp <= target.totalhp / 4 score += 50 if target.hp <= target.totalhp / 8 score -= 40 if target.effects[PBEffects::Yawn] > 0 end - if ai.skill_check(Battle::AI::AILevel.high) - score += 10 if pbRoughStat(target, :DEFENSE) > 100 - score += 10 if pbRoughStat(target, :SPECIAL_DEFENSE) > 100 - score -= 40 if target.hasActiveAbility?([:GUTS, :MARVELSCALE, :TOXICBOOST]) + if ai.trainer.high_skill? + score += 10 if target.rough_stat(:DEFENSE) > 100 + score += 10 if target.rough_stat(:SPECIAL_DEFENSE) > 100 end + score -= 40 if target.has_active_ability?([:GUTS, :MARVELSCALE, :TOXICBOOST]) next score } ) Battle::AI::Handlers::MoveEffectScore.add("HitTwoTimesFlinchTarget", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| next score + 30 if target.effects[PBEffects::Minimize] } ) @@ -33,10 +33,10 @@ Battle::AI::Handlers::MoveEffectScore.add("HitTwoTimesFlinchTarget", # HitThreeTimesPowersUpWithEachHit Battle::AI::Handlers::MoveEffectScore.add("HitThreeTimesAlwaysCriticalHit", - proc { |score, move, user, target, skill, ai, battle| - if ai.skill_check(Battle::AI::AILevel.high) + proc { |score, move, user, target, ai, battle| + if ai.trainer.high_skill? stat = (move.physicalMove?) ? :DEFENSE : :SPECIAL_DEFENSE - next score + 50 if targets.stages[stat] > 1 + next score + 50 if target.stages[stat] > 1 end } ) @@ -46,9 +46,9 @@ Battle::AI::Handlers::MoveEffectScore.add("HitThreeTimesAlwaysCriticalHit", # HitTwoToFiveTimesOrThreeForAshGreninja Battle::AI::Handlers::MoveEffectScore.add("HitTwoToFiveTimesRaiseUserSpd1LowerUserDef1", - proc { |score, move, user, target, skill, ai, battle| - aspeed = pbRoughStat(user, :SPEED) - ospeed = pbRoughStat(target, :SPEED) + proc { |score, move, user, target, ai, battle| + aspeed = user.rough_stat(:SPEED) + ospeed = target.rough_stat(:SPEED) if aspeed > ospeed && aspeed * 2 / 3 < ospeed score -= 50 elsif aspeed < ospeed && aspeed * 1.5 > ospeed @@ -68,25 +68,20 @@ Battle::AI::Handlers::MoveEffectScore.add("HitTwoToFiveTimesRaiseUserSpd1LowerUs # TwoTurnAttackOneTurnInSun Battle::AI::Handlers::MoveEffectScore.add("TwoTurnAttackParalyzeTarget", - proc { |score, move, user, target, skill, ai, battle| - if target.pbCanParalyze?(user, false) && - !(ai.skill_check(Battle::AI::AILevel.medium) && - move.id == :THUNDERWAVE && - Effectiveness.ineffective?(pbCalcTypeMod(move.type, user, target))) + proc { |score, move, user, target, ai, battle| + if target.battler.pbCanParalyze?(user.battler, false) score += 30 - if ai.skill_check(Battle::AI::AILevel.medium) - aspeed = pbRoughStat(user, :SPEED) - ospeed = pbRoughStat(target, :SPEED) + if ai.trainer.medium_skill? + aspeed = user.rough_stat(:SPEED) + ospeed = target.rough_stat(:SPEED) if aspeed < ospeed score += 30 elsif aspeed > ospeed score -= 40 end end - if ai.skill_check(Battle::AI::AILevel.high) - score -= 40 if target.hasActiveAbility?([:GUTS, :MARVELSCALE, :QUICKFEET]) - end - elsif ai.skill_check(Battle::AI::AILevel.medium) + score -= 40 if target.has_active_ability?([:GUTS, :MARVELSCALE, :QUICKFEET]) + elsif ai.trainer.medium_skill? score -= 90 if move.statusMove? end next score @@ -94,29 +89,25 @@ Battle::AI::Handlers::MoveEffectScore.add("TwoTurnAttackParalyzeTarget", ) Battle::AI::Handlers::MoveEffectScore.add("TwoTurnAttackBurnTarget", - proc { |score, move, user, target, skill, ai, battle| - next 0 if !target.pbCanBurn?(user, false) + proc { |score, move, user, target, ai, battle| + next 0 if !target.battler.pbCanBurn?(user.battler, false) score += 30 - if ai.skill_check(Battle::AI::AILevel.high) - score -= 40 if target.hasActiveAbility?([:GUTS, :MARVELSCALE, :QUICKFEET, :FLAREBOOST]) - end + score -= 40 if target.has_active_ability?([:GUTS, :MARVELSCALE, :QUICKFEET, :FLAREBOOST]) next score } ) Battle::AI::Handlers::MoveEffectScore.add("TwoTurnAttackFlinchTarget", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| score += 20 if user.effects[PBEffects::FocusEnergy] > 0 - if ai.skill_check(Battle::AI::AILevel.high) - score += 20 if !target.hasActiveAbility?(:INNERFOCUS) && - target.effects[PBEffects::Substitute] == 0 - end + score += 20 if !target.has_active_ability?(:INNERFOCUS) && + target.effects[PBEffects::Substitute] == 0 next score } ) Battle::AI::Handlers::MoveEffectScore.add("TwoTurnAttackRaiseUserSpAtkSpDefSpd2", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if user.statStageAtMax?(:SPECIAL_ATTACK) && user.statStageAtMax?(:SPECIAL_DEFENSE) && user.statStageAtMax?(:SPEED) @@ -125,22 +116,22 @@ Battle::AI::Handlers::MoveEffectScore.add("TwoTurnAttackRaiseUserSpAtkSpDefSpd2" score -= user.stages[:SPECIAL_ATTACK] * 10 # Only *10 instead of *20 score -= user.stages[:SPECIAL_DEFENSE] * 10 # because two-turn attack score -= user.stages[:SPEED] * 10 - if ai.skill_check(Battle::AI::AILevel.medium) + if ai.trainer.medium_skill? hasSpecialAttack = false - user.eachMove do |m| + user.battler.eachMove do |m| next if !m.specialMove?(m.type) hasSpecialAttack = true break end if hasSpecialAttack score += 20 - elsif ai.skill_check(Battle::AI::AILevel.high) + elsif ai.trainer.high_skill? score -= 90 end end - if ai.skill_check(Battle::AI::AILevel.high) - aspeed = pbRoughStat(user, :SPEED) - ospeed = pbRoughStat(target, :SPEED) + if ai.trainer.high_skill? + aspeed = user.rough_stat(:SPEED) + ospeed = target.rough_stat(:SPEED) score += 30 if aspeed < ospeed && aspeed * 2 > ospeed end end @@ -149,7 +140,7 @@ Battle::AI::Handlers::MoveEffectScore.add("TwoTurnAttackRaiseUserSpAtkSpDefSpd2" ) Battle::AI::Handlers::MoveEffectScore.add("TwoTurnAttackChargeRaiseUserDefense1", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if move.statusMove? if user.statStageAtMax?(:DEFENSE) score -= 90 @@ -164,9 +155,9 @@ Battle::AI::Handlers::MoveEffectScore.add("TwoTurnAttackChargeRaiseUserDefense1" ) Battle::AI::Handlers::MoveEffectScore.add("TwoTurnAttackChargeRaiseUserSpAtk1", - proc { |score, move, user, target, skill, ai, battle| - aspeed = pbRoughStat(user, :SPEED) - ospeed = pbRoughStat(target, :SPEED) + proc { |score, move, user, target, ai, battle| + aspeed = user.rough_stat(:SPEED) + ospeed = target.rough_stat(:SPEED) if (aspeed > ospeed && user.hp > user.totalhp / 3) || user.hp > user.totalhp / 2 score += 60 else @@ -196,7 +187,7 @@ Battle::AI::Handlers::MoveEffectScore.add("TwoTurnAttackChargeRaiseUserSpAtk1", # MultiTurnAttackPowersUpEachTurn Battle::AI::Handlers::MoveEffectScore.add("MultiTurnAttackBideThenReturnDoubleDamage", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if user.hp <= user.totalhp / 4 score -= 90 elsif user.hp <= user.totalhp / 2 diff --git a/Data/Scripts/011_Battle/005_AI/056_AI_MoveHandlers_Healing.rb b/Data/Scripts/011_Battle/005_AI/056_AI_MoveHandlers_Healing.rb index 6b0a3a6d6..381014f26 100644 --- a/Data/Scripts/011_Battle/005_AI/056_AI_MoveHandlers_Healing.rb +++ b/Data/Scripts/011_Battle/005_AI/056_AI_MoveHandlers_Healing.rb @@ -2,8 +2,9 @@ # #=============================================================================== Battle::AI::Handlers::MoveEffectScore.add("HealUserFullyAndFallAsleep", - proc { |score, move, user, target, skill, ai, battle| - next 0 if user.hp == user.totalhp || !user.pbCanSleep?(user, false, nil, true) + proc { |score, move, user, target, ai, battle| + next 0 if user.hp == user.totalhp || + !user.battler.pbCanSleep?(user.battler, false, nil, true) score += 70 score -= user.hp * 140 / user.totalhp score += 30 if user.status != :NONE @@ -12,8 +13,9 @@ Battle::AI::Handlers::MoveEffectScore.add("HealUserFullyAndFallAsleep", ) Battle::AI::Handlers::MoveEffectScore.add("HealUserHalfOfTotalHP", - proc { |score, move, user, target, skill, ai, battle| - next 0 if user.hp == user.totalhp || (ai.skill_check(Battle::AI::AILevel.medium) && !user.canHeal?) + proc { |score, move, user, target, ai, battle| + next 0 if user.hp == user.totalhp || + (ai.trainer.medium_skill? && !user.battler.canHeal?) score += 50 score -= user.hp * 100 / user.totalhp next score @@ -21,9 +23,10 @@ Battle::AI::Handlers::MoveEffectScore.add("HealUserHalfOfTotalHP", ) Battle::AI::Handlers::MoveEffectScore.add("HealUserDependingOnWeather", - proc { |score, move, user, target, skill, ai, battle| - next 0 if user.hp == user.totalhp || (ai.skill_check(Battle::AI::AILevel.medium) && !user.canHeal?) - case user.effectiveWeather + proc { |score, move, user, target, ai, battle| + next 0 if user.hp == user.totalhp || + (ai.trainer.medium_skill? && !user.battler.canHeal?) + case user.battler.effectiveWeather when :Sun, :HarshSun score += 30 when :None @@ -37,18 +40,20 @@ Battle::AI::Handlers::MoveEffectScore.add("HealUserDependingOnWeather", ) Battle::AI::Handlers::MoveEffectScore.add("HealUserDependingOnSandstorm", - proc { |score, move, user, target, skill, ai, battle| - next 0 if user.hp == user.totalhp || (ai.skill_check(Battle::AI::AILevel.medium) && !user.canHeal?) + proc { |score, move, user, target, ai, battle| + next 0 if user.hp == user.totalhp || + (ai.trainer.medium_skill? && !user.battler.canHeal?) score += 50 score -= user.hp * 100 / user.totalhp - score += 30 if user.effectiveWeather == :Sandstorm + score += 30 if user.battler.effectiveWeather == :Sandstorm next score } ) Battle::AI::Handlers::MoveEffectScore.add("HealUserHalfOfTotalHPLoseFlyingTypeThisTurn", - proc { |score, move, user, target, skill, ai, battle| - next 0 if user.hp == user.totalhp || (ai.skill_check(Battle::AI::AILevel.medium) && !user.canHeal?) + proc { |score, move, user, target, ai, battle| + next 0 if user.hp == user.totalhp || + (ai.trainer.medium_skill? && !user.battler.canHeal?) score += 50 score -= user.hp * 100 / user.totalhp next score @@ -56,7 +61,7 @@ Battle::AI::Handlers::MoveEffectScore.add("HealUserHalfOfTotalHPLoseFlyingTypeTh ) Battle::AI::Handlers::MoveEffectScore.add("CureTargetStatusHealUserHalfOfTotalHP", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if target.status == :NONE score -= 90 elsif user.hp == user.totalhp && target.opposes?(user) @@ -70,22 +75,22 @@ Battle::AI::Handlers::MoveEffectScore.add("CureTargetStatusHealUserHalfOfTotalHP ) Battle::AI::Handlers::MoveEffectScore.add("HealUserByTargetAttackLowerTargetAttack1", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if target.statStageAtMin?(:ATTACK) score -= 90 else - if target.pbCanLowerStatStage?(:ATTACK, user) + if target.battler.pbCanLowerStatStage?(:ATTACK, user.battler) score += target.stages[:ATTACK] * 20 - if ai.skill_check(Battle::AI::AILevel.medium) + if ai.trainer.medium_skill? hasPhysicalAttack = false - target.eachMove do |m| + target.battler.eachMove do |m| next if !m.physicalMove?(m.type) hasPhysicalAttack = true break end if hasPhysicalAttack score += 20 - elsif ai.skill_check(Battle::AI::AILevel.high) + elsif ai.trainer.high_skill? score -= 90 end end @@ -97,8 +102,8 @@ Battle::AI::Handlers::MoveEffectScore.add("HealUserByTargetAttackLowerTargetAtta ) Battle::AI::Handlers::MoveEffectScore.add("HealUserByHalfOfDamageDone", - proc { |score, move, user, target, skill, ai, battle| - if ai.skill_check(Battle::AI::AILevel.high) && target.hasActiveAbility?(:LIQUIDOOZE) + proc { |score, move, user, target, ai, battle| + if target.has_active_ability?(:LIQUIDOOZE) score -= 70 elsif user.hp <= user.totalhp / 2 score += 20 @@ -108,9 +113,9 @@ Battle::AI::Handlers::MoveEffectScore.add("HealUserByHalfOfDamageDone", ) Battle::AI::Handlers::MoveEffectScore.add("HealUserByHalfOfDamageDoneIfTargetAsleep", - proc { |score, move, user, target, skill, ai, battle| - next 0 if !target.asleep? - if ai.skill_check(Battle::AI::AILevel.high) && target.hasActiveAbility?(:LIQUIDOOZE) + proc { |score, move, user, target, ai, battle| + next 0 if !target.battler.asleep? + if target.has_active_ability?(:LIQUIDOOZE) score -= 70 elsif user.hp <= user.totalhp / 2 score += 20 @@ -120,8 +125,8 @@ Battle::AI::Handlers::MoveEffectScore.add("HealUserByHalfOfDamageDoneIfTargetAsl ) Battle::AI::Handlers::MoveEffectScore.add("HealUserByThreeQuartersOfDamageDone", - proc { |score, move, user, target, skill, ai, battle| - if ai.skill_check(Battle::AI::AILevel.high) && target.hasActiveAbility?(:LIQUIDOOZE) + proc { |score, move, user, target, ai, battle| + if target.has_active_ability?(:LIQUIDOOZE) score -= 80 elsif user.hp <= user.totalhp / 2 score += 40 @@ -131,10 +136,10 @@ Battle::AI::Handlers::MoveEffectScore.add("HealUserByThreeQuartersOfDamageDone", ) Battle::AI::Handlers::MoveEffectScore.add("HealUserAndAlliesQuarterOfTotalHP", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| ally_amt = 30 battle.allSameSideBattlers(user.index).each do |b| - if b.hp == b.totalhp || (ai.skill_check(Battle::AI::AILevel.medium) && !b.canHeal?) + if b.hp == b.totalhp || (ai.trainer.medium_skill? && !b.canHeal?) score -= ally_amt / 2 elsif b.hp < b.totalhp * 3 / 4 score += ally_amt @@ -145,10 +150,10 @@ Battle::AI::Handlers::MoveEffectScore.add("HealUserAndAlliesQuarterOfTotalHP", ) Battle::AI::Handlers::MoveEffectScore.add("HealUserAndAlliesQuarterOfTotalHPCureStatus", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| ally_amt = 80 / battle.pbSideSize(user.index) battle.allSameSideBattlers(user.index).each do |b| - if b.hp == b.totalhp || (ai.skill_check(Battle::AI::AILevel.medium) && !b.canHeal?) + if b.hp == b.totalhp || (ai.trainer.medium_skill? && !b.canHeal?) score -= ally_amt elsif b.hp < b.totalhp * 3 / 4 score += ally_amt @@ -160,7 +165,7 @@ Battle::AI::Handlers::MoveEffectScore.add("HealUserAndAlliesQuarterOfTotalHPCure ) Battle::AI::Handlers::MoveEffectScore.add("HealTargetHalfOfTotalHP", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| next 0 if user.opposes?(target) if target.hp < target.totalhp / 2 && target.effects[PBEffects::Substitute] == 0 score += 20 @@ -170,11 +175,12 @@ Battle::AI::Handlers::MoveEffectScore.add("HealTargetHalfOfTotalHP", ) Battle::AI::Handlers::MoveEffectScore.add("HealTargetDependingOnGrassyTerrain", - proc { |score, move, user, target, skill, ai, battle| - next 0 if user.hp == user.totalhp || (ai.skill_check(Battle::AI::AILevel.medium) && !user.canHeal?) + proc { |score, move, user, target, ai, battle| + next 0 if user.hp == user.totalhp || + (ai.trainer.medium_skill? && !user.battler.canHeal?) score += 50 score -= user.hp * 100 / user.totalhp - if ai.skill_check(Battle::AI::AILevel.medium) + if ai.trainer.medium_skill? score += 30 if battle.field.terrain == :Grassy end next score @@ -182,29 +188,29 @@ Battle::AI::Handlers::MoveEffectScore.add("HealTargetDependingOnGrassyTerrain", ) Battle::AI::Handlers::MoveEffectScore.add("HealUserPositionNextTurn", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| next 0 if battle.positions[user.index].effects[PBEffects::Wish] > 0 } ) Battle::AI::Handlers::MoveEffectScore.add("StartHealUserEachTurn", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| next 0 if user.effects[PBEffects::AquaRing] } ) Battle::AI::Handlers::MoveEffectScore.add("StartHealUserEachTurnTrapUserInBattle", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| next 0 if user.effects[PBEffects::Ingrain] } ) Battle::AI::Handlers::MoveEffectScore.add("StartDamageTargetEachTurnIfTargetAsleep", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if target.effects[PBEffects::Nightmare] || target.effects[PBEffects::Substitute] > 0 score -= 90 - elsif !target.asleep? + elsif !target.battler.asleep? score -= 90 else score -= 90 if target.statusCount <= 1 @@ -215,10 +221,10 @@ Battle::AI::Handlers::MoveEffectScore.add("StartDamageTargetEachTurnIfTargetAsle ) Battle::AI::Handlers::MoveEffectScore.add("StartLeechSeedTarget", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if target.effects[PBEffects::LeechSeed] >= 0 score -= 90 - elsif ai.skill_check(Battle::AI::AILevel.medium) && target.pbHasType?(:GRASS) + elsif target.has_type?(:GRASS) score -= 90 elsif user.turnCount == 0 score += 60 @@ -228,20 +234,20 @@ Battle::AI::Handlers::MoveEffectScore.add("StartLeechSeedTarget", ) Battle::AI::Handlers::MoveEffectScore.add("UserLosesHalfOfTotalHP", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| next 0 if user.hp <= user.totalhp / 2 } ) Battle::AI::Handlers::MoveEffectScore.add("UserLosesHalfOfTotalHPExplosive", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| reserves = battle.pbAbleNonActiveCount(user.idxOwnSide) foes = battle.pbAbleNonActiveCount(user.idxOpposingSide) if battle.pbCheckGlobalAbility(:DAMP) score -= 100 - elsif ai.skill_check(Battle::AI::AILevel.medium) && reserves == 0 && foes > 0 + elsif ai.trainer.medium_skill? && reserves == 0 && foes > 0 score -= 100 # don't want to lose - elsif ai.skill_check(Battle::AI::AILevel.high) && reserves == 0 && foes == 0 + elsif ai.trainer.high_skill? && reserves == 0 && foes == 0 score += 80 # want to draw else score -= (user.totalhp - user.hp) * 75 / user.totalhp @@ -251,14 +257,14 @@ Battle::AI::Handlers::MoveEffectScore.add("UserLosesHalfOfTotalHPExplosive", ) Battle::AI::Handlers::MoveEffectScore.add("UserFaintsExplosive", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| reserves = battle.pbAbleNonActiveCount(user.idxOwnSide) foes = battle.pbAbleNonActiveCount(user.idxOpposingSide) if battle.pbCheckGlobalAbility(:DAMP) score -= 100 - elsif ai.skill_check(Battle::AI::AILevel.medium) && reserves == 0 && foes > 0 + elsif ai.trainer.medium_skill? && reserves == 0 && foes > 0 score -= 100 # don't want to lose - elsif ai.skill_check(Battle::AI::AILevel.high) && reserves == 0 && foes == 0 + elsif ai.trainer.high_skill? && reserves == 0 && foes == 0 score += 80 # want to draw else score -= user.hp * 100 / user.totalhp @@ -268,14 +274,14 @@ Battle::AI::Handlers::MoveEffectScore.add("UserFaintsExplosive", ) Battle::AI::Handlers::MoveEffectScore.add("UserFaintsPowersUpInMistyTerrainExplosive", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| reserves = battle.pbAbleNonActiveCount(user.idxOwnSide) foes = battle.pbAbleNonActiveCount(user.idxOpposingSide) if battle.pbCheckGlobalAbility(:DAMP) score -= 100 - elsif ai.skill_check(Battle::AI::AILevel.medium) && reserves == 0 && foes > 0 + elsif ai.trainer.medium_skill? && reserves == 0 && foes > 0 score -= 100 # don't want to lose - elsif ai.skill_check(Battle::AI::AILevel.high) && reserves == 0 && foes == 0 + elsif ai.trainer.high_skill? && reserves == 0 && foes == 0 score += 40 # want to draw score += 40 if battle.field.terrain == :Misty else @@ -289,9 +295,9 @@ Battle::AI::Handlers::MoveEffectScore.add("UserFaintsPowersUpInMistyTerrainExplo # UserFaintsFixedDamageUserHP Battle::AI::Handlers::MoveEffectScore.add("UserFaintsLowerTargetAtkSpAtk2", - proc { |score, move, user, target, skill, ai, battle| - if !target.pbCanLowerStatStage?(:ATTACK, user) && - !target.pbCanLowerStatStage?(:SPECIAL_ATTACK, user) + proc { |score, move, user, target, ai, battle| + if !target.battler.pbCanLowerStatStage?(:ATTACK, user.battler) && + !target.battler.pbCanLowerStatStage?(:SPECIAL_ATTACK, user.battler) score -= 100 elsif battle.pbAbleNonActiveCount(user.idxOwnSide) == 0 score -= 100 @@ -305,7 +311,7 @@ Battle::AI::Handlers::MoveEffectScore.add("UserFaintsLowerTargetAtkSpAtk2", ) Battle::AI::Handlers::MoveEffectScore.add("UserFaintsHealAndCureReplacement", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| next score - 70 } ) @@ -314,7 +320,7 @@ Battle::AI::Handlers::MoveEffectScore.copy("UserFaintsHealAndCureReplacement", "UserFaintsHealAndCureReplacementRestorePP") Battle::AI::Handlers::MoveEffectScore.add("StartPerishCountsForAllBattlers", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if battle.pbAbleNonActiveCount(user.idxOwnSide) == 0 score -= 90 elsif target.effects[PBEffects::PerishSong] > 0 @@ -325,7 +331,7 @@ Battle::AI::Handlers::MoveEffectScore.add("StartPerishCountsForAllBattlers", ) Battle::AI::Handlers::MoveEffectScore.add("AttackerFaintsIfUserFaints", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| score += 50 score -= user.hp * 100 / user.totalhp score += 30 if user.hp <= user.totalhp / 10 @@ -334,7 +340,7 @@ Battle::AI::Handlers::MoveEffectScore.add("AttackerFaintsIfUserFaints", ) Battle::AI::Handlers::MoveEffectScore.add("SetAttackerMovePPTo0IfUserFaints", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| score += 50 score -= user.hp * 100 / user.totalhp score += 30 if user.hp <= user.totalhp / 10 diff --git a/Data/Scripts/011_Battle/005_AI/057_AI_MoveHandlers_Items.rb b/Data/Scripts/011_Battle/005_AI/057_AI_MoveHandlers_Items.rb index 12bc23ee9..7add4b991 100644 --- a/Data/Scripts/011_Battle/005_AI/057_AI_MoveHandlers_Items.rb +++ b/Data/Scripts/011_Battle/005_AI/057_AI_MoveHandlers_Items.rb @@ -2,8 +2,8 @@ # #=============================================================================== Battle::AI::Handlers::MoveEffectScore.add("UserTakesTargetItem", - proc { |score, move, user, target, skill, ai, battle| - if ai.skill_check(Battle::AI::AILevel.high) + proc { |score, move, user, target, ai, battle| + if ai.trainer.high_skill? if !user.item && target.item score += 40 else @@ -17,11 +17,11 @@ Battle::AI::Handlers::MoveEffectScore.add("UserTakesTargetItem", ) Battle::AI::Handlers::MoveEffectScore.add("TargetTakesUserItem", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if !user.item || target.item score -= 90 - elsif user.hasActiveItem?([:FLAMEORB, :TOXICORB, :STICKYBARB, :IRONBALL, - :CHOICEBAND, :CHOICESCARF, :CHOICESPECS]) + elsif user.has_active_item?([:FLAMEORB, :TOXICORB, :STICKYBARB, :IRONBALL, + :CHOICEBAND, :CHOICESCARF, :CHOICESPECS]) score += 50 else score -= 80 @@ -31,27 +31,27 @@ Battle::AI::Handlers::MoveEffectScore.add("TargetTakesUserItem", ) Battle::AI::Handlers::MoveEffectScore.add("UserTargetSwapItems", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if !user.item && !target.item score -= 90 - elsif ai.skill_check(Battle::AI::AILevel.high) && target.hasActiveAbility?(:STICKYHOLD) + elsif target.has_active_ability?(:STICKYHOLD) score -= 90 - elsif user.hasActiveItem?([:FLAMEORB, :TOXICORB, :STICKYBARB, :IRONBALL, - :CHOICEBAND, :CHOICESCARF, :CHOICESPECS]) + elsif user.has_active_item?([:FLAMEORB, :TOXICORB, :STICKYBARB, :IRONBALL, + :CHOICEBAND, :CHOICESCARF, :CHOICESPECS]) score += 50 elsif !user.item && target.item - score -= 30 if user.lastMoveUsed && - GameData::Move.get(user.lastMoveUsed).function_code == "UserTargetSwapItems" + score -= 30 if user.battler.lastMoveUsed && + GameData::Move.get(user.battler.lastMoveUsed).function_code == "UserTargetSwapItems" end next score } ) Battle::AI::Handlers::MoveEffectScore.add("RestoreUserConsumedItem", - proc { |score, move, user, target, skill, ai, battle| - if !user.recycleItem || user.item + proc { |score, move, user, target, ai, battle| + if !user.battler.recycleItem || user.item score -= 80 - elsif user.recycleItem + elsif user.battler.recycleItem score += 30 end next score @@ -59,8 +59,8 @@ Battle::AI::Handlers::MoveEffectScore.add("RestoreUserConsumedItem", ) Battle::AI::Handlers::MoveEffectScore.add("RemoveTargetItem", - proc { |score, move, user, target, skill, ai, battle| - if ai.skill_check(Battle::AI::AILevel.high) + proc { |score, move, user, target, ai, battle| + if ai.trainer.high_skill? score += 20 if target.item end next score @@ -68,9 +68,9 @@ Battle::AI::Handlers::MoveEffectScore.add("RemoveTargetItem", ) Battle::AI::Handlers::MoveEffectScore.add("DestroyTargetBerryOrGem", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if target.effects[PBEffects::Substitute] == 0 - if ai.skill_check(Battle::AI::AILevel.high) && target.item && target.item.is_berry? + if ai.trainer.high_skill? && target.item && target.item.is_berry? score += 30 end end @@ -79,11 +79,11 @@ Battle::AI::Handlers::MoveEffectScore.add("DestroyTargetBerryOrGem", ) Battle::AI::Handlers::MoveEffectScore.add("CorrodeTargetItem", - proc { |score, move, user, target, skill, ai, battle| - if battle.corrosiveGas[target.index % 2][target.pokemonIndex] + proc { |score, move, user, target, ai, battle| + if battle.corrosiveGas[target.side][target.party_index] score -= 100 - elsif !target.item || !target.itemActive? || target.unlosableItem?(target.item) || - target.hasActiveAbility?(:STICKYHOLD) + elsif !target.item || !target.item_active? || target.battler.unlosableItem?(target.item) || + target.has_active_ability?(:STICKYHOLD) score -= 90 elsif target.effects[PBEffects::Substitute] > 0 score -= 90 @@ -95,24 +95,24 @@ Battle::AI::Handlers::MoveEffectScore.add("CorrodeTargetItem", ) Battle::AI::Handlers::MoveEffectScore.add("StartTargetCannotUseItem", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| next 0 if target.effects[PBEffects::Embargo] > 0 } ) Battle::AI::Handlers::MoveEffectScore.add("StartNegateHeldItems", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| next 0 if battle.field.effects[PBEffects::MagicRoom] > 0 next score + 30 if !user.item && target.item } ) Battle::AI::Handlers::MoveEffectScore.add("UserConsumeBerryRaiseDefense2", - proc { |score, move, user, target, skill, ai, battle| - if !user.item || !user.item.is_berry? || !user.itemActive? + proc { |score, move, user, target, ai, battle| + if !user.item || !user.item.is_berry? || !user.item_active? score -= 100 else - if ai.skill_check(Battle::AI::AILevel.high) + if ai.trainer.high_skill? useful_berries = [ :ORANBERRY, :SITRUSBERRY, :AGUAVBERRY, :APICOTBERRY, :CHERIBERRY, :CHESTOBERRY, :FIGYBERRY, :GANLONBERRY, :IAPAPABERRY, :KEEBERRY, @@ -122,11 +122,12 @@ Battle::AI::Handlers::MoveEffectScore.add("UserConsumeBerryRaiseDefense2", ] score += 30 if useful_berries.include?(user.item_id) end - if ai.skill_check(Battle::AI::AILevel.medium) - score += 20 if user.canHeal? && user.hp < user.totalhp / 3 && user.hasActiveAbility?(:CHEEKPOUCH) - score += 20 if user.hasActiveAbility?([:HARVEST, :RIPEN]) || - user.pbHasMoveFunction?("RestoreUserConsumedItem") # Recycle - score += 20 if !user.canConsumeBerry? + if ai.trainer.medium_skill? + score += 20 if user.battler.canHeal? && user.hp < user.totalhp / 3 && + user.has_active_ability?(:CHEEKPOUCH) + score += 20 if user.has_active_ability?([:HARVEST, :RIPEN]) || + user.battler.pbHasMoveFunction?("RestoreUserConsumedItem") # Recycle + score += 20 if !user.battler.canConsumeBerry? end score -= user.stages[:DEFENSE] * 20 end @@ -135,7 +136,7 @@ Battle::AI::Handlers::MoveEffectScore.add("UserConsumeBerryRaiseDefense2", ) Battle::AI::Handlers::MoveEffectScore.add("AllBattlersConsumeBerry", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| useful_berries = [ :ORANBERRY, :SITRUSBERRY, :AGUAVBERRY, :APICOTBERRY, :CHERIBERRY, :CHESTOBERRY, :FIGYBERRY, :GANLONBERRY, :IAPAPABERRY, :KEEBERRY, @@ -147,11 +148,11 @@ Battle::AI::Handlers::MoveEffectScore.add("AllBattlersConsumeBerry", if !b.item || !b.item.is_berry? || !b.itemActive? score -= 100 / battle.pbSideSize(user.index) else - if ai.skill_check(Battle::AI::AILevel.high) + if ai.trainer.high_skill? amt = 30 / battle.pbSideSize(user.index) score += amt if useful_berries.include?(b.item_id) end - if ai.skill_check(Battle::AI::AILevel.medium) + if ai.trainer.medium_skill? amt = 20 / battle.pbSideSize(user.index) score += amt if b.canHeal? && b.hp < b.totalhp / 3 && b.hasActiveAbility?(:CHEEKPOUCH) score += amt if b.hasActiveAbility?([:HARVEST, :RIPEN]) || @@ -160,7 +161,7 @@ Battle::AI::Handlers::MoveEffectScore.add("AllBattlersConsumeBerry", end end end - if ai.skill_check(Battle::AI::AILevel.high) + if ai.trainer.high_skill? battle.allOtherSideBattlers(user.index).each do |b| amt = 10 / battle.pbSideSize(target.index) score -= amt if b.hasActiveItem?(useful_berries) @@ -175,9 +176,9 @@ Battle::AI::Handlers::MoveEffectScore.add("AllBattlersConsumeBerry", ) Battle::AI::Handlers::MoveEffectScore.add("UserConsumeTargetBerry", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if target.effects[PBEffects::Substitute] == 0 - if ai.skill_check(Battle::AI::AILevel.high) && target.item && target.item.is_berry? + if ai.trainer.high_skill? && target.item && target.item.is_berry? score += 30 end end @@ -186,8 +187,8 @@ Battle::AI::Handlers::MoveEffectScore.add("UserConsumeTargetBerry", ) Battle::AI::Handlers::MoveEffectScore.add("ThrowUserItemAtTarget", - proc { |score, move, user, target, skill, ai, battle| - next 0 if !user.item || !user.itemActive? || - user.unlosableItem?(user.item) || user.item.is_poke_ball? + proc { |score, move, user, target, ai, battle| + next 0 if !user.item || !user.item_active? || + user.battler.unlosableItem?(user.item) || user.item.is_poke_ball? } ) diff --git a/Data/Scripts/011_Battle/005_AI/058_AI_MoveHandlers_ChangeMoveEffect.rb b/Data/Scripts/011_Battle/005_AI/058_AI_MoveHandlers_ChangeMoveEffect.rb index 399b34488..bd9d16487 100644 --- a/Data/Scripts/011_Battle/005_AI/058_AI_MoveHandlers_ChangeMoveEffect.rb +++ b/Data/Scripts/011_Battle/005_AI/058_AI_MoveHandlers_ChangeMoveEffect.rb @@ -2,21 +2,21 @@ # #=============================================================================== Battle::AI::Handlers::MoveEffectScore.add("RedirectAllMovesToUser", - proc { |score, move, user, target, skill, ai, battle| - next 0 if user.allAllies.length == 0 + proc { |score, move, user, target, ai, battle| + next 0 if user.battler.allAllies.length == 0 } ) Battle::AI::Handlers::MoveEffectScore.add("RedirectAllMovesToTarget", - proc { |score, move, user, target, skill, ai, battle| - next 0 if user.allAllies.length == 0 + proc { |score, move, user, target, ai, battle| + next 0 if user.battler.allAllies.length == 0 } ) Battle::AI::Handlers::MoveEffectScore.add("CannotBeRedirected", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| redirection = false - user.allOpposing.each do |b| + user.battler.allOpposing.each do |b| next if b.index == target.index if b.effects[PBEffects::RagePowder] || b.effects[PBEffects::Spotlight] > 0 || @@ -27,7 +27,7 @@ Battle::AI::Handlers::MoveEffectScore.add("CannotBeRedirected", break end end - score += 50 if redirection && ai.skill_check(Battle::AI::AILevel.medium) + score += 50 if redirection && ai.trainer.medium_skill? next score } ) @@ -35,9 +35,9 @@ Battle::AI::Handlers::MoveEffectScore.add("CannotBeRedirected", # RandomlyDamageOrHealTarget Battle::AI::Handlers::MoveEffectScore.add("HealAllyOrDamageFoe", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if !target.opposes?(user) - if target.hp == target.totalhp || (ai.skill_check(Battle::AI::AILevel.medium) && !target.canHeal?) + if target.hp == target.totalhp || (ai.trainer.medium_skill? && !target.battler.canHeal?) score -= 90 else score += 50 @@ -49,8 +49,8 @@ Battle::AI::Handlers::MoveEffectScore.add("HealAllyOrDamageFoe", ) Battle::AI::Handlers::MoveEffectScore.add("CurseTargetOrLowerUserSpd1RaiseUserAtkDef1", - proc { |score, move, user, target, skill, ai, battle| - if user.pbHasType?(:GHOST) + proc { |score, move, user, target, ai, battle| + if user.has_type?(:GHOST) if target.effects[PBEffects::Curse] score -= 90 elsif user.hp <= user.totalhp / 2 @@ -74,18 +74,18 @@ Battle::AI::Handlers::MoveEffectScore.add("CurseTargetOrLowerUserSpd1RaiseUserAt # EffectDependsOnEnvironment Battle::AI::Handlers::MoveEffectScore.add("HitsAllFoesAndPowersUpInPsychicTerrain", - proc { |score, move, user, target, skill, ai, battle| - next score + 40 if battle.field.terrain == :Psychic && user.affectedByTerrain? + proc { |score, move, user, target, ai, battle| + next score + 40 if battle.field.terrain == :Psychic && user.battler.affectedByTerrain? } ) Battle::AI::Handlers::MoveEffectScore.add("TargetNextFireMoveDamagesTarget", - proc { |score, move, user, target, skill, ai, battle| - aspeed = pbRoughStat(user, :SPEED) - ospeed = pbRoughStat(target, :SPEED) + proc { |score, move, user, target, ai, battle| + aspeed = user.rough_stat(:SPEED) + ospeed = target.rough_stat(:SPEED) if aspeed > ospeed score -= 90 - elsif target.pbHasMoveType?(:FIRE) + elsif target.battler.pbHasMoveType?(:FIRE) score += 30 end next score @@ -97,23 +97,23 @@ Battle::AI::Handlers::MoveEffectScore.add("TargetNextFireMoveDamagesTarget", # DoublePowerAfterFusionBolt Battle::AI::Handlers::MoveEffectScore.add("PowerUpAllyMove", - proc { |score, move, user, target, skill, ai, battle| - next 0 if user.allAllies.empty? + proc { |score, move, user, target, ai, battle| + next 0 if user.battler.allAllies.empty? next score + 30 } ) Battle::AI::Handlers::MoveEffectScore.add("CounterPhysicalDamage", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if target.effects[PBEffects::HyperBeam] > 0 score -= 90 else - attack = pbRoughStat(user, :ATTACK) - spatk = pbRoughStat(user, :SPECIAL_ATTACK) + attack = user.rough_stat(:ATTACK) + spatk = user.rough_stat(:SPECIAL_ATTACK) if attack * 1.5 < spatk score -= 60 - elsif ai.skill_check(Battle::AI::AILevel.medium) && target.lastMoveUsed - moveData = GameData::Move.get(target.lastMoveUsed) + elsif ai.trainer.medium_skill? && target.battler.lastMoveUsed + moveData = GameData::Move.get(target.battler.lastMoveUsed) score += 60 if moveData.physical? end end @@ -122,16 +122,16 @@ Battle::AI::Handlers::MoveEffectScore.add("CounterPhysicalDamage", ) Battle::AI::Handlers::MoveEffectScore.add("CounterSpecialDamage", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if target.effects[PBEffects::HyperBeam] > 0 score -= 90 else - attack = pbRoughStat(user, :ATTACK) - spatk = pbRoughStat(user, :SPECIAL_ATTACK) + attack = user.rough_stat(:ATTACK) + spatk = user.rough_stat(:SPECIAL_ATTACK) if attack > spatk * 1.5 score -= 60 - elsif ai.skill_check(Battle::AI::AILevel.medium) && target.lastMoveUsed - moveData = GameData::Move.get(target.lastMoveUsed) + elsif ai.trainer.medium_skill? && target.battler.lastMoveUsed + moveData = GameData::Move.get(target.battler.lastMoveUsed) score += 60 if moveData.special? end end @@ -140,21 +140,21 @@ Battle::AI::Handlers::MoveEffectScore.add("CounterSpecialDamage", ) Battle::AI::Handlers::MoveEffectScore.add("CounterDamagePlusHalf", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| next score - 90 if target.effects[PBEffects::HyperBeam] > 0 } ) Battle::AI::Handlers::MoveEffectScore.add("UserAddStockpileRaiseDefSpDef1", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| avg = 0 avg -= user.stages[:DEFENSE] * 10 avg -= user.stages[:SPECIAL_DEFENSE] * 10 score += avg / 2 if user.effects[PBEffects::Stockpile] >= 3 score -= 80 - elsif user.pbHasMoveFunction?("PowerDependsOnUserStockpile", - "HealUserDependingOnUserStockpile") # Spit Up, Swallow + elsif user.battler.pbHasMoveFunction?("PowerDependsOnUserStockpile", + "HealUserDependingOnUserStockpile") # Spit Up, Swallow score += 20 # More preferable if user also has Spit Up/Swallow end next score @@ -162,13 +162,13 @@ Battle::AI::Handlers::MoveEffectScore.add("UserAddStockpileRaiseDefSpDef1", ) Battle::AI::Handlers::MoveEffectScore.add("PowerDependsOnUserStockpile", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| next 0 if user.effects[PBEffects::Stockpile] == 0 } ) Battle::AI::Handlers::MoveEffectScore.add("HealUserDependingOnUserStockpile", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| next 0 if user.effects[PBEffects::Stockpile] == 0 next 0 if user.hp == user.totalhp mult = [0, 25, 50, 100][user.effects[PBEffects::Stockpile]] @@ -187,11 +187,11 @@ Battle::AI::Handlers::MoveEffectScore.add("HealUserDependingOnUserStockpile", # UseLastMoveUsed Battle::AI::Handlers::MoveEffectScore.add("UseLastMoveUsedByTarget", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| score -= 40 - if ai.skill_check(Battle::AI::AILevel.high) - score -= 100 if !target.lastRegularMoveUsed || - GameData::Move.get(target.lastRegularMoveUsed).flags.none? { |f| f[/^CanMirrorMove$/i] } + if ai.trainer.high_skill? + score -= 100 if !target.battler.lastRegularMoveUsed || + GameData::Move.get(target.battler.lastRegularMoveUsed).flags.none? { |f| f[/^CanMirrorMove$/i] } end next score } @@ -206,8 +206,8 @@ Battle::AI::Handlers::MoveEffectScore.add("UseLastMoveUsedByTarget", # UseRandomMoveFromUserParty Battle::AI::Handlers::MoveEffectScore.add("UseRandomUserMoveIfAsleep", - proc { |score, move, user, target, skill, ai, battle| - if user.asleep? + proc { |score, move, user, target, ai, battle| + if user.battler.asleep? score += 100 # Because it can only be used while asleep else score -= 90 @@ -221,23 +221,23 @@ Battle::AI::Handlers::MoveEffectScore.add("UseRandomUserMoveIfAsleep", # StealAndUseBeneficialStatusMove Battle::AI::Handlers::MoveEffectScore.add("ReplaceMoveThisBattleWithTargetLastMoveUsed", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| moveBlacklist = [ "Struggle", # Struggle "ReplaceMoveThisBattleWithTargetLastMoveUsed", # Mimic "ReplaceMoveWithTargetLastMoveUsed", # Sketch "UseRandomMove" # Metronome ] - if user.effects[PBEffects::Transform] || !target.lastRegularMoveUsed + if user.effects[PBEffects::Transform] || !target.battler.lastRegularMoveUsed score -= 90 else - lastMoveData = GameData::Move.get(target.lastRegularMoveUsed) + lastMoveData = GameData::Move.get(target.battler.lastRegularMoveUsed) if moveBlacklist.include?(lastMoveData.function_code) || lastMoveData.type == :SHADOW score -= 90 end - user.eachMove do |m| - next if m != target.lastRegularMoveUsed + user.battler.eachMove do |m| + next if m != target.battler.lastRegularMoveUsed score -= 90 break end @@ -247,21 +247,21 @@ Battle::AI::Handlers::MoveEffectScore.add("ReplaceMoveThisBattleWithTargetLastMo ) Battle::AI::Handlers::MoveEffectScore.add("ReplaceMoveWithTargetLastMoveUsed", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| moveBlacklist = [ "Struggle", # Struggle "ReplaceMoveWithTargetLastMoveUsed" # Sketch ] - if user.effects[PBEffects::Transform] || !target.lastRegularMoveUsed + if user.effects[PBEffects::Transform] || !target.battler.lastRegularMoveUsed score -= 90 else - lastMoveData = GameData::Move.get(target.lastRegularMoveUsed) + lastMoveData = GameData::Move.get(target.battler.lastRegularMoveUsed) if moveBlacklist.include?(lastMoveData.function_code) || lastMoveData.type == :SHADOW score -= 90 end - user.eachMove do |m| - next if m != target.lastRegularMoveUsed + user.battler.eachMove do |m| + next if m != target.battler.lastRegularMoveUsed score -= 90 # User already knows the move that will be Sketched break end diff --git a/Data/Scripts/011_Battle/005_AI/059_AI_MoveHandlers_SwitchingActing.rb b/Data/Scripts/011_Battle/005_AI/059_AI_MoveHandlers_SwitchingActing.rb index 499df268d..c65cf26a2 100644 --- a/Data/Scripts/011_Battle/005_AI/059_AI_MoveHandlers_SwitchingActing.rb +++ b/Data/Scripts/011_Battle/005_AI/059_AI_MoveHandlers_SwitchingActing.rb @@ -2,13 +2,13 @@ # #=============================================================================== Battle::AI::Handlers::MoveEffectScore.add("FleeFromBattle", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| next 0 if battle.trainerBattle? } ) Battle::AI::Handlers::MoveEffectScore.add("SwitchOutUserStatusMove", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if !battle.pbCanChooseNonActive?(user.index) || battle.pbTeamAbleNonActiveCount(user.index) > 1 # Don't switch in ace score -= 100 @@ -22,7 +22,7 @@ Battle::AI::Handlers::MoveEffectScore.add("SwitchOutUserStatusMove", score -= total * 10 # special case: user has no damaging moves hasDamagingMove = false - user.eachMove do |m| + user.battler.eachMove do |m| next if !m.damagingMove? hasDamagingMove = true break @@ -35,14 +35,14 @@ Battle::AI::Handlers::MoveEffectScore.add("SwitchOutUserStatusMove", ) Battle::AI::Handlers::MoveEffectScore.add("SwitchOutUserDamagingMove", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| next 0 if !battle.pbCanChooseNonActive?(user.index) || battle.pbTeamAbleNonActiveCount(user.index) > 1 # Don't switch in ace } ) Battle::AI::Handlers::MoveEffectScore.add("LowerTargetAtkSpAtk1SwitchOutUser", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| avg = target.stages[:ATTACK] * 10 avg += target.stages[:SPECIAL_ATTACK] * 10 score += avg / 2 @@ -51,7 +51,7 @@ Battle::AI::Handlers::MoveEffectScore.add("LowerTargetAtkSpAtk1SwitchOutUser", ) Battle::AI::Handlers::MoveEffectScore.add("SwitchOutUserPassOnEffects", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if battle.pbCanChooseNonActive?(user.index) score -= 40 if user.effects[PBEffects::Confusion] > 0 total = 0 @@ -62,7 +62,7 @@ Battle::AI::Handlers::MoveEffectScore.add("SwitchOutUserPassOnEffects", score += total * 10 # special case: user has no damaging moves hasDamagingMove = false - user.eachMove do |m| + user.battler.eachMove do |m| next if !m.damagingMove? hasDamagingMove = true break @@ -77,9 +77,9 @@ Battle::AI::Handlers::MoveEffectScore.add("SwitchOutUserPassOnEffects", ) Battle::AI::Handlers::MoveEffectScore.add("SwitchOutTargetStatusMove", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if target.effects[PBEffects::Ingrain] || - (ai.skill_check(Battle::AI::AILevel.high) && target.hasActiveAbility?(:SUCTIONCUPS)) + target.has_active_ability?(:SUCTIONCUPS) score -= 90 else ch = 0 @@ -98,9 +98,9 @@ Battle::AI::Handlers::MoveEffectScore.add("SwitchOutTargetStatusMove", ) Battle::AI::Handlers::MoveEffectScore.add("SwitchOutTargetDamagingMove", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if !target.effects[PBEffects::Ingrain] && - !(ai.skill_check(Battle::AI::AILevel.high) && target.hasActiveAbility?(:SUCTIONCUPS)) + !target.has_active_ability?(:SUCTIONCUPS) score += 40 if target.pbOwnSide.effects[PBEffects::Spikes] > 0 score += 40 if target.pbOwnSide.effects[PBEffects::ToxicSpikes] > 0 score += 40 if target.pbOwnSide.effects[PBEffects::StealthRock] @@ -110,37 +110,37 @@ Battle::AI::Handlers::MoveEffectScore.add("SwitchOutTargetDamagingMove", ) Battle::AI::Handlers::MoveEffectScore.add("BindTarget", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| next score + 40 if target.effects[PBEffects::Trapping] == 0 } ) Battle::AI::Handlers::MoveEffectScore.add("BindTargetDoublePowerIfTargetUnderwater", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| next score + 40 if target.effects[PBEffects::Trapping] == 0 } ) Battle::AI::Handlers::MoveEffectScore.add("TrapTargetInBattle", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| next 0 if target.effects[PBEffects::MeanLook] >= 0 } ) Battle::AI::Handlers::MoveEffectScore.add("TrapTargetInBattleLowerTargetDefSpDef1EachTurn", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| next 0 if target.effects[PBEffects::Octolock] >= 0 - score += 30 if !target.trappedInBattle? - score -= 100 if !target.pbCanLowerStatStage?(:DEFENSE, user, move) && - !target.pbCanLowerStatStage?(:SPECIAL_DEFENSE, user, move) + score += 30 if !target.battler.trappedInBattle? + score -= 100 if !target.battler.pbCanLowerStatStage?(:DEFENSE, user.battler, move.move) && + !target.battler.pbCanLowerStatStage?(:SPECIAL_DEFENSE, user.battler, move.move) next score } ) Battle::AI::Handlers::MoveEffectScore.add("TrapUserAndTargetInBattle", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| if target.effects[PBEffects::JawLock] < 0 - score += 40 if !user.trappedInBattle? && !target.trappedInBattle? + score += 40 if !user.battler.trappedInBattle? && !target.battler.trappedInBattle? end next score } @@ -151,10 +151,10 @@ Battle::AI::Handlers::MoveEffectScore.add("TrapUserAndTargetInBattle", # PursueSwitchingFoe Battle::AI::Handlers::MoveEffectScore.add("UsedAfterUserTakesPhysicalDamage", - proc { |score, move, user, target, skill, ai, battle| - if ai.skill_check(Battle::AI::AILevel.medium) + proc { |score, move, user, target, ai, battle| + if ai.trainer.medium_skill? hasPhysicalAttack = false - target.eachMove do |m| + target.battler.eachMove do |m| next if !m.physicalMove?(m.type) hasPhysicalAttack = true break @@ -166,9 +166,9 @@ Battle::AI::Handlers::MoveEffectScore.add("UsedAfterUserTakesPhysicalDamage", ) Battle::AI::Handlers::MoveEffectScore.add("UsedAfterAllyRoundWithDoublePower", - proc { |score, move, user, target, skill, ai, battle| - if ai.skill_check(Battle::AI::AILevel.medium) - user.allAllies.each do |b| + proc { |score, move, user, target, ai, battle| + if ai.trainer.medium_skill? + user.battler.allAllies.each do |b| next if !b.pbHasMove?(move.id) score += 20 end @@ -182,11 +182,11 @@ Battle::AI::Handlers::MoveEffectScore.add("UsedAfterAllyRoundWithDoublePower", # TargetActsLast Battle::AI::Handlers::MoveEffectScore.add("TargetUsesItsLastUsedMoveAgain", - proc { |score, move, user, target, skill, ai, battle| - if ai.skill_check(Battle::AI::AILevel.medium) - if !target.lastRegularMoveUsed || - !target.pbHasMove?(target.lastRegularMoveUsed) || - target.usingMultiTurnAttack? + proc { |score, move, user, target, ai, battle| + if ai.trainer.medium_skill? + if !target.battler.lastRegularMoveUsed || + !target.battler.pbHasMove?(target.battler.lastRegularMoveUsed) || + target.battler.usingMultiTurnAttack? score -= 90 else # Without lots of code here to determine good/bad moves and relative @@ -201,19 +201,17 @@ Battle::AI::Handlers::MoveEffectScore.add("TargetUsesItsLastUsedMoveAgain", # StartSlowerBattlersActFirst Battle::AI::Handlers::MoveEffectScore.add("HigherPriorityInGrassyTerrain", - proc { |score, move, user, target, skill, ai, battle| - if ai.skill_check(Battle::AI::AILevel.medium) && @battle.field.terrain == :Grassy - aspeed = pbRoughStat(user, :SPEED) - ospeed = pbRoughStat(target, :SPEED) - score += 40 if aspeed < ospeed + proc { |score, move, user, target, ai, battle| + if ai.trainer.medium_skill? && @battle.field.terrain == :Grassy + score += 40 if target.faster_than?(user) end next score } ) Battle::AI::Handlers::MoveEffectScore.add("LowerPPOfTargetLastMoveBy3", - proc { |score, move, user, target, skill, ai, battle| - last_move = target.pbGetMoveWithID(target.lastRegularMoveUsed) + proc { |score, move, user, target, ai, battle| + last_move = target.battler.pbGetMoveWithID(target.battler.lastRegularMoveUsed) if last_move && last_move.total_pp > 0 && last_move.pp <= 3 score += 50 end @@ -222,38 +220,36 @@ Battle::AI::Handlers::MoveEffectScore.add("LowerPPOfTargetLastMoveBy3", ) Battle::AI::Handlers::MoveEffectScore.add("LowerPPOfTargetLastMoveBy4", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| next score - 40 } ) Battle::AI::Handlers::MoveEffectScore.add("DisableTargetLastMoveUsed", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| next 0 if target.effects[PBEffects::Disable] > 0 } ) Battle::AI::Handlers::MoveEffectScore.add("DisableTargetUsingSameMoveConsecutively", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| next 0 if target.effects[PBEffects::Torment] } ) Battle::AI::Handlers::MoveEffectScore.add("DisableTargetUsingDifferentMove", - proc { |score, move, user, target, skill, ai, battle| - aspeed = pbRoughStat(user, :SPEED) - ospeed = pbRoughStat(target, :SPEED) + proc { |score, move, user, target, ai, battle| if target.effects[PBEffects::Encore] > 0 score -= 90 - elsif aspeed > ospeed - if target.lastRegularMoveUsed - moveData = GameData::Move.get(target.lastRegularMoveUsed) + elsif user.faster_than?(target) + if target.battler.lastRegularMoveUsed + moveData = GameData::Move.get(target.battler.lastRegularMoveUsed) if moveData.category == 2 && # Status move [:User, :BothSides].include?(moveData.target) score += 60 elsif moveData.category != 2 && # Damaging move moveData.target == :NearOther && - Effectiveness.ineffective?(pbCalcTypeMod(moveData.type, target, user)) + Effectiveness.ineffective?(user.effectiveness_of_type_against_battler(moveData.type, target)) score += 60 end else @@ -265,22 +261,22 @@ Battle::AI::Handlers::MoveEffectScore.add("DisableTargetUsingDifferentMove", ) Battle::AI::Handlers::MoveEffectScore.add("DisableTargetStatusMoves", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| next 0 if target.effects[PBEffects::Taunt] > 0 } ) Battle::AI::Handlers::MoveEffectScore.add("DisableTargetHealingMoves", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| next 0 if target.effects[PBEffects::HealBlock] > 0 } ) Battle::AI::Handlers::MoveEffectScore.add("DisableTargetSoundMoves", - proc { |score, move, user, target, skill, ai, battle| - if target.effects[PBEffects::ThroatChop] == 0 && ai.skill_check(Battle::AI::AILevel.high) + proc { |score, move, user, target, ai, battle| + if target.effects[PBEffects::ThroatChop] == 0 && ai.trainer.high_skill? hasSoundMove = false - user.eachMove do |m| + user.battler.eachMove do |m| next if !m.soundMove? hasSoundMove = true break @@ -292,13 +288,13 @@ Battle::AI::Handlers::MoveEffectScore.add("DisableTargetSoundMoves", ) Battle::AI::Handlers::MoveEffectScore.add("DisableTargetMovesKnownByUser", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| next 0 if target.effects[PBEffects::Imprison] } ) Battle::AI::Handlers::MoveEffectScore.add("AllBattlersLoseHalfHPUserSkipsNextTurn", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| score += 20 # Shadow moves are more preferable score += 20 if target.hp >= target.totalhp / 2 score -= 20 if user.hp < user.hp / 2 @@ -307,7 +303,7 @@ Battle::AI::Handlers::MoveEffectScore.add("AllBattlersLoseHalfHPUserSkipsNextTur ) Battle::AI::Handlers::MoveEffectScore.add("AllBattlersLoseHalfHPUserSkipsNextTurn", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| score += 20 # Shadow moves are more preferable score -= 40 next score @@ -315,7 +311,7 @@ Battle::AI::Handlers::MoveEffectScore.add("AllBattlersLoseHalfHPUserSkipsNextTur ) Battle::AI::Handlers::MoveEffectScore.add("StartShadowSkyWeather", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| score += 20 # Shadow moves are more preferable if battle.pbCheckGlobalAbility(:AIRLOCK) || battle.pbCheckGlobalAbility(:CLOUDNINE) @@ -328,7 +324,7 @@ Battle::AI::Handlers::MoveEffectScore.add("StartShadowSkyWeather", ) Battle::AI::Handlers::MoveEffectScore.add("RemoveAllScreens", - proc { |score, move, user, target, skill, ai, battle| + proc { |score, move, user, target, ai, battle| score += 20 # Shadow moves are more preferable if target.pbOwnSide.effects[PBEffects::AuroraVeil] > 0 || target.pbOwnSide.effects[PBEffects::Reflect] > 0 || diff --git a/Data/Scripts/011_Battle/005_AI/101_AITrainer.rb b/Data/Scripts/011_Battle/005_AI/101_AITrainer.rb new file mode 100644 index 000000000..9b556d6bb --- /dev/null +++ b/Data/Scripts/011_Battle/005_AI/101_AITrainer.rb @@ -0,0 +1,53 @@ +#=============================================================================== +# AI skill levels: +# 0: Wild Pokémon +# 1-31: Basic trainer (young/inexperienced) +# 32-47: Medium skill +# 48-99: High skill +# 100+: Best skill (Gym Leaders, Elite Four, Champion) +# NOTE: A trainer's skill value can range from 0-255, but by default only four +# distinct skill levels exist. The skill value is typically the same as +# the trainer's base money value. +# +# Skill flags: +#=============================================================================== +class Battle::AI::AITrainer + attr_reader :side, :trainer_index + attr_reader :skill + + def initialize(ai, side, index, trainer) + @ai = ai + @side = side + @trainer_index = index + @trainer = trainer + + @skill = 0 + @skill_flags = [] + set_up_skill + end + + def set_up_skill + return if !@trainer + @skill = @trainer.skill_level + # TODO: Add skill flags depending on @skill. + end + + def has_skill_flag?(flag) + return @skill_flags.include?(flag) + end + + # TODO: This will eventually be replaced by something else, maybe skill flags. + def medium_skill? + return @skill >= 32 + end + + # TODO: This will eventually be replaced by something else, maybe skill flags. + def high_skill? + return @skill >= 48 + end + + # TODO: This will eventually be replaced by something else, maybe skill flags. + def best_skill? + return @skill >= 100 + end +end diff --git a/Data/Scripts/011_Battle/005_AI/102_AIBattler.rb b/Data/Scripts/011_Battle/005_AI/102_AIBattler.rb new file mode 100644 index 000000000..68fbe3bfc --- /dev/null +++ b/Data/Scripts/011_Battle/005_AI/102_AIBattler.rb @@ -0,0 +1,239 @@ +#=============================================================================== +# +#=============================================================================== +class Battle::AI::AIBattler + attr_reader :index, :side, :party_index + attr_reader :battler + + def initialize(ai, index) + @ai = ai + @index = index + @side = (@ai.battle.opposes?(@index)) ? 1 : 0 + refresh_battler + end + + def refresh_battler + old_party_index = @party_index + @battler = @ai.battle.battlers[@index] + @party_index = @battler.pokemonIndex + if @party_index != old_party_index + # TODO: Start of battle or Pokémon switched/shifted; recalculate roles, + # etc. + end + end + + def level; return @battler.level; end + def hp; return @battler.hp; end + def status; return @Battler.status; end + def statusCount; return @battler.statusCount; end + def totalhp; return @battler.totalhp; end + def gender; return @battler.gender; end + def turnCount; return @battler.turnCount; end + def effects; return @battler.effects; end + def stages; return @battler.stages; end + def statStageAtMax?(stat); return @battler.statStageAtMax?(stat); end + def statStageAtMin?(stat); return @battler.statStageAtMin?(stat); end + + def wild? + return @ai.battle.wildBattle? && opposes? + end + + def opposes?(other = nil) + return @side == 1 if other.nil? + return other.side != @side + end + + def idxOwnSide; return @battler.idxOwnSide; end + def pbOwnSide; return @battler.pbOwnSide; end + def idxOpposingSide; return @battler.idxOpposingSide; end + def pbOpposingSide; return @battler.pbOpposingSide; end + + def faster_than?(other) + return false if other.nil? + this_speed = rough_stat(:SPEED) + other_speed = other.rough_stat(:SPEED) + return (this_speed > other_speed) ^ (@ai.battle.field.effects[PBEffects::TrickRoom] > 0) + end + + #============================================================================= + + def speed; return @battler.speed; end + + # TODO: Cache calculated rough stats? Forget them in def refresh_battler. + def rough_stat(stat) + return @battler.pbSpeed if stat == :SPEED && @ai.trainer.high_skill? + stageMul = [2, 2, 2, 2, 2, 2, 2, 3, 4, 5, 6, 7, 8] + stageDiv = [8, 7, 6, 5, 4, 3, 2, 2, 2, 2, 2, 2, 2] + stage = @battler.stages[stat] + 6 + value = 0 + case stat + when :ATTACK then value = @battler.attack + when :DEFENSE then value = @battler.defense + when :SPECIAL_ATTACK then value = @battler.spatk + when :SPECIAL_DEFENSE then value = @battler.spdef + when :SPEED then value = @battler.speed + end + return (value.to_f * stageMul[stage] / stageDiv[stage]).floor + end + + #============================================================================= + + def types; return @battler.types; end + + def has_type?(type) + return @battler.pbHasType?(type) + end + + def effectiveness_of_type_against_battler(type, user = nil) + return Effectiveness::NORMAL_EFFECTIVE if !type + return Effectiveness::NORMAL_EFFECTIVE if type == :GROUND && + has_type?(:FLYING) && + has_active_item?(:IRONBALL) + # Get effectivenesses + type_mults = [Effectiveness::NORMAL_EFFECTIVE_ONE] * 3 # 3 types max + if type == :SHADOW + if @battler.shadowPokemon? + type_mults[0] = Effectiveness::NOT_VERY_EFFECTIVE_ONE + else + type_mults[0] = Effectiveness::SUPER_EFFECTIVE_ONE + end + else + @battler.pbTypes(true).each_with_index do |defend_type, i| + type_mults[i] = effectiveness_of_type_against_single_battler_type(type, defend_type, user) + end + end + # Multiply all effectivenesses together + ret = 1 + type_mults.each { |m| ret *= m } + return ret + end + + #============================================================================= + + def ability_id; return @battler.ability_id; end + def ability; return @battler.ability; end + + def ability_active? + # Only a high skill AI knows what an opponent's ability is + return false if @ai.trainer.side != @side && !@ai.trainer.high_skill? + return @battler.abilityActive? + end + + def has_active_ability?(ability) + # Only a high skill AI knows what an opponent's ability is + return false if @ai.trainer.side != @side && !@ai.trainer.high_skill? + return @battler.hasActiveAbility?(ability) + end + + #============================================================================= + + def item_id; return @battler.item_id; end + def item; return @battler.item; end + + def item_active? + # Only a high skill AI knows what an opponent's held item is + return false if @ai.trainer.side != @side && !@ai.trainer.high_skill? + return @battler.itemActive? + end + + def has_active_item?(item) + # Only a high skill AI knows what an opponent's held item is + return false if @ai.trainer.side != @side && !@ai.trainer.high_skill? + return @battler.hasActiveItem?(item) + end + + #============================================================================= + + def can_switch_lax? + return false if wild? + @ai.battle.eachInTeamFromBattlerIndex(@index) do |pkmn, i| + return true if @ai.battle.pbCanSwitchLax?(@index, i) + end + return false + end + + #============================================================================= + + def immune_to_move? + user = @ai.user + user_battler = user.battler + move = @ai.move + # TODO: Add consideration of user's Mold Breaker. + move_type = move.rough_type + typeMod = effectiveness_of_type_against_battler(move_type, user) + # Type effectiveness + return true if move.damagingMove? && Effectiveness.ineffective?(typeMod) + # Immunity due to ability/item/other effects + if @ai.trainer.medium_skill? + case move_type + when :GROUND + # TODO: Split target.airborne? into separate parts to allow different + # skill levels to apply to each part. + return true if @battler.airborne? && !move.move.hitsFlyingTargets? + when :FIRE + return true if has_active_ability?(:FLASHFIRE) + when :WATER + return true if has_active_ability?([:DRYSKIN, :STORMDRAIN, :WATERABSORB]) + when :GRASS + return true if has_active_ability?(:SAPSIPPER) + when :ELECTRIC + return true if has_active_ability?([:LIGHTNINGROD, :MOTORDRIVE, :VOLTABSORB]) + end + return true if move.damagingMove? && Effectiveness.not_very_effective?(typeMod) && + has_active_ability?(:WONDERGUARD) + return true if move.damagingMove? && user.index != @index && !opposes?(user) && + has_active_ability?(:TELEPATHY) + return true if move.statusMove? && move.move.canMagicCoat? && has_active_ability?(:MAGICBOUNCE) && + opposes?(user) + return true if move.move.soundMove? && has_active_ability?(:SOUNDPROOF) + return true if move.move.bombMove? && has_active_ability?(:BULLETPROOF) + if move.move.powderMove? + return true if has_type?(:GRASS) + return true if has_active_ability?(:OVERCOAT) + return true if has_active_ability?(:SAFETYGOGGLES) + end + return true if move.move.statusMove? && @battler.effects[PBEffects::Substitute] > 0 && + !move.move.ignoresSubstitute?(user) && user.index != @index + return true if move.move.statusMove? && Settings::MECHANICS_GENERATION >= 7 && + user.has_active_ability?(:PRANKSTER) && has_type?(:DARK) && + opposes?(user) + return true if move.move.priority > 0 && @ai.battle.field.terrain == :Psychic && + @battler.affectedByTerrain? && opposes?(user) + # TODO: Dazzling/Queenly Majesty go here. + end + return false + end + + #============================================================================= + + private + + def effectiveness_of_type_against_single_battler_type(type, defend_type, user = nil) + ret = Effectiveness.calculate_one(type, defend_type) + if Effectiveness.ineffective_type?(type, defend_type) + # Ring Target + if has_active_item?(:RINGTARGET) + ret = Effectiveness::NORMAL_EFFECTIVE_ONE + end + # Foresight + if (user&.has_active_ability?(:SCRAPPY) || @battler.effects[PBEffects::Foresight]) && + defend_type == :GHOST + ret = Effectiveness::NORMAL_EFFECTIVE_ONE + end + # Miracle Eye + if @battler.effects[PBEffects::MiracleEye] && defend_type == :DARK + ret = Effectiveness::NORMAL_EFFECTIVE_ONE + end + elsif Effectiveness.super_effective_type?(type, defend_type) + # Delta Stream's weather + if @battler.effectiveWeather == :StrongWinds && defend_type == :FLYING + ret = Effectiveness::NORMAL_EFFECTIVE_ONE + end + end + # Grounded Flying-type Pokémon become susceptible to Ground moves + if !@battler.airborne? && type == :GROUND && defend_type == :FLYING + ret = Effectiveness::NORMAL_EFFECTIVE_ONE + end + return ret + end +end diff --git a/Data/Scripts/011_Battle/005_AI/103_AIMove.rb b/Data/Scripts/011_Battle/005_AI/103_AIMove.rb new file mode 100644 index 000000000..736be5247 --- /dev/null +++ b/Data/Scripts/011_Battle/005_AI/103_AIMove.rb @@ -0,0 +1,366 @@ +#=============================================================================== +# +#=============================================================================== +class Battle::AI::AIMove + attr_reader :move + + def initialize(ai) + @ai = ai + end + + def set_up(move, ai_battler) + @move = move + @ai_battler = ai_battler + end + + #============================================================================= + + # pp + # priority + # usableWhenAsleep? + # thawsUser? + # flinchingMove? + # tramplesMinimize? + # hitsFlyingTargets? + # canMagicCoat? + # soundMove? + # bombMove? + # powderMove? + # ignoresSubstitute? + # highCriticalRate? + # ignoresReflect? + + def id; return @move.id; end + def physicalMove?(thisType = nil); return @move.physicalMove?(thisType); end + def specialMove?(thisType = nil); return @move.specialMove?(thisType); end + def damagingMove?; return @move.damagingMove?; end + def statusMove?; return @move.statusMove?; end + def function; return @move.function; end + + #============================================================================= + + # Returns whether this move targets multiple battlers. + def targets_multiple_battlers? + user_battler = @ai_battler.battler + target_data = @move.pbTarget(user_battler) + return false if target_data.num_targets <= 1 + num_targets = 0 + case target_data.id + when :AllAllies + @ai.battle.allSameSideBattlers(user_battler).each { |b| num_targets += 1 if b.index != user_battler.index } + when :UserAndAllies + @ai.battle.allSameSideBattlers(user_battler).each { |_b| num_targets += 1 } + when :AllNearFoes + @ai.battle.allOtherSideBattlers(user_battler).each { |b| num_targets += 1 if b.near?(user_battler) } + when :AllFoes + @ai.battle.allOtherSideBattlers(user_battler).each { |_b| num_targets += 1 } + when :AllNearOthers + @ai.battle.allBattlers.each { |b| num_targets += 1 if b.near?(user_battler) } + when :AllBattlers + @ai.battle.allBattlers.each { |_b| num_targets += 1 } + end + return num_targets > 1 + end + + #============================================================================= + + def type; return @move.type; end + + def rough_type + return @move.pbCalcType(@ai.user.battler) if @ai.trainer.high_skill? + return @move.type + end + + def pbCalcType(user); return @move.pbCalcType(user); end + + #============================================================================= + + # Returns this move's base power, taking into account various effects that + # modify it. + def base_power + ret = @move.baseDamage + ret = 60 if ret == 1 + return ret if !@ai.trainer.medium_skill? + user = @ai.user + user_battler = user.battler + target = @ai.target + target_battler = target.battler + # Covers all function codes which have their own def pbBaseDamage + case @move.function + when "FixedDamage20", "FixedDamage40", "FixedDamageHalfTargetHP", + "FixedDamageUserLevel", "LowerTargetHPToUserHP" + ret = @move.pbFixedDamage(user_battler, target_battler) + when "FixedDamageUserLevelRandom" + ret = user_battler.level + when "OHKO", "OHKOIce", "OHKOHitsUndergroundTarget" + ret = 200 + when "CounterPhysicalDamage", "CounterSpecialDamage", "CounterDamagePlusHalf" + ret = 60 + when "DoublePowerIfTargetUnderwater", "DoublePowerIfTargetUnderground", + "BindTargetDoublePowerIfTargetUnderwater" + ret = @move.pbModifyDamage(ret, user_battler, target_battler) + when "DoublePowerIfTargetInSky", + "FlinchTargetDoublePowerIfTargetInSky", + "DoublePowerIfTargetPoisoned", + "DoublePowerIfTargetParalyzedCureTarget", + "DoublePowerIfTargetAsleepCureTarget", + "DoublePowerIfUserPoisonedBurnedParalyzed", + "DoublePowerIfTargetStatusProblem", + "DoublePowerIfTargetHPLessThanHalf", + "DoublePowerIfAllyFaintedLastTurn", + "TypeAndPowerDependOnWeather", + "PowerHigherWithUserHappiness", + "PowerLowerWithUserHappiness", + "PowerHigherWithUserHP", + "PowerHigherWithTargetHP", + "PowerHigherWithUserPositiveStatStages", + "PowerHigherWithTargetPositiveStatStages", + "TypeDependsOnUserIVs", + "PowerHigherWithConsecutiveUse", + "PowerHigherWithConsecutiveUseOnUserSide", + "PowerHigherWithLessPP", + "PowerLowerWithUserHP", + "PowerHigherWithUserFasterThanTarget", + "PowerHigherWithTargetWeight", + "ThrowUserItemAtTarget", + "PowerDependsOnUserStockpile" + ret = @move.pbBaseDamage(ret, user_battler, target_battler) + when "DoublePowerIfUserHasNoItem" + ret *= 2 if !user_battler.item || user.has_active_item?(:FLYINGGEM) + when "PowerHigherWithTargetFasterThanUser" + targetSpeed = target.rough_stat(:SPEED) + userSpeed = user.rough_stat(:SPEED) + ret = [[(25 * targetSpeed / userSpeed).floor, 150].min, 1].max + when "RandomlyDamageOrHealTarget" + ret = 50 + when "RandomPowerDoublePowerIfTargetUnderground" + ret = 71 + ret *= 2 if target_battler.inTwoTurnAttack?("TwoTurnAttackInvulnerableUnderground") # Dig + when "TypeAndPowerDependOnUserBerry" + ret = @move.pbNaturalGiftBaseDamage(user_battler.item_id) + when "PowerHigherWithUserHeavierThanTarget" + ret = @move.pbBaseDamage(ret, user_battler, target_battler) + ret *= 2 if Settings::MECHANICS_GENERATION >= 7 && @trainer.medium_skill? && + target_battler.effects[PBEffects::Minimize] + when "AlwaysCriticalHit", "HitTwoTimes", "HitTwoTimesPoisonTarget" + ret *= 2 + when "HitThreeTimesPowersUpWithEachHit" + ret *= 6 # Hits do x1, x2, x3 ret in turn, for x6 in total + when "HitTwoToFiveTimes" + if user.has_active_ability?(:SKILLLINK) + ret *= 5 + else + ret = (ret * 31 / 10).floor # Average damage dealt + end + when "HitTwoToFiveTimesOrThreeForAshGreninja" + if user_battler.isSpecies?(:GRENINJA) && user_battler.form == 2 + ret *= 4 # 3 hits at 20 power = 4 hits at 15 power + elsif user.has_active_ability?(:SKILLLINK) + ret *= 5 + else + ret = (ret * 31 / 10).floor # Average damage dealt + end + when "HitOncePerUserTeamMember" + mult = 0 + @ai.battle.eachInTeamFromBattlerIndex(user.index) do |pkmn, _i| + mult += 1 if pkmn&.able? && pkmn.status == :NONE + end + ret *= mult + when "TwoTurnAttackOneTurnInSun" + ret = @move.pbBaseDamageMultiplier(ret, user_battler, target_battler) + when "MultiTurnAttackPowersUpEachTurn" + ret *= 2 if user_battler.effects[PBEffects::DefenseCurl] + when "MultiTurnAttackBideThenReturnDoubleDamage" + ret = 40 + when "UserFaintsFixedDamageUserHP" + ret = user_battler.hp + when "EffectivenessIncludesFlyingType" + if GameData::Type.exists?(:FLYING) + if @trainer.high_skill? + targetTypes = target_battler.pbTypes(true) + mult = Effectiveness.calculate( + :FLYING, targetTypes[0], targetTypes[1], targetTypes[2] + ) + else + mult = Effectiveness.calculate( + :FLYING, target.types[0], target.types[1], target.effects[PBEffects::Type3] + ) + end + ret = (ret.to_f * mult / Effectiveness::NORMAL_EFFECTIVE).round + end + ret *= 2 if @trainer.medium_skill? && target_battler.effects[PBEffects::Minimize] + when "DoublePowerIfUserLastMoveFailed" + ret *= 2 if user_battler.lastRoundMoveFailed + when "HitTwoTimesFlinchTarget" + ret *= 2 + ret *= 2 if @trainer.medium_skill? && target_battler.effects[PBEffects::Minimize] + end + return ret + end + + #============================================================================= + + def accuracy + return @move.accuracy + end + + def rough_accuracy + baseAcc = self.accuracy + return 100 if baseAcc == 0 + # Determine user and target + user = @ai.user + user_battler = user.battler + target = @ai.target + target_battler = target.battler + # Get better base accuracy + if @ai.trainer.medium_skill? + baseAcc = @move.pbBaseAccuracy(user_battler, target_battler) + return 100 if baseAcc == 0 + end + # "Always hit" effects and "always hit" accuracy + if @ai.trainer.medium_skill? + return 100 if target_battler.effects[PBEffects::Minimize] && @move.tramplesMinimize? && + Settings::MECHANICS_GENERATION >= 6 + return 100 if target_battler.effects[PBEffects::Telekinesis] > 0 + end + # Get the move's type + type = rough_type + # Calculate all modifier effects + modifiers = {} + modifiers[:base_accuracy] = baseAcc + modifiers[:accuracy_stage] = user_battler.stages[:ACCURACY] + modifiers[:evasion_stage] = target_battler.stages[:EVASION] + modifiers[:accuracy_multiplier] = 1.0 + modifiers[:evasion_multiplier] = 1.0 + apply_rough_accuracy_modifiers(user, target, type, modifiers) + # Check if move certainly misses/can't miss + return 0 if modifiers[:base_accuracy] < 0 + return 100 if modifiers[:base_accuracy] == 0 + # Calculation + accStage = [[modifiers[:accuracy_stage], -6].max, 6].min + 6 + evaStage = [[modifiers[:evasion_stage], -6].max, 6].min + 6 + stageMul = [3, 3, 3, 3, 3, 3, 3, 4, 5, 6, 7, 8, 9] + stageDiv = [9, 8, 7, 6, 5, 4, 3, 3, 3, 3, 3, 3, 3] + accuracy = 100.0 * stageMul[accStage] / stageDiv[accStage] + evasion = 100.0 * stageMul[evaStage] / stageDiv[evaStage] + accuracy = (accuracy * modifiers[:accuracy_multiplier]).round + evasion = (evasion * modifiers[:evasion_multiplier]).round + evasion = 1 if evasion < 1 + return modifiers[:base_accuracy] * accuracy / evasion + end + + def apply_rough_accuracy_modifiers(user, target, type, modifiers) + user_battler = user.battler + target_battler = target.battler + mold_breaker = (@ai.trainer.medium_skill? && target_battler.hasMoldBreaker?) + # Ability effects that alter accuracy calculation + if user.ability_active? + Battle::AbilityEffects.triggerAccuracyCalcFromUser( + user_battler.ability, modifiers, user_battler, target_battler, @move, type + ) + end + user_battler.allAllies.each do |b| + next if !b.abilityActive? + Battle::AbilityEffects.triggerAccuracyCalcFromAlly( + b.ability, modifiers, user_battler, target_battler, @move, type + ) + end + if !mold_breaker && target.ability_active? + Battle::AbilityEffects.triggerAccuracyCalcFromTarget( + target_battler.ability, modifiers, user_battler, target_battler, @move, type + ) + end + # Item effects that alter accuracy calculation + if user.item_active? + # TODO: Zoom Lens needs to be checked differently (compare speeds of + # user and target). + Battle::ItemEffects.triggerAccuracyCalcFromUser( + user_battler.item, modifiers, user_battler, target_battler, @move, type + ) + end + if target.item_active? + Battle::ItemEffects.triggerAccuracyCalcFromTarget( + target_battler.item, modifiers, user_battler, target_battler, @move, type + ) + end + # Other effects, inc. ones that set accuracy_multiplier or evasion_stage to specific values + if @ai.battle.field.effects[PBEffects::Gravity] > 0 + modifiers[:accuracy_multiplier] *= 5 / 3.0 + end + if @ai.trainer.medium_skill? + if user_battler.effects[PBEffects::MicleBerry] + modifiers[:accuracy_multiplier] *= 1.2 + end + modifiers[:evasion_stage] = 0 if target_battler.effects[PBEffects::Foresight] && modifiers[:evasion_stage] > 0 + modifiers[:evasion_stage] = 0 if target_battler.effects[PBEffects::MiracleEye] && modifiers[:evasion_stage] > 0 + end + # "AI-specific calculations below" + modifiers[:evasion_stage] = 0 if @move.function == "IgnoreTargetDefSpDefEvaStatStages" # Chip Away + if @ai.trainer.medium_skill? + modifiers[:base_accuracy] = 0 if user_battler.effects[PBEffects::LockOn] > 0 && + user_battler.effects[PBEffects::LockOnPos] == target_battler.index + end + if @ai.trainer.medium_skill? + case @move.function + when "BadPoisonTarget" + modifiers[:base_accuracy] = 0 if Settings::MORE_TYPE_EFFECTS && + @move.statusMove? && @user.has_type?(:POISON) + when "OHKO", "OHKOIce", "OHKOHitsUndergroundTarget" + modifiers[:base_accuracy] = self.accuracy + user_battler.level - target_battler.level + modifiers[:accuracy_multiplier] = 0 if target_battler.level > user_battler.level + modifiers[:accuracy_multiplier] = 0 if target.has_active_ability?(:STURDY) + end + end + end + + #============================================================================= + + def rough_critical_hit_stage + user = @ai.user + user_battler = user.battler + target = @ai.target + target_battler = target.battler + return -1 if target_battler.pbOwnSide.effects[PBEffects::LuckyChant] > 0 + mold_breaker = (@ai.trainer.medium_skill? && user_battler.hasMoldBreaker?) + crit_stage = 0 + # Ability effects that alter critical hit rate + if user.ability_active? + crit_stage = BattleHandlers.triggerCriticalCalcUserAbility(user_battler.ability, + user_battler, target_battler, crit_stage) + return -1 if crit_stage < 0 + end + if !mold_breaker && target.ability_active? + crit_stage = BattleHandlers.triggerCriticalCalcTargetAbility(target_battler.ability, + user_battler, target_battler, crit_stage) + return -1 if crit_stage < 0 + end + # Item effects that alter critical hit rate + if user.item_active? + crit_stage = BattleHandlers.triggerCriticalCalcUserItem(user_battler.item, + user_battler, target_battler, crit_stage) + return -1 if crit_stage < 0 + end + if target.item_active? + crit_stage = BattleHandlers.triggerCriticalCalcTargetItem(user_battler.item, + user_battler, target_battler, crit_stage) + return -1 if crit_stage < 0 + end + # Other effects + case @move.pbCritialOverride(user_battler, target_battler) + when 1 then return 99 + when -1 then return -1 + end + return 99 if crit_stage > 50 # Merciless + return 99 if user_battler.effects[PBEffects::LaserFocus] > 0 + crit_stage += 1 if @move.highCriticalRate? + crit_stage += user_battler.effects[PBEffects::FocusEnergy] + crit_stage += 1 if user_battler.inHyperMode? && @move.type == :SHADOW + crit_stage = [crit_stage, Battle::Move::CRITICAL_HIT_RATIOS.length - 1].min + return crit_stage + end + + #============================================================================= + + # pbBaseAccuracy(@ai.user.battler, @ai.target.battler) if @ai.trainer.medium_skill? + # pbCriticalOverride(@ai.user.battler, @ai.target.battler) +end diff --git a/PBS/Gen 8/moves.txt b/PBS/Gen 8/moves.txt index 9a917af5f..228ed8109 100644 --- a/PBS/Gen 8/moves.txt +++ b/PBS/Gen 8/moves.txt @@ -757,7 +757,7 @@ Description = The user stimulates its brain by thinking bad thoughts. It sharply Name = Obstruct Type = DARK Category = Status -Accuracy = 100 +Accuracy = 0 TotalPP = 10 Target = User Priority = 4 @@ -1102,7 +1102,7 @@ Description = This attack hits the target with a shock wave of pure rage. This a Name = Clangorous Soul Type = DRAGON Category = Status -Accuracy = 100 +Accuracy = 0 TotalPP = 5 Target = User FunctionCode = RaiseUserMainStats1LoseThirdOfTotalHP @@ -5846,7 +5846,7 @@ Description = The user mimics the move used immediately before it. The move fail Name = Court Change Type = NORMAL Category = Status -Accuracy = 100 +Accuracy = 0 TotalPP = 10 Target = BothSides FunctionCode = SwapSideEffects diff --git a/PBS/moves.txt b/PBS/moves.txt index 9a917af5f..228ed8109 100644 --- a/PBS/moves.txt +++ b/PBS/moves.txt @@ -757,7 +757,7 @@ Description = The user stimulates its brain by thinking bad thoughts. It sharply Name = Obstruct Type = DARK Category = Status -Accuracy = 100 +Accuracy = 0 TotalPP = 10 Target = User Priority = 4 @@ -1102,7 +1102,7 @@ Description = This attack hits the target with a shock wave of pure rage. This a Name = Clangorous Soul Type = DRAGON Category = Status -Accuracy = 100 +Accuracy = 0 TotalPP = 5 Target = User FunctionCode = RaiseUserMainStats1LoseThirdOfTotalHP @@ -5846,7 +5846,7 @@ Description = The user mimics the move used immediately before it. The move fail Name = Court Change Type = NORMAL Category = Status -Accuracy = 100 +Accuracy = 0 TotalPP = 10 Target = BothSides FunctionCode = SwapSideEffects