More AI rewrites of various function codes, made move score threshold multiplier depend on trainer skill

This commit is contained in:
Maruno17
2022-11-26 22:31:28 +00:00
parent 6f2e72eed6
commit c53a52564b
7 changed files with 174 additions and 48 deletions

View File

@@ -3,6 +3,12 @@ class Battle::AI
MOVE_USELESS_SCORE = 60 # Move predicted to do nothing or just be detrimental
MOVE_BASE_SCORE = 100
# Returns a value between 0.0 and 1.0. All move scores are lowered by this
# value multiplied by the highest-scoring move's score.
def move_score_threshold
return 0.6 + 0.35 * (([@trainer.skill, 100].min / 100.0) ** 0.5) # 0.6 to 0.95
end
#=============================================================================
# Get scores for the user's moves (done before any action is assessed).
#=============================================================================
@@ -105,6 +111,9 @@ class Battle::AI
@user.statusCount > 1 && !@move.move.usableWhenAsleep?
# User will be truanting
return true if @user.has_active_ability?(:TRUANT) && @user.effects[PBEffects::Truant]
# Primal weather
return true if @battle.pbWeather == :HeavyRain && @move.rough_type == :FIRE
return true if @battle.pbWeather == :HarshSun && @move.rough_type == :WATER
# Move effect-specific checks
return true if Battle::AI::Handlers.move_will_fail?(@move.function, @move, @user, self, @battle)
return false
@@ -116,12 +125,18 @@ class Battle::AI
# Immunity to priority moves because of Psychic Terrain
return true if @battle.field.terrain == :Psychic && @target.battler.affectedByTerrain? &&
@target.opposes?(@user) && @move.rough_priority(@user) > 0
# Immunity because of ability (intentionally before type immunity check)
# Immunity because of ability
# TODO: Check for target-redirecting abilities that also provide immunity.
# If an ally has such an ability, may want to just not prefer the move
# instead of predicting its failure, as might want to hit the ally
# after all.
return true if @move.move.pbImmunityByAbility(@user.battler, @target.battler, false)
# Immunity because of Dazzling/Queenly Majesty
if @move.rough_priority(@user) > 0 && @target.opposes?(@user)
each_same_side_battler(@target.side) do |b, i|
return true if b.has_active_ability?([:DAZZLING, :QUEENLYMAJESTY])
end
end
# Type immunity
calc_type = @move.rough_type
typeMod = @move.move.pbCalcTypeMod(calc_type, @user.battler, @target.battler)
@@ -237,7 +252,7 @@ class Battle::AI
end
end
# Calculate a minimum score threshold and reduce all move scores by it
threshold = (max_score * 0.85).floor
threshold = (max_score * move_score_threshold.to_f).floor
choices.each { |c| c[3] = [c[1] - threshold, 0].max }
total_score = choices.sum { |c| c[3] }
# Log the available choices

View File

@@ -823,7 +823,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.copy("LowerTargetAttack1",
"LowerTargetSpAtk1")
#===============================================================================
# TODO: Review score modifiers.
#
#===============================================================================
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.copy("LowerTargetSpAtk1",
"LowerTargetSpAtk2")

View File

