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 "130" then new_code = "UserLosesHalfHP"
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 "134" then new_code = "DoesNothingCongratulations"
when "135" then new_code = "FreezeTargetSuperEffectiveAgainstWater"

View File

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

View File

@@ -839,9 +839,9 @@ class Battle::Move::RemoveScreens < Battle::Move
end
def pbShowAnimation(id, user, targets, hitNum = 0, showAnimation = true)
if user.pbOpposingSide.effects[PBEffects::LightScreen] > 0 ||
user.pbOpposingSide.effects[PBEffects::Reflect] > 0 ||
user.pbOpposingSide.effects[PBEffects::AuroraVeil] > 0
if user.pbOpposingSide.effects[PBEffects::AuroraVeil] > 0 ||
user.pbOpposingSide.effects[PBEffects::LightScreen] > 0 ||
user.pbOpposingSide.effects[PBEffects::Reflect] > 0
hitNum = 1 # Wall-breaking anim
end
super
@@ -1540,6 +1540,8 @@ class Battle::Move::TypeAndPowerDependOnWeather < Battle::Move
ret = :ROCK if GameData::Type.exists?(:ROCK)
when :Hail
ret = :ICE if GameData::Type.exists?(:ICE)
when :ShadowSky
ret = :NONE
end
return ret
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
user_faster_count = 0
foe_faster_count = 0
ai.battlers.each_with_index do |b, i|
next if !user.opposes?(b) || b.battler.fainted?
ai.each_foe_battler(user.side) do |b, i|
if user.faster_than?(b)
user_faster_count += 1
else
@@ -121,10 +120,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("FailsIfUserDamagedThisTu
score += 10 if foe_faster_count == 0
# Effects that make the target unlikely to act before the user
if ai.trainer.high_skill?
if target.effects[PBEffects::HyperBeam] > 0 ||
target.effects[PBEffects::Truant] ||
(target.battler.asleep? && target.statusCount > 1) ||
target.battler.frozen?
if !target.can_attack?
score += 20
elsif target.effects[PBEffects::Confusion] > 1 ||
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 -= 10 if user.hp < user.totalhp / 2 # Not worth it at lower HP
# Check for Fire/Water moves
ai.battlers.each do |b|
next if !b || b.battler.fainted?
ai.each_battler do |b, i|
if b.has_damaging_move_of_type?(:FIRE)
score += (b.opposes?(user)) ? -15 : 15
end
@@ -229,8 +224,7 @@ Battle::AI::Handlers::MoveEffectScore.add("StartRainWeather",
score += 15 if user.has_active_item?(:DAMPROCK)
score -= 10 if user.hp < user.totalhp / 2 # Not worth it at lower HP
# Check for Fire/Water moves
ai.battlers.each do |b|
next if !b || b.battler.fainted?
ai.each_battler do |b, i|
if b.has_damaging_move_of_type?(:WATER)
score += (b.opposes?(user)) ? -15 : 15
end
@@ -271,8 +265,7 @@ Battle::AI::Handlers::MoveEffectScore.add("StartSandstormWeather",
score += 15 if user.has_active_item?(:SMOOTHROCK)
score -= 10 if user.hp < user.totalhp / 2 # Not worth it at lower HP
# Check for battlers affected by sandstorm's effects
ai.battlers.each do |b|
next if !b || b.battler.fainted?
ai.each_battler do |b, i|
if b.battler.takesSandstormDamage? # End of round damage
score += (b.opposes?(user)) ? 15 : -15
end
@@ -312,8 +305,7 @@ Battle::AI::Handlers::MoveEffectScore.add("StartHailWeather",
score += 15 if user.has_active_item?(:ICYROCK)
score -= 10 if user.hp < user.totalhp / 2 # Not worth it at lower HP
# Check for battlers affected by hail's effects
ai.battlers.each do |b|
next if !b || b.battler.fainted?
ai.each_battler do |b, i|
if b.battler.takesHailDamage? # End of round damage
score += (b.opposes?(user)) ? 15 : -15
end
@@ -667,9 +659,9 @@ Battle::AI::Handlers::MoveFailureCheck.add("UserSwapsPositionsWithAlly",
proc { |move, user, ai, battle|
num_targets = 0
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 !b.near?(user)
next if !b.battler.near?(user.battler)
num_targets += 1
end
next num_targets != 1
@@ -686,8 +678,7 @@ Battle::AI::Handlers::MoveEffectScore.add("UserSwapsPositionsWithAlly",
#===============================================================================
Battle::AI::Handlers::MoveEffectScore.add("BurnAttackerBeforeUserActs",
proc { |score, move, user, ai, battle|
ai.battlers.each do |b|
next if !b || !b.opposes?(user)
ai.each_foe_battler(user.side) do |b|
next if !b.battler.affectedByContactEffect?
next if !b.battler.pbCanBurn?(user.battler, false, move.move)
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",
proc { |move, user, target, ai, battle|
next target.hp <= 1
}
)
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("AllBattlersLoseHalfHPUserSkipsNextTurn",
proc { |score, move, user, target, ai, battle|
score += 20 if target.hp >= target.totalhp / 2
Battle::AI::Handlers::MoveEffectScore.add("AllBattlersLoseHalfHPUserSkipsNextTurn",
proc { |score, move, user, ai, battle|
# HP halving
foe_hp_lost = 0
ally_hp_lost = 0
ai.each_battler do |b, i|
next if b.hp == 1
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
}
)
#===============================================================================
# TODO: Review score modifiers.
#
#===============================================================================
Battle::AI::Handlers::MoveEffectScore.add("UserLosesHalfHP",
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",
"StartShadowSkyWeather")
@@ -734,39 +737,64 @@ Battle::AI::Handlers::MoveEffectScore.add("StartShadowSkyWeather",
battle.pbCheckGlobalAbility(:CLOUDNINE)
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
# 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
}
)
#===============================================================================
# TODO: Review score modifiers.
#
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.add("RemoveAllScreens",
Battle::AI::Handlers::MoveFailureCheck.add("RemoveAllScreensAndSafeguard",
proc { |move, user, ai, battle|
will_fail = true
battle.sides.each do |side|
will_fail = false if side.effects[PBEffects::AuroraVeil] > 0 ||
side.effects[PBEffects::Reflect] > 0 ||
side.effects[PBEffects::LightScreen] > 0 ||
side.effects[PBEffects::Reflect] > 0 ||
side.effects[PBEffects::Safeguard] > 0
end
next will_fail
}
)
Battle::AI::Handlers::MoveEffectScore.add("RemoveAllScreens",
Battle::AI::Handlers::MoveEffectScore.add("RemoveAllScreensAndSafeguard",
proc { |score, move, user, ai, battle|
if user.pbOpposingSide.effects[PBEffects::AuroraVeil] > 0 ||
user.pbOpposingSide.effects[PBEffects::Reflect] > 0 ||
user.pbOpposingSide.effects[PBEffects::LightScreen] > 0 ||
user.pbOpposingSide.effects[PBEffects::Safeguard] > 0
score += 30
foe_side = user.pbOpposingSide
# Useless if the foe's side has no screens/Safeguard to remove, or if
# they'll end this round anyway
if foe_side.effects[PBEffects::AuroraVeil] <= 1 &&
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
if user.pbOwnSide.effects[PBEffects::AuroraVeil] > 0 ||
user.pbOwnSide.effects[PBEffects::Reflect] > 0 ||
user.pbOwnSide.effects[PBEffects::LightScreen] > 0 ||
user.pbOwnSide.effects[PBEffects::Safeguard] > 0
score -= 70
# Prefer removing opposing screens
score = Battle::AI::Handlers.apply_move_effect_score("RemoveScreens",
score, move, user, ai, battle)
# Don't prefer removing same side screens
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
# Safeguard
score += 10 if foe_side.effects[PBEffects::Safeguard] > 0
score -= 10 if user.pbOwnSide.effects[PBEffects::Safeguard] > 0
next score
}
)

View File

@@ -371,9 +371,7 @@ Battle::AI::Handlers::MoveEffectScore.add("DoublePowerIfUserLostHPThisTurn",
proc { |score, move, user, ai, battle|
# Prefer if user is slower than its foe(s) and the foe(s) can attack
ai.each_foe_battler(user.side) do |b, i|
next if user.faster_than?(b) || (b.status == :SLEEP && b.statusCount > 1) ||
b.status == :FROZEN || b.effects[PBEffects::HyperBeam] > 0 ||
b.effects[PBEffects::Truant] || b.effects[PBEffects::SkyDrop] >= 0
next if user.faster_than?(b) || !b.can_attack?
score += 4
end
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
ai.each_foe_battler(target.side) do |b, i|
next if i == user.index
next if user.faster_than?(b) || (b.status == :SLEEP && b.statusCount > 1) ||
b.status == :FROZEN || b.effects[PBEffects::HyperBeam] > 0 ||
b.effects[PBEffects::Truant] || b.effects[PBEffects::SkyDrop] >= 0
next if user.faster_than?(b) || !b.can_attack?
score += 4
end
next score
@@ -428,25 +424,85 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("DoublePowerIfTargetNotAc
# AlwaysCriticalHit
#===============================================================================
# TODO: Review score modifiers.
#
#===============================================================================
Battle::AI::Handlers::MoveEffectScore.add("EnsureNextCriticalHit",
proc { |score, move, user, ai, battle|
next Battle::AI::MOVE_USELESS_SCORE if user.effects[PBEffects::LaserFocus] > 0
# TODO: Useless if user will already always critical hit ("AlwaysCriticalHit"
# or Lucky Chant/crit stage is +3/etc.).
next score + 10
# Useless if the user's critical hit stage ensures critical hits already, or
# critical hits are impossible (e.g. via Lucky Chant)
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",
proc { |move, user, ai, battle|
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
useless = true
ai.each_foe_battler(user.side) do |b, i|
next if (b.status == :SLEEP && b.statusCount > 1) ||
b.status == :FROZEN || b.effects[PBEffects::HyperBeam] > 0 ||
b.effects[PBEffects::Truant] || b.effects[PBEffects::SkyDrop] >= 0
next if !b.can_attack?
useless = false
score += 4
end
@@ -639,15 +693,15 @@ Battle::AI::Handlers::MoveEffectScore.add("StartWeakenDamageAgainstUserSideIfHai
Battle::AI::Handlers::MoveEffectScore.add("RemoveScreens",
proc { |score, move, user, ai, battle|
# Prefer if allies have physical moves that are being weakened
if user.pbOpposingSide.effects[PBEffects::Reflect] > 0 ||
user.pbOpposingSide.effects[PBEffects::AuroraVeil] > 0
if user.pbOpposingSide.effects[PBEffects::Reflect] > 1 ||
user.pbOpposingSide.effects[PBEffects::AuroraVeil] > 1
ai.each_same_side_battler(user.side) do |b, i|
score += 10 if b.check_for_move { |m| m.physicalMove?(m.type) }
end
end
# Prefer if allies have special moves that are being weakened
if user.pbOpposingSide.effects[PBEffects::LightScreen] > 0 ||
user.pbOpposingSide.effects[PBEffects::AuroraVeil] > 0
if user.pbOpposingSide.effects[PBEffects::LightScreen] > 1 ||
user.pbOpposingSide.effects[PBEffects::AuroraVeil] > 1
ai.each_same_side_battler(user.side) do |b, i|
score += 10 if b.check_for_move { |m| m.specialMove?(m.type) }
end
@@ -666,9 +720,7 @@ Battle::AI::Handlers::MoveEffectScore.add("ProtectUser",
# Prefer for each foe that can attack
useless = true
ai.each_foe_battler(user.side) do |b, i|
next if (b.status == :SLEEP && b.statusCount > 1) ||
b.status == :FROZEN || b.effects[PBEffects::HyperBeam] > 0 ||
b.effects[PBEffects::Truant] || b.effects[PBEffects::SkyDrop] >= 0
next if !b.can_attack?
useless = false
score += 4
score += 4 if b.effects[PBEffects::TwoTurnAttack]

View File

@@ -646,8 +646,7 @@ Battle::AI::Handlers::MoveEffectScore.add("AttackerFaintsIfUserFaints",
score -= 25
# Check whether user is faster than its foe(s) and could use this move
user_faster_count = 0
ai.battlers.each_with_index do |b, i|
next if !user.opposes?(b) || b.battler.fainted?
ai.each_foe_battler(user.side) do |b, i|
user_faster_count += 1 if user.faster_than?(b)
end
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
# Check whether user is faster than its foe(s) and could use this move
user_faster_count = 0
ai.battlers.each_with_index do |b, i|
next if !user.opposes?(b) || b.battler.fainted?
ai.each_foe_battler(user.side) do |b, i|
user_faster_count += 1 if user.faster_than?(b)
end
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)
target_item_preference = ai.battler_wants_item?(target, target.item_id)
target_no_item_preference = ai.battler_wants_item?(target, :NONE)
score += (user_item_preference - user_no_item_preference) * 5
score += (target_item_preference - target_no_item_preference) * 5
score += (user_item_preference - user_no_item_preference) * 3
score += (target_item_preference - target_no_item_preference) * 3
next score
}
)
@@ -35,8 +35,8 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("TargetTakesUserItem",
user_no_item_preference = ai.battler_wants_item?(user, :NONE)
target_item_preference = ai.battler_wants_item?(target, user.item_id)
target_no_item_preference = ai.battler_wants_item?(target, :NONE)
score -= (user_item_preference - user_no_item_preference) * 5
score -= (target_item_preference - target_no_item_preference) * 5
score -= (user_item_preference - user_no_item_preference) * 3
score -= (target_item_preference - target_no_item_preference) * 3
next score
}
)
@@ -60,8 +60,8 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("UserTargetSwapItems",
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_old_item_preference = ai.battler_wants_item?(target, target.item_id)
score += (user_new_item_preference - user_old_item_preference) * 5
score -= (target_new_item_preference - target_old_item_preference) * 5
score += (user_new_item_preference - user_old_item_preference) * 3
score -= (target_new_item_preference - target_old_item_preference) * 3
# Don't prefer if user used this move in the last round
score -= 15 if user.battler.lastMoveUsed &&
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|
user_new_item_preference = ai.battler_wants_item?(user, user.battler.recycleItem)
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
}
)
@@ -103,7 +103,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("RemoveTargetItem",
# User can knock off the target's item; score it
target_item_preference = ai.battler_wants_item?(target, target.item_id)
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
}
)
@@ -121,7 +121,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("DestroyTargetBerryOrGem"
# User can incinerate the target's item; score it
target_item_preference = ai.battler_wants_item?(target, target.item_id)
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
}
)
@@ -142,7 +142,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("CorrodeTargetItem",
proc { |score, move, user, target, ai, battle|
target_item_preference = ai.battler_wants_item?(target, target.item_id)
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
}
)
@@ -258,13 +258,13 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("UserConsumeTargetBerry",
# User can consume the target's berry; score it
target_item_preference = ai.battler_wants_item?(target, target.item_id)
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
}
)
#===============================================================================
# TODO: Review score modifiers.
#
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.add("ThrowUserItemAtTarget",
proc { |move, user, ai, battle|
@@ -280,3 +280,40 @@ Battle::AI::Handlers::MoveBasePower.add("ThrowUserItemAtTarget",
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",
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
next Battle::AI::MOVE_USELESS_SCORE if target.opposes?(user)
# 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
# Useless if the target will move next anyway
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",
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
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
speeds = []
ai.each_battler { |b, i| speeds.push([i, rough_stat(:SPEED)]) }
@@ -338,11 +340,16 @@ Battle::AI::Handlers::MoveEffectScore.add("TargetActsLast",
end
idx_user = speeds.index { |ele| ele[0] == user.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
next Battle::AI::MOVE_USELESS_SCORE if idx_target < idx_user
# Useless if the target will move last anyway
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
#===============================================================================
# TODO: Review score modifiers.
#
#===============================================================================
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("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
}
)
# HigherPriorityInGrassyTerrain
#===============================================================================
#

View File

@@ -212,7 +212,7 @@ class Battle::AI::AIBattler
# TODO: Need to check the move's pbCalcTypeModSingle.
ret *= effectiveness_of_type_against_single_battler_type(type, defend_type, user)
end
ret *= 2 if @battler.effects[PBEffects::TarShot] && type == :FIRE
ret *= 2 if self.effects[PBEffects::TarShot] && type == :FIRE
end
return ret
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?
return false if wild?
@ai.battle.eachInTeamFromBattlerIndex(@index) do |pkmn, i|

View File

@@ -546,6 +546,7 @@ class Battle::AI::AIMove
# 2 = additional effect will work
# 3 = additional effect has an increased chance to work
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 1 if target.has_active_ability?(:SHIELDDUST) && !@ai.battle.moldBreaker
return 3 if (Settings::MECHANICS_GENERATION >= 6 || self.function != "EffectDependsOnEnvironment") &&

View File

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