Yet more AI function code rewrites

This commit is contained in:
Maruno17
2022-12-31 15:26:41 +00:00
parent 1258e4b9c9
commit dd7cd414f0
9 changed files with 249 additions and 179 deletions

View File

@@ -47,8 +47,8 @@ class Battle::AI
when 1 # One target to be chosen by the trainer when 1 # One target to be chosen by the trainer
# Includes: Foe, NearAlly, NearFoe, NearOther, Other, RandomNearFoe, UserOrNearAlly # Includes: Foe, NearAlly, NearFoe, NearOther, Other, RandomNearFoe, UserOrNearAlly
# TODO: Figure out first which targets are valid. Includes the call to # TODO: Figure out first which targets are valid. Includes the call to
# pbMoveCanTarget?, but also includes move-redirecting effects like # pbMoveCanTarget?, but also includes move-redirecting effects
# Lightning Rod. Skip any battlers that can't be targeted. # like Lightning Rod. Skip any battlers that can't be targeted.
@battle.allBattlers.each do |b| @battle.allBattlers.each do |b|
next if !@battle.pbMoveCanTarget?(@user.battler.index, b.index, target_data) next if !@battle.pbMoveCanTarget?(@user.battler.index, b.index, target_data)
# TODO: Should this sometimes consider targeting an ally? See def # TODO: Should this sometimes consider targeting an ally? See def

View File

@@ -617,6 +617,15 @@ Battle::AI::Handlers::MoveFailureCheck.add("UserMakeSubstitute",
next true if user.hp <= [user.totalhp / 4, 1].max next true if user.hp <= [user.totalhp / 4, 1].max
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("UserMakeSubstitute",
proc { |score, move, user, ai, battle|
# Prefer more the higher the user's HP
score += 8.0 * user.hp / user.totalhp
# TODO: Predict incoming damage, and prefer if it's greater than
# user.totalhp / 4?
next score
}
)
#=============================================================================== #===============================================================================
# #
@@ -688,3 +697,74 @@ Battle::AI::Handlers::MoveEffectScore.add("BurnAttackerBeforeUserActs",
next score next score
} }
) )
#===============================================================================
# TODO: Review score modifiers.
#===============================================================================
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("AllBattlersLoseHalfHPUserSkipsNextTurn",
proc { |move, user, target, ai, battle|
next true if target.hp <= 1
}
)
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("AllBattlersLoseHalfHPUserSkipsNextTurn",
proc { |score, move, user, target, ai, battle|
next score + 20 if target.hp >= target.totalhp / 2
}
)
#===============================================================================
# TODO: Review score modifiers.
#===============================================================================
Battle::AI::Handlers::MoveEffectScore.add("UserLosesHalfHP",
proc { |score, move, user, ai, battle|
next score - 40
}
)
#===============================================================================
# TODO: Review score modifiers.
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.copy("StartSunWeather",
"StartShadowSkyWeather")
Battle::AI::Handlers::MoveEffectScore.add("StartShadowSkyWeather",
proc { |score, move, user, ai, battle|
next Battle::AI::MOVE_USELESS_SCORE if battle.pbCheckGlobalAbility(:AIRLOCK) ||
battle.pbCheckGlobalAbility(:CLOUDNINE)
score += 10 if battle.field.weather != :None # Prefer replacing another weather
score -= 10 if user.hp < user.totalhp / 2 # Not worth it at lower HP
next score
}
)
#===============================================================================
# TODO: Review score modifiers.
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.add("RemoveAllScreens",
proc { |move, user, ai, battle|
will_fail = true
battle.sides.each do |side|
will_fail = false if side.effects[PBEffects::AuroraVeil] > 0 ||
side.effects[PBEffects::Reflect] > 0 ||
side.effects[PBEffects::LightScreen] > 0 ||
side.effects[PBEffects::Safeguard] > 0
end
next will_fail
}
)
Battle::AI::Handlers::MoveEffectScore.add("RemoveAllScreens",
proc { |score, move, user, ai, battle|
if user.pbOpposingSide.effects[PBEffects::AuroraVeil] > 0 ||
user.pbOpposingSide.effects[PBEffects::Reflect] > 0 ||
user.pbOpposingSide.effects[PBEffects::LightScreen] > 0 ||
user.pbOpposingSide.effects[PBEffects::Safeguard] > 0
score += 30
end
if user.pbOwnSide.effects[PBEffects::AuroraVeil] > 0 ||
user.pbOwnSide.effects[PBEffects::Reflect] > 0 ||
user.pbOwnSide.effects[PBEffects::LightScreen] > 0 ||
user.pbOwnSide.effects[PBEffects::Safeguard] > 0
score -= 70
end
next score
}
)

