More rewrites of AI for some function codes

This commit is contained in:
Maruno17
2022-11-08 22:54:16 +00:00
parent b31400b9ae
commit 8f014135e5
4 changed files with 201 additions and 70 deletions

View File

@@ -872,7 +872,7 @@ class Battle::Move::AddGhostTypeToTarget < Battle::Move
def canMagicCoat?; return true; end
def pbFailsAgainstTarget?(user, target, show_message)
if !GameData::Type.exists?(:GHOST) || target.pbHasType?(:GHOST) || !target.canChangeType?
if !target.canChangeType? || !GameData::Type.exists?(:GHOST) || target.pbHasType?(:GHOST)
@battle.pbDisplay(_INTL("But it failed!")) if show_message
return true
end
@@ -893,7 +893,7 @@ class Battle::Move::AddGrassTypeToTarget < Battle::Move
def canMagicCoat?; return true; end
def pbFailsAgainstTarget?(user, target, show_message)
if !GameData::Type.exists?(:GRASS) || target.pbHasType?(:GRASS) || !target.canChangeType?
if !target.canChangeType? || !GameData::Type.exists?(:GRASS) || target.pbHasType?(:GRASS)
@battle.pbDisplay(_INTL("But it failed!")) if show_message
return true
end

View File

@@ -7,6 +7,10 @@ class Battle::AI
if !@battle.moldBreaker && @user.has_active_ability?(:CONTRARY)
return (@move.statusMove?) ? MOVE_USELESS_SCORE : score - 20
end
# Don't make score changes if user will faint from EOR damage
if @user.rough_end_of_round_damage > @user.hp
return (@move.statusMove?) ? MOVE_USELESS_SCORE : score
end
# Don't make score changes if foes have Unaware and user can't make use of
# extra stat stages
if !@user.check_for_move { |m| m.function == "PowerHigherWithUserPositiveStatStages" }
@@ -14,7 +18,9 @@ class Battle::AI
each_foe_battler(@user.side) do |b, i|
foe_is_aware = true if !b.has_active_ability?(:UNAWARE)
end
return score if !foe_is_aware
if !foe_is_aware
return (@move.statusMove?) ? MOVE_USELESS_SCORE : score
end
end
# Figure out which stat raises can happen
@@ -124,9 +130,6 @@ class Battle::AI
score += total_increment * ((100 * @user.hp / @user.totalhp) - 50) / 4 # +5 to -12 per stage
end
# Don't prefer if user is about to faint due to EOR damage
score -= 30 if @user.rough_end_of_round_damage > @user.hp
# TODO: Look at abilities that trigger upon stat raise. There are none.
return score
@@ -239,45 +242,45 @@ class Battle::AI
when :ATTACK
# Modify score depending on current stat stage
# More strongly prefer if the user has no special moves
if old_stage >= 3
if old_stage >= 2
score -= 20
else
has_special_moves = @user.check_for_move { |m| m.specialMove?(m.type) }
inc = (has_special_moves) ? 5 : 10
score += inc * (3 - old_stage) * inc_mult
score += 5 * inc_mult if @user.hp == @user.totalhp
score += inc * (2 - old_stage) * inc_mult
score += 4 * inc_mult if @user.hp == @user.totalhp
end
when :DEFENSE
# Modify score depending on current stat stage
if old_stage >= 3
if old_stage >= 2
score -= 20
else
score += 5 * (3 - old_stage) * inc_mult
score += 5 * inc_mult if @user.hp == @user.totalhp
score += 5 * (2 - old_stage) * inc_mult
score += 4 * inc_mult if @user.hp == @user.totalhp
end
when :SPECIAL_ATTACK
# Modify score depending on current stat stage
# More strongly prefer if the user has no physical moves
if old_stage >= 3
if old_stage >= 2
score -= 20
else
has_physical_moves = @user.check_for_move { |m| m.physicalMove?(m.type) &&
m.function != "UseUserDefenseInsteadOfUserAttack" &&
m.function != "UseTargetAttackInsteadOfUserAttack" }
inc = (has_physical_moves) ? 5 : 10
score += inc * (3 - old_stage) * inc_mult
score += 5 * inc_mult if @user.hp == @user.totalhp
score += inc * (2 - old_stage) * inc_mult
score += 4 * inc_mult if @user.hp == @user.totalhp
end
when :SPECIAL_DEFENSE
# Modify score depending on current stat stage
if old_stage >= 3
if old_stage >= 2
score -= 20
else
score += 5 * (3 - old_stage) * inc_mult
score += 5 * inc_mult if @user.hp == @user.totalhp
score += 5 * (2 - old_stage) * inc_mult
score += 4 * inc_mult if @user.hp == @user.totalhp
end
when :SPEED
@@ -299,7 +302,7 @@ class Battle::AI
when :ACCURACY
# Modify score depending on current stat stage
if old_stage >= 3
if old_stage >= 2
score -= 20
else
min_accuracy = 100
@@ -309,8 +312,8 @@ class Battle::AI
end
min_accuracy = min_accuracy * stage_mul[old_stage] / stage_div[old_stage]
if min_accuracy < 90
score += 5 * (3 - old_stage) * inc_mult
score += 5 * inc_mult if @user.hp == @user.totalhp
score += 5 * (2 - old_stage) * inc_mult
score += 4 * inc_mult if @user.hp == @user.totalhp
end
end
@@ -324,11 +327,11 @@ class Battle::AI
score += 60 * eor_damage / b.totalhp if eor_damage > 0
end
# Modify score depending on current stat stage
if old_stage >= 3
if old_stage >= 2
score -= 20
else
score += 5 * (3 - old_stage) * inc_mult
score += 5 * inc_mult if @user.hp == @user.totalhp
score += 5 * (2 - old_stage) * inc_mult
score += 4 * inc_mult if @user.hp == @user.totalhp
end
end
@@ -563,13 +566,19 @@ class Battle::AI
if !@battle.moldBreaker && @target.has_active_ability?(:CONTRARY)
return (@move.statusMove?) ? MOVE_USELESS_SCORE : score - 20
end
# Don't make score changes if foes have Unaware and user can't make use of
# extra stat stages
# Don't make score changes if target will faint from EOR damage
if @target.rough_end_of_round_damage > @target.hp
return (@move.statusMove?) ? MOVE_USELESS_SCORE : score
end
# Don't make score changes if allies have Unaware and can't make use of
# target's lowered stat stages
ally_is_aware = false
each_foe_battler(@target.side) do |b, i|
ally_is_aware = true if !b.has_active_ability?(:UNAWARE)
end
return score if !ally_is_aware
if !ally_is_aware
return (@move.statusMove?) ? MOVE_USELESS_SCORE : score
end
# Figure out which stat raises can happen
stat_changes = []
@@ -663,19 +672,22 @@ class Battle::AI
# TODO: Don't prefer if target is semi-invulnerable and user is faster.
# Prefer if move is a status move and it's the user's first/second turn
# if @user.turnCount < 2 && @move.statusMove?
# score += total_decrement * 4
# end
if @user.turnCount < 2 && @move.statusMove?
score += total_decrement * 4
end
# Prefer if user is at high HP, don't prefer if user is at low HP
# if @user.hp >= @user.totalhp * 0.7
# score += 4 * total_decrement
# else
# score += total_decrement * ((100 * @user.hp / @user.totalhp) - 50) / 4 # +5 to -12 per stage
# end
# Don't prefer if user is about to faint due to EOR damage
# score -= 30 if @user.rough_end_of_round_damage > @user.hp
if @user.hp >= @user.totalhp * 0.7
score += 3 * total_decrement
else
score += total_decrement * ((100 * @user.hp / @user.totalhp) - 50) / 6 # +3 to -8 per stage
end
# Prefer if target is at high HP, don't prefer if target is at low HP
if @target.hp >= @target.totalhp * 0.7
score += 3 * total_decrement
else
score += total_decrement * ((100 * @target.hp / @target.totalhp) - 50) / 6 # +3 to -8 per stage
end
# TODO: Look at abilities that trigger upon stat lowering.
@@ -703,45 +715,45 @@ class Battle::AI
when :ATTACK
# Modify score depending on current stat stage
# More strongly prefer if the target has no special moves
if old_stage <= -3
if old_stage <= -2
score -= 20
else
has_special_moves = @target.check_for_move { |m| m.specialMove?(m.type) }
dec = (has_special_moves) ? 5 : 10
score += dec * (3 + old_stage) * dec_mult
score += 5 * dec_mult if @target.hp == @target.totalhp
score += dec * (2 + old_stage) * dec_mult
score += 4 * dec_mult if @user.hp == @user.totalhp
end
when :DEFENSE
# Modify score depending on current stat stage
if old_stage <= -3
if old_stage <= -2
score -= 20
else
score += 5 * (3 + old_stage) * dec_mult
score += 5 * dec_mult if @target.hp == @target.totalhp
score += 5 * (2 + old_stage) * dec_mult
score += 4 * dec_mult if @user.hp == @user.totalhp
end
when :SPECIAL_ATTACK
# Modify score depending on current stat stage
# More strongly prefer if the target has no physical moves
if old_stage <= -3
if old_stage <= -2
score -= 20
else
has_physical_moves = @target.check_for_move { |m| m.physicalMove?(m.type) &&
m.function != "UseUserDefenseInsteadOfUserAttack" &&
m.function != "UseTargetAttackInsteadOfUserAttack" }
dec = (has_physical_moves) ? 5 : 10
score += dec * (3 + old_stage) * dec_mult
score += 5 * dec_mult if @target.hp == @target.totalhp
score += dec * (2 + old_stage) * dec_mult
score += 4 * dec_mult if @user.hp == @user.totalhp
end
when :SPECIAL_DEFENSE
# Modify score depending on current stat stage
if old_stage <= -3
if old_stage <= -2
score -= 20
else
score += 5 * (3 + old_stage) * dec_mult
score += 5 * dec_mult if @target.hp == @target.totalhp
score += 5 * (2 + old_stage) * dec_mult
score += 4 * dec_mult if @user.hp == @user.totalhp
end
when :SPEED
@@ -763,20 +775,21 @@ class Battle::AI
when :ACCURACY
# Modify score depending on current stat stage
if old_stage <= -3
if old_stage <= -2
score -= 20
else
score += 5 * (3 + old_stage) * dec_mult
score += 5 * dec_mult if @target.hp == @target.totalhp
score += 5 * (2 + old_stage) * dec_mult
score += 4 * dec_mult if @user.hp == @user.totalhp
end
# TODO: Prefer if target is poisoned/toxiced/Leech Seeded/cursed.
when :EVASION
# Modify score depending on current stat stage
if old_stage <= -3
if old_stage <= -2
score -= 20
else
score += 5 * (3 + old_stage) * dec_mult
score += 5 * dec_mult if @target.hp == @target.totalhp
score += 5 * (2 + old_stage) * dec_mult
score += 4 * dec_mult if @user.hp == @user.totalhp
end
end

