AI function code rewrites, added Shadow Sky's missing effects, fixed Shadow End's recoil damage

This commit is contained in:
Maruno17
2023-01-22 21:21:19 +00:00
parent f7578002ea
commit d8f38947f4
11 changed files with 243 additions and 111 deletions

View File

@@ -750,7 +750,7 @@ module GameData
when "12F" then new_code = "TrapTargetInBattle" when "12F" then new_code = "TrapTargetInBattle"
when "130" then new_code = "UserLosesHalfHP" when "130" then new_code = "UserLosesHalfHP"
when "131" then new_code = "StartShadowSkyWeather" when "131" then new_code = "StartShadowSkyWeather"
when "132" then new_code = "RemoveAllScreens" when "132" then new_code = "RemoveAllScreensAndSafeguard"
when "133" then new_code = "DoesNothingFailsIfNoAlly" when "133" then new_code = "DoesNothingFailsIfNoAlly"
when "134" then new_code = "DoesNothingCongratulations" when "134" then new_code = "DoesNothingCongratulations"
when "135" then new_code = "FreezeTargetSuperEffectiveAgainstWater" when "135" then new_code = "FreezeTargetSuperEffectiveAgainstWater"

View File

@@ -423,6 +423,8 @@ class Battle::Move
if target.pbHasType?(:ROCK) && specialMove? && @function != "UseTargetDefenseInsteadOfTargetSpDef" if target.pbHasType?(:ROCK) && specialMove? && @function != "UseTargetDefenseInsteadOfTargetSpDef"
multipliers[:defense_multiplier] *= 1.5 multipliers[:defense_multiplier] *= 1.5
end end
when :ShadowSky
multipliers[:final_damage_multiplier] *= 1.5 if type == :SHADOW
end end
# Critical hits # Critical hits
if target.damageState.critical if target.damageState.critical

View File

@@ -839,9 +839,9 @@ class Battle::Move::RemoveScreens < Battle::Move
end end
def pbShowAnimation(id, user, targets, hitNum = 0, showAnimation = true) def pbShowAnimation(id, user, targets, hitNum = 0, showAnimation = true)
if user.pbOpposingSide.effects[PBEffects::LightScreen] > 0 || if user.pbOpposingSide.effects[PBEffects::AuroraVeil] > 0 ||
user.pbOpposingSide.effects[PBEffects::Reflect] > 0 || user.pbOpposingSide.effects[PBEffects::LightScreen] > 0 ||
user.pbOpposingSide.effects[PBEffects::AuroraVeil] > 0 user.pbOpposingSide.effects[PBEffects::Reflect] > 0
hitNum = 1 # Wall-breaking anim hitNum = 1 # Wall-breaking anim
end end
super super
@@ -1540,6 +1540,8 @@ class Battle::Move::TypeAndPowerDependOnWeather < Battle::Move
ret = :ROCK if GameData::Type.exists?(:ROCK) ret = :ROCK if GameData::Type.exists?(:ROCK)
when :Hail when :Hail
ret = :ICE if GameData::Type.exists?(:ICE) ret = :ICE if GameData::Type.exists?(:ICE)
when :ShadowSky
ret = :NONE
end end
return ret return ret
end end

View File