View File

@@ -506,11 +506,24 @@ Battle::AI::Handlers::MoveEffectScore.add("RaiseUserMainStats1TrapUserInBattle",
) )
#=============================================================================== #===============================================================================
# TODO: Review score modifiers. #
#=============================================================================== #===============================================================================
Battle::AI::Handlers::MoveEffectScore.add("StartRaiseUserAtk1WhenDamaged", Battle::AI::Handlers::MoveEffectScore.add("StartRaiseUserAtk1WhenDamaged",
proc { |score, move, user, ai, battle| proc { |score, move, user, ai, battle|
next score + 25 if user.effects[PBEffects::Rage] # Ignore the stat-raising effect if user is at a low HP and likely won't
# benefit from it
next score if user.hp < user.totalhp / 3
# TODO: Check whether any foe has damaging moves that will trigger the stat
# raise?
# Prefer if user benefits from a raised Attack stat
if user.check_for_move { |m| m.physicalMove?(m.type) &&
m.function != "UseUserDefenseInsteadOfUserAttack" &&
m.function != "UseTargetAttackInsteadOfUserAttack" }
score += 8
elsif user.check_for_move { |m| m.function == "PowerHigherWithUserPositiveStatStages" }
score += 4
end
next score
} }
) )
@@ -596,7 +609,7 @@ Battle::AI::Handlers::MoveEffectScore.copy("LowerUserAttack1",
"LowerUserDefSpDefSpd1") "LowerUserDefSpDefSpd1")
#=============================================================================== #===============================================================================
# TODO: Review score modifiers. #
#=============================================================================== #===============================================================================
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("RaiseTargetAttack1", Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("RaiseTargetAttack1",
proc { |move, user, target, ai, battle| proc { |move, user, target, ai, battle|
@@ -611,7 +624,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("RaiseTargetAttack1",
) )
#=============================================================================== #===============================================================================
# TODO: Review score modifiers. #
#=============================================================================== #===============================================================================
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("RaiseTargetAttack2ConfuseTarget", Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("RaiseTargetAttack2ConfuseTarget",
proc { |move, user, target, ai, battle| proc { |move, user, target, ai, battle|
@@ -621,7 +634,9 @@ Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("RaiseTargetAttack2Confu
) )
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("RaiseTargetAttack2ConfuseTarget", Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("RaiseTargetAttack2ConfuseTarget",
proc { |score, move, user, target, ai, battle| proc { |score, move, user, target, ai, battle|
if !target.has_active_ability?(:CONTRARY) || @battle.moldBreaker
next Battle::AI::MOVE_USELESS_SCORE if !target.battler.pbCanConfuse?(user.battler, false, move.move) next Battle::AI::MOVE_USELESS_SCORE if !target.battler.pbCanConfuse?(user.battler, false, move.move)
end
# Score for stat raise # Score for stat raise
score = ai.get_score_for_target_stat_raise(score, target, [:ATTACK, 2], false) score = ai.get_score_for_target_stat_raise(score, target, [:ATTACK, 2], false)
# Score for confusing the target # Score for confusing the target
@@ -631,7 +646,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("RaiseTargetAttack2Confus
) )
#=============================================================================== #===============================================================================
# TODO: Review score modifiers. #
#=============================================================================== #===============================================================================
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("RaiseTargetSpAtk1ConfuseTarget", Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("RaiseTargetSpAtk1ConfuseTarget",
proc { |move, user, target, ai, battle| proc { |move, user, target, ai, battle|
@@ -641,7 +656,9 @@ Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("RaiseTargetSpAtk1Confus
) )
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("RaiseTargetSpAtk1ConfuseTarget", Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("RaiseTargetSpAtk1ConfuseTarget",
proc { |score, move, user, target, ai, battle| proc { |score, move, user, target, ai, battle|
if !target.has_active_ability?(:CONTRARY) || @battle.moldBreaker
next Battle::AI::MOVE_USELESS_SCORE if !target.battler.pbCanConfuse?(user.battler, false, move.move) next Battle::AI::MOVE_USELESS_SCORE if !target.battler.pbCanConfuse?(user.battler, false, move.move)
end
# Score for stat raise # Score for stat raise
score = ai.get_score_for_target_stat_raise(score, target, [:SPECIAL_ATTACK, 1], false) score = ai.get_score_for_target_stat_raise(score, target, [:SPECIAL_ATTACK, 1], false)
# Score for confusing the target # Score for confusing the target
@@ -1155,10 +1172,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("RaiseGrassBattlersDef1",
) )
#=============================================================================== #===============================================================================
# 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("UserTargetSwapAtkSpAtkStages", Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("UserTargetSwapAtkSpAtkStages",
proc { |score, move, user, target, ai, battle| proc { |score, move, user, target, ai, battle|
@@ -1166,12 +1180,22 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("UserTargetSwapAtkSpAtkSt
user_spatk = user.stages[:SPECIAL_ATTACK] user_spatk = user.stages[:SPECIAL_ATTACK]
target_attack = target.stages[:ATTACK] target_attack = target.stages[:ATTACK]
target_spatk = target.stages[:SPECIAL_ATTACK] target_spatk = target.stages[:SPECIAL_ATTACK]
# Useless if both of the user's stats are already higher than the target's
next Battle::AI::MOVE_USELESS_SCORE if user_attack >= target_attack && user_spatk >= target_spatk next Battle::AI::MOVE_USELESS_SCORE if user_attack >= target_attack && user_spatk >= target_spatk
next score - 20 if user_attack + user_spatk >= target_attack + target_spatk # Useless if neither the user nor the target make use of these stats
# TODO: Check whether the user has physical/special moves that will be useless_attack = !user.check_for_move { |m| m.physicalMove?(m.type) &&
# stronger after the swap, and vice versa for the target? m.function != "UseUserDefenseInsteadOfUserAttack" &&
score += (target_attack - user_attack) * 5 m.function != "UseTargetAttackInsteadOfUserAttack" }
score += (target_spatk - user_spatk) * 5 useless_attack = false if useless_attack &&
target.check_for_move { |m| m.physicalMove?(m.type) &&
m.function != "UseUserDefenseInsteadOfUserAttack" &&
m.function != "UseTargetAttackInsteadOfUserAttack" }
useless_spatk = !user.check_for_move { |m| m.specialMove?(m.type) }
useless_spatk = false if useless_spatk && target.check_for_move { |m| m.specialMove?(m.type) }
next Battle::AI::MOVE_USELESS_SCORE if useless_attack && useless_spatk
# 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
} }
) )
@@ -1234,7 +1258,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("UserCopyTargetStatStages
score += stagediff * 10 score += stagediff * 10
equal = false if stagediff != 0 equal = false if stagediff != 0
end end
next 60 if equal # No stat changes next Battle::AI::MOVE_USELESS_SCORE if equal # No stat changes
next score next score
} }
) )
@@ -1248,17 +1272,19 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("UserCopyTargetStatStages
#=============================================================================== #===============================================================================
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|
numStages = 0 num_stages = 0
GameData::Stat.each_battle do |s| GameData::Stat.each_battle do |s|
next if target.stages[s.id] <= 0 num_stages += target.stages[s.id] if target.stages[s.id] > 0
numStages += target.stages[s.id]
end end
next score + numStages * 20 if num_stages > 0
next Battle::AI::MOVE_USELESS_SCORE if user.has_active_ability?(:CONTRARY)
score += num_stages * 5
end
next score
} }
) )
#=============================================================================== #===============================================================================
# TODO: Review score modifiers.
# TODO: target should probably be treated as an enemy when deciding the 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 # since the score will be inverted elsewhere due to the target being an
# ally. # ally.
@@ -1270,14 +1296,14 @@ 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|
next 0 if target.effects[PBEffects::Substitute] > 0 pos_stages = 0
numpos = 0 neg_stages = 0
numneg = 0
GameData::Stat.each_battle do |s| GameData::Stat.each_battle do |s|
numpos += target.stages[s.id] if target.stages[s.id] > 0 pos_stages += target.stages[s.id] if target.stages[s.id] > 0
numneg += target.stages[s.id] if target.stages[s.id] < 0 neg_stages += target.stages[s.id] if target.stages[s.id] < 0
end end
next score + (numpos - numneg) * 10 next Battle::AI::MOVE_USELESS_SCORE if pos_stages == 0
next score + (pos_stages - neg_stages) * 10
} }
) )
@@ -1289,16 +1315,17 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("InvertTargetStatStages",
#=============================================================================== #===============================================================================
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|
next 0 if target.effects[PBEffects::Substitute] > 0
avg = 0 avg = 0
anyChange = false pos_change = false
any_change = false
GameData::Stat.each_battle do |s| GameData::Stat.each_battle do |s|
next if target.stages[s.id] == 0 next if target.stages[s.id] == 0
avg += target.stages[s.id] avg += target.stages[s.id]
anyChange = true pos_change = true if target.stages[s.id] > 0
any_change = true
end end
next 0 if !anyChange next Battle::AI::MOVE_USELESS_SCORE if !any_change || !pos_change
next score + avg * 10 next score + avg * 5
} }
) )

