More AI function codes, tweaked AI score threshold, renumbered all PBEffects constants

This commit is contained in:
Maruno17
2023-03-19 17:22:53 +00:00
parent e9a44377ce
commit e2648032c1
11 changed files with 402 additions and 233 deletions

View File

@@ -59,7 +59,7 @@ end
#=============================================================================== #===============================================================================
# After inflicting damage, user switches out. Ignores trapping moves. # After inflicting damage, user switches out. Ignores trapping moves.
# (U-turn, Volt Switch) # (Flip Turn, U-turn, Volt Switch)
#=============================================================================== #===============================================================================
class Battle::Move::SwitchOutUserDamagingMove < Battle::Move class Battle::Move::SwitchOutUserDamagingMove < Battle::Move
def pbEndOfMoveUsageEffect(user, targets, numHits, switchedBattlers) def pbEndOfMoveUsageEffect(user, targets, numHits, switchedBattlers)

View File

@@ -6,7 +6,7 @@ class Battle::AI
# Returns a value between 0.0 and 1.0. All move scores are lowered by this # Returns a value between 0.0 and 1.0. All move scores are lowered by this
# value multiplied by the highest-scoring move's score. # value multiplied by the highest-scoring move's score.
def move_score_threshold def move_score_threshold
return 0.6 + 0.35 * (([@trainer.skill, 100].min / 100.0) ** 0.5) # 0.6 to 0.95 return 0.6 + 0.3 * (([@trainer.skill, 100].min / 100.0) ** 0.5) # 0.6 to 0.9
end end
#============================================================================= #=============================================================================
@@ -147,8 +147,8 @@ class Battle::AI
move.pbOnStartUse(@user.battler, []) # Determine which move is used instead move.pbOnStartUse(@user.battler, []) # Determine which move is used instead
move = Battle::Move.from_pokemon_move(@battle, Pokemon::Move.new(move.npMove)) move = Battle::Move.from_pokemon_move(@battle, Pokemon::Move.new(move.npMove))
end end
@move.set_up(move)
@battle.moldBreaker = @user.has_mold_breaker? @battle.moldBreaker = @user.has_mold_breaker?
@move.set_up(move)
end end
def set_up_move_check_target(target) def set_up_move_check_target(target)
@@ -158,6 +158,7 @@ class Battle::AI
if @target.battler.lastRegularMoveUsed && if @target.battler.lastRegularMoveUsed &&
GameData::Move.get(@target.battler.lastRegularMoveUsed).has_flag?("CanMirrorMove") GameData::Move.get(@target.battler.lastRegularMoveUsed).has_flag?("CanMirrorMove")
mov = Battle::Move.from_pokemon_move(@battle, Pokemon::Move.new(@target.battler.lastRegularMoveUsed)) mov = Battle::Move.from_pokemon_move(@battle, Pokemon::Move.new(@target.battler.lastRegularMoveUsed))
@battle.moldBreaker = @user.has_mold_breaker?
@move.set_up(mov) @move.set_up(mov)
end end
end end
@@ -291,7 +292,7 @@ class Battle::AI
# TODO: The above also applies if the move is Heal Pulse or a few other moves # TODO: The above also applies if the move is Heal Pulse or a few other moves
# like that, which CAN target a foe but you'd never do so. Maybe use a # like that, which CAN target a foe but you'd never do so. Maybe use a
# move flag to determine such moves? The implication is that such moves # move flag to determine such moves? The implication is that such moves
# wouldn't apply the "175 - score" bit, which would make their # wouldn't apply the "185 - score" bit, which would make their
# MoveHandlers do the opposite calculations to other moves with the same # MoveHandlers do the opposite calculations to other moves with the same
# targets, but is this desirable? # targets, but is this desirable?
#============================================================================= #=============================================================================
@@ -322,7 +323,7 @@ class Battle::AI
end end
# TODO: Is this reversal of the score okay? # TODO: Is this reversal of the score okay?
old_score = score old_score = score
score = 175 - score score = 185 - score
PBDebug.log_score_change(score - old_score, "score inverted (move targets ally but can target foe)") PBDebug.log_score_change(score - old_score, "score inverted (move targets ally but can target foe)")
end end
return score return score

View File