@@ -109,8 +109,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("FailsIfUserDamagedThisTu
# Check whether user is faster than its foe(s) and could use this move # Check whether user is faster than its foe(s) and could use this move
user_faster_count = 0 user_faster_count = 0
foe_faster_count = 0 foe_faster_count = 0
ai.battlers.each_with_index do |b, i| ai.each_foe_battler(user.side) do |b, i|
next if !user.opposes?(b) || b.battler.fainted?
if user.faster_than?(b) if user.faster_than?(b)
user_faster_count += 1 user_faster_count += 1
else else
@@ -121,10 +120,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("FailsIfUserDamagedThisTu
score += 10 if foe_faster_count == 0 score += 10 if foe_faster_count == 0
# Effects that make the target unlikely to act before the user # Effects that make the target unlikely to act before the user
if ai.trainer.high_skill? if ai.trainer.high_skill?
if target.effects[PBEffects::HyperBeam] > 0 || if !target.can_attack?
target.effects[PBEffects::Truant] ||
(target.battler.asleep? && target.statusCount > 1) ||
target.battler.frozen?
score += 20 score += 20
elsif target.effects[PBEffects::Confusion] > 1 || elsif target.effects[PBEffects::Confusion] > 1 ||
target.effects[PBEffects::Attract] == user.index target.effects[PBEffects::Attract] == user.index
@@ -183,8 +179,7 @@ Battle::AI::Handlers::MoveEffectScore.add("StartSunWeather",
score += 15 if user.has_active_item?(:HEATROCK) score += 15 if user.has_active_item?(:HEATROCK)
score -= 10 if user.hp < user.totalhp / 2 # Not worth it at lower HP score -= 10 if user.hp < user.totalhp / 2 # Not worth it at lower HP
# Check for Fire/Water moves # Check for Fire/Water moves
ai.battlers.each do |b| ai.each_battler do |b, i|
next if !b || b.battler.fainted?
if b.has_damaging_move_of_type?(:FIRE) if b.has_damaging_move_of_type?(:FIRE)
score += (b.opposes?(user)) ? -15 : 15 score += (b.opposes?(user)) ? -15 : 15
end end
@@ -229,8 +224,7 @@ Battle::AI::Handlers::MoveEffectScore.add("StartRainWeather",
score += 15 if user.has_active_item?(:DAMPROCK) score += 15 if user.has_active_item?(:DAMPROCK)
score -= 10 if user.hp < user.totalhp / 2 # Not worth it at lower HP score -= 10 if user.hp < user.totalhp / 2 # Not worth it at lower HP
# Check for Fire/Water moves # Check for Fire/Water moves
ai.battlers.each do |b| ai.each_battler do |b, i|
next if !b || b.battler.fainted?
if b.has_damaging_move_of_type?(:WATER) if b.has_damaging_move_of_type?(:WATER)
score += (b.opposes?(user)) ? -15 : 15 score += (b.opposes?(user)) ? -15 : 15
end end
@@ -271,8 +265,7 @@ Battle::AI::Handlers::MoveEffectScore.add("StartSandstormWeather",
score += 15 if user.has_active_item?(:SMOOTHROCK) score += 15 if user.has_active_item?(:SMOOTHROCK)
score -= 10 if user.hp < user.totalhp / 2 # Not worth it at lower HP score -= 10 if user.hp < user.totalhp / 2 # Not worth it at lower HP
# Check for battlers affected by sandstorm's effects # Check for battlers affected by sandstorm's effects
ai.battlers.each do |b| ai.each_battler do |b, i|
next if !b || b.battler.fainted?
if b.battler.takesSandstormDamage? # End of round damage if b.battler.takesSandstormDamage? # End of round damage
score += (b.opposes?(user)) ? 15 : -15 score += (b.opposes?(user)) ? 15 : -15
end end
@@ -312,8 +305,7 @@ Battle::AI::Handlers::MoveEffectScore.add("StartHailWeather",
score += 15 if user.has_active_item?(:ICYROCK) score += 15 if user.has_active_item?(:ICYROCK)
score -= 10 if user.hp < user.totalhp / 2 # Not worth it at lower HP score -= 10 if user.hp < user.totalhp / 2 # Not worth it at lower HP
# Check for battlers affected by hail's effects # Check for battlers affected by hail's effects
ai.battlers.each do |b| ai.each_battler do |b, i|
next if !b || b.battler.fainted?
if b.battler.takesHailDamage? # End of round damage if b.battler.takesHailDamage? # End of round damage
score += (b.opposes?(user)) ? 15 : -15 score += (b.opposes?(user)) ? 15 : -15
end end
@@ -667,9 +659,9 @@ Battle::AI::Handlers::MoveFailureCheck.add("UserSwapsPositionsWithAlly",
proc { |move, user, ai, battle| proc { |move, user, ai, battle|
num_targets = 0 num_targets = 0
idxUserOwner = battle.pbGetOwnerIndexFromBattlerIndex(user.index) idxUserOwner = battle.pbGetOwnerIndexFromBattlerIndex(user.index)
user.battler.allAllies.each do |b| ai.each_ally(user.side) do |b, i|
next if battle.pbGetOwnerIndexFromBattlerIndex(b.index) != idxUserOwner next if battle.pbGetOwnerIndexFromBattlerIndex(b.index) != idxUserOwner
next if !b.near?(user) next if !b.battler.near?(user.battler)
num_targets += 1 num_targets += 1
end end
next num_targets != 1 next num_targets != 1
@@ -686,8 +678,7 @@ Battle::AI::Handlers::MoveEffectScore.add("UserSwapsPositionsWithAlly",
#=============================================================================== #===============================================================================
Battle::AI::Handlers::MoveEffectScore.add("BurnAttackerBeforeUserActs", Battle::AI::Handlers::MoveEffectScore.add("BurnAttackerBeforeUserActs",
proc { |score, move, user, ai, battle| proc { |score, move, user, ai, battle|
ai.battlers.each do |b| ai.each_foe_battler(user.side) do |b|
next if !b || !b.opposes?(user)
next if !b.battler.affectedByContactEffect? next if !b.battler.affectedByContactEffect?
next if !b.battler.pbCanBurn?(user.battler, false, move.move) next if !b.battler.pbCanBurn?(user.battler, false, move.move)
if ai.trainer.high_skill? if ai.trainer.high_skill?
@@ -700,31 +691,43 @@ Battle::AI::Handlers::MoveEffectScore.add("BurnAttackerBeforeUserActs",
) )
#=============================================================================== #===============================================================================
# TODO: Review score modifiers. #
#=============================================================================== #===============================================================================
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("AllBattlersLoseHalfHPUserSkipsNextTurn", Battle::AI::Handlers::MoveEffectScore.add("AllBattlersLoseHalfHPUserSkipsNextTurn",
proc { |move, user, target, ai, battle| proc { |score, move, user, ai, battle|
next target.hp <= 1 # HP halving
} foe_hp_lost = 0
) ally_hp_lost = 0
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("AllBattlersLoseHalfHPUserSkipsNextTurn", ai.each_battler do |b, i|
proc { |score, move, user, target, ai, battle| next if b.hp == 1
score += 20 if target.hp >= target.totalhp / 2 if b.battler.opposes?(user.battler)
foe_hp_lost += b.hp / 2
else
ally_hp_lost += b.hp / 2
end
end
score += 15 * foe_hp_lost / ally_hp_lost
score -= 15 * ally_hp_lost / foe_hp_lost
# Recharging
score = Battle::AI::Handlers.apply_move_effect_score("AttackAndSkipNextTurn",
score, move, user, ai, battle)
next score next score
} }
) )
#=============================================================================== #===============================================================================
# TODO: Review score modifiers. #
#=============================================================================== #===============================================================================
Battle::AI::Handlers::MoveEffectScore.add("UserLosesHalfHP", Battle::AI::Handlers::MoveEffectScore.add("UserLosesHalfHP",
proc { |score, move, user, ai, battle| proc { |score, move, user, ai, battle|
next score - 40 score = Battle::AI::Handlers.apply_move_effect_score("UserLosesHalfOfTotalHP",
score, move, user, ai, battle)
next score
} }
) )
#=============================================================================== #===============================================================================
# TODO: Review score modifiers. #
#=============================================================================== #===============================================================================
Battle::AI::Handlers::MoveFailureCheck.copy("StartSunWeather", Battle::AI::Handlers::MoveFailureCheck.copy("StartSunWeather",
"StartShadowSkyWeather") "StartShadowSkyWeather")
@@ -734,39 +737,64 @@ Battle::AI::Handlers::MoveEffectScore.add("StartShadowSkyWeather",
battle.pbCheckGlobalAbility(:CLOUDNINE) battle.pbCheckGlobalAbility(:CLOUDNINE)
score += 10 if battle.field.weather != :None # Prefer replacing another weather score += 10 if battle.field.weather != :None # Prefer replacing another weather
score -= 10 if user.hp < user.totalhp / 2 # Not worth it at lower HP score -= 10 if user.hp < user.totalhp / 2 # Not worth it at lower HP
# Check for battlers affected by Shadow Sky's effects
ai.each_battler do |b, i|
if b.has_damaging_move_of_type?(:SHADOW)
score += (b.opposes?(user)) ? 15 : -15
end
if b.battler.takesShadowSkyDamage? # End of round damage
score += (b.opposes?(user)) ? 15 : -15
end
end
# Check for moves affected by Shadow Sky
# TODO: Check other battlers for these as well?
if ai.trainer.medium_skill? && !user.has_active_item?(:UTILITYUMBRELLA)
if user.has_move_with_function?("TypeAndPowerDependOnWeather")
score += 10
end
end
next score next score
} }
) )
#=============================================================================== #===============================================================================
# TODO: Review score modifiers. #
#=============================================================================== #===============================================================================
Battle::AI::Handlers::MoveFailureCheck.add("RemoveAllScreens", Battle::AI::Handlers::MoveFailureCheck.add("RemoveAllScreensAndSafeguard",
proc { |move, user, ai, battle| proc { |move, user, ai, battle|
will_fail = true will_fail = true
battle.sides.each do |side| battle.sides.each do |side|
will_fail = false if side.effects[PBEffects::AuroraVeil] > 0 || will_fail = false if side.effects[PBEffects::AuroraVeil] > 0 ||
side.effects[PBEffects::Reflect] > 0 ||
side.effects[PBEffects::LightScreen] > 0 || side.effects[PBEffects::LightScreen] > 0 ||
side.effects[PBEffects::Reflect] > 0 ||
side.effects[PBEffects::Safeguard] > 0 side.effects[PBEffects::Safeguard] > 0
end end
next will_fail next will_fail
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("RemoveAllScreens", Battle::AI::Handlers::MoveEffectScore.add("RemoveAllScreensAndSafeguard",
proc { |score, move, user, ai, battle| proc { |score, move, user, ai, battle|
if user.pbOpposingSide.effects[PBEffects::AuroraVeil] > 0 || foe_side = user.pbOpposingSide
user.pbOpposingSide.effects[PBEffects::Reflect] > 0 || # Useless if the foe's side has no screens/Safeguard to remove, or if
user.pbOpposingSide.effects[PBEffects::LightScreen] > 0 || # they'll end this round anyway
user.pbOpposingSide.effects[PBEffects::Safeguard] > 0 if foe_side.effects[PBEffects::AuroraVeil] <= 1 &&
score += 30 foe_side.effects[PBEffects::LightScreen] <= 1 &&
foe_side.effects[PBEffects::Reflect] <= 1 &&
foe_side.effects[PBEffects::Safeguard] <= 1
next Battle::AI::MOVE_USELESS_SCORE
end end
if user.pbOwnSide.effects[PBEffects::AuroraVeil] > 0 || # Prefer removing opposing screens
user.pbOwnSide.effects[PBEffects::Reflect] > 0 || score = Battle::AI::Handlers.apply_move_effect_score("RemoveScreens",
user.pbOwnSide.effects[PBEffects::LightScreen] > 0 || score, move, user, ai, battle)
user.pbOwnSide.effects[PBEffects::Safeguard] > 0 # Don't prefer removing same side screens
score -= 70 ai.each_foe_battler(user.side) do |b, i|
score -= Battle::AI::Handlers.apply_move_effect_score("RemoveScreens",
0, move, b, ai, battle)
break
end end
# Safeguard
score += 10 if foe_side.effects[PBEffects::Safeguard] > 0
score -= 10 if user.pbOwnSide.effects[PBEffects::Safeguard] > 0
next score next score
} }
) )

View File

@@ -371,9 +371,7 @@ Battle::AI::Handlers::MoveEffectScore.add("DoublePowerIfUserLostHPThisTurn",
proc { |score, move, user, ai, battle| proc { |score, move, user, ai, battle|
# Prefer if user is slower than its foe(s) and the foe(s) can attack # Prefer if user is slower than its foe(s) and the foe(s) can attack
ai.each_foe_battler(user.side) do |b, i| ai.each_foe_battler(user.side) do |b, i|
next if user.faster_than?(b) || (b.status == :SLEEP && b.statusCount > 1) || next if user.faster_than?(b) || !b.can_attack?
b.status == :FROZEN || b.effects[PBEffects::HyperBeam] > 0 ||
b.effects[PBEffects::Truant] || b.effects[PBEffects::SkyDrop] >= 0
score += 4 score += 4
end end
next score next score
@@ -388,9 +386,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("DoublePowerIfTargetLostH
# Prefer if a user's ally is faster than the user and that ally can attack # Prefer if a user's ally is faster than the user and that ally can attack
ai.each_foe_battler(target.side) do |b, i| ai.each_foe_battler(target.side) do |b, i|
next if i == user.index next if i == user.index
next if user.faster_than?(b) || (b.status == :SLEEP && b.statusCount > 1) || next if user.faster_than?(b) || !b.can_attack?
b.status == :FROZEN || b.effects[PBEffects::HyperBeam] > 0 ||
b.effects[PBEffects::Truant] || b.effects[PBEffects::SkyDrop] >= 0
score += 4 score += 4
end end
next score next score
@@ -428,25 +424,85 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("DoublePowerIfTargetNotAc
# AlwaysCriticalHit # AlwaysCriticalHit
#=============================================================================== #===============================================================================
# TODO: Review score modifiers. #
#=============================================================================== #===============================================================================
Battle::AI::Handlers::MoveEffectScore.add("EnsureNextCriticalHit", Battle::AI::Handlers::MoveEffectScore.add("EnsureNextCriticalHit",
proc { |score, move, user, ai, battle| proc { |score, move, user, ai, battle|
next Battle::AI::MOVE_USELESS_SCORE if user.effects[PBEffects::LaserFocus] > 0 next Battle::AI::MOVE_USELESS_SCORE if user.effects[PBEffects::LaserFocus] > 0
# TODO: Useless if user will already always critical hit ("AlwaysCriticalHit" # Useless if the user's critical hit stage ensures critical hits already, or
# or Lucky Chant/crit stage is +3/etc.). # critical hits are impossible (e.g. via Lucky Chant)
next score + 10 crit_stage = move.rough_critical_hit_stage
if crit_stage < 0 ||
crit_stage >= Battle::Move::CRITICAL_HIT_RATIOS.length ||
Battle::Move::CRITICAL_HIT_RATIOS[crit_stage] == 1
next Battle::AI::MOVE_USELESS_SCORE
end
# Prefer if user knows a damaging move which won't definitely critical hit
if user.check_for_move { |m| m.damagingMove? && m.function != "AlwaysCriticalHit"}
# TODO: Change the score depending on how much of an effect a critical hit
# will have? Critical hits ignore the user's offensive stat drops
# and the target's defensive stat raises, and multiply the damage.
score += 10
end
next score
} }
) )
#=============================================================================== #===============================================================================
# TODO: Review score modifiers. #
#=============================================================================== #===============================================================================
Battle::AI::Handlers::MoveFailureCheck.add("StartPreventCriticalHitsAgainstUserSide", Battle::AI::Handlers::MoveFailureCheck.add("StartPreventCriticalHitsAgainstUserSide",
proc { |move, user, ai, battle| proc { |move, user, ai, battle|
next user.pbOwnSide.effects[PBEffects::LuckyChant] > 0 next user.pbOwnSide.effects[PBEffects::LuckyChant] > 0
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("StartPreventCriticalHitsAgainstUserSide",
proc { |score, move, user, ai, battle|
# Useless if Pokémon on the user's side are immune to critical hits
user_side_immune = true
ai.each_same_side_battler(user.side) do |b, i|
crit_stage = 0
if b.ability_active?
crit_stage = Battle::AbilityEffects.triggerCriticalCalcFromTarget(b.battler.ability,
b.battler, b.battler, crit_stage)
next if crit_stage < 0
end
if b.item_active?
crit_stage = Battle::ItemEffects.triggerCriticalCalcFromTarget(b.battler.item,
b.battler, b.battler, crit_stage)
next if crit_stage < 0
end
user_side_immune = false
break
end
next Battle::AI::MOVE_USELESS_SCORE if user_side_immune
# Prefer if any foe has an increased critical hit rate or moves/effects that
# make critical hits more likely
ai.each_foe_battler(user.side) do |b, i|
crit_stage = 0
if b.ability_active?
crit_stage = Battle::AbilityEffects.triggerCriticalCalcFromUser(b.battler.ability,
b.battler, user.battler, crit_stage)
next if crit_stage < 0
end
if b.item_active?
crit_stage = Battle::ItemEffects.triggerCriticalCalcFromUser(b.battler.item,
b.battler, user.battler, crit_stage)
next if crit_stage < 0
end
crit_stage += b.effects[PBEffects::FocusEnergy]
crit_stage += 1 if m.check_for_move { |m| m.highCriticalRate? }
crit_stage = [crit_stage, Battle::Move::CRITICAL_HIT_RATIOS.length - 1].min
crit_stage = 3 if crit_stage < 3 && m.check_for_move { |m| m.pbCritialOverride(b.battler, user.battler) > 0 }
# TODO: Change the score depending on how much of an effect a critical hit
# will have? Critical hits ignore the user's offensive stat drops
# and the target's defensive stat raises, and multiply the damage.
score += 5 * crit_stage if crit_stage > 0
score += 10 if b.effects[PBEffects::LaserFocus] > 0
end
next score
}
)
#=============================================================================== #===============================================================================
# #
@@ -466,9 +522,7 @@ Battle::AI::Handlers::MoveEffectScore.add("UserEnduresFaintingThisTurn",
# Prefer for each foe that can attack # Prefer for each foe that can attack
useless = true useless = true
ai.each_foe_battler(user.side) do |b, i| ai.each_foe_battler(user.side) do |b, i|
next if (b.status == :SLEEP && b.statusCount > 1) || next if !b.can_attack?
b.status == :FROZEN || b.effects[PBEffects::HyperBeam] > 0 ||
b.effects[PBEffects::Truant] || b.effects[PBEffects::SkyDrop] >= 0
useless = false useless = false
score += 4 score += 4
end end
@@ -639,15 +693,15 @@ Battle::AI::Handlers::MoveEffectScore.add("StartWeakenDamageAgainstUserSideIfHai
Battle::AI::Handlers::MoveEffectScore.add("RemoveScreens", Battle::AI::Handlers::MoveEffectScore.add("RemoveScreens",
proc { |score, move, user, ai, battle| proc { |score, move, user, ai, battle|
# Prefer if allies have physical moves that are being weakened # Prefer if allies have physical moves that are being weakened
if user.pbOpposingSide.effects[PBEffects::Reflect] > 0 || if user.pbOpposingSide.effects[PBEffects::Reflect] > 1 ||
user.pbOpposingSide.effects[PBEffects::AuroraVeil] > 0 user.pbOpposingSide.effects[PBEffects::AuroraVeil] > 1
ai.each_same_side_battler(user.side) do |b, i| ai.each_same_side_battler(user.side) do |b, i|
score += 10 if b.check_for_move { |m| m.physicalMove?(m.type) } score += 10 if b.check_for_move { |m| m.physicalMove?(m.type) }
end end
end end
# Prefer if allies have special moves that are being weakened # Prefer if allies have special moves that are being weakened
if user.pbOpposingSide.effects[PBEffects::LightScreen] > 0 || if user.pbOpposingSide.effects[PBEffects::LightScreen] > 1 ||
user.pbOpposingSide.effects[PBEffects::AuroraVeil] > 0 user.pbOpposingSide.effects[PBEffects::AuroraVeil] > 1
ai.each_same_side_battler(user.side) do |b, i| ai.each_same_side_battler(user.side) do |b, i|
score += 10 if b.check_for_move { |m| m.specialMove?(m.type) } score += 10 if b.check_for_move { |m| m.specialMove?(m.type) }
end end
@@ -666,9 +720,7 @@ Battle::AI::Handlers::MoveEffectScore.add("ProtectUser",
# Prefer for each foe that can attack # Prefer for each foe that can attack
useless = true useless = true
ai.each_foe_battler(user.side) do |b, i| ai.each_foe_battler(user.side) do |b, i|
next if (b.status == :SLEEP && b.statusCount > 1) || next if !b.can_attack?
b.status == :FROZEN || b.effects[PBEffects::HyperBeam] > 0 ||
b.effects[PBEffects::Truant] || b.effects[PBEffects::SkyDrop] >= 0
useless = false useless = false
score += 4 score += 4
score += 4 if b.effects[PBEffects::TwoTurnAttack] score += 4 if b.effects[PBEffects::TwoTurnAttack]

View File

@@ -646,8 +646,7 @@ Battle::AI::Handlers::MoveEffectScore.add("AttackerFaintsIfUserFaints",
score -= 25 score -= 25
# Check whether user is faster than its foe(s) and could use this move # Check whether user is faster than its foe(s) and could use this move
user_faster_count = 0 user_faster_count = 0
ai.battlers.each_with_index do |b, i| ai.each_foe_battler(user.side) do |b, i|
next if !user.opposes?(b) || b.battler.fainted?
user_faster_count += 1 if user.faster_than?(b) user_faster_count += 1 if user.faster_than?(b)
end end
next score if user_faster_count == 0 # Move will almost certainly have no effect next score if user_faster_count == 0 # Move will almost certainly have no effect
@@ -670,8 +669,7 @@ Battle::AI::Handlers::MoveEffectScore.add("SetAttackerMovePPTo0IfUserFaints",
score -= 25 score -= 25
# Check whether user is faster than its foe(s) and could use this move # Check whether user is faster than its foe(s) and could use this move
user_faster_count = 0 user_faster_count = 0
ai.battlers.each_with_index do |b, i| ai.each_foe_battler(user.side) do |b, i|
next if !user.opposes?(b) || b.battler.fainted?
user_faster_count += 1 if user.faster_than?(b) user_faster_count += 1 if user.faster_than?(b)
end end
next score if user_faster_count == 0 # Move will almost certainly have no effect next score if user_faster_count == 0 # Move will almost certainly have no effect

View File

@@ -13,8 +13,8 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("UserTakesTargetItem",
user_no_item_preference = ai.battler_wants_item?(user, :NONE) user_no_item_preference = ai.battler_wants_item?(user, :NONE)
target_item_preference = ai.battler_wants_item?(target, target.item_id) target_item_preference = ai.battler_wants_item?(target, target.item_id)
target_no_item_preference = ai.battler_wants_item?(target, :NONE) target_no_item_preference = ai.battler_wants_item?(target, :NONE)
score += (user_item_preference - user_no_item_preference) * 5 score += (user_item_preference - user_no_item_preference) * 3
score += (target_item_preference - target_no_item_preference) * 5 score += (target_item_preference - target_no_item_preference) * 3
next score next score
} }
) )
@@ -35,8 +35,8 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("TargetTakesUserItem",
user_no_item_preference = ai.battler_wants_item?(user, :NONE) user_no_item_preference = ai.battler_wants_item?(user, :NONE)
target_item_preference = ai.battler_wants_item?(target, user.item_id) target_item_preference = ai.battler_wants_item?(target, user.item_id)
target_no_item_preference = ai.battler_wants_item?(target, :NONE) target_no_item_preference = ai.battler_wants_item?(target, :NONE)
score -= (user_item_preference - user_no_item_preference) * 5 score -= (user_item_preference - user_no_item_preference) * 3
score -= (target_item_preference - target_no_item_preference) * 5 score -= (target_item_preference - target_no_item_preference) * 3
next score next score
} }
) )
@@ -60,8 +60,8 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("UserTargetSwapItems",
user_old_item_preference = ai.battler_wants_item?(user, user.item_id) user_old_item_preference = ai.battler_wants_item?(user, user.item_id)
target_new_item_preference = ai.battler_wants_item?(target, user.item_id) target_new_item_preference = ai.battler_wants_item?(target, user.item_id)
target_old_item_preference = ai.battler_wants_item?(target, target.item_id) target_old_item_preference = ai.battler_wants_item?(target, target.item_id)
score += (user_new_item_preference - user_old_item_preference) * 5 score += (user_new_item_preference - user_old_item_preference) * 3
score -= (target_new_item_preference - target_old_item_preference) * 5 score -= (target_new_item_preference - target_old_item_preference) * 3
# Don't prefer if user used this move in the last round # Don't prefer if user used this move in the last round
score -= 15 if user.battler.lastMoveUsed && score -= 15 if user.battler.lastMoveUsed &&
GameData::Move.get(user.battler.lastMoveUsed).function_code == "UserTargetSwapItems" GameData::Move.get(user.battler.lastMoveUsed).function_code == "UserTargetSwapItems"
@@ -81,7 +81,7 @@ Battle::AI::Handlers::MoveEffectScore.add("RestoreUserConsumedItem",
proc { |score, move, user, ai, battle| proc { |score, move, user, ai, battle|
user_new_item_preference = ai.battler_wants_item?(user, user.battler.recycleItem) user_new_item_preference = ai.battler_wants_item?(user, user.battler.recycleItem)
user_old_item_preference = ai.battler_wants_item?(user, user.item_id) user_old_item_preference = ai.battler_wants_item?(user, user.item_id)
score += (user_new_item_preference - user_old_item_preference) * 8 score += (user_new_item_preference - user_old_item_preference) * 4
next score next score
} }
) )
@@ -103,7 +103,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("RemoveTargetItem",
# User can knock off the target's item; score it # User can knock off the target's item; score it
target_item_preference = ai.battler_wants_item?(target, target.item_id) target_item_preference = ai.battler_wants_item?(target, target.item_id)
target_no_item_preference = ai.battler_wants_item?(target, :NONE) target_no_item_preference = ai.battler_wants_item?(target, :NONE)
score += (target_item_preference - target_no_item_preference) * 5 score += (target_item_preference - target_no_item_preference) * 4
next score next score
} }
) )
@@ -121,7 +121,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("DestroyTargetBerryOrGem"
# User can incinerate the target's item; score it # User can incinerate the target's item; score it
target_item_preference = ai.battler_wants_item?(target, target.item_id) target_item_preference = ai.battler_wants_item?(target, target.item_id)
target_no_item_preference = ai.battler_wants_item?(target, :NONE) target_no_item_preference = ai.battler_wants_item?(target, :NONE)
score += (target_item_preference - target_no_item_preference) * 8 score += (target_item_preference - target_no_item_preference) * 4
next score next score
} }
) )
@@ -142,7 +142,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("CorrodeTargetItem",
proc { |score, move, user, target, ai, battle| proc { |score, move, user, target, ai, battle|
target_item_preference = ai.battler_wants_item?(target, target.item_id) target_item_preference = ai.battler_wants_item?(target, target.item_id)
target_no_item_preference = ai.battler_wants_item?(target, :NONE) target_no_item_preference = ai.battler_wants_item?(target, :NONE)
score += (target_item_preference - target_no_item_preference) * 8 score += (target_item_preference - target_no_item_preference) * 4
next score next score
} }
) )
@@ -258,13 +258,13 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("UserConsumeTargetBerry",
# User can consume the target's berry; score it # User can consume the target's berry; score it
target_item_preference = ai.battler_wants_item?(target, target.item_id) target_item_preference = ai.battler_wants_item?(target, target.item_id)
target_no_item_preference = ai.battler_wants_item?(target, :NONE) target_no_item_preference = ai.battler_wants_item?(target, :NONE)
score += (target_item_preference - target_no_item_preference) * 8 score += (target_item_preference - target_no_item_preference) * 4
next score next score
} }
) )
#=============================================================================== #===============================================================================
# TODO: Review score modifiers. #
#=============================================================================== #===============================================================================
Battle::AI::Handlers::MoveFailureCheck.add("ThrowUserItemAtTarget", Battle::AI::Handlers::MoveFailureCheck.add("ThrowUserItemAtTarget",
proc { |move, user, ai, battle| proc { |move, user, ai, battle|
@@ -280,3 +280,40 @@ Battle::AI::Handlers::MoveBasePower.add("ThrowUserItemAtTarget",
next move.move.pbBaseDamage(power, user.battler, target.battler) next move.move.pbBaseDamage(power, user.battler, target.battler)
} }
) )
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("ThrowUserItemAtTarget",
proc { |score, move, user, target, ai, battle|
case user.item_id
when :POISONBARB, :TOXICORB
score = Battle::AI::Handlers.apply_move_effect_against_target_score("PoisonTarget",
score, move, user, target, ai, battle)
when :FLAMEORB
score = Battle::AI::Handlers.apply_move_effect_against_target_score("BurnTarget",
score, move, user, target, ai, battle)
when :LIGHTBALL
score = Battle::AI::Handlers.apply_move_effect_against_target_score("ParalyzeTarget",
score, move, user, target, ai, battle)
when :KINGSROCK, :RAZORFANG
score = Battle::AI::Handlers.apply_move_effect_against_target_score("FlinchTarget",
score, move, user, target, ai, battle)
else
# TODO: Berries/Berry Juice/Mental Herb/White Herb also have Fling
# effects. Should they be accounted for individually, or is it okay
# to consider it bad to Fling these in general? Note that they all
# do minimal damage so this move probably won't be used anyway.
if Battle::ItemEffects::HPHeal[user.item_id] ||
Battle::ItemEffects::StatusCure[user.item_id] ||
Battle::ItemEffects::OnEndOfUsingMove[user.item_id] ||
Battle::ItemEffects::OnEndOfUsingMoveStatRestore[user.item_id]
score -= 8
end
end
# Prefer if the user doesn't want its held item/don't prefer if it wants to
# keep its held item
user_item_preference = ai.battler_wants_item?(user, user.item_id)
user_no_item_preference = ai.battler_wants_item?(user, :NONE)
score += (user_item_preference - user_no_item_preference) * 4
# Prefer if user will benefit from not having an item
score += 5 if user.has_active_ability?(:UNBURDEN)
next score
}
)

View File

@@ -289,14 +289,10 @@ Battle::AI::Handlers::MoveEffectScore.add("UsedAfterAllyRoundWithDoublePower",
) )
#=============================================================================== #===============================================================================
# TODO: Review score modifiers. This could reasonably used on an ally. #
#=============================================================================== #===============================================================================
Battle::AI::Handlers::MoveEffectScore.add("TargetActsNext", Battle::AI::Handlers::MoveEffectScore.add("TargetActsNext",
proc { |score, move, user, ai, battle| proc { |score, move, user, ai, battle|
# Useless if the user has no ally
has_ally = false
ai.each_ally(user.index) { |b, i| has_ally = true }
next Battle::AI::MOVE_USELESS_SCORE if !has_ally
# Useless if the target is a foe # Useless if the target is a foe
next Battle::AI::MOVE_USELESS_SCORE if target.opposes?(user) next Battle::AI::MOVE_USELESS_SCORE if target.opposes?(user)
# Compare the speeds of all battlers # Compare the speeds of all battlers
@@ -313,21 +309,27 @@ Battle::AI::Handlers::MoveEffectScore.add("TargetActsNext",
next Battle::AI::MOVE_USELESS_SCORE if idx_target < idx_user next Battle::AI::MOVE_USELESS_SCORE if idx_target < idx_user
# Useless if the target will move next anyway # Useless if the target will move next anyway
next Battle::AI::MOVE_USELESS_SCORE if idx_target - idx_user <= 1 next Battle::AI::MOVE_USELESS_SCORE if idx_target - idx_user <= 1
next score # Generally not worth using
# NOTE: Because this move can be used against a foe but is being used on an
# ally (since we're here in this code), this move's score will be
# inverted later. A higher score here means this move will be less
# preferred, which is the result we want.
next score + 10
} }
) )
#=============================================================================== #===============================================================================
# TODO: Review score modifiers. #
#=============================================================================== #===============================================================================
Battle::AI::Handlers::MoveEffectScore.add("TargetActsLast", Battle::AI::Handlers::MoveEffectScore.add("TargetActsLast",
proc { |score, move, user, ai, battle| proc { |score, move, user, ai, battle|
# Useless if the user has no ally
has_ally = false
ai.each_ally(user.index) { |b, i| has_ally = true }
next Battle::AI::MOVE_USELESS_SCORE if !has_ally
# Useless if the target is an ally # Useless if the target is an ally
next Battle::AI::MOVE_USELESS_SCORE if !target.opposes?(user) next Battle::AI::MOVE_USELESS_SCORE if !target.opposes?(user)
# Useless if the user has no ally (the point of this move is to let the ally
# get in a hit before the foe)
has_ally = false
ai.each_ally(user.index) { |b, i| has_ally = true if b.can_attack? }
next Battle::AI::MOVE_USELESS_SCORE if !has_ally
# Compare the speeds of all battlers # Compare the speeds of all battlers
speeds = [] speeds = []
ai.each_battler { |b, i| speeds.push([i, rough_stat(:SPEED)]) } ai.each_battler { |b, i| speeds.push([i, rough_stat(:SPEED)]) }
@@ -338,11 +340,16 @@ Battle::AI::Handlers::MoveEffectScore.add("TargetActsLast",
end end
idx_user = speeds.index { |ele| ele[0] == user.index } idx_user = speeds.index { |ele| ele[0] == user.index }
idx_target = speeds.index { |ele| ele[0] == target.index } idx_target = speeds.index { |ele| ele[0] == target.index }
idx_slowest_ally = -1
speeds.each_with_index { |ele, i| idx_slowest_ally = i if user.index.even? == ele[0].even? }
# Useless if the target is faster than the user # Useless if the target is faster than the user
next Battle::AI::MOVE_USELESS_SCORE if idx_target < idx_user next Battle::AI::MOVE_USELESS_SCORE if idx_target < idx_user
# Useless if the target will move last anyway # Useless if the target will move last anyway
next Battle::AI::MOVE_USELESS_SCORE if idx_target == speeds.length - 1 next Battle::AI::MOVE_USELESS_SCORE if idx_target == speeds.length - 1
next score # Useless if the slowest ally is faster than the target
next Battle::AI::MOVE_USELESS_SCORE if idx_slowest_ally < idx_target
# Generally not worth using
next score - 10
} }
) )
@@ -378,16 +385,9 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("TargetUsesItsLastUsedMov
# StartSlowerBattlersActFirst # StartSlowerBattlersActFirst
#=============================================================================== #===============================================================================
# TODO: Review score modifiers. #
#=============================================================================== #===============================================================================
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("HigherPriorityInGrassyTerrain", # HigherPriorityInGrassyTerrain
proc { |score, move, user, target, ai, battle|
if ai.trainer.medium_skill? && battle.field.terrain == :Grassy
score += 15 if target.faster_than?(user)
end
next score
}
)
#=============================================================================== #===============================================================================
# #

View File

@@ -212,7 +212,7 @@ class Battle::AI::AIBattler
# TODO: Need to check the move's pbCalcTypeModSingle. # TODO: Need to check the move's pbCalcTypeModSingle.
ret *= effectiveness_of_type_against_single_battler_type(type, defend_type, user) ret *= effectiveness_of_type_against_single_battler_type(type, defend_type, user)
end end
ret *= 2 if @battler.effects[PBEffects::TarShot] && type == :FIRE ret *= 2 if self.effects[PBEffects::TarShot] && type == :FIRE
end end
return ret return ret
end end
@@ -281,6 +281,18 @@ class Battle::AI::AIBattler
#============================================================================= #=============================================================================
def can_attack?
return false if self.effects[PBEffects::SkyDrop] >= 0
return false if self.effects[PBEffects::HyperBeam] > 0
return false if status == :SLEEP && statusCount > 1
return false if status == :FROZEN # Only 20% chance of unthawing; assune it won't
return false if self.effects[PBEffects::Truant]
return false if self.effects[PBEffects::Flinch]
# NOTE: Confusion/infatuation/paralysis have higher chances of allowing the
# attack, so the battler is treated as able to attack in those cases.
return true
end
def can_switch_lax? def can_switch_lax?
return false if wild? return false if wild?
@ai.battle.eachInTeamFromBattlerIndex(@index) do |pkmn, i| @ai.battle.eachInTeamFromBattlerIndex(@index) do |pkmn, i|

View File

@@ -546,6 +546,7 @@ class Battle::AI::AIMove
# 2 = additional effect will work # 2 = additional effect will work
# 3 = additional effect has an increased chance to work # 3 = additional effect has an increased chance to work
def additional_effect_usability(user, target) def additional_effect_usability(user, target)
return 3 if self.function == "ThrowUserItemAtTarget"
return 0 if @move.addlEffect == 0 # Doesn't have an additional effect return 0 if @move.addlEffect == 0 # Doesn't have an additional effect
return 1 if target.has_active_ability?(:SHIELDDUST) && !@ai.battle.moldBreaker return 1 if target.has_active_ability?(:SHIELDDUST) && !@ai.battle.moldBreaker
return 3 if (Settings::MECHANICS_GENERATION >= 6 || self.function != "EffectDependsOnEnvironment") && return 3 if (Settings::MECHANICS_GENERATION >= 6 || self.function != "EffectDependsOnEnvironment") &&

View File

@@ -366,7 +366,7 @@ end
#=============================================================================== #===============================================================================
class Battle::Move::UserLosesHalfHP < Battle::Move::RecoilMove class Battle::Move::UserLosesHalfHP < Battle::Move::RecoilMove
def pbRecoilDamage(user, target) def pbRecoilDamage(user, target)
return (target.damageState.totalHPLost / 2.0).round return (user.hp / 2.0).round
end end
def pbEffectAfterAllHits(user, target) def pbEffectAfterAllHits(user, target)
@@ -398,13 +398,13 @@ end
# Ends the effects of Light Screen, Reflect and Safeguard on both sides. # Ends the effects of Light Screen, Reflect and Safeguard on both sides.
# (Shadow Shed) # (Shadow Shed)
#=============================================================================== #===============================================================================
class Battle::Move::RemoveAllScreens < Battle::Move class Battle::Move::RemoveAllScreensAndSafeguard < Battle::Move
def pbMoveFailed?(user, targets) def pbMoveFailed?(user, targets)
will_fail = true will_fail = true
@battle.sides.each do |side| @battle.sides.each do |side|
will_fail = false if side.effects[PBEffects::AuroraVeil] > 0 || will_fail = false if side.effects[PBEffects::AuroraVeil] > 0 ||
side.effects[PBEffects::Reflect] > 0 ||
side.effects[PBEffects::LightScreen] > 0 || side.effects[PBEffects::LightScreen] > 0 ||
side.effects[PBEffects::Reflect] > 0 ||
side.effects[PBEffects::Safeguard] > 0 side.effects[PBEffects::Safeguard] > 0
end end
if will_fail if will_fail
@@ -417,8 +417,8 @@ class Battle::Move::RemoveAllScreens < Battle::Move
def pbEffectGeneral(user) def pbEffectGeneral(user)
@battle.sides.each do |i| @battle.sides.each do |i|
i.effects[PBEffects::AuroraVeil] = 0 i.effects[PBEffects::AuroraVeil] = 0
i.effects[PBEffects::Reflect] = 0
i.effects[PBEffects::LightScreen] = 0 i.effects[PBEffects::LightScreen] = 0
i.effects[PBEffects::Reflect] = 0
i.effects[PBEffects::Safeguard] = 0 i.effects[PBEffects::Safeguard] = 0
end end
@battle.pbDisplay(_INTL("It broke all barriers!")) @battle.pbDisplay(_INTL("It broke all barriers!"))