View File

@@ -538,7 +538,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("CureTargetBurn",
)
#===============================================================================
# TODO: Review score modifiers.
#
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.add("StartUserSideImmunityToInflictedStatus",
proc { |move, user, ai, battle|
@@ -547,11 +547,19 @@ Battle::AI::Handlers::MoveFailureCheck.add("StartUserSideImmunityToInflictedStat
)
Battle::AI::Handlers::MoveEffectScore.add("StartUserSideImmunityToInflictedStatus",
proc { |score, move, user, ai, battle|
if user.status != :NONE
score -= 20
else
score += 10
# Not worth it if Misty Terrain is already safeguarding all user side battlers
if battle.field.terrain == :Misty &&
(battle.field.terrainDuration > 1 || battle.field.terrainDuration < 0)
already_immune = true
ai.each_same_side_battler(user.side) do |b|
already_immune = false if !b.battler.affectedByTerrain?
end
next Battle::AI::MOVE_USELESS_SCORE if already_immune
end
# Tends to be wasteful if the foe just has one Pokémon left
next score - 20 if battle.pbAbleNonActiveCount(user.idxOpposingSide) == 0
# Prefer for each user side battler
ai.each_same_side_battler(user.side) { |b| score += 10 }
next score
}
)
@@ -705,7 +713,7 @@ Battle::AI::Handlers::MoveFailureCheck.add("SetUserTypesBasedOnEnvironment",
)
#===============================================================================
# TODO: Review score modifiers.
#
#===============================================================================
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("SetUserTypesToResistLastAttack",
proc { |move, user, target, ai, battle|
@@ -722,9 +730,24 @@ Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("SetUserTypesToResistLas
next !has_possible_type
}
)
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("SetUserTypesToResistLastAttack",
proc { |score, move, user, target, ai, battle|
effectiveness = user.effectiveness_of_type_against_battler(target.battler.lastMoveUsedType, target)
if Effectiveness.ineffective?(effectiveness)
next Battle::AI::MOVE_USELESS_SCORE
elsif Effectiveness.super_effective?(effectiveness)
score += 12
elsif Effectiveness.normal?(effectiveness)
score += 8
else # Not very effective
score += 4
end
next score
}
)
#===============================================================================
# TODO: Review score modifiers.
#
#===============================================================================
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("SetUserTypesToTargetTypes",
proc { |move, user, target, ai, battle|
@@ -736,7 +759,7 @@ Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("SetUserTypesToTargetTyp
)
#===============================================================================
# TODO: Review score modifiers.
#
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.add("SetUserTypesToUserMoveType",
proc { |move, user, ai, battle|
@@ -752,36 +775,131 @@ Battle::AI::Handlers::MoveFailureCheck.add("SetUserTypesToUserMoveType",
next !has_possible_type
}
)
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("SetUserTypesToUserMoveType",
proc { |score, move, user, target, ai, battle|
possible_types = []
user.battler.eachMoveWithIndex do |m, i|
break if Settings::MECHANICS_GENERATION >= 6 && i > 0
next if GameData::Type.get(m.type).pseudo_type
next if user.has_type?(m.type)
possible_types.push(m.type)
end
# Check if any user's moves will get STAB because of the type change
possible_types.each do |type|
if user.check_for_move { |m| m.damagingMove? }
score += 10
break
end
end
# NOTE: Other things could be considered, like the foes' moves'
# effectivenesses against the current and new user's type(s), and
# whether any of the user's moves will lose STAB because of the type
# change (and if so, which set of STAB is more beneficial). However,
# I'm keeping this simple because, if you know this move, you probably
# want to use it just because.
next score
}
)
#===============================================================================
# TODO: Review score modifiers.
#
#===============================================================================
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("SetTargetTypesToPsychic",
proc { |move, user, target, ai, battle|
next move.move.pbFailsAgainstTarget?(user.battler, target.battler, false)
}
)
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("SetTargetTypesToPsychic",
proc { |score, move, user, target, ai, battle|
# Prefer if user knows damaging moves that are super-effective against
# Psychic, and don't prefer if they know damaging moves that are ineffective
# against Psychic
user.battler.eachMoveWithIndex do |m, i|
next if !m.damagingMove?
effectiveness = Effectiveness.calculate(m.pbCalcType(user.battler), :PSYCHIC)
if Effectiveness.super_effective?(effectiveness)
score += 8
elsif Effectiveness.ineffective?(effectiveness)
score -= 10
end
end
next score
}
)
#===============================================================================
# TODO: Review score modifiers.
#
#===============================================================================
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.copy("SetTargetTypesToPsychic",
"SetTargetTypesToWater")
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("SetTargetTypesToWater",
proc { |score, move, user, target, ai, battle|
# Prefer if user knows damaging moves that are super-effective against
# Water, and don't prefer if they know damaging moves that are ineffective
# against Water
user.battler.eachMoveWithIndex do |m, i|
next if !m.damagingMove?
effectiveness = Effectiveness.calculate(m.pbCalcType(user.battler), :WATER)
if Effectiveness.super_effective?(effectiveness)
score += 8
elsif Effectiveness.ineffective?(effectiveness)
score -= 10
end
end
next score
}
)
#===============================================================================
# TODO: Review score modifiers.
#
#===============================================================================
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.copy("SetTargetTypesToWater",
"AddGhostTypeToTarget")
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("AddGhostTypeToTarget",
proc { |score, move, user, target, ai, battle|
# Prefer/don't prefer depending on the effectiveness of the user's damaging
# moves against the added type
user.battler.eachMoveWithIndex do |m, i|
next if !m.damagingMove?
effectiveness = Effectiveness.calculate(m.pbCalcType(user.battler), :GHOST)
if Effectiveness.super_effective?(effectiveness)
score += 8
elsif Effectiveness.not_very_effective?(effectiveness)
score -= 5
elsif Effectiveness.ineffective?(effectiveness)
score -= 10
end
end
next score
}
)
#===============================================================================
# TODO: Review score modifiers.
#
#===============================================================================
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.copy("AddGhostTypeToTarget",
"AddGrassTypeToTarget")
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("AddGrassTypeToTarget",
proc { |score, move, user, target, ai, battle|
# Prefer/don't prefer depending on the effectiveness of the user's damaging
# moves against the added type
user.battler.eachMoveWithIndex do |m, i|
next if !m.damagingMove?
effectiveness = Effectiveness.calculate(m.pbCalcType(user.battler), :GRASS)
if Effectiveness.super_effective?(effectiveness)
score += 8
elsif Effectiveness.not_very_effective?(effectiveness)
score -= 5
elsif Effectiveness.ineffective?(effectiveness)
score -= 10
end
end
next score
}
)
#===============================================================================
# TODO: Review score modifiers.
#
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.add("UserLosesFireType",
proc { |move, user, ai, battle|

View File

@@ -44,7 +44,7 @@ Battle::AI::Handlers::GeneralMoveAgainstTargetScore.add(:add_predicted_damage,
if move.damagingMove?
dmg = move.rough_damage
score += [15.0 * dmg / target.hp, 20].min
score += 10 if dmg > target.hp * 1.1 # Predicted to KO the target
score += 15 if dmg > target.hp * 1.1 # Predicted to KO the target
next score.to_i
end
}