View File

@@ -688,7 +688,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("AttractTarget",
) )
#=============================================================================== #===============================================================================
# TODO: Review score modifiers. #
#=============================================================================== #===============================================================================
Battle::AI::Handlers::MoveFailureCheck.add("SetUserTypesBasedOnEnvironment", Battle::AI::Handlers::MoveFailureCheck.add("SetUserTypesBasedOnEnvironment",
proc { |move, user, ai, battle| proc { |move, user, ai, battle|
@@ -706,6 +706,38 @@ Battle::AI::Handlers::MoveFailureCheck.add("SetUserTypesBasedOnEnvironment",
next true if !GameData::Type.exists?(new_type) || !user.battler.pbHasOtherType?(new_type) next true if !GameData::Type.exists?(new_type) || !user.battler.pbHasOtherType?(new_type)
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("SetUserTypesBasedOnEnvironment",
proc { |score, move, user, ai, battle|
# Determine the new type
new_type = nil
terr_types = Battle::Move::SetUserTypesBasedOnEnvironment::TERRAIN_TYPES
terr_type = terr_types[battle.field.terrain]
if terr_type && GameData::Type.exists?(terr_type)
new_type = terr_type
else
env_types = Battle::Move::SetUserTypesBasedOnEnvironment::ENVIRONMENT_TYPES
new_type = env_types[battle.environment] || :NORMAL
new_type = :NORMAL if !GameData::Type.exists?(new_type)
end
# Check if any user's moves will get STAB because of the type change
if user.check_for_move { |m| m.damagingMove? && m.pbCalcType(user.battler) == new_type }
score += 8
end
# Check if any user's moves will lose STAB because of the type change
user.battler.pbTypes(true).each do |type|
next if type == new_type
if user.check_for_move { |m| m.damagingMove? && m.pbCalcType(user.battler) == type }
score -= 8
end
end
# NOTE: Other things could be considered, like the foes' moves'
# effectivenesses against the current and new user's type(s), and
# 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
}
)
#=============================================================================== #===============================================================================
# #
@@ -781,7 +813,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("SetUserTypesToUserMoveTy
end end
# Check if any user's moves will get STAB because of the type change # Check if any user's moves will get STAB because of the type change
possible_types.each do |type| possible_types.each do |type|
if user.check_for_move { |m| m.damagingMove? } if user.check_for_move { |m| m.damagingMove? && m.pbCalcType(user.battler) == type }
score += 10 score += 10
break break
end end
@@ -1234,7 +1266,7 @@ Battle::AI::Handlers::MoveEffectScore.add("StartGravity",
) )
#=============================================================================== #===============================================================================
# TODO: Review score modifiers. #
#=============================================================================== #===============================================================================
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("TransformUserIntoTarget", Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("TransformUserIntoTarget",
proc { |move, user, target, ai, battle| proc { |move, user, target, ai, battle|
@@ -1245,6 +1277,6 @@ Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("TransformUserIntoTarget
) )
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("TransformUserIntoTarget", Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("TransformUserIntoTarget",
proc { |score, move, user, target, ai, battle| proc { |score, move, user, target, ai, battle|
next score - 10 next score - 5
} }
) )

View File

@@ -362,26 +362,40 @@ Battle::AI::Handlers::MoveBasePower.copy("DoublePowerIfTargetInSky",
"DoublePowerIfAllyFaintedLastTurn") "DoublePowerIfAllyFaintedLastTurn")
#=============================================================================== #===============================================================================
# TODO: Review score modifiers. #
#=============================================================================== #===============================================================================
Battle::AI::Handlers::MoveEffectScore.add("DoublePowerIfUserLostHPThisTurn", Battle::AI::Handlers::MoveEffectScore.add("DoublePowerIfUserLostHPThisTurn",
proc { |score, move, user, ai, battle| proc { |score, move, user, ai, battle|
# TODO: Remove target from this; consider the speeds of all foes instead. # Prefer if user is slower than its foe(s) and the foe(s) can attack
# next score + 15 if target.faster_than?(user) ai.each_foe_battler(user.side) do |b, i|
next if user.faster_than?(b) || (b.status == :SLEEP && b.statusCount > 1) ||
b.status == :FROZEN || b.effects[PBEffects::HyperBeam] > 0 ||
b.effects[PBEffects::Truant] || b.effects[PBEffects::SkyDrop] >= 0
score += 4
end
next score
} }
) )
#=============================================================================== #===============================================================================
# TODO: Review score modifiers. #
#=============================================================================== #===============================================================================
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("DoublePowerIfTargetLostHPThisTurn", Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("DoublePowerIfTargetLostHPThisTurn",
proc { |score, move, user, target, ai, battle| proc { |score, move, user, target, ai, battle|
next score + 15 if battle.pbOpposingBattlerCount(user.battler) > 1 # Prefer if a user's ally is faster than the user and that ally can attack
ai.each_foe_battler(target.side) do |b, i|
next if i == user.index
next if user.faster_than?(b) || (b.status == :SLEEP && b.statusCount > 1) ||
b.status == :FROZEN || b.effects[PBEffects::HyperBeam] > 0 ||
b.effects[PBEffects::Truant] || b.effects[PBEffects::SkyDrop] >= 0
score += 4
end
next score
} }
) )
#=============================================================================== #===============================================================================
# TODO: Review score modifiers. #
#=============================================================================== #===============================================================================
# DoublePowerIfUserStatsLoweredThisTurn # DoublePowerIfUserStatsLoweredThisTurn
@@ -439,18 +453,31 @@ Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("CannotMakeTargetFaint",
) )
#=============================================================================== #===============================================================================
# TODO: Review score modifiers. #
# TODO: This code shouldn't make use of target.
#=============================================================================== #===============================================================================
Battle::AI::Handlers::MoveEffectScore.add("UserEnduresFaintingThisTurn", Battle::AI::Handlers::MoveEffectScore.add("UserEnduresFaintingThisTurn",
proc { |score, move, user, ai, battle| proc { |score, move, user, ai, battle|
score -= 10 if user.hp > user.totalhp / 2 next Battle::AI::MOVE_USELESS_SCORE if user.rough_end_of_round_damage > 0
if ai.trainer.medium_skill? # Prefer for each foe that can attack
score -= 20 if user.effects[PBEffects::ProtectRate] > 1 useless = true
# score -= 20 if target.effects[PBEffects::HyperBeam] > 0 ai.each_foe_battler(user.side) do |b, i|
else next if (b.status == :SLEEP && b.statusCount > 1) ||
score -= user.effects[PBEffects::ProtectRate] * 10 b.status == :FROZEN || b.effects[PBEffects::HyperBeam] > 0 ||
b.effects[PBEffects::Truant] || b.effects[PBEffects::SkyDrop] >= 0
useless = false
score += 4
end end
next Battle::AI::MOVE_USELESS_SCORE if useless
# Don't prefer if user has high HP, prefer if user has lower HP
if user.hp >= user.totalhp / 2
score -= 8
elsif user.hp >= user.totalhp / 8
score += 4
end
# Don't prefer if the user used a protection move last turn, making this one
# less likely to work
score -= (user.effects[PBEffects::ProtectRate] - 1) * 8
# TODO: Check for combos with Flail/Endeavor?
next score next score
} }
) )
@@ -635,16 +662,21 @@ Battle::AI::Handlers::MoveEffectScore.add("RemoveScreens",
#=============================================================================== #===============================================================================
Battle::AI::Handlers::MoveEffectScore.add("ProtectUser", Battle::AI::Handlers::MoveEffectScore.add("ProtectUser",
proc { |score, move, user, ai, battle| proc { |score, move, user, ai, battle|
if user.effects[PBEffects::ProtectRate] > 1 # || score += 12 if user.turnCount == 0
# target.effects[PBEffects::HyperBeam] > 0 # Prefer for each foe that can attack
score -= 50 useless = true
else ai.each_foe_battler(user.side) do |b, i|
if ai.trainer.medium_skill? next if (b.status == :SLEEP && b.statusCount > 1) ||
score -= user.effects[PBEffects::ProtectRate] * 40 b.status == :FROZEN || b.effects[PBEffects::HyperBeam] > 0 ||
end b.effects[PBEffects::Truant] || b.effects[PBEffects::SkyDrop] >= 0
score += 50 if user.turnCount == 0 useless = false
# score += 30 if target.effects[PBEffects::TwoTurnAttack] score += 4
score += 4 if b.effects[PBEffects::TwoTurnAttack]
end end
next Battle::AI::MOVE_USELESS_SCORE if useless
# Don't prefer if the user used a protection move last turn, making this one
# less likely to work
score -= (user.effects[PBEffects::ProtectRate] - 1) * 8
next score next score
} }
) )

View File

@@ -54,7 +54,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("HitTwoTimesFlinchTarget"
) )
#=============================================================================== #===============================================================================
# TODO: Review score modifiers. #
#=============================================================================== #===============================================================================
Battle::AI::Handlers::MoveBasePower.add("HitTwoTimesTargetThenTargetAlly", Battle::AI::Handlers::MoveBasePower.add("HitTwoTimesTargetThenTargetAlly",
proc { |power, move, user, target, ai, battle| proc { |power, move, user, target, ai, battle|

View File

@@ -31,36 +31,24 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("RedirectAllMovesToTarget
) )
#=============================================================================== #===============================================================================
# TODO: Review score modifiers. #
#=============================================================================== #===============================================================================
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("CannotBeRedirected", # 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
if b.effects[PBEffects::RagePowder] ||
b.effects[PBEffects::Spotlight] > 0 ||
b.effects[PBEffects::FollowMe] > 0 ||
(b.hasActiveAbility?(:LIGHTNINGROD) && move.rough_type == :ELECTRIC) ||
(b.hasActiveAbility?(:STORMDRAIN) && move.rough_type == :WATER)
redirection = true
break
end
end
score += 20 if redirection && ai.trainer.medium_skill?
next score
}
)
#=============================================================================== #===============================================================================
# TODO: Review score modifiers. #
#=============================================================================== #===============================================================================
Battle::AI::Handlers::MoveBasePower.add("RandomlyDamageOrHealTarget", Battle::AI::Handlers::MoveBasePower.add("RandomlyDamageOrHealTarget",
proc { |power, move, user, target, ai, battle| proc { |power, move, user, target, ai, battle|
next 50 # Average power, ish next 50 # Average power, ish
} }
) )
Battle::AI::Handlers::MoveEffectScore.add("RandomlyDamageOrHealTarget",
proc { |score, move, user, ai, battle|
# Generaly don't prefer this move, as it may heal the target instead
next score - 8
}
)
#=============================================================================== #===============================================================================
# #

View File

@@ -511,74 +511,3 @@ Battle::AI::Handlers::MoveFailureCheck.add("DisableTargetMovesKnownByUser",
next true if user.effects[PBEffects::Imprison] next true if user.effects[PBEffects::Imprison]
} }
) )
#===============================================================================
# TODO: Review score modifiers.
#===============================================================================
Battle::AI::Handlers::MoveFailureAgainstTargetCheck.add("AllBattlersLoseHalfHPUserSkipsNextTurn",
proc { |move, user, target, ai, battle|
next true if target.hp <= 1
}
)
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("AllBattlersLoseHalfHPUserSkipsNextTurn",
proc { |score, move, user, target, ai, battle|
next score + 20 if target.hp >= target.totalhp / 2
}
)
#===============================================================================
# TODO: Review score modifiers.
#===============================================================================
Battle::AI::Handlers::MoveEffectScore.add("UserLosesHalfHP",
proc { |score, move, user, ai, battle|
next score - 40
}
)
#===============================================================================
# TODO: Review score modifiers.
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.copy("StartSunWeather",
"StartShadowSkyWeather")
Battle::AI::Handlers::MoveEffectScore.add("StartShadowSkyWeather",
proc { |score, move, user, ai, battle|
next Battle::AI::MOVE_USELESS_SCORE if battle.pbCheckGlobalAbility(:AIRLOCK) ||
battle.pbCheckGlobalAbility(:CLOUDNINE)
score += 10 if battle.field.weather != :None # Prefer replacing another weather
score -= 10 if user.hp < user.totalhp / 2 # Not worth it at lower HP
next score
}
)
#===============================================================================
# TODO: Review score modifiers.
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.add("RemoveAllScreens",
proc { |move, user, ai, battle|
will_fail = true
battle.sides.each do |side|
will_fail = false if side.effects[PBEffects::AuroraVeil] > 0 ||
side.effects[PBEffects::Reflect] > 0 ||
side.effects[PBEffects::LightScreen] > 0 ||
side.effects[PBEffects::Safeguard] > 0
end
next will_fail
}
)
Battle::AI::Handlers::MoveEffectScore.add("RemoveAllScreens",
proc { |score, move, user, ai, battle|
if user.pbOpposingSide.effects[PBEffects::AuroraVeil] > 0 ||
user.pbOpposingSide.effects[PBEffects::Reflect] > 0 ||
user.pbOpposingSide.effects[PBEffects::LightScreen] > 0 ||
user.pbOpposingSide.effects[PBEffects::Safeguard] > 0
score += 30
end
if user.pbOwnSide.effects[PBEffects::AuroraVeil] > 0 ||
user.pbOwnSide.effects[PBEffects::Reflect] > 0 ||
user.pbOwnSide.effects[PBEffects::LightScreen] > 0 ||
user.pbOwnSide.effects[PBEffects::Safeguard] > 0
score -= 70
end
next score
}
)

View File

@@ -389,6 +389,12 @@ class Battle::AI::AIMove
user_battler = user.battler user_battler = user.battler
target = @ai.target target = @ai.target
target_battler = target.battler target_battler = target.battler
# OHKO move accuracy
if @move.is_a?(Battle::Move::OHKO)
ret = self.accuracy + user.level - target.level
ret -= 10 if function == "OHKOIce" && !user.pbHasType?(:ICE)
return [ret, 0].max
end
# "Always hit" effects and "always hit" accuracy # "Always hit" effects and "always hit" accuracy
if @ai.trainer.medium_skill? if @ai.trainer.medium_skill?
return 100 if target.effects[PBEffects::Telekinesis] > 0 return 100 if target.effects[PBEffects::Telekinesis] > 0
@@ -427,30 +433,6 @@ class Battle::AI::AIMove
def apply_rough_accuracy_modifiers(user, target, calc_type, modifiers) def apply_rough_accuracy_modifiers(user, target, calc_type, modifiers)
user_battler = user.battler user_battler = user.battler
target_battler = target.battler target_battler = target.battler
# OHKO special calculation
if @ai.trainer.medium_skill?
# TODO: This is insufficient for OHKO moves, as they should also ignore
# effects like Telekinesis and Minimize but def rough_accuracy
# treats them as applying to OHKO moves.
case function
when "OHKO", "OHKOHitsUndergroundTarget"
modifiers[:base_accuracy] = self.accuracy + user.level - target.level
modifiers[:base_accuracy] = -1 if target.level > user.level
modifiers[:base_accuracy] = -1 if !@ai.battle.moldBreaker && target.has_active_ability?(:STURDY)
modifiers[:accuracy_stage] = 6
modifiers[:evasion_stage] = 6
return
when "OHKOIce"
modifiers[:base_accuracy] = self.accuracy + user.level - target.level
modifiers[:base_accuracy] -= 10 if !user.has_type?(:ICE)
modifiers[:base_accuracy] = -1 if modifiers[:base_accuracy] == 0
modifiers[:base_accuracy] = -1 if target.level > user.level
modifiers[:base_accuracy] = -1 if !@ai.battle.moldBreaker && target.has_active_ability?(:STURDY)
modifiers[:accuracy_stage] = 6
modifiers[:evasion_stage] = 6
return
end
end
# Ability effects that alter accuracy calculation # Ability effects that alter accuracy calculation
if user.ability_active? if user.ability_active?
Battle::AbilityEffects.triggerAccuracyCalcFromUser( Battle::AbilityEffects.triggerAccuracyCalcFromUser(