mirror of
https://github.com/infinitefusion/infinitefusion-e18.git
synced 2025-12-08 21:54:58 +00:00
AI function code rewrites
This commit is contained in:
@@ -84,6 +84,7 @@ class Battle
|
|||||||
attr_accessor :poke_ball_failed # Set after first_poke_ball to prevent it being set again
|
attr_accessor :poke_ball_failed # Set after first_poke_ball to prevent it being set again
|
||||||
attr_reader :switching # True if during the switching phase of the round
|
attr_reader :switching # True if during the switching phase of the round
|
||||||
attr_reader :futureSight # True if Future Sight is hitting
|
attr_reader :futureSight # True if Future Sight is hitting
|
||||||
|
attr_reader :command_phase
|
||||||
attr_reader :endOfRound # True during the end of round
|
attr_reader :endOfRound # True during the end of round
|
||||||
attr_accessor :moldBreaker # True if Mold Breaker applies
|
attr_accessor :moldBreaker # True if Mold Breaker applies
|
||||||
attr_reader :struggle # The Struggle move
|
attr_reader :struggle # The Struggle move
|
||||||
@@ -159,6 +160,7 @@ class Battle
|
|||||||
@lastMoveUser = -1
|
@lastMoveUser = -1
|
||||||
@switching = false
|
@switching = false
|
||||||
@futureSight = false
|
@futureSight = false
|
||||||
|
@command_phase = false
|
||||||
@endOfRound = false
|
@endOfRound = false
|
||||||
@moldBreaker = false
|
@moldBreaker = false
|
||||||
@runCommand = 0
|
@runCommand = 0
|
||||||
|
|||||||
@@ -172,6 +172,7 @@ class Battle
|
|||||||
# Command phase
|
# Command phase
|
||||||
#=============================================================================
|
#=============================================================================
|
||||||
def pbCommandPhase
|
def pbCommandPhase
|
||||||
|
@command_phase = true
|
||||||
@scene.pbBeginCommandPhase
|
@scene.pbBeginCommandPhase
|
||||||
# Reset choices if commands can be shown
|
# Reset choices if commands can be shown
|
||||||
@battlers.each_with_index do |b, i|
|
@battlers.each_with_index do |b, i|
|
||||||
@@ -186,8 +187,12 @@ class Battle
|
|||||||
end
|
end
|
||||||
# Choose actions for the round (player first, then AI)
|
# Choose actions for the round (player first, then AI)
|
||||||
pbCommandPhaseLoop(true) # Player chooses their actions
|
pbCommandPhaseLoop(true) # Player chooses their actions
|
||||||
return if @decision != 0 # Battle ended, stop choosing actions
|
if @decision != 0 # Battle ended, stop choosing actions
|
||||||
|
@command_phase = false
|
||||||
|
return
|
||||||
|
end
|
||||||
pbCommandPhaseLoop(false) # AI chooses their actions
|
pbCommandPhaseLoop(false) # AI chooses their actions
|
||||||
|
@command_phase = false
|
||||||
end
|
end
|
||||||
|
|
||||||
def pbCommandPhaseLoop(isPlayer)
|
def pbCommandPhaseLoop(isPlayer)
|
||||||
|
|||||||
@@ -1152,7 +1152,7 @@ class Battle::Move::CategoryDependsOnHigherDamagePoisonTarget < Battle::Move::Po
|
|||||||
special_damage = real_special_attack.to_f / real_special_defense
|
special_damage = real_special_attack.to_f / real_special_defense
|
||||||
# Determine move's category
|
# Determine move's category
|
||||||
if physical_damage == special_damage
|
if physical_damage == special_damage
|
||||||
@calcCategry = @battle.pbRandom(2)
|
@calcCategory = (@battle.command_phase) ? rand(2) : @battle.pbRandom(2)
|
||||||
else
|
else
|
||||||
@calcCategory = (physical_damage > special_damage) ? 0 : 1
|
@calcCategory = (physical_damage > special_damage) ? 0 : 1
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ class Battle::AI
|
|||||||
# could target a foe but is targeting an ally, the score is also inverted, but
|
# could target a foe but is targeting an ally, the score is also inverted, but
|
||||||
# only because it is inverted again in def pbGetMoveScoreAgainstTarget.
|
# only because it is inverted again in def pbGetMoveScoreAgainstTarget.
|
||||||
#=============================================================================
|
#=============================================================================
|
||||||
def get_score_for_target_stat_raise(score, target, stat_changes, whole_effect = true)
|
def get_score_for_target_stat_raise(score, target, stat_changes, whole_effect = true, fixed_change = false)
|
||||||
whole_effect = false if @move.damagingMove?
|
whole_effect = false if @move.damagingMove?
|
||||||
# Decide whether the target raising its stat(s) is a good thing
|
# Decide whether the target raising its stat(s) is a good thing
|
||||||
desire_mult = 1
|
desire_mult = 1
|
||||||
@@ -18,11 +18,11 @@ class Battle::AI
|
|||||||
# Discard status move/don't prefer damaging move if target has Contrary
|
# Discard status move/don't prefer damaging move if target has Contrary
|
||||||
# TODO: Maybe this should return get_score_for_target_stat_drop if Contrary
|
# TODO: Maybe this should return get_score_for_target_stat_drop if Contrary
|
||||||
# applies and desire_mult < 1.
|
# applies and desire_mult < 1.
|
||||||
if !@battle.moldBreaker && target.has_active_ability?(:CONTRARY) && desire_mult > 1
|
if !fixed_change && !@battle.moldBreaker && target.has_active_ability?(:CONTRARY) && desire_mult > 1
|
||||||
return (whole_effect) ? MOVE_USELESS_SCORE : score - 20
|
return (whole_effect) ? MOVE_USELESS_SCORE : score - 20
|
||||||
end
|
end
|
||||||
# Don't make score changes if target will faint from EOR damage
|
# Don't make score changes if target will faint from EOR damage
|
||||||
if target.rough_end_of_round_damage > target.hp
|
if target.rough_end_of_round_damage >= target.hp
|
||||||
return (whole_effect) ? MOVE_USELESS_SCORE : score
|
return (whole_effect) ? MOVE_USELESS_SCORE : score
|
||||||
end
|
end
|
||||||
# Don't make score changes if foes have Unaware and target can't make use of
|
# Don't make score changes if foes have Unaware and target can't make use of
|
||||||
@@ -41,14 +41,10 @@ class Battle::AI
|
|||||||
real_stat_changes = []
|
real_stat_changes = []
|
||||||
stat_changes.each_with_index do |stat, idx|
|
stat_changes.each_with_index do |stat, idx|
|
||||||
next if idx.odd?
|
next if idx.odd?
|
||||||
next if !stat_raise_worthwhile?(target, stat)
|
next if !stat_raise_worthwhile?(target, stat, fixed_change)
|
||||||
# Calculate amount that stat will be raised by
|
# Calculate amount that stat will be raised by
|
||||||
increment = stat_changes[idx + 1]
|
increment = stat_changes[idx + 1]
|
||||||
if @move.function == "RaiseUserAtkSpAtk1Or2InSun"
|
increment *= 2 if !fixed_change && !@battle.moldBreaker && target.has_active_ability?(:SIMPLE)
|
||||||
increment = 1
|
|
||||||
increment = 2 if [:Sun, :HarshSun].include?(target.battler.effectiveWeather)
|
|
||||||
end
|
|
||||||
increment *= 2 if !@battle.moldBreaker && target.has_active_ability?(:SIMPLE)
|
|
||||||
increment = [increment, 6 - target.stages[stat]].min # The actual stages gained
|
increment = [increment, 6 - target.stages[stat]].min # The actual stages gained
|
||||||
# Count this as a valid stat raise
|
# Count this as a valid stat raise
|
||||||
real_stat_changes.push([stat, increment]) if increment > 0
|
real_stat_changes.push([stat, increment]) if increment > 0
|
||||||
@@ -76,8 +72,10 @@ class Battle::AI
|
|||||||
# i.e. CategoryDependsOnHigherDamagePoisonTarget and
|
# i.e. CategoryDependsOnHigherDamagePoisonTarget and
|
||||||
# CategoryDependsOnHigherDamageIgnoreTargetAbility.
|
# CategoryDependsOnHigherDamageIgnoreTargetAbility.
|
||||||
#=============================================================================
|
#=============================================================================
|
||||||
def stat_raise_worthwhile?(target, stat)
|
def stat_raise_worthwhile?(target, stat, fixed_change = false)
|
||||||
return false if !target.battler.pbCanRaiseStatStage?(stat, @user.battler, @move.move)
|
if !fixed_change
|
||||||
|
return false if !target.battler.pbCanRaiseStatStage?(stat, @user.battler, @move.move)
|
||||||
|
end
|
||||||
# Check if target won't benefit from the stat being raised
|
# Check if target won't benefit from the stat being raised
|
||||||
# TODO: Exception if target knows Baton Pass/Stored Power?
|
# TODO: Exception if target knows Baton Pass/Stored Power?
|
||||||
case stat
|
case stat
|
||||||
@@ -589,8 +587,10 @@ class Battle::AI
|
|||||||
# ally, but only because it is inverted in def pbGetMoveScoreAgainstTarget
|
# ally, but only because it is inverted in def pbGetMoveScoreAgainstTarget
|
||||||
# instead.
|
# instead.
|
||||||
# TODO: Revisit this method as parts may need rewriting.
|
# TODO: Revisit this method as parts may need rewriting.
|
||||||
|
# TODO: fixed_change should make this ignore Mist/Clear Body/other effects
|
||||||
|
# that prevent increments/decrements to stat stages.
|
||||||
#=============================================================================
|
#=============================================================================
|
||||||
def get_score_for_target_stat_drop(score, target, stat_changes, whole_effect = true)
|
def get_score_for_target_stat_drop(score, target, stat_changes, whole_effect = true, fixed_change = false)
|
||||||
whole_effect = false if @move.damagingMove?
|
whole_effect = false if @move.damagingMove?
|
||||||
# Decide whether the target raising its stat(s) is a good thing
|
# Decide whether the target raising its stat(s) is a good thing
|
||||||
desire_mult = -1
|
desire_mult = -1
|
||||||
@@ -601,11 +601,11 @@ class Battle::AI
|
|||||||
# Discard status move/don't prefer damaging move if target has Contrary
|
# Discard status move/don't prefer damaging move if target has Contrary
|
||||||
# TODO: Maybe this should return get_score_for_target_stat_raise if Contrary
|
# TODO: Maybe this should return get_score_for_target_stat_raise if Contrary
|
||||||
# applies and desire_mult < 1.
|
# applies and desire_mult < 1.
|
||||||
if !@battle.moldBreaker && target.has_active_ability?(:CONTRARY) && desire_mult > 1
|
if !fixed_change && !@battle.moldBreaker && target.has_active_ability?(:CONTRARY) && desire_mult > 1
|
||||||
return (whole_effect) ? MOVE_USELESS_SCORE : score - 20
|
return (whole_effect) ? MOVE_USELESS_SCORE : score - 20
|
||||||
end
|
end
|
||||||
# Don't make score changes if target will faint from EOR damage
|
# Don't make score changes if target will faint from EOR damage
|
||||||
if target.rough_end_of_round_damage > target.hp
|
if target.rough_end_of_round_damage >= target.hp
|
||||||
return (whole_effect) ? MOVE_USELESS_SCORE : score
|
return (whole_effect) ? MOVE_USELESS_SCORE : score
|
||||||
end
|
end
|
||||||
# Don't make score changes if foes have Unaware and target can't make use of
|
# Don't make score changes if foes have Unaware and target can't make use of
|
||||||
@@ -622,10 +622,10 @@ class Battle::AI
|
|||||||
real_stat_changes = []
|
real_stat_changes = []
|
||||||
stat_changes.each_with_index do |stat, idx|
|
stat_changes.each_with_index do |stat, idx|
|
||||||
next if idx.odd?
|
next if idx.odd?
|
||||||
next if !stat_drop_worthwhile?(target, stat)
|
next if !stat_drop_worthwhile?(target, stat, fixed_change)
|
||||||
# Calculate amount that stat will be raised by
|
# Calculate amount that stat will be raised by
|
||||||
decrement = stat_changes[idx + 1]
|
decrement = stat_changes[idx + 1]
|
||||||
decrement *= 2 if !@battle.moldBreaker && @user.has_active_ability?(:SIMPLE)
|
decrement *= 2 if !fixed_change && !@battle.moldBreaker && @user.has_active_ability?(:SIMPLE)
|
||||||
decrement = [decrement, 6 + target.stages[stat]].min # The actual stages lost
|
decrement = [decrement, 6 + target.stages[stat]].min # The actual stages lost
|
||||||
# Count this as a valid stat drop
|
# Count this as a valid stat drop
|
||||||
real_stat_changes.push([stat, decrement]) if decrement > 0
|
real_stat_changes.push([stat, decrement]) if decrement > 0
|
||||||
@@ -654,8 +654,10 @@ class Battle::AI
|
|||||||
# CategoryDependsOnHigherDamageIgnoreTargetAbility.
|
# CategoryDependsOnHigherDamageIgnoreTargetAbility.
|
||||||
# TODO: Revisit this method as parts may need rewriting.
|
# TODO: Revisit this method as parts may need rewriting.
|
||||||
#=============================================================================
|
#=============================================================================
|
||||||
def stat_drop_worthwhile?(target, stat)
|
def stat_drop_worthwhile?(target, stat, fixed_change = false)
|
||||||
return false if !target.battler.pbCanLowerStatStage?(stat, @user.battler, @move.move)
|
if !fixed_change
|
||||||
|
return false if !target.battler.pbCanLowerStatStage?(stat, @user.battler, @move.move)
|
||||||
|
end
|
||||||
# Check if target won't benefit from the stat being lowered
|
# Check if target won't benefit from the stat being lowered
|
||||||
case stat
|
case stat
|
||||||
when :ATTACK
|
when :ATTACK
|
||||||
@@ -983,8 +985,11 @@ class Battle::AI
|
|||||||
:TOXICORB
|
:TOXICORB
|
||||||
]
|
]
|
||||||
ret = 0
|
ret = 0
|
||||||
ret = 2 if preferred_items.include?(item)
|
if preferred_items.include?(item)
|
||||||
ret = -2 if unpreferred_items.include?(item)
|
ret = 2
|
||||||
|
elsif unpreferred_items.include?(item)
|
||||||
|
ret = -2
|
||||||
|
end
|
||||||
# Don't prefer if the battler knows Acrobatics
|
# Don't prefer if the battler knows Acrobatics
|
||||||
if battler.check_for_move { |m| m.function == "DoublePowerIfUserHasNoItem" }
|
if battler.check_for_move { |m| m.function == "DoublePowerIfUserHasNoItem" }
|
||||||
ret += (item == :NONE) ? 1 : -1
|
ret += (item == :NONE) ? 1 : -1
|
||||||
|
|||||||
@@ -364,8 +364,16 @@ Battle::AI::Handlers::MoveEffectScore.copy("RaiseUserAtkDef1",
|
|||||||
#===============================================================================
|
#===============================================================================
|
||||||
Battle::AI::Handlers::MoveFailureCheck.copy("RaiseUserAtkSpAtk1",
|
Battle::AI::Handlers::MoveFailureCheck.copy("RaiseUserAtkSpAtk1",
|
||||||
"RaiseUserAtkSpAtk1Or2InSun")
|
"RaiseUserAtkSpAtk1Or2InSun")
|
||||||
Battle::AI::Handlers::MoveEffectScore.copy("RaiseUserAtkSpAtk1",
|
Battle::AI::Handlers::MoveEffectScore.add("RaiseUserAtkSpAtk1Or2InSun",
|
||||||
"RaiseUserAtkSpAtk1Or2InSun")
|
proc { |score, move, user, ai, battle|
|
||||||
|
raises = move.move.statUp.clone
|
||||||
|
if [:Sun, :HarshSun].include?(user.battler.effectiveWeather)
|
||||||
|
raises[1] = 2
|
||||||
|
raises[3] = 2
|
||||||
|
end
|
||||||
|
next ai.get_score_for_target_stat_raise(score, user, raises)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
#
|
#
|
||||||
@@ -682,7 +690,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("RaiseTargetSpDef1",
|
|||||||
)
|
)
|
||||||
|
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
# TODO: Review score modifiers.
|
#
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("RaiseTargetRandomStat2",
|
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("RaiseTargetRandomStat2",
|
||||||
proc { |move, user, target, ai, battle|
|
proc { |move, user, target, ai, battle|
|
||||||
@@ -696,12 +704,26 @@ Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("RaiseTargetRandomStat2"
|
|||||||
)
|
)
|
||||||
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("RaiseTargetRandomStat2",
|
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("RaiseTargetRandomStat2",
|
||||||
proc { |score, move, user, target, ai, battle|
|
proc { |score, move, user, target, ai, battle|
|
||||||
avgStat = 0
|
next Battle::AI::MOVE_USELESS_SCORE if !battle.moldBreaker && target.has_active_ability?(:CONTRARY)
|
||||||
GameData::Stat.each_battle do |s|
|
next Battle::AI::MOVE_USELESS_SCORE if target.rough_end_of_round_damage >= target.hp
|
||||||
avgStat -= target.stages[s.id] if !target.statStageAtMax?(s.id)
|
score -= 5 if target.index != user.index # Less likely to use on ally
|
||||||
|
score += 5 if target.has_active_ability?(:SIMPLE)
|
||||||
|
# Prefer if target is at high HP, don't prefer if target is at low HP
|
||||||
|
if target.hp >= target.totalhp * 0.7
|
||||||
|
score += 8
|
||||||
|
else
|
||||||
|
score += ((100 * target.hp / target.totalhp) - 50) / 4 # +5 to -12
|
||||||
end
|
end
|
||||||
avgStat = avgStat / 2 if avgStat < 0 # More chance of getting even better
|
# Prefer if target has Stored Power
|
||||||
next + avgStat * 10
|
if target.check_for_move { |m| m.function == "PowerHigherWithUserPositiveStatStages" }
|
||||||
|
score += 8
|
||||||
|
end
|
||||||
|
# Don't prefer if any foe has Punishment
|
||||||
|
each_foe_battler(target.side) do |b, i|
|
||||||
|
next if !b.check_for_move { |m| m.function == "PowerHigherWithTargetPositiveStatStages" }
|
||||||
|
score -= 5
|
||||||
|
end
|
||||||
|
next score
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -881,7 +903,7 @@ Battle::AI::Handlers::MoveBasePower.add("LowerTargetSpeed1WeakerInGrassyTerrain"
|
|||||||
)
|
)
|
||||||
|
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
# TODO: Review score modifiers.
|
#
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("LowerTargetSpeed1MakeTargetWeakerToFire",
|
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("LowerTargetSpeed1MakeTargetWeakerToFire",
|
||||||
proc { |move, user, target, ai, battle|
|
proc { |move, user, target, ai, battle|
|
||||||
@@ -897,7 +919,10 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("LowerTargetSpeed1MakeTar
|
|||||||
score = ai.get_score_for_target_stat_drop(score, target, move.move.statDown)
|
score = ai.get_score_for_target_stat_drop(score, target, move.move.statDown)
|
||||||
# Score for adding weakness to Fire
|
# Score for adding weakness to Fire
|
||||||
if !target.effects[PBEffects::TarShot]
|
if !target.effects[PBEffects::TarShot]
|
||||||
score += 20 if user.battler.moves.any? { |m| m.damagingMove? && m.pbCalcType(user.battler) == :FIRE }
|
eff = target.effectiveness_of_type_against_battler(:FIRE)
|
||||||
|
if !Effectiveness.ineffective?(eff)
|
||||||
|
score += 8 * eff if user.check_for_move { |m| m.damagingMove? && m.pbCalcType(user.battler) == :FIRE }
|
||||||
|
end
|
||||||
end
|
end
|
||||||
next score
|
next score
|
||||||
}
|
}
|
||||||
@@ -952,7 +977,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.copy("LowerTargetAccuracy1",
|
|||||||
"LowerTargetEvasion1")
|
"LowerTargetEvasion1")
|
||||||
|
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
# TODO: Review score modifiers.
|
#
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("LowerTargetEvasion1RemoveSideEffects",
|
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("LowerTargetEvasion1RemoveSideEffects",
|
||||||
proc { |move, user, target, ai, battle|
|
proc { |move, user, target, ai, battle|
|
||||||
@@ -982,14 +1007,26 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("LowerTargetEvasion1Remov
|
|||||||
# Score for stat drop
|
# Score for stat drop
|
||||||
score = ai.get_score_for_target_stat_drop(score, target, move.move.statDown)
|
score = ai.get_score_for_target_stat_drop(score, target, move.move.statDown)
|
||||||
# Score for removing side effects/terrain
|
# Score for removing side effects/terrain
|
||||||
score += 30 if target.pbOwnSide.effects[PBEffects::AuroraVeil] > 0 ||
|
score += 8 if target.pbOwnSide.effects[PBEffects::AuroraVeil] > 1 ||
|
||||||
target.pbOwnSide.effects[PBEffects::Reflect] > 0 ||
|
target.pbOwnSide.effects[PBEffects::Reflect] > 1 ||
|
||||||
target.pbOwnSide.effects[PBEffects::LightScreen] > 0 ||
|
target.pbOwnSide.effects[PBEffects::LightScreen] > 1 ||
|
||||||
target.pbOwnSide.effects[PBEffects::Mist] > 0 ||
|
target.pbOwnSide.effects[PBEffects::Mist] > 1 ||
|
||||||
target.pbOwnSide.effects[PBEffects::Safeguard] > 0
|
target.pbOwnSide.effects[PBEffects::Safeguard] > 1
|
||||||
score -= 30 if target.pbOwnSide.effects[PBEffects::Spikes] > 0 ||
|
if target.can_switch_lax?
|
||||||
target.pbOwnSide.effects[PBEffects::ToxicSpikes] > 0 ||
|
score -= 10 if target.pbOwnSide.effects[PBEffects::Spikes] > 0 ||
|
||||||
target.pbOwnSide.effects[PBEffects::StealthRock]
|
target.pbOwnSide.effects[PBEffects::ToxicSpikes] > 0 ||
|
||||||
|
target.pbOwnSide.effects[PBEffects::StealthRock] ||
|
||||||
|
target.pbOwnSide.effects[PBEffects::StickyWeb]
|
||||||
|
end
|
||||||
|
if user.opposes?(target) && user.can_switch_lax? && Settings::MECHANICS_GENERATION >= 6
|
||||||
|
score += 10 if target.pbOpposingSide.effects[PBEffects::Spikes] > 0 ||
|
||||||
|
target.pbOpposingSide.effects[PBEffects::ToxicSpikes] > 0 ||
|
||||||
|
target.pbOpposingSide.effects[PBEffects::StealthRock] ||
|
||||||
|
target.pbOpposingSide.effects[PBEffects::StickyWeb]
|
||||||
|
end
|
||||||
|
if Settings::MECHANICS_GENERATION >= 8 && battle.field.terrain != :None
|
||||||
|
score -= ai.get_score_for_terrain(battle.field.terrain, user)
|
||||||
|
end
|
||||||
next score
|
next score
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -1176,118 +1213,139 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("RaiseGrassBattlersDef1",
|
|||||||
#===============================================================================
|
#===============================================================================
|
||||||
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("UserTargetSwapAtkSpAtkStages",
|
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("UserTargetSwapAtkSpAtkStages",
|
||||||
proc { |score, move, user, target, ai, battle|
|
proc { |score, move, user, target, ai, battle|
|
||||||
user_attack = user.stages[:ATTACK]
|
raises = []
|
||||||
user_spatk = user.stages[:SPECIAL_ATTACK]
|
drops = []
|
||||||
target_attack = target.stages[:ATTACK]
|
[:ATTACK, :SPECIAL_ATTACK].each do |stat|
|
||||||
target_spatk = target.stages[:SPECIAL_ATTACK]
|
stage_diff = target.stages[stat] - user.stages[stat]
|
||||||
# Useless if both of the user's stats are already higher than the target's
|
if stage_diff > 0
|
||||||
next Battle::AI::MOVE_USELESS_SCORE if user_attack >= target_attack && user_spatk >= target_spatk
|
raises.push(stat)
|
||||||
# Useless if neither the user nor the target make use of these stats
|
raises.push(stage_diff)
|
||||||
useless_attack = !user.check_for_move { |m| m.physicalMove?(m.type) &&
|
elsif stage_diff < 0
|
||||||
m.function != "UseUserDefenseInsteadOfUserAttack" &&
|
drops.push(stat)
|
||||||
m.function != "UseTargetAttackInsteadOfUserAttack" }
|
drops.push(stage_diff)
|
||||||
useless_attack = false if useless_attack &&
|
end
|
||||||
target.check_for_move { |m| m.physicalMove?(m.type) &&
|
end
|
||||||
m.function != "UseUserDefenseInsteadOfUserAttack" &&
|
next Battle::AI::MOVE_USELESS_SCORE if raises.length == 0 # No stat raises
|
||||||
m.function != "UseTargetAttackInsteadOfUserAttack" }
|
score += ai.get_score_for_target_stat_raise(score, user, raises, false, true) if raises.length > 0
|
||||||
useless_spatk = !user.check_for_move { |m| m.specialMove?(m.type) }
|
score += ai.get_score_for_target_stat_drop(score, target, raises, false, true) if raises.length > 0
|
||||||
useless_spatk = false if useless_spatk && target.check_for_move { |m| m.specialMove?(m.type) }
|
score += ai.get_score_for_target_stat_drop(score, user, drops, false, true) if drops.length > 0
|
||||||
next Battle::AI::MOVE_USELESS_SCORE if useless_attack && useless_spatk
|
score += ai.get_score_for_target_stat_raise(score, target, drops, false, true) if drops.length > 0
|
||||||
# Apply score modifiers
|
|
||||||
score += (target_attack - user_attack) * 5 if !useless_attack
|
|
||||||
score += (target_spatk - user_spatk) * 5 if !useless_spatk
|
|
||||||
next score
|
next score
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
# 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("UserTargetSwapDefSpDefStages",
|
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("UserTargetSwapDefSpDefStages",
|
||||||
proc { |score, move, user, target, ai, battle|
|
proc { |score, move, user, target, ai, battle|
|
||||||
user_def = user.stages[:DEFENSE]
|
raises = []
|
||||||
user_spdef = user.stages[:SPECIAL_DEFENSE]
|
drops = []
|
||||||
target_def = target.stages[:DEFENSE]
|
[:DEFENSE, :SPECIAL_DEFENSE].each do |stat|
|
||||||
target_spdef = target.stages[:SPECIAL_DEFENSE]
|
stage_diff = target.stages[stat] - user.stages[stat]
|
||||||
next Battle::AI::MOVE_USELESS_SCORE if user_def >= target_def && user_spdef >= target_spdef
|
if stage_diff > 0
|
||||||
next score - 20 if user_def + user_spdef >= target_def + target_spdef
|
raises.push(stat)
|
||||||
# TODO: Check whether the target has physical/special moves that will be
|
raises.push(stage_diff)
|
||||||
# more resisted after the swap, and vice versa for the user?
|
elsif stage_diff < 0
|
||||||
score += (target_def - user_def) * 5
|
drops.push(stat)
|
||||||
score += (target_spdef - user_spdef) * 5
|
drops.push(stage_diff)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
next Battle::AI::MOVE_USELESS_SCORE if raises.length == 0 # No stat raises
|
||||||
|
score += ai.get_score_for_target_stat_raise(score, user, raises, false, true) if raises.length > 0
|
||||||
|
score += ai.get_score_for_target_stat_drop(score, target, raises, false, true) if raises.length > 0
|
||||||
|
score += ai.get_score_for_target_stat_drop(score, user, drops, false, true) if drops.length > 0
|
||||||
|
score += ai.get_score_for_target_stat_raise(score, target, drops, false, true) if drops.length > 0
|
||||||
next score
|
next score
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
# 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("UserTargetSwapStatStages",
|
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("UserTargetSwapStatStages",
|
||||||
proc { |score, move, user, target, ai, battle|
|
proc { |score, move, user, target, ai, battle|
|
||||||
user_stages = 0
|
raises = []
|
||||||
target_stages = 0
|
drops = []
|
||||||
target_stage_better = false
|
|
||||||
GameData::Stat.each_battle do |s|
|
GameData::Stat.each_battle do |s|
|
||||||
user_stages += user.stages[s.id]
|
stage_diff = target.stages[s.id] - user.stages[s.id]
|
||||||
target_stages += target.stages[s.id]
|
if stage_diff > 0
|
||||||
target_stage_better = true if target.stages[s.id] > user.stages[s.id]
|
raises.push(s.id)
|
||||||
|
raises.push(stage_diff)
|
||||||
|
elsif stage_diff < 0
|
||||||
|
drops.push(s.id)
|
||||||
|
drops.push(stage_diff)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
next Battle::AI::MOVE_USELESS_SCORE if !target_stage_better
|
next Battle::AI::MOVE_USELESS_SCORE if raises.length == 0 # No stat raises
|
||||||
score += (target_stages - user_stages) * 10
|
score += ai.get_score_for_target_stat_raise(score, user, raises, false, true) if raises.length > 0
|
||||||
|
score += ai.get_score_for_target_stat_drop(score, target, raises, false, true) if raises.length > 0
|
||||||
|
score += ai.get_score_for_target_stat_drop(score, user, drops, false, true) if drops.length > 0
|
||||||
|
score += ai.get_score_for_target_stat_raise(score, target, drops, false, true) if drops.length > 0
|
||||||
next score
|
next score
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
# 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("UserCopyTargetStatStages",
|
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("UserCopyTargetStatStages",
|
||||||
proc { |score, move, user, target, ai, battle|
|
proc { |score, move, user, target, ai, battle|
|
||||||
equal = true
|
raises = []
|
||||||
|
drops = []
|
||||||
GameData::Stat.each_battle do |s|
|
GameData::Stat.each_battle do |s|
|
||||||
stagediff = target.stages[s.id] - user.stages[s.id]
|
stage_diff = target.stages[s.id] - user.stages[s.id]
|
||||||
score += stagediff * 10
|
if stage_diff > 0
|
||||||
equal = false if stagediff != 0
|
raises.push(s.id)
|
||||||
|
raises.push(stage_diff)
|
||||||
|
elsif stage_diff < 0
|
||||||
|
drops.push(s.id)
|
||||||
|
drops.push(stage_diff)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
next Battle::AI::MOVE_USELESS_SCORE if raises.length == 0 # No stat raises
|
||||||
|
score += ai.get_score_for_target_stat_raise(score, user, raises, false, true) if raises.length > 0
|
||||||
|
score += ai.get_score_for_target_stat_drop(score, user, drops, false, true) if drops.length > 0
|
||||||
|
if Settings::NEW_CRITICAL_HIT_RATE_MECHANICS
|
||||||
|
if user.effects[PBEffects::FocusEnergy] > 0 && target.effects[PBEffects::FocusEnergy] == 0
|
||||||
|
score -= 4
|
||||||
|
elsif user.effects[PBEffects::FocusEnergy] == 0 && target.effects[PBEffects::FocusEnergy] > 0
|
||||||
|
score += 4
|
||||||
|
end
|
||||||
|
if user.effects[PBEffects::LaserFocus] > 0 && target.effects[PBEffects::LaserFocus] == 0
|
||||||
|
score -= 3
|
||||||
|
elsif user.effects[PBEffects::LaserFocus] == 0 && target.effects[PBEffects::LaserFocus] > 0
|
||||||
|
score += 3
|
||||||
|
end
|
||||||
end
|
end
|
||||||
next Battle::AI::MOVE_USELESS_SCORE if equal # No stat changes
|
|
||||||
next score
|
next score
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
# TODO: Review score modifiers.
|
# TODO: Review score modifiers.
|
||||||
# TODO: Account for stat theft before damage calculation.
|
# TODO: Account for stat theft before damage calculation. This would be complex,
|
||||||
# TODO: target should probably be treated as an enemy when deciding the score,
|
# involving pbCanRaiseStatStage? and Contrary and Simple; do I want to
|
||||||
# since the score will be inverted elsewhere due to the target being an
|
# account for all that or simplify things?
|
||||||
# ally.
|
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("UserStealTargetPositiveStatStages",
|
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("UserStealTargetPositiveStatStages",
|
||||||
proc { |score, move, user, target, ai, battle|
|
proc { |score, move, user, target, ai, battle|
|
||||||
num_stages = 0
|
raises = []
|
||||||
GameData::Stat.each_battle do |s|
|
GameData::Stat.each_battle do |s|
|
||||||
num_stages += target.stages[s.id] if target.stages[s.id] > 0
|
next if target.stages[s.id] <= 0
|
||||||
|
raises.push(s.id)
|
||||||
|
raises.push(target.stages[s.id])
|
||||||
end
|
end
|
||||||
if num_stages > 0
|
if raises.length > 0
|
||||||
next Battle::AI::MOVE_USELESS_SCORE if user.has_active_ability?(:CONTRARY)
|
score += ai.get_score_for_target_stat_raise(score, user, raises, false)
|
||||||
score += num_stages * 5
|
score += ai.get_score_for_target_stat_drop(score, target, raises, false, true)
|
||||||
end
|
end
|
||||||
next score
|
next score
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
# 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::MoveFailureAgainstTargetCheck.add("InvertTargetStatStages",
|
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("InvertTargetStatStages",
|
||||||
proc { |move, user, target, ai, battle|
|
proc { |move, user, target, ai, battle|
|
||||||
@@ -1296,41 +1354,48 @@ Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("InvertTargetStatStages"
|
|||||||
)
|
)
|
||||||
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("InvertTargetStatStages",
|
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("InvertTargetStatStages",
|
||||||
proc { |score, move, user, target, ai, battle|
|
proc { |score, move, user, target, ai, battle|
|
||||||
pos_stages = 0
|
raises = []
|
||||||
neg_stages = 0
|
drops = []
|
||||||
GameData::Stat.each_battle do |s|
|
GameData::Stat.each_battle do |s|
|
||||||
pos_stages += target.stages[s.id] if target.stages[s.id] > 0
|
if target.stages[s.id] > 0
|
||||||
neg_stages += target.stages[s.id] if target.stages[s.id] < 0
|
drops.push(s.id)
|
||||||
|
drops.push(target.stages[s.id] * 2)
|
||||||
|
elsif target.stages[s.id] < 0
|
||||||
|
raises.push(s.id)
|
||||||
|
raises.push(target.stages[s.id] * 2)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
next Battle::AI::MOVE_USELESS_SCORE if pos_stages == 0
|
next Battle::AI::MOVE_USELESS_SCORE if drops.length == 0 # No stats will drop
|
||||||
next score + (pos_stages - neg_stages) * 10
|
score += ai.get_score_for_target_stat_raise(score, target, raises, false, true) if raises.length > 0
|
||||||
|
score += ai.get_score_for_target_stat_drop(score, target, drops, false, true) if drops.length > 0
|
||||||
|
next score
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
# 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("ResetTargetStatStages",
|
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("ResetTargetStatStages",
|
||||||
proc { |score, move, user, target, ai, battle|
|
proc { |score, move, user, target, ai, battle|
|
||||||
avg = 0
|
raises = []
|
||||||
pos_change = false
|
drops = []
|
||||||
any_change = false
|
|
||||||
GameData::Stat.each_battle do |s|
|
GameData::Stat.each_battle do |s|
|
||||||
next if target.stages[s.id] == 0
|
if target.stages[s.id] > 0
|
||||||
avg += target.stages[s.id]
|
drops.push(s.id)
|
||||||
pos_change = true if target.stages[s.id] > 0
|
drops.push(target.stages[s.id])
|
||||||
any_change = true
|
elsif target.stages[s.id] < 0
|
||||||
|
raises.push(s.id)
|
||||||
|
raises.push(target.stages[s.id])
|
||||||
|
end
|
||||||
end
|
end
|
||||||
next Battle::AI::MOVE_USELESS_SCORE if !any_change || !pos_change
|
score += ai.get_score_for_target_stat_raise(score, target, raises, false, true) if raises.length > 0
|
||||||
next score + avg * 5
|
score += ai.get_score_for_target_stat_drop(score, target, drops, false, true) if drops.length > 0
|
||||||
|
next score
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
# TODO: Review score modifiers.
|
#
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
Battle::AI::Handlers::MoveFailureCheck.add("ResetAllBattlersStatStages",
|
Battle::AI::Handlers::MoveFailureCheck.add("ResetAllBattlersStatStages",
|
||||||
proc { |move, user, ai, battle|
|
proc { |move, user, ai, battle|
|
||||||
@@ -1339,17 +1404,22 @@ Battle::AI::Handlers::MoveFailureCheck.add("ResetAllBattlersStatStages",
|
|||||||
)
|
)
|
||||||
Battle::AI::Handlers::MoveEffectScore.add("ResetAllBattlersStatStages",
|
Battle::AI::Handlers::MoveEffectScore.add("ResetAllBattlersStatStages",
|
||||||
proc { |score, move, user, ai, battle|
|
proc { |score, move, user, ai, battle|
|
||||||
stages = 0
|
ai.each_battler do |b|
|
||||||
battle.allBattlers.each do |b|
|
raises = []
|
||||||
totalStages = 0
|
drops = []
|
||||||
GameData::Stat.each_battle { |s| totalStages += b.stages[s.id] }
|
GameData::Stat.each_battle do |s|
|
||||||
if b.opposes?(user.battler)
|
if b.stages[s.id] > 0
|
||||||
stages += totalStages
|
drops.push(s.id)
|
||||||
else
|
drops.push(b.stages[s.id])
|
||||||
stages -= totalStages
|
elsif b.stages[s.id] < 0
|
||||||
|
raises.push(s.id)
|
||||||
|
raises.push(b.stages[s.id])
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
score += ai.get_score_for_target_stat_raise(score, b, raises, false, true) if raises.length > 0
|
||||||
|
score += ai.get_score_for_target_stat_drop(score, b, drops, false, true) if drops.length > 0
|
||||||
end
|
end
|
||||||
next score + stages * 10
|
next score
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -912,16 +912,13 @@ Battle::AI::Handlers::MoveBasePower.add("EffectivenessIncludesFlyingType",
|
|||||||
)
|
)
|
||||||
|
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
# TODO: Review score modifiers.
|
#
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("CategoryDependsOnHigherDamagePoisonTarget",
|
Battle::AI::Handlers::MoveEffectAgainstTargetScore.copy("PoisonTarget",
|
||||||
proc { |score, move, user, target, ai, battle|
|
"CategoryDependsOnHigherDamagePoisonTarget")
|
||||||
next score + 5 if target.battler.pbCanPoison?(user.battler, false)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
# TODO: Review score modifiers.
|
# TODO: Review score modifiers. Category part is already accounted for.
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
# CategoryDependsOnHigherDamageIgnoreTargetAbility
|
# CategoryDependsOnHigherDamageIgnoreTargetAbility
|
||||||
|
|
||||||
@@ -1095,7 +1092,7 @@ Battle::AI::Handlers::MoveBasePower.copy("TypeAndPowerDependOnWeather",
|
|||||||
#===============================================================================
|
#===============================================================================
|
||||||
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("TargetMovesBecomeElectric",
|
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("TargetMovesBecomeElectric",
|
||||||
proc { |score, move, user, target, ai, battle|
|
proc { |score, move, user, target, ai, battle|
|
||||||
next Battle::AI::MOVE_USELESS_SCORE if user.faster_than?(target)
|
next Battle::AI::MOVE_USELESS_SCORE if !user.faster_than?(target)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("DestroyTargetBerryOrGem"
|
|||||||
)
|
)
|
||||||
|
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
# TODO: Review score modifiers.
|
#
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("CorrodeTargetItem",
|
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("CorrodeTargetItem",
|
||||||
proc { |move, user, target, ai, battle|
|
proc { |move, user, target, ai, battle|
|
||||||
@@ -137,11 +137,9 @@ Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("CorrodeTargetItem",
|
|||||||
)
|
)
|
||||||
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("CorrodeTargetItem",
|
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("CorrodeTargetItem",
|
||||||
proc { |score, move, user, target, ai, battle|
|
proc { |score, move, user, target, ai, battle|
|
||||||
if target.item_active?
|
target_item_preference = ai.battler_wants_item?(target, target.item_id)
|
||||||
score += 30
|
target_no_item_preference = ai.battler_wants_item?(target, :NONE)
|
||||||
else
|
score += (target_item_preference - target_no_item_preference) * 8
|
||||||
score -= 50
|
|
||||||
end
|
|
||||||
next score
|
next score
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -201,7 +201,8 @@ Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("PowerUpAllyMove",
|
|||||||
)
|
)
|
||||||
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("PowerUpAllyMove",
|
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("PowerUpAllyMove",
|
||||||
proc { |score, move, user, target, ai, battle|
|
proc { |score, move, user, target, ai, battle|
|
||||||
next score + 15
|
next Battle::AI::MOVE_USELESS_SCORE if !target.check_for_move { |m| m.damagingMove? }
|
||||||
|
next score + 8
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -269,7 +270,7 @@ Battle::AI::Handlers::MoveEffectScore.add("CounterDamagePlusHalf",
|
|||||||
)
|
)
|
||||||
|
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
# TODO: Review score modifiers.
|
#
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
Battle::AI::Handlers::MoveFailureCheck.add("UserAddStockpileRaiseDefSpDef1",
|
Battle::AI::Handlers::MoveFailureCheck.add("UserAddStockpileRaiseDefSpDef1",
|
||||||
proc { |move, user, ai, battle|
|
proc { |move, user, ai, battle|
|
||||||
@@ -280,14 +281,17 @@ Battle::AI::Handlers::MoveEffectScore.add("UserAddStockpileRaiseDefSpDef1",
|
|||||||
proc { |score, move, user, ai, battle|
|
proc { |score, move, user, ai, battle|
|
||||||
score = ai.get_score_for_target_stat_raise(score, user, [:DEFENSE, 1, :SPECIAL_DEFENSE, 1], false)
|
score = ai.get_score_for_target_stat_raise(score, user, [:DEFENSE, 1, :SPECIAL_DEFENSE, 1], false)
|
||||||
# More preferable if user also has Spit Up/Swallow
|
# More preferable if user also has Spit Up/Swallow
|
||||||
score += 20 if user.battler.pbHasMoveFunction?("PowerDependsOnUserStockpile",
|
if user.battler.pbHasMoveFunction?("PowerDependsOnUserStockpile",
|
||||||
"HealUserDependingOnUserStockpile")
|
"HealUserDependingOnUserStockpile")
|
||||||
|
score += [10, 8, 5, 3][user.effects[PBEffects::Stockpile]]
|
||||||
|
end
|
||||||
next score
|
next score
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
# TODO: Review score modifiers.
|
# NOTE: Don't worry about the stat drops caused by losing the stockpile, because
|
||||||
|
# if these moves are known, they want to be used.
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
Battle::AI::Handlers::MoveFailureCheck.add("PowerDependsOnUserStockpile",
|
Battle::AI::Handlers::MoveFailureCheck.add("PowerDependsOnUserStockpile",
|
||||||
proc { |move, user, ai, battle|
|
proc { |move, user, ai, battle|
|
||||||
@@ -299,9 +303,17 @@ Battle::AI::Handlers::MoveBasePower.add("PowerDependsOnUserStockpile",
|
|||||||
next move.move.pbBaseDamage(power, user.battler, target.battler)
|
next move.move.pbBaseDamage(power, user.battler, target.battler)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
Battle::AI::Handlers::MoveEffectScore.add("PowerDependsOnUserStockpile",
|
||||||
|
proc { |score, move, user, ai, battle|
|
||||||
|
# Slightly prefer to hold out for another Stockpile to make this move stronger
|
||||||
|
score -= 5 if user.effects[PBEffects::Stockpile] < 2
|
||||||
|
next score
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
# TODO: Review score modifiers.
|
# NOTE: Don't worry about the stat drops caused by losing the stockpile, because
|
||||||
|
# if these moves are known, they want to be used.
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
Battle::AI::Handlers::MoveFailureCheck.add("HealUserDependingOnUserStockpile",
|
Battle::AI::Handlers::MoveFailureCheck.add("HealUserDependingOnUserStockpile",
|
||||||
proc { |move, user, ai, battle|
|
proc { |move, user, ai, battle|
|
||||||
@@ -313,9 +325,15 @@ Battle::AI::Handlers::MoveFailureCheck.add("HealUserDependingOnUserStockpile",
|
|||||||
)
|
)
|
||||||
Battle::AI::Handlers::MoveEffectScore.add("HealUserDependingOnUserStockpile",
|
Battle::AI::Handlers::MoveEffectScore.add("HealUserDependingOnUserStockpile",
|
||||||
proc { |score, move, user, ai, battle|
|
proc { |score, move, user, ai, battle|
|
||||||
mult = [0, 25, 50, 100][user.effects[PBEffects::Stockpile]]
|
next Battle::AI::MOVE_USELESS_SCORE if !user.battler.canHeal?
|
||||||
score += mult
|
# Consider how much HP will be restored
|
||||||
score -= user.hp * mult * 2 / user.totalhp
|
if user.hp >= user.totalhp * 0.5
|
||||||
|
score -= 10
|
||||||
|
else
|
||||||
|
# Slightly prefer to hold out for another Stockpile to make this move stronger
|
||||||
|
score -= 5 if user.effects[PBEffects::Stockpile] < 2
|
||||||
|
score += 20 * (user.totalhp - user.hp) / user.totalhp
|
||||||
|
end
|
||||||
next score
|
next score
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -271,19 +271,16 @@ Battle::AI::Handlers::MoveFailureCheck.add("TrapAllBattlersInBattleForOneTurn",
|
|||||||
|
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
# TODO: Review score modifiers.
|
# TODO: Review score modifiers.
|
||||||
# TODO: Consider all foes rather than just target. Can't use "target".
|
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
Battle::AI::Handlers::MoveEffectScore.add("UsedAfterUserTakesPhysicalDamage",
|
Battle::AI::Handlers::MoveEffectScore.add("UsedAfterUserTakesPhysicalDamage",
|
||||||
proc { |score, move, user, ai, battle|
|
proc { |score, move, user, ai, battle|
|
||||||
if ai.trainer.medium_skill?
|
found_physical_move = false
|
||||||
hasPhysicalAttack = false
|
ai.each_foe_battler(user.side) do |b, i|
|
||||||
# target.battler.eachMove do |m|
|
next if !b.check_for_move { |m| m.physicalMove?(m.type) }
|
||||||
# next if !m.physicalMove?(m.type)
|
found_physical_move = true
|
||||||
# hasPhysicalAttack = true
|
break
|
||||||
# break
|
|
||||||
# end
|
|
||||||
score -= 50 if !hasPhysicalAttack
|
|
||||||
end
|
end
|
||||||
|
next Battle::AI::MOVE_USELESS_SCORE if !found_physical_move
|
||||||
next score
|
next score
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -304,14 +301,62 @@ Battle::AI::Handlers::MoveEffectScore.add("UsedAfterAllyRoundWithDoublePower",
|
|||||||
)
|
)
|
||||||
|
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
# TODO: Review score modifiers.
|
# TODO: Review score modifiers. This could reasonably used on an ally.
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
# TargetActsNext
|
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
|
||||||
|
speeds = []
|
||||||
|
ai.each_battler { |b, i| speeds.push([i, rough_stat(:SPEED)]) }
|
||||||
|
if battle.field.effects[PBEffects::TrickRoom] > 0
|
||||||
|
speeds.sort! { |a, b| a[1] <=> b[1] }
|
||||||
|
else
|
||||||
|
speeds.sort! { |a, b| b[1] <=> a[1] }
|
||||||
|
end
|
||||||
|
idx_user = speeds.index { |ele| ele[0] == user.index }
|
||||||
|
idx_target = speeds.index { |ele| ele[0] == target.index }
|
||||||
|
# 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 next anyway
|
||||||
|
next Battle::AI::MOVE_USELESS_SCORE if idx_target - idx_user <= 1
|
||||||
|
next score
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
# TODO: Review score modifiers.
|
# TODO: Review score modifiers.
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
# TargetActsLast
|
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)
|
||||||
|
# Compare the speeds of all battlers
|
||||||
|
speeds = []
|
||||||
|
ai.each_battler { |b, i| speeds.push([i, rough_stat(:SPEED)]) }
|
||||||
|
if battle.field.effects[PBEffects::TrickRoom] > 0
|
||||||
|
speeds.sort! { |a, b| a[1] <=> b[1] }
|
||||||
|
else
|
||||||
|
speeds.sort! { |a, b| b[1] <=> a[1] }
|
||||||
|
end
|
||||||
|
idx_user = speeds.index { |ele| ele[0] == user.index }
|
||||||
|
idx_target = speeds.index { |ele| ele[0] == target.index }
|
||||||
|
# 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
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
# TODO: Review score modifiers.
|
# TODO: Review score modifiers.
|
||||||
@@ -474,6 +519,12 @@ Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("DisableTargetStatusMove
|
|||||||
!battle.moldBreaker && target.has_active_ability?(:OBLIVIOUS)
|
!battle.moldBreaker && target.has_active_ability?(:OBLIVIOUS)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("DisableTargetStatusMoves",
|
||||||
|
proc { |score, move, user, target, ai, battle|
|
||||||
|
next Battle::AI::MOVE_USELESS_SCORE if !target.check_for_move { |m| m.statusMove? }
|
||||||
|
next score
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
# TODO: Review score modifiers.
|
# TODO: Review score modifiers.
|
||||||
@@ -484,20 +535,20 @@ Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("DisableTargetHealingMov
|
|||||||
next true if move.move.pbMoveFailedAromaVeil?(user.battler, target.battler, false)
|
next true if move.move.pbMoveFailedAromaVeil?(user.battler, target.battler, false)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("DisableTargetHealingMoves",
|
||||||
|
proc { |score, move, user, target, ai, battle|
|
||||||
|
next Battle::AI::MOVE_USELESS_SCORE if !target.check_for_move { |m| m.healingMove? }
|
||||||
|
next score
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
# TODO: Review score modifiers.
|
# TODO: Review score modifiers.
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("DisableTargetSoundMoves",
|
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("DisableTargetSoundMoves",
|
||||||
proc { |score, move, user, target, ai, battle|
|
proc { |score, move, user, target, ai, battle|
|
||||||
if target.effects[PBEffects::ThroatChop] == 0 && ai.trainer.high_skill?
|
if target.effects[PBEffects::ThroatChop] == 0
|
||||||
hasSoundMove = false
|
score += 10 if target.check_for_move { |m| m.soundMove? }
|
||||||
user.battler.eachMove do |m|
|
|
||||||
next if !m.soundMove?
|
|
||||||
hasSoundMove = true
|
|
||||||
break
|
|
||||||
end
|
|
||||||
score += 40 if hasSoundMove
|
|
||||||
end
|
end
|
||||||
next score
|
next score
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -113,6 +113,10 @@ class Battle::AI::AIMove
|
|||||||
is_critical = rough_critical_hit_stage >= Battle::Move::CRITICAL_HIT_RATIOS.length
|
is_critical = rough_critical_hit_stage >= Battle::Move::CRITICAL_HIT_RATIOS.length
|
||||||
|
|
||||||
##### Calculate user's attack stat #####
|
##### Calculate user's attack stat #####
|
||||||
|
if ["CategoryDependsOnHigherDamagePoisonTarget",
|
||||||
|
"CategoryDependsOnHigherDamageIgnoreTargetAbility"].include?(function)
|
||||||
|
@move.pbOnStartUse(user.battler, [target.battler]) # Calculate category
|
||||||
|
end
|
||||||
atk, atk_stage = @move.pbGetAttackStats(user.battler, target.battler)
|
atk, atk_stage = @move.pbGetAttackStats(user.battler, target.battler)
|
||||||
if !target.has_active_ability?(:UNAWARE) || @ai.battle.moldBreaker
|
if !target.has_active_ability?(:UNAWARE) || @ai.battle.moldBreaker
|
||||||
atk_stage = 6 if is_critical && atk_stage < 6
|
atk_stage = 6 if is_critical && atk_stage < 6
|
||||||
|
|||||||
Reference in New Issue
Block a user