@@ -299,6 +299,59 @@ class Battle::AI::AIBattler
return false return false
end end
# NOTE: This specifically means "is not currently trapped but can become
# trapped by an effect". Similar to def pbCanSwitchOut? but this returns
# false if any certain switching OR certain trapping applies.
def can_become_trapped?
return false if fainted?
# Ability/item effects that allow switching no matter what
if ability_active? && Battle::AbilityEffects.triggerCertainSwitching(ability, @battler, @ai.battle)
return false
end
if item_active? && Battle::ItemEffects.triggerCertainSwitching(item, @battler, @ai.battle)
return false
end
# Other certain switching effects
return false if Settings::MORE_TYPE_EFFECTS && has_type?(:GHOST)
# Other certain trapping effects
return false if @battler.trappedInBattle?
# Trapping abilities/items
ai.each_foe_battler(side) do |b, i|
if b.ability_active? &&
Battle::AbilityEffects.triggerTrappingByTarget(b.ability, @battler, b.battler, @ai.battle)
return false
end
if b.item_active? &&
Battle::ItemEffects.triggerTrappingByTarget(b.item, @battler, b.battler, @ai.battle)
return false
end
end
return true
end
#=============================================================================
def wants_status_problem?(new_status)
return true if new_status == :NONE
if ability_active?
case ability_id
when :GUTS
return true if stat_raise_worthwhile?(self, :ATTACK, true)
when :MARVELSCALE
return true if stat_raise_worthwhile?(self, :DEFENSE, true)
when :QUICKFEET
return true if stat_raise_worthwhile?(self, :SPEED, true)
when :FLAREBOOST
return true if new_status == :BURN && stat_raise_worthwhile?(self, :SPECIAL_ATTACK, true)
end
end
return true if new_status == :SLEEP && check_for_move { |m| m.usableWhenAsleep? }
if has_move_with_function?("DoublePowerIfUserPoisonedBurnedParalyzed")
return true if [:POISON, :BURN, :PARALYSIS].include?(new_status)
end
return false
end
#============================================================================= #=============================================================================
# TODO: Add more items. # TODO: Add more items.

View File

@@ -11,6 +11,8 @@ class Battle::AI::AIMove
def set_up(move) def set_up(move)
@move = move @move = move
@move.calcType = rough_type @move.calcType = rough_type
@ai.battle.moldBreaker ||= ["IgnoreTargetAbility",
"CategoryDependsOnHigherDamageIgnoreTargetAbility"].include?(function)
end end
#============================================================================= #=============================================================================

View File