@@ -814,8 +814,8 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("SetTargetTypesToPsychic"
# Prefer if target's foes know damaging moves that are super-effective
# against Psychic, and don't prefer if they know damaging moves that are
# ineffective against Psychic
ai.each_foe_battler(target.side) do |b, b|
b.battler.eachMove do |m,|
ai.each_foe_battler(target.side) do |b, i|
b.battler.eachMove do |m|
next if !m.damagingMove?
effectiveness = Effectiveness.calculate(m.pbCalcType(b.battler), :PSYCHIC)
if Effectiveness.super_effective?(effectiveness)
@@ -824,6 +824,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("SetTargetTypesToPsychic"
score -= 10
end
end
end
next score
}
)
@@ -1144,7 +1145,7 @@ Battle::AI::Handlers::MoveEffectScore.add("StartGravity",
score += (user.opposes?(b)) ? score_change : -score_change
# Prefer if allies have any damaging Ground moves they'll be able to use
# on a grounded foe, and vice versa
ai.each_foe_battler(b.side) do |b2|
ai.each_foe_battler(b.side) do |b2, j|
if b2.check_for_move { |m| m.damagingMove? && m.pbCalcType(b2.battler) == :GROUND }
score += (user.opposes?(b2)) ? -5 : 5
end

View File

@@ -192,22 +192,40 @@ Battle::AI::Handlers::MoveBasePower.copy("PowerHigherWithTargetWeight",
"PowerHigherWithUserHeavierThanTarget")
#===============================================================================
# TODO: Review score modifiers.
#
#===============================================================================
Battle::AI::Handlers::MoveBasePower.add("PowerHigherWithConsecutiveUse",
proc { |power, move, user, target, ai, battle|
next power << user.effects[PBEffects::FuryCutter]
}
)
Battle::AI::Handlers::MoveEffectScore.add("PowerHigherWithConsecutiveUse",
proc { |score, move, user, ai, battle|
# Prefer continuing to use this move
score += 10 if user.effects[PBEffects::FuryCutter] > 0
# Prefer if holding the Metronome
score += 5 if user.has_active_item?(:METRONOME)
next score
}
)
#===============================================================================
# TODO: Review score modifiers.
#
#===============================================================================
Battle::AI::Handlers::MoveBasePower.add("PowerHigherWithConsecutiveUseOnUserSide",
proc { |power, move, user, target, ai, battle|
next power * (user.pbOwnSide.effects[PBEffects::EchoedVoiceCounter] + 1)
}
)
Battle::AI::Handlers::MoveEffectScore.add("PowerHigherWithConsecutiveUse",
proc { |score, move, user, ai, battle|
# Prefer continuing to use this move
score += 10 if user.pbOwnSide.effects[PBEffects::EchoedVoiceCounter] > 0
# Prefer if holding the Metronome
score += 5 if user.has_active_item?(:METRONOME)
next score
}
)
#===============================================================================
#
@@ -351,7 +369,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("DoublePowerIfTargetLostH
# DoublePowerIfUserStatsLoweredThisTurn
#===============================================================================
# TODO: Review score modifiers.
#
#===============================================================================
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("DoublePowerIfTargetActed",
proc { |score, move, user, target, ai, battle|
@@ -360,7 +378,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("DoublePowerIfTargetActed
)
#===============================================================================
# TODO: Review score modifiers.
#
#===============================================================================
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("DoublePowerIfTargetNotActed",
proc { |score, move, user, target, ai, battle|
@@ -369,7 +387,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("DoublePowerIfTargetNotAc
)
#===============================================================================
# TODO: Review score modifiers.
#
#===============================================================================
# AlwaysCriticalHit
@@ -378,12 +396,8 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("DoublePowerIfTargetNotAc
#===============================================================================
Battle::AI::Handlers::MoveEffectScore.add("EnsureNextCriticalHit",
proc { |score, move, user, ai, battle|
if user.effects[PBEffects::LaserFocus] > 0
score -= 90
else
score += 40
end
next score
next Battle::AI::MOVE_USELESS_SCORE if user.effects[PBEffects::LaserFocus] > 0
next score + 10
}
)
@@ -423,7 +437,7 @@ Battle::AI::Handlers::MoveEffectScore.add("UserEnduresFaintingThisTurn",
)
#===============================================================================
# TODO: Review score modifiers.
#
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.add("StartWeakenElectricMoves",
proc { |move, user, ai, battle|
@@ -434,9 +448,30 @@ Battle::AI::Handlers::MoveFailureCheck.add("StartWeakenElectricMoves",
end
}
)
Battle::AI::Handlers::MoveEffectScore.add("StartWeakenElectricMoves",
proc { |score, move, user, ai, battle|
# Don't prefer the lower the user's HP is
if user.hp < user.totalhp / 2
score -= 40 * (0.75 - (user.hp.to_f / user.totalhp)) # -10 to -30
end
# Prefer if foes have Electric moves
ai.each_foe_battler(user.side) do |b, i|
next if !b.check_for_move { |m| m.damagingMove? && m.pbCalcType(b.battler) == :ELECTRIC }
score += 10
score += 5 if !b.check_for_move { |m| m.damagingMove? && m.pbCalcType(b.battler) != :ELECTRIC }
end
# Don't prefer if any allies have Electric moves
ai.each_same_side_battler(user.side) do |b, i|
next if !b.check_for_move { |m| m.damagingMove? && m.pbCalcType(b.battler) == :ELECTRIC }
score -= 8
score -= 4 if !b.check_for_move { |m| m.damagingMove? && m.pbCalcType(b.battler) != :ELECTRIC }
end
next score
}
)
#===============================================================================
# TODO: Review score modifiers.
#
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.add("StartWeakenFireMoves",
proc { |move, user, ai, battle|
@@ -447,27 +482,82 @@ Battle::AI::Handlers::MoveFailureCheck.add("StartWeakenFireMoves",
end
}
)
Battle::AI::Handlers::MoveEffectScore.add("StartWeakenElectricMoves",
proc { |score, move, user, ai, battle|
# Don't prefer the lower the user's HP is
if user.hp < user.totalhp / 2
score -= 40 * (0.75 - (user.hp.to_f / user.totalhp)) # -10 to -30
end
# Prefer if foes have Fire moves
ai.each_foe_battler(user.side) do |b, i|
next if !b.check_for_move { |m| m.damagingMove? && m.pbCalcType(b.battler) == :FIRE }
score += 10
score += 5 if !b.check_for_move { |m| m.damagingMove? && m.pbCalcType(b.battler) != :FIRE }
end
# Don't prefer if any allies have Fire moves
ai.each_same_side_battler(user.side) do |b, i|
next if !b.check_for_move { |m| m.damagingMove? && m.pbCalcType(b.battler) == :FIRE }
score -= 8
score -= 4 if !b.check_for_move { |m| m.damagingMove? && m.pbCalcType(b.battler) != :FIRE }
end
next score
}
)
#===============================================================================
# TODO: Review score modifiers.
#
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.add("StartWeakenPhysicalDamageAgainstUserSide",
proc { |move, user, ai, battle|
next true if user.pbOwnSide.effects[PBEffects::Reflect] > 0
}
)
Battle::AI::Handlers::MoveEffectScore.add("StartWeakenPhysicalDamageAgainstUserSide",
proc { |score, move, user, ai, battle|
# Doesn't stack with Aurora Veil
next Battle::AI::MOVE_USELESS_SCORE if user.pbOwnSide.effects[PBEffects::AuroraVeil] > 0
# Don't prefer the lower the user's HP is
if user.hp < user.totalhp / 2
score -= 40 * (0.75 - (user.hp.to_f / user.totalhp)) # -10 to -30
end
# Prefer if foes have physical moves (moreso if they don't have special moves)
ai.each_foe_battler(user.side) do |b, i|
next if !b.check_for_move { |m| m.physicalMove?(m.type) }
score += 8
score += 5 if !b.check_for_move { |m| m.specialMove?(m.type) }
end
next score
}
)
#===============================================================================
# TODO: Review score modifiers.
#
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.add("StartWeakenSpecialDamageAgainstUserSide",
proc { |move, user, ai, battle|
next true if user.pbOwnSide.effects[PBEffects::LightScreen] > 0
}
)
Battle::AI::Handlers::MoveEffectScore.add("StartWeakenSpecialDamageAgainstUserSide",
proc { |score, move, user, ai, battle|
# Doesn't stack with Aurora Veil
next Battle::AI::MOVE_USELESS_SCORE if user.pbOwnSide.effects[PBEffects::AuroraVeil] > 0
# Don't prefer the lower the user's HP is
if user.hp < user.totalhp / 2
score -= 40 * (0.75 - (user.hp.to_f / user.totalhp)) # -10 to -30
end
# Prefer if foes have special moves (moreso if they don't have physical moves)
ai.each_foe_battler(user.side) do |b, i|
next if !b.check_for_move { |m| m.specialMove?(m.type) }
score += 8
score += 5 if !b.check_for_move { |m| m.physicalMove?(m.type) }
end
next score
}
)
#===============================================================================
# TODO: Review score modifiers.
#
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.add("StartWeakenDamageAgainstUserSideIfHail",
proc { |move, user, ai, battle|
@@ -477,18 +567,36 @@ Battle::AI::Handlers::MoveFailureCheck.add("StartWeakenDamageAgainstUserSideIfHa
)
Battle::AI::Handlers::MoveEffectScore.add("StartWeakenDamageAgainstUserSideIfHail",
proc { |score, move, user, ai, battle|
next score + 40
# Doesn't stack with Reflect/Light Screen
next Battle::AI::MOVE_USELESS_SCORE if user.pbOwnSide.effects[PBEffects::Reflect] > 0 &&
user.pbOwnSide.effects[PBEffects::LightScreen] > 0
# Don't prefer the lower the user's HP is
if user.hp < user.totalhp / 2
score -= 40 * (0.75 - (user.hp.to_f / user.totalhp)) # -10 to -30
end
next score + 15
}
)
#===============================================================================
# TODO: Review score modifiers.
#
#===============================================================================
Battle::AI::Handlers::MoveEffectScore.add("RemoveScreens",
proc { |score, move, user, ai, battle|
score += 10 if user.pbOpposingSide.effects[PBEffects::AuroraVeil] > 0
score += 10 if user.pbOpposingSide.effects[PBEffects::Reflect] > 0
score += 10 if user.pbOpposingSide.effects[PBEffects::LightScreen] > 0
# Prefer if allies have physical moves that are being weakened
if user.pbOpposingSide.effects[PBEffects::Reflect] > 0 ||
user.pbOpposingSide.effects[PBEffects::AuroraVeil] > 0
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
ai.each_same_side_battler(user.side) do |b, i|
score += 10 if b.check_for_move { |m| m.specialMove?(m.type) }
end
end
next score
}
)

View File

@@ -3,7 +3,7 @@
#===============================================================================
Battle::AI::Handlers::MoveEffectScore.add("RedirectAllMovesToUser",
proc { |score, move, user, ai, battle|
next 0 if user.battler.allAllies.length == 0
next Battle::AI::MOVE_USELESS_SCORE if user.battler.allAllies.length == 0
}
)
@@ -12,7 +12,7 @@ Battle::AI::Handlers::MoveEffectScore.add("RedirectAllMovesToUser",
#===============================================================================
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("RedirectAllMovesToTarget",
proc { |score, move, user, target, ai, battle|
next 0 if user.battler.allAllies.length == 0
next Battle::AI::MOVE_USELESS_SCORE if user.battler.allAllies.length == 0
}
)
@@ -21,6 +21,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("RedirectAllMovesToTarget
#===============================================================================
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("CannotBeRedirected",
proc { |score, move, user, target, ai, battle|
next score if target.battler.allAllies.length == 0
redirection = false
user.battler.allOpposing.each do |b|
next if b.index == target.index
@@ -113,22 +114,16 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("CurseTargetOrLowerUserSp
# EffectDependsOnEnvironment
#===============================================================================
# TODO: Review score modifiers.
#
#===============================================================================
Battle::AI::Handlers::MoveBasePower.add("HitsAllFoesAndPowersUpInPsychicTerrain",
proc { |power, move, user, target, ai, battle|
next move.move.pbBaseDamage(power, user.battler, target.battler)
}
)
Battle::AI::Handlers::MoveEffectScore.add("HitsAllFoesAndPowersUpInPsychicTerrain",
proc { |score, move, user, ai, battle|
next score + 20 if battle.field.terrain == :Psychic && user.battler.affectedByTerrain? &&
battle.allOtherSideBattlers(user.index).length > 1
}
)
#===============================================================================
# TODO: Review score modifiers.
#
#===============================================================================
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("TargetNextFireMoveDamagesTarget",
proc { |move, user, target, ai, battle|
@@ -137,12 +132,12 @@ Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("TargetNextFireMoveDamag
)
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("TargetNextFireMoveDamagesTarget",
proc { |score, move, user, target, ai, battle|
aspeed = user.rough_stat(:SPEED)
ospeed = target.rough_stat(:SPEED)
if aspeed > ospeed
score -= 50
elsif target.battler.pbHasMoveType?(:FIRE)
score += 30
# Effect wears off at the end of the round
next Battle::AI::MOVE_USELESS_SCORE if target.faster_than?(user)
# Prefer if target knows any Fire moves (moreso if that's the only type they know)
if target.check_for_move { |m| m.pbCalcType(b.battler) == :FIRE }
score += 10
score += 10 if !target.check_for_move { |m| m.pbCalcType(b.battler) != :FIRE }
end
next score
}
@@ -168,7 +163,7 @@ Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("PowerUpAllyMove",
)
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("PowerUpAllyMove",
proc { |score, move, user, target, ai, battle|
next score + 30
next score + 15
}
)
@@ -342,8 +337,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("UseLastMoveUsedByTarget"
# UseMoveDependingOnEnvironment
#===============================================================================
# TODO: Review score modifiers.
# TODO: This code shouldn't make use of target.
#
#===============================================================================
# UseRandomMove

View File

@@ -22,7 +22,7 @@ Battle::AI::Handlers::MoveFailureCheck.add("SwitchOutUserStatusMove",
Battle::AI::Handlers::MoveEffectScore.add("SwitchOutUserStatusMove",
proc { |score, move, user, ai, battle|
next score + 10 if user.wild?
if battle.pbTeamAbleNonActiveCount(user.index) > 1 # Don't switch in ace
if battle.pbTeamAbleNonActiveCount(user.index) == 1 # Don't switch in ace
score -= 60
else
score += 40 if user.effects[PBEffects::Confusion] > 0
@@ -52,7 +52,7 @@ Battle::AI::Handlers::MoveEffectScore.add("SwitchOutUserStatusMove",
Battle::AI::Handlers::MoveEffectScore.add("SwitchOutUserDamagingMove",
proc { |score, move, user, ai, battle|
next 0 if !battle.pbCanChooseNonActive?(user.index) ||
battle.pbTeamAbleNonActiveCount(user.index) > 1 # Don't switch in ace
battle.pbTeamAbleNonActiveCount(user.index) == 1 # Don't switch in ace
}
)

View File

@@ -157,6 +157,14 @@ Battle::AI::Handlers::GeneralMoveAgainstTargetScore.add(:dance_move_against_danc
}
)
#===============================================================================
# TODO: Review score modifier.
#===============================================================================
# TODO: Prefer a higher priority move if the user is slower than the foe(s) and
# the user is at risk of being knocked out. Consider whether the foe(s)
# have priority moves of their own? Limit this to prefer priority damaging
# moves?
#===============================================================================
# TODO: Review score modifier.
#===============================================================================