@@ -455,13 +455,7 @@ Battle::AI::Handlers::MoveEffectScore.copy("RaiseUserAtkSpAtk1",
Battle::AI::Handlers::MoveFailureCheck.add("RaiseUserMainStats1LoseThirdOfTotalHP", Battle::AI::Handlers::MoveFailureCheck.add("RaiseUserMainStats1LoseThirdOfTotalHP",
proc { |move, user, ai, battle| proc { |move, user, ai, battle|
next true if user.hp <= [user.totalhp / 3, 1].max next true if user.hp <= [user.totalhp / 3, 1].max
will_fail = true next Battle::AI::Handlers.move_will_fail?("RaiseUserAtkDef1", move, user, ai, battle)
(move.move.statUp.length / 2).times do |i|
next if !user.battler.pbCanRaiseStatStage?(move.move.statUp[i * 2], user.battler, move.move)
will_fail = false
break
end
next will_fail
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("RaiseUserMainStats1LoseThirdOfTotalHP", Battle::AI::Handlers::MoveEffectScore.add("RaiseUserMainStats1LoseThirdOfTotalHP",
@@ -478,27 +472,35 @@ Battle::AI::Handlers::MoveEffectScore.add("RaiseUserMainStats1LoseThirdOfTotalHP
) )
#=============================================================================== #===============================================================================
# TODO: Review score modifiers. #
#=============================================================================== #===============================================================================
Battle::AI::Handlers::MoveFailureCheck.add("RaiseUserMainStats1TrapUserInBattle", Battle::AI::Handlers::MoveFailureCheck.add("RaiseUserMainStats1TrapUserInBattle",
proc { |move, user, ai, battle| proc { |move, user, ai, battle|
next true if user.effects[PBEffects::NoRetreat] next true if user.effects[PBEffects::NoRetreat]
will_fail = true next Battle::AI::Handlers.move_will_fail?("RaiseUserAtkDef1", move, user, ai, battle)
(move.move.statUp.length / 2).times do |i|
next if !user.battler.pbCanRaiseStatStage?(move.move.statUp[i * 2], user.battler, move.move)
will_fail = false
break
end
next will_fail
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("RaiseUserMainStats1TrapUserInBattle", Battle::AI::Handlers::MoveEffectScore.add("RaiseUserMainStats1TrapUserInBattle",
proc { |score, move, user, ai, battle| proc { |score, move, user, ai, battle|
# Score for stat increase # Score for stat increase
score = ai.get_score_for_target_stat_raise(score, user, move.move.statUp) score = ai.get_score_for_target_stat_raise(score, user, move.move.statUp)
# Score for trapping user in battle # Score for user becoming trapped in battle
if ai.trainer.medium_skill? && !user.battler.trappedInBattle? if user.can_become_trapped? && battle.pbCanChooseNonActive?(user.index)
score -= 10 if user.hp <= user.totalhp / 2 # Not worth trapping if user will faint this round anyway
eor_damage = user.rough_end_of_round_damage
if eor_damage >= user.hp
next (move.damagingMove?) ? score : Battle::AI::MOVE_USELESS_SCORE
end
# Score for user becoming trapped in battle
# TODO: These checks are related to desire to switch, and there can be a lot
# more things to consider, e.g. effectiveness of the target's moves
# against its foes. Also applies to other code that calls
# can_become_trapped?
if user.effects[PBEffects::PerishSong] > 0 ||
user.effects[PBEffects::Attract] >= 0 ||
eor_damage > 0
score -= 12
end
end end
next score next score
} }

View File

@@ -506,23 +506,16 @@ Battle::AI::Handlers::MoveEffectScore.add("CureUserPartyStatus",
) )
#=============================================================================== #===============================================================================
# TODO: Review score modifiers. #
# TODO: target should probably be treated as an enemy when deciding the score,
# since the score will be inverted elsewhere due to the target being an
# ally.
#=============================================================================== #===============================================================================
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("CureTargetBurn", Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("CureTargetBurn",
proc { |score, move, user, target, ai, battle| proc { |score, move, user, target, ai, battle|
add_effect = move.get_score_change_for_additional_effect(user, target) add_effect = move.get_score_change_for_additional_effect(user, target)
next score if add_effect == -999 # Additional effect will be negated next score if add_effect == -999 # Additional effect will be negated
if target.status == :BURN if target.status == :BURN
if target.opposes?(user) score -= add_effect
score -= add_effect score -= 10
score -= 10 score += 15 if target.wants_status_problem?(:BURN)
else
score += add_effect
score += 10
end
end end
next score next score
} }
@@ -1089,7 +1082,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("NegateTargetAbilityIfTar
) )
#=============================================================================== #===============================================================================
# TODO: Review score modifiers. #
#=============================================================================== #===============================================================================
# IgnoreTargetAbility # IgnoreTargetAbility

View File

@@ -267,13 +267,16 @@ Battle::AI::Handlers::MoveBasePower.copy("DoublePowerIfTargetHPLessThanHalf",
"DoublePowerIfUserPoisonedBurnedParalyzed") "DoublePowerIfUserPoisonedBurnedParalyzed")
#=============================================================================== #===============================================================================
# TODO: Review score modifiers. #
#=============================================================================== #===============================================================================
Battle::AI::Handlers::MoveBasePower.copy("DoublePowerIfTargetHPLessThanHalf", Battle::AI::Handlers::MoveBasePower.copy("DoublePowerIfTargetHPLessThanHalf",
"DoublePowerIfTargetAsleepCureTarget") "DoublePowerIfTargetAsleepCureTarget")
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("DoublePowerIfTargetAsleepCureTarget", Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("DoublePowerIfTargetAsleepCureTarget",
proc { |score, move, user, target, ai, battle| proc { |score, move, user, target, ai, battle|
score -= 20 if target.status == :SLEEP && target.statusCount > 1 # Will cure status if target.status == :SLEEP && target.statusCount > 1 # Will cure status
score -= 10
score += 15 if target.wants_status_problem?(:SLEEP)
end
next score next score
} }
) )
@@ -288,13 +291,16 @@ Battle::AI::Handlers::MoveBasePower.add("DoublePowerIfTargetPoisoned",
) )
#=============================================================================== #===============================================================================
# TODO: Review score modifiers. #
#=============================================================================== #===============================================================================
Battle::AI::Handlers::MoveBasePower.copy("DoublePowerIfTargetPoisoned", Battle::AI::Handlers::MoveBasePower.copy("DoublePowerIfTargetPoisoned",
"DoublePowerIfTargetParalyzedCureTarget") "DoublePowerIfTargetParalyzedCureTarget")
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("DoublePowerIfTargetParalyzedCureTarget", Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("DoublePowerIfTargetParalyzedCureTarget",
proc { |score, move, user, target, ai, battle| proc { |score, move, user, target, ai, battle|
score -= 20 if target.status == :PARALYSIS # Will cure status if target.status == :PARALYSIS # Will cure status
score -= 10
score += 15 if target.wants_status_problem?(:PARALYSIS)
end
next score next score
} }
) )
@@ -1284,7 +1290,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.copy("PoisonTarget",
"CategoryDependsOnHigherDamagePoisonTarget") "CategoryDependsOnHigherDamagePoisonTarget")
#=============================================================================== #===============================================================================
# TODO: Review score modifiers. Category part is already accounted for. #
#=============================================================================== #===============================================================================
# CategoryDependsOnHigherDamageIgnoreTargetAbility # CategoryDependsOnHigherDamageIgnoreTargetAbility

View File

@@ -116,7 +116,7 @@ Battle::AI::Handlers::MoveEffectScore.add("HealUserHalfOfTotalHPLoseFlyingTypeTh
) )
#=============================================================================== #===============================================================================
# TODO: Review score modifiers. #
#=============================================================================== #===============================================================================
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("CureTargetStatusHealUserHalfOfTotalHP", Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("CureTargetStatusHealUserHalfOfTotalHP",
proc { |move, user, target, ai, battle| proc { |move, user, target, ai, battle|
@@ -125,13 +125,9 @@ Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("CureTargetStatusHealUse
) )
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("CureTargetStatusHealUserHalfOfTotalHP", Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("CureTargetStatusHealUserHalfOfTotalHP",
proc { |score, move, user, target, ai, battle| proc { |score, move, user, target, ai, battle|
# TODO: Add high level checks for whether the target wants to lose their # Will cure status
# status problem, and change the score accordingly. score -= 10
if target.opposes?(user) score += 15 if target.wants_status_problem?(target.status)
score -= 10
else
score += 15
end
# Consider how much HP will be restored # Consider how much HP will be restored
if user.hp >= user.totalhp * 0.5 if user.hp >= user.totalhp * 0.5
score -= 10 score -= 10
@@ -422,7 +418,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("StartLeechSeedTarget",
score += 15 score += 15
end end
# Don't prefer if target can remove the seed # Don't prefer if target can remove the seed
if target.check_for_move { |m| m.is_a?(Battle::Move::RemoveUserBindingAndEntryHazards) } if target.has_move_with_function?("RemoveUserBindingAndEntryHazards")
score -= 15 score -= 15
end end
end end

View File

@@ -165,13 +165,40 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("StartTargetCannotUseItem
) )
#=============================================================================== #===============================================================================
# TODO: Review score modifiers. #
# TODO: This code shouldn't make use of target.
#=============================================================================== #===============================================================================
Battle::AI::Handlers::MoveEffectScore.add("StartNegateHeldItems", Battle::AI::Handlers::MoveEffectScore.add("StartNegateHeldItems",
proc { |score, move, user, ai, battle| proc { |score, move, user, ai, battle|
next Battle::AI::MOVE_USELESS_SCORE if battle.field.effects[PBEffects::MagicRoom] > 0 next if battle.field.effects[PBEffects::MagicRoom] == 1 # About to expire anyway
score += 30 if !user.item # && target.item any_held_items = false
total_want = 0 # Positive means foes want their items more than allies do
ai.each_battler do |b, i|
next if !b.item
# Skip b if its item is disabled
if ai.trainer.medium_skill?
if battle.field.effects[PBEffects::MagicRoom] > 0
# NOTE: Same as b.item_active? but ignoring the Magic Room part.
next if b.effects[PBEffects::Embargo] > 0
next if battle.corrosiveGas[b.index % 2][b.party_index]
next if b.has_active_ability?(:KLUTZ)
else
next if !b.item_active?
end
end
# Rate b's held item and add it to total_want
any_held_items = true
want = b.wants_item?(b.item_id)
total_want += (b.opposes?(user)) ? want : -want
end
# Alter score
next Battle::AI::MOVE_USELESS_SCORE if !any_held_items
if battle.field.effects[PBEffects::MagicRoom] > 0
next Battle::AI::MOVE_USELESS_SCORE if total_want >= 0
score -= [total_want, -5].max * 5 # Will enable items, prefer if allies affected more
else
next Battle::AI::MOVE_USELESS_SCORE if total_want <= 0
score += [total_want, 5].min * 5 # Will disable items, prefer if foes affected more
end
next score next score
} }
) )

View File

@@ -9,7 +9,7 @@ Battle::AI::Handlers::MoveFailureCheck.add("FleeFromBattle",
Battle::AI::Handlers::MoveEffectScore.add("FleeFromBattle", Battle::AI::Handlers::MoveEffectScore.add("FleeFromBattle",
proc { |score, move, user, ai, battle| proc { |score, move, user, ai, battle|
# Generally don't prefer (don't want to end the battle too easily) # Generally don't prefer (don't want to end the battle too easily)
next score - 15 next score - 20
} }
) )
@@ -24,21 +24,19 @@ Battle::AI::Handlers::MoveFailureCheck.add("SwitchOutUserStatusMove",
) )
Battle::AI::Handlers::MoveEffectScore.add("SwitchOutUserStatusMove", Battle::AI::Handlers::MoveEffectScore.add("SwitchOutUserStatusMove",
proc { |score, move, user, ai, battle| proc { |score, move, user, ai, battle|
next score + 10 if user.wild? # Wild Pokémon run from battle
next score - 20 if user.wild?
# Trainer-owned Pokémon switch out
if ai.trainer.has_skill_flag?("ReserveLastPokemon") && battle.pbTeamAbleNonActiveCount(user.index) == 1 if ai.trainer.has_skill_flag?("ReserveLastPokemon") && battle.pbTeamAbleNonActiveCount(user.index) == 1
score -= 60 # Don't switch in ace next Battle::AI::MOVE_USELESS_SCORE # Don't switch in ace
else
score += 40 if user.effects[PBEffects::Confusion] > 0
total = 0
GameData::Stat.each_battle { |s| total += user.stages[s.id] }
if total <= 0 || user.turnCount == 0
score += 60
else
score -= total * 10
# special case: user has no damaging moves
score += 75 if !user.check_for_move { |m| m.damagingMove? }
end
end end
# Prefer if the user switching out will lose a negative effect
score += 10 if user.effects[PBEffects::Confusion] > 1
# Prefer if the user doesn't have any damaging moves
# TODO: Check effectiveness of moves.
score += 15 if !user.check_for_move { |m| m.damagingMove? }
# Don't prefer the more stat raises the user has
GameData::Stat.each_battle { |s| score -= user.stages[s.id] * 5 }
next score next score
} }
) )
@@ -48,8 +46,14 @@ Battle::AI::Handlers::MoveEffectScore.add("SwitchOutUserStatusMove",
#=============================================================================== #===============================================================================
Battle::AI::Handlers::MoveEffectScore.add("SwitchOutUserDamagingMove", Battle::AI::Handlers::MoveEffectScore.add("SwitchOutUserDamagingMove",
proc { |score, move, user, ai, battle| proc { |score, move, user, ai, battle|
next 0 if !battle.pbCanChooseNonActive?(user.index) next score if !battle.pbCanChooseNonActive?(user.index)
next 0 if ai.trainer.has_skill_flag?("ReserveLastPokemon") && battle.pbTeamAbleNonActiveCount(user.index) == 1 # Don't switch in ace # Don't want to switch in ace
score -= 20 if ai.trainer.has_skill_flag?("ReserveLastPokemon") &&
battle.pbTeamAbleNonActiveCount(user.index) == 1
# Prefer if the user switching out will lose a negative effect
score += 10 if user.effects[PBEffects::Confusion] > 1
# Don't prefer the more stat raises the user has
GameData::Stat.each_battle { |s| score -= user.stages[s.id] * 5 }
next score next score
} }
) )
@@ -72,6 +76,18 @@ Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("LowerTargetAtkSpAtk1Swi
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("LowerTargetAtkSpAtk1SwitchOutUser", Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("LowerTargetAtkSpAtk1SwitchOutUser",
proc { |score, move, user, target, ai, battle| proc { |score, move, user, target, ai, battle|
score = ai.get_score_for_target_stat_drop(score, target, move.move.statDown, false) score = ai.get_score_for_target_stat_drop(score, target, move.move.statDown, false)
if battle.pbCanChooseNonActive?(user.index)
# Don't want to switch in ace
score -= 20 if ai.trainer.has_skill_flag?("ReserveLastPokemon") &&
battle.pbTeamAbleNonActiveCount(user.index) == 1
# Prefer if the user switching out will lose a negative effect
score += 10 if user.effects[PBEffects::Confusion] > 1
# Prefer if the user doesn't have any damaging moves
# TODO: Check effectiveness of moves.
score += 15 if !user.check_for_move { |m| m.damagingMove? }
# Don't prefer the more stat raises the user has
GameData::Stat.each_battle { |s| score -= user.stages[s.id] * 5 }
end
next score next score
} }
) )
@@ -86,20 +102,16 @@ Battle::AI::Handlers::MoveFailureCheck.add("SwitchOutUserPassOnEffects",
) )
Battle::AI::Handlers::MoveEffectScore.add("SwitchOutUserPassOnEffects", Battle::AI::Handlers::MoveEffectScore.add("SwitchOutUserPassOnEffects",
proc { |score, move, user, ai, battle| proc { |score, move, user, ai, battle|
if battle.pbCanChooseNonActive?(user.index) # Don't want to switch in ace
score -= 40 if user.effects[PBEffects::Confusion] > 0 score -= 20 if ai.trainer.has_skill_flag?("ReserveLastPokemon") &&
total = 0 battle.pbTeamAbleNonActiveCount(user.index) == 1
GameData::Stat.each_battle { |s| total += user.stages[s.id] } # Don't prefer if the user will pass on a negative effect
if total <= 0 || user.turnCount == 0 score -= 10 if user.effects[PBEffects::Confusion] > 1
score -= 60 # Prefer if the user doesn't have any damaging moves
else # TODO: Check effectiveness of moves.
score += total * 10 score += 15 if !user.check_for_move { |m| m.damagingMove? }
# special case: user has no damaging moves # Prefer if the user will pass on good stat stages
score += 75 if !user.check_for_move { |m| m.damagingMove? } GameData::Stat.each_battle { |s| score += user.stages[s.id] * 5 }
end
else
score -= 100
end
next score next score
} }
) )
@@ -162,14 +174,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("BindTarget",
# Target will take damage at the end of each round from the binding # Target will take damage at the end of each round from the binding
score += 8 if target.battler.takesIndirectDamage? score += 8 if target.battler.takesIndirectDamage?
# Check whether the target will be trapped in battle by the binding # Check whether the target will be trapped in battle by the binding
untrappable = Settings::MORE_TYPE_EFFECTS && target.has_type?(:GHOST) if target.can_become_trapped?
if !untrappable && target.ability_active?
untrappable = Battle::AbilityEffects.triggerCertainSwitching(target.ability, target.battler, battle)
end
if !untrappable && target.item_active?
untrappable = Battle::ItemEffects.triggerCertainSwitching(target.ability, target.battler, battle)
end
if !untrappable && !target.battler.trappedInBattle?
score += 8 # Prefer if the target will become trapped by this move score += 8 # Prefer if the target will become trapped by this move
eor_damage = target.rough_end_of_round_damage eor_damage = target.rough_end_of_round_damage
if eor_damage > 0 if eor_damage > 0
@@ -185,8 +190,9 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("BindTarget",
end end
# Don't prefer if the target can remove the binding (and the binding has an # Don't prefer if the target can remove the binding (and the binding has an
# effect) # effect)
if (!untrappable && !target.battler.trappedInBattle?) || target.battler.takesIndirectDamage? if target.can_become_trapped? || target.battler.takesIndirectDamage?
if target.has_move_with_function?("RemoveUserBindingAndEntryHazards") if ai.trainer.medium_skill? &&
target.has_move_with_function?("RemoveUserBindingAndEntryHazards")
score -= 8 score -= 8
end end
end end
@@ -206,8 +212,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.copy("BindTarget",
"BindTargetDoublePowerIfTargetUnderwater") "BindTargetDoublePowerIfTargetUnderwater")
#=============================================================================== #===============================================================================
# TODO: Review score modifiers. #
# TODO: Include get_score_change_for_additional_effect usage.
#=============================================================================== #===============================================================================
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("TrapTargetInBattle", Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("TrapTargetInBattle",
proc { |move, user, target, ai, battle| proc { |move, user, target, ai, battle|
@@ -217,15 +222,56 @@ Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("TrapTargetInBattle",
next false next false
} }
) )
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("TrapTargetInBattle",
proc { |score, move, user, target, ai, battle|
if !target.can_become_trapped? || !battle.pbCanChooseNonActive?(target.index)
next (move.damagingMove?) ? score : Battle::AI::MOVE_USELESS_SCORE
end
# Not worth trapping if target will faint this round anyway
eor_damage = target.rough_end_of_round_damage
if eor_damage >= target.hp
next (move.damagingMove?) ? score : Battle::AI::MOVE_USELESS_SCORE
end
# Score for EOR damage (intentionally before Rapid Spin check)
hp_fraction = (Settings::MECHANICS_GENERATION >= 6) ? 8 : 16
if user.has_active_item?(:BINDINGBAND)
hp_fraction = (Settings::MECHANICS_GENERATION >= 6) ? 6 : 8
end
rounds_to_deplete_hp = (hp_fraction.to_f * target.hp / target.totalhp).ceil
score += 30 / rounds_to_deplete_hp
# Not worth trapping if target can remove the binding
if ai.trainer.medium_skill? &&
target.has_move_with_function?("RemoveUserBindingAndEntryHazards")
next (move.damagingMove?) ? score : Battle::AI::MOVE_USELESS_SCORE
end
# Score for being an additional effect
add_effect = move.get_score_change_for_additional_effect(user, target)
next score if add_effect == -999 # Additional effect will be negated
score += add_effect
# Score for target becoming trapped in battle
# TODO: These checks are related to desire to switch, and there can be a lot
# more things to consider, e.g. effectiveness of the target's moves
# against its foes. Also applies to other code that calls
# can_become_trapped?
if target.effects[PBEffects::PerishSong] > 0 ||
target.effects[PBEffects::Attract] >= 0 ||
eor_damage > 0
score += 12
end
next score
}
)
#=============================================================================== #===============================================================================
# TODO: Review score modifiers. #
#=============================================================================== #===============================================================================
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.copy("TrapTargetInBattle", Battle::AI::Handlers::MoveFailureAgainstTargetCheck.copy("TrapTargetInBattle",
"TrapTargetInBattleMainEffect") "TrapTargetInBattleMainEffect")
Battle::AI::Handlers::MoveEffectAgainstTargetScore.copy("TrapTargetInBattle",
"TrapTargetInBattleMainEffect")
#=============================================================================== #===============================================================================
# TODO: Review score modifiers. #
#=============================================================================== #===============================================================================
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("TrapTargetInBattleLowerTargetDefSpDef1EachTurn", Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("TrapTargetInBattleLowerTargetDefSpDef1EachTurn",
proc { |move, user, target, ai, battle| proc { |move, user, target, ai, battle|
@@ -237,20 +283,63 @@ Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("TrapTargetInBattleLower
) )
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("TrapTargetInBattleLowerTargetDefSpDef1EachTurn", Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("TrapTargetInBattleLowerTargetDefSpDef1EachTurn",
proc { |score, move, user, target, ai, battle| proc { |score, move, user, target, ai, battle|
score += 30 if !target.battler.trappedInBattle? # Score for stat drop
score -= 50 if !target.battler.pbCanLowerStatStage?(:DEFENSE, user.battler, move.move) && score = ai.get_score_for_target_stat_drop(score, target, [:DEFENSE, 1, :SPECIAL_DEFENSE], false)
!target.battler.pbCanLowerStatStage?(:SPECIAL_DEFENSE, user.battler, move.move) # Score for target becoming trapped in battle
if target.can_become_trapped? && battle.pbCanChooseNonActive?(target.index)
# Not worth trapping if target will faint this round anyway
eor_damage = target.rough_end_of_round_damage
if eor_damage >= target.hp
next (move.damagingMove?) ? score : Battle::AI::MOVE_USELESS_SCORE
end
# Not worth trapping if target can remove the binding
if target.has_move_with_function?("RemoveUserBindingAndEntryHazards")
next (move.damagingMove?) ? score : Battle::AI::MOVE_USELESS_SCORE
end
# Score for target becoming trapped in battle
# TODO: These checks are related to desire to switch, and there can be a lot
# more things to consider, e.g. effectiveness of the target's moves
# against its foes. Also applies to other code that calls
# can_become_trapped?
if target.effects[PBEffects::PerishSong] > 0 ||
target.effects[PBEffects::Attract] >= 0 ||
eor_damage > 0
score += 12
end
end
next score next score
} }
) )
#=============================================================================== #===============================================================================
# TODO: Review score modifiers. #
#=============================================================================== #===============================================================================
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("TrapUserAndTargetInBattle", Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("TrapUserAndTargetInBattle",
proc { |score, move, user, target, ai, battle| proc { |score, move, user, target, ai, battle|
if target.effects[PBEffects::JawLock] < 0 # NOTE: Don't worry about scoring for the user also becoming trapped in
score += 40 if !user.battler.trappedInBattle? && !target.battler.trappedInBattle? # battle, because it knows this move and accepts what it's getting
# itself into.
if target.can_become_trapped? && battle.pbCanChooseNonActive?(target.index)
# Not worth trapping if target will faint this round anyway
eor_damage = target.rough_end_of_round_damage
if eor_damage >= target.hp
next (move.damagingMove?) ? score : Battle::AI::MOVE_USELESS_SCORE
end
# Not worth trapping if target can remove the binding
if ai.trainer.medium_skill? &&
target.has_move_with_function?("RemoveUserBindingAndEntryHazards")
next (move.damagingMove?) ? score : Battle::AI::MOVE_USELESS_SCORE
end
# Score for target becoming trapped in battle
# TODO: These checks are related to desire to switch, and there can be a lot
# more things to consider, e.g. effectiveness of the target's moves
# against its foes. Also applies to other code that calls
# can_become_trapped?
if target.effects[PBEffects::PerishSong] > 0 ||
target.effects[PBEffects::Attract] >= 0 ||
eor_damage > 0
score += 12
end
end end
next score next score
} }

View File

@@ -28,92 +28,92 @@ module PBEffects
Encore = 23 Encore = 23
EncoreMove = 24 EncoreMove = 24
Endure = 25 Endure = 25
ExtraType = 111 ExtraType = 26
FirstPledge = 26 FirstPledge = 27
FlashFire = 27 FlashFire = 28
Flinch = 28 Flinch = 29
FocusEnergy = 29 FocusEnergy = 30
FocusPunch = 30 FocusPunch = 31
FollowMe = 31 FollowMe = 32
Foresight = 32 Foresight = 33
FuryCutter = 33 FuryCutter = 34
GastroAcid = 34 GastroAcid = 35
GemConsumed = 35 GemConsumed = 36
Grudge = 36 Grudge = 37
HealBlock = 37 HealBlock = 38
HelpingHand = 38 HelpingHand = 39
HyperBeam = 39 HyperBeam = 40
Illusion = 40 Illusion = 41
Imprison = 41 Imprison = 42
Ingrain = 42 Ingrain = 43
Instruct = 43 Instruct = 44
Instructed = 44 Instructed = 45
JawLock = 45 JawLock = 46
KingsShield = 46 KingsShield = 47
LaserFocus = 47 LaserFocus = 48
LeechSeed = 48 LeechSeed = 49
LockOn = 49 LockOn = 50
LockOnPos = 50 LockOnPos = 51
MagicBounce = 51 MagicBounce = 52
MagicCoat = 52 MagicCoat = 53
MagnetRise = 53 MagnetRise = 54
MeanLook = 54 MeanLook = 55
MeFirst = 55 MeFirst = 56
Metronome = 56 Metronome = 57
MicleBerry = 57 MicleBerry = 58
Minimize = 58 Minimize = 59
MiracleEye = 59 MiracleEye = 60
MirrorCoat = 60 MirrorCoat = 61
MirrorCoatTarget = 61 MirrorCoatTarget = 62
MoveNext = 62 MoveNext = 63
MudSport = 63 MudSport = 64
Nightmare = 64 Nightmare = 65
NoRetreat = 65 NoRetreat = 66
Obstruct = 66 Obstruct = 67
Octolock = 67 Octolock = 68
Outrage = 68 Outrage = 69
ParentalBond = 69 ParentalBond = 70
PerishSong = 70 PerishSong = 71
PerishSongUser = 71 PerishSongUser = 72
PickupItem = 72 PickupItem = 73
PickupUse = 73 PickupUse = 74
Pinch = 74 # Battle Palace only Pinch = 75 # Battle Palace only
Powder = 75 Powder = 76
PowerTrick = 76 PowerTrick = 77
Prankster = 77 Prankster = 78
PriorityAbility = 78 PriorityAbility = 79
PriorityItem = 79 PriorityItem = 80
Protect = 80 Protect = 81
ProtectRate = 81 ProtectRate = 82
Quash = 82 Quash = 83
Rage = 83 Rage = 84
RagePowder = 84 # Used along with FollowMe RagePowder = 85 # Used along with FollowMe
Rollout = 85 Rollout = 86
Roost = 86 Roost = 87
ShellTrap = 87 ShellTrap = 88
SkyDrop = 88 SkyDrop = 89
SlowStart = 89 SlowStart = 90
SmackDown = 90 SmackDown = 91
Snatch = 91 Snatch = 92
SpikyShield = 92 SpikyShield = 93
Spotlight = 93 Spotlight = 94
Stockpile = 94 Stockpile = 95
StockpileDef = 95 StockpileDef = 96
StockpileSpDef = 96 StockpileSpDef = 97
Substitute = 97 Substitute = 98
TarShot = 98 TarShot = 99
Taunt = 99 Taunt = 100
Telekinesis = 100 Telekinesis = 101
ThroatChop = 101 ThroatChop = 102
Torment = 102 Torment = 103
Toxic = 103 Toxic = 104
Transform = 104 Transform = 105
TransformSpecies = 105 TransformSpecies = 106
Trapping = 106 # Trapping move Trapping = 107 # Trapping move that deals EOR damage
TrappingMove = 107 TrappingMove = 108
TrappingUser = 108 TrappingUser = 109
Truant = 109 Truant = 110
TwoTurnAttack = 110 TwoTurnAttack = 111
Unburden = 112 Unburden = 112
Uproar = 113 Uproar = 113
WaterSport = 114 WaterSport = 114
@@ -123,56 +123,56 @@ module PBEffects
#============================================================================= #=============================================================================
# These effects apply to a battler position # These effects apply to a battler position
#============================================================================= #=============================================================================
FutureSightCounter = 0 FutureSightCounter = 700
FutureSightMove = 1 FutureSightMove = 701
FutureSightUserIndex = 2 FutureSightUserIndex = 702
FutureSightUserPartyIndex = 3 FutureSightUserPartyIndex = 703
HealingWish = 4 HealingWish = 704
LunarDance = 5 LunarDance = 705
Wish = 6 Wish = 706
WishAmount = 7 WishAmount = 707
WishMaker = 8 WishMaker = 708
#============================================================================= #=============================================================================
# These effects apply to a side # These effects apply to a side
#============================================================================= #=============================================================================
AuroraVeil = 0 AuroraVeil = 800
CraftyShield = 1 CraftyShield = 801
EchoedVoiceCounter = 2 EchoedVoiceCounter = 802
EchoedVoiceUsed = 3 EchoedVoiceUsed = 803
LastRoundFainted = 4 LastRoundFainted = 804
LightScreen = 5 LightScreen = 805
LuckyChant = 6 LuckyChant = 806
MatBlock = 7 MatBlock = 807
Mist = 8 Mist = 808
QuickGuard = 9 QuickGuard = 809
Rainbow = 10 Rainbow = 810
Reflect = 11 Reflect = 811
Round = 12 Round = 812
Safeguard = 13 Safeguard = 813
SeaOfFire = 14 SeaOfFire = 814
Spikes = 15 Spikes = 815
StealthRock = 16 StealthRock = 816
StickyWeb = 17 StickyWeb = 817
Swamp = 18 Swamp = 818
Tailwind = 19 Tailwind = 819
ToxicSpikes = 20 ToxicSpikes = 820
WideGuard = 21 WideGuard = 821
#============================================================================= #=============================================================================
# These effects apply to the battle (i.e. both sides) # These effects apply to the battle (i.e. both sides)
#============================================================================= #=============================================================================
AmuletCoin = 0 AmuletCoin = 900
FairyLock = 1 FairyLock = 901
FusionBolt = 2 FusionBolt = 902
FusionFlare = 3 FusionFlare = 903
Gravity = 4 Gravity = 904
HappyHour = 5 HappyHour = 905
IonDeluge = 6 IonDeluge = 906
MagicRoom = 7 MagicRoom = 907
MudSportField = 8 MudSportField = 908
PayDay = 9 PayDay = 909
TrickRoom = 10 TrickRoom = 910
WaterSportField = 11 WaterSportField = 911
WonderRoom = 12 WonderRoom = 912
end end