mirror of
https://github.com/infinitefusion/infinitefusion-e18.git
synced 2025-12-06 06:01:46 +00:00
Split AI general move score modifiers into handlers
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
class Battle::AI
|
||||
#=============================================================================
|
||||
# Get scores for the user's moves (done before any action is assessed)
|
||||
# NOTE: A move is only added to the choices array if it has a non-zero score.
|
||||
# Get scores for the user's moves (done before any action is assessed).
|
||||
#=============================================================================
|
||||
def pbGetMoveScores
|
||||
battler = @user.battler
|
||||
@@ -30,7 +29,7 @@ class Battle::AI
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Get scores for the given move against each possible target
|
||||
# Get scores for the given move against each possible target.
|
||||
#=============================================================================
|
||||
# Wild Pokémon choose their moves randomly.
|
||||
# Trainer Pokémon calculate how much they want to use each of their moves.
|
||||
@@ -58,19 +57,22 @@ class Battle::AI
|
||||
# specially affects multiple Pokémon and the AI calculates an overall
|
||||
# score at once instead of per target
|
||||
score = pbGetMoveScore(move)
|
||||
choices.push([idxMove, score, -1]) if score > 0
|
||||
choices.push([idxMove, score, -1])
|
||||
elsif target_data.num_targets > 1
|
||||
# Includes: AllFoes, AllNearFoes, AllNearOthers
|
||||
# Would also include UserAndAllies, AllAllies, AllBattlers, but they're above
|
||||
# If move affects multiple battlers and you don't choose a particular one
|
||||
# TODO: Should the scores from each target be averaged instead of summed?
|
||||
totalScore = 0
|
||||
total_score = 0
|
||||
num_targets = 0
|
||||
@battle.allBattlers.each do |b|
|
||||
next if !@battle.pbMoveCanTarget?(battler.index, b.index, target_data)
|
||||
score = pbGetMoveScore(move, b)
|
||||
totalScore += ((battler.opposes?(b)) ? score : -score)
|
||||
total_score += ((battler.opposes?(b)) ? score : -score)
|
||||
num_targets += 1
|
||||
end
|
||||
choices.push([idxMove, totalScore, -1]) if totalScore > 0
|
||||
final_score = (num_targets == 1) ? total_score : 1.5 * total_score / num_targets
|
||||
choices.push([idxMove, final_score, -1])
|
||||
else
|
||||
# Includes: Foe, NearAlly, NearFoe, NearOther, Other, RandomNearFoe, UserOrNearAlly
|
||||
# If move affects one battler and you have to choose which one
|
||||
@@ -85,13 +87,13 @@ class Battle::AI
|
||||
# attack the ally anyway so it gains the effect of that ability).
|
||||
next if target_data.targets_foe && !battler.opposes?(b)
|
||||
score = pbGetMoveScore(move, b)
|
||||
choices.push([idxMove, score, b.index]) if score > 0
|
||||
choices.push([idxMove, score, b.index])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Set some extra class variables for the move/target combo being assessed
|
||||
# Set some extra class variables for the move/target combo being assessed.
|
||||
#=============================================================================
|
||||
def set_up_move_check(move, target)
|
||||
@move.set_up(move, @user)
|
||||
@@ -105,7 +107,7 @@ class Battle::AI
|
||||
|
||||
#=============================================================================
|
||||
# Returns whether the move will definitely fail (assuming no battle conditions
|
||||
# change between now and using the move)
|
||||
# change between now and using the move).
|
||||
# TODO: Add skill checks in here for particular calculations?
|
||||
#=============================================================================
|
||||
def pbPredictMoveFailure
|
||||
@@ -153,7 +155,7 @@ class Battle::AI
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Get a score for the given move being used against the given target
|
||||
# Get a score for the given move being used against the given target.
|
||||
#=============================================================================
|
||||
def pbGetMoveScore(move, target = nil)
|
||||
set_up_move_check(move, target)
|
||||
@@ -161,7 +163,7 @@ class Battle::AI
|
||||
target_battler = @target.battler
|
||||
|
||||
# Predict whether the move will fail
|
||||
return 10 if pbPredictMoveFailure
|
||||
return 50 if pbPredictMoveFailure
|
||||
|
||||
# Get the base score for the move
|
||||
if @move.damagingMove?
|
||||
@@ -174,485 +176,15 @@ class Battle::AI
|
||||
# Modify the score according to the move's effect
|
||||
score = Battle::AI::Handlers.apply_move_effect_score(@move.function,
|
||||
score, @move, @user, @target, self, @battle)
|
||||
# Modify the score according to various other effects
|
||||
score = Battle::AI::Handlers.apply_general_move_score_modifiers(
|
||||
score, @move, @user, @target, self, @battle)
|
||||
|
||||
# A score of 0 here means it absolutely should not be used
|
||||
return 0 if score <= 0
|
||||
|
||||
# TODO: High priority checks:
|
||||
# => Prefer move if it will KO the target (moreso if user is slower than target)
|
||||
# => Don't prefer damaging move if it won't KO, user has Stance Change and
|
||||
# is in shield form, and user is slower than the target
|
||||
# => Check memory for past damage dealt by a target's non-high priority move,
|
||||
# and prefer move if user is slower than the target and another hit from
|
||||
# the same amount will KO the user
|
||||
# => Check memory for past damage dealt by a target's priority move, and don't
|
||||
# prefer the move if user is slower than the target and can't move faster
|
||||
# than it because of priority
|
||||
# => Discard move if user is slower than the target and target is semi-
|
||||
# invulnerable (and move won't hit it)
|
||||
# => Check memory for whether target has previously used Quick Guard, and
|
||||
# don't prefer move if so
|
||||
|
||||
# TODO: Low priority checks:
|
||||
# => Don't prefer move if user is faster than the target
|
||||
# => Prefer move if user is faster than the target and target is semi-
|
||||
# invulnerable
|
||||
|
||||
# Don't prefer a dancing move if the target has the Dancer ability
|
||||
# TODO: Check all battlers, not just the target.
|
||||
if @move.move.danceMove? && @target.has_active_ability?(:DANCER)
|
||||
score /= 2
|
||||
end
|
||||
|
||||
# TODO: Check memory for whether target has previously used Ion Deluge, and
|
||||
# don't prefer move if it's Normal-type and target is immune because
|
||||
# of its ability (Lightning Rod, etc.).
|
||||
|
||||
# TODO: Don't prefer sound move if user hasn't been Throat Chopped but
|
||||
# target has previously used Throat Chop.
|
||||
|
||||
# TODO: Prefer move if it has a high critical hit rate, critical hits are
|
||||
# possible but not certain, and target has raised defences/user has
|
||||
# lowered offences (Atk/Def or SpAtk/SpDef, whichever is relevant).
|
||||
|
||||
# TODO: Don't prefer damaging moves if target is Destiny Bonding.
|
||||
# => Also don't prefer damaging moves if user is slower than the target, move
|
||||
# is likely to be lethal, and target has previously used Destiny Bond
|
||||
|
||||
# TODO: Don't prefer a move that is stopped by Wide Guard if target has
|
||||
# previously used Wide Guard.
|
||||
|
||||
# TODO: Don't prefer Fire-type moves if target has previously used Powder.
|
||||
|
||||
# TODO: Don't prefer contact move if making contact with the target could
|
||||
# trigger an effect that's bad for the user (Static, etc.).
|
||||
# => Also check if target has previously used Spiky Shield.King's Shield/
|
||||
# Baneful Bunker, and don't prefer move if so
|
||||
|
||||
# TODO: Prefer a contact move if making contact with the target could trigger
|
||||
# an effect that's good for the user (Poison Touch/Pickpocket).
|
||||
|
||||
# TODO: Don't prefer a status move if user has a damaging move that will KO
|
||||
# the target.
|
||||
# => If target has previously used a move that will hurt the user by 30% of
|
||||
# its current HP or more, moreso don't prefer a status move.
|
||||
|
||||
# Prefer damaging moves if AI has no more Pokémon or AI is less clever
|
||||
if @trainer.medium_skill? && @battle.pbAbleNonActiveCount(user_battler.idxOwnSide) == 0 &&
|
||||
!(@trainer.high_skill? && @battle.pbAbleNonActiveCount(target_battler.idxOwnSide) > 0)
|
||||
if @move.move.statusMove?
|
||||
score *= 0.9
|
||||
elsif target_battler.hp <= target_battler.totalhp / 2
|
||||
score *= 1.1
|
||||
end
|
||||
end
|
||||
|
||||
# Don't prefer attacking the target if they'd be semi-invulnerable
|
||||
if @move.accuracy > 0 && @user_faster &&
|
||||
(target_battler.semiInvulnerable? || target_battler.effects[PBEffects::SkyDrop] >= 0)
|
||||
miss = true
|
||||
miss = false if @user.has_active_ability?(:NOGUARD)
|
||||
miss = false if @trainer.best_skill? && @target.has_active_ability?(:NOGUARD)
|
||||
if @trainer.best_skill? && miss
|
||||
# Knows what can get past semi-invulnerability
|
||||
if target_battler.effects[PBEffects::SkyDrop] >= 0 ||
|
||||
target_battler.inTwoTurnAttack?("TwoTurnAttackInvulnerableInSky",
|
||||
"TwoTurnAttackInvulnerableInSkyParalyzeTarget",
|
||||
"TwoTurnAttackInvulnerableInSkyTargetCannotAct")
|
||||
miss = false if move.hitsFlyingTargets?
|
||||
elsif target.inTwoTurnAttack?("TwoTurnAttackInvulnerableUnderground")
|
||||
miss = false if move.hitsDiggingTargets?
|
||||
elsif target.inTwoTurnAttack?("TwoTurnAttackInvulnerableUnderwater")
|
||||
miss = false if move.hitsDivingTargets?
|
||||
end
|
||||
end
|
||||
score = 10 if miss
|
||||
end
|
||||
|
||||
# Pick a good move for the Choice items
|
||||
if @trainer.medium_skill?
|
||||
if @user.has_active_item?([:CHOICEBAND, :CHOICESPECS, :CHOICESCARF]) ||
|
||||
@user.has_active_ability?(:GORILLATACTICS)
|
||||
# Really don't prefer status moves (except Trick)
|
||||
score *= 0.1 if @move.move.statusMove? && @move.move.function != "UserTargetSwapItems"
|
||||
# Don't prefer moves of certain types
|
||||
move_type = @move.rough_type
|
||||
# Most unpreferred types are 0x effective against another type, except
|
||||
# Fire/Water/Grass
|
||||
# TODO: Actually check through the types for 0x instead of hardcoding
|
||||
# them.
|
||||
# TODO: Reborn separately doesn't prefer Fire/Water/Grass/Electric, also
|
||||
# with a 0.95x score, meaning Electric can be 0.95x twice. Why are
|
||||
# these four types not preferred? Maybe because they're all not
|
||||
# very effective against Dragon.
|
||||
unpreferred_types = [:NORMAL, :FIGHTING, :POISON, :GROUND, :GHOST,
|
||||
:FIRE, :WATER, :GRASS, :ELECTRIC, :PSYCHIC, :DRAGON]
|
||||
score *= 0.95 if unpreferred_types.include?(move_type)
|
||||
# Don't prefer moves with lower accuracy
|
||||
score *= @move.accuracy / 100.0 if @move.accuracy > 0
|
||||
# Don't prefer moves with low PP
|
||||
score *= 0.9 if @move.move.pp < 6
|
||||
end
|
||||
end
|
||||
|
||||
# If user is frozen, prefer a move that can thaw the user
|
||||
if @trainer.medium_skill? && user_battler.status == :FROZEN
|
||||
if @move.move.thawsUser?
|
||||
score += 30
|
||||
else
|
||||
user_battler.eachMove do |m|
|
||||
next unless m.thawsUser?
|
||||
score -= 30 # Don't prefer this move if user knows another move that thaws
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# If target is frozen, don't prefer moves that could thaw them
|
||||
if @trainer.medium_skill? && target_battler.status == :FROZEN
|
||||
if @move.rough_type == :FIRE || (Settings::MECHANICS_GENERATION >= 6 && @move.move.thawsUser?)
|
||||
score *= 0.1
|
||||
end
|
||||
end
|
||||
|
||||
# Don't prefer hitting a wild shiny Pokémon
|
||||
if @target.wild? && target_battler.shiny?
|
||||
score *= 0.15
|
||||
end
|
||||
|
||||
# TODO: Discard a move that can be Magic Coated if either opponent has Magic
|
||||
# Bounce.
|
||||
|
||||
# Account for accuracy of move
|
||||
accuracy = @move.rough_accuracy
|
||||
score *= accuracy / 100.0
|
||||
|
||||
# Prefer flinching external effects (note that move effects which cause
|
||||
# flinching are dealt with in the function code part of score calculation)
|
||||
if @trainer.medium_skill?
|
||||
if !@target.has_active_ability?([:INNERFOCUS, :SHIELDDUST]) &&
|
||||
target_battler.effects[PBEffects::Substitute] == 0
|
||||
if @move.move.flinchingMove? ||
|
||||
(@move.move.damagingMove? &&
|
||||
(@user.has_active_item?([:KINGSROCK, :RAZORFANG]) ||
|
||||
@user.has_active_ability?(:STENCH)))
|
||||
score *= 1.3
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# # Adjust score based on how much damage it can deal
|
||||
# if move.damagingMove?
|
||||
# score = pbGetMoveScoreDamage(score, move, @user, @target, @trainer.skill)
|
||||
# else # Status moves
|
||||
# # Don't prefer attacks which don't deal damage
|
||||
# score -= 10
|
||||
# # Account for accuracy of move
|
||||
# accuracy = pbRoughAccuracy(move, target)
|
||||
# score *= accuracy / 100.0
|
||||
# score = 0 if score <= 10 && @trainer.high_skill?
|
||||
# end
|
||||
score = score.to_i
|
||||
score = 0 if score < 0
|
||||
return score
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Calculate how much damage a move is likely to do to a given target (as a
|
||||
# percentage of the target's current HP)
|
||||
# TODO: How much is this going to be used? Should the predicted percentage of
|
||||
# damage be used as the initial score for damaging moves?
|
||||
#=============================================================================
|
||||
def pbGetDamagingMoveBaseScore
|
||||
# Don't prefer moves that are ineffective because of abilities or effects
|
||||
return 0 if @target.immune_to_move?
|
||||
user_battler = @user.battler
|
||||
target_battler = @target.battler
|
||||
|
||||
# Calculate how much damage the move will do (roughly)
|
||||
calc_damage = @move.rough_damage
|
||||
|
||||
# TODO: Maybe move this check elsewhere? Note that Reborn's base score does
|
||||
# not include this halving, but the predicted damage does.
|
||||
# Two-turn attacks waste 2 turns to deal one lot of damage
|
||||
calc_damage /= 2 if @move.move.chargingTurnMove?
|
||||
|
||||
# TODO: Maybe move this check elsewhere?
|
||||
# Increased critical hit rate
|
||||
if @trainer.medium_skill?
|
||||
crit_stage = @move.rough_critical_hit_stage
|
||||
if crit_stage >= 0
|
||||
crit_fraction = (crit_stage > 50) ? 1 : Battle::Move::CRITICAL_HIT_RATIOS[crit_stage]
|
||||
crit_mult = (Settings::NEW_CRITICAL_HIT_RATE_MECHANICS) ? 0.5 : 1
|
||||
calc_damage *= (1 + crit_mult / crit_fraction)
|
||||
end
|
||||
end
|
||||
|
||||
# Convert damage to percentage of target's remaining HP
|
||||
damage_percentage = calc_damage * 100.0 / target_battler.hp
|
||||
|
||||
# Don't prefer weak attacks
|
||||
# damage_percentage /= 2 if damage_percentage < 20
|
||||
|
||||
# Prefer damaging attack if level difference is significantly high
|
||||
# damage_percentage *= 1.2 if user_battler.level - 10 > target_battler.level
|
||||
|
||||
# Adjust score
|
||||
damage_percentage = 110 if damage_percentage > 110 # Treat all lethal moves the same
|
||||
damage_percentage += 40 if damage_percentage > 100 # Prefer moves likely to be lethal
|
||||
|
||||
return damage_percentage.to_i
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# TODO: Remove this method. If we're keeping any score changes inherent to a
|
||||
# move's effect, they will go in MoveEffectScore handlers instead.
|
||||
#=============================================================================
|
||||
def pbGetStatusMoveBaseScore
|
||||
# TODO: Call @target.immune_to_move? here too, not just for damaging moves
|
||||
# (only if this status move will be affected).
|
||||
|
||||
# TODO: Make sure all status moves are accounted for.
|
||||
# TODO: Duplicates in Reborn's AI:
|
||||
# "SleepTarget" Grass Whistle (15), Hypnosis (15), Sing (15),
|
||||
# Lovely Kiss (20), Sleep Powder (20), Spore (60)
|
||||
# "PoisonTarget" - Poison Powder (15), Poison Gas (20)
|
||||
# "ParalyzeTarget" - Stun Spore (25), Glare (30)
|
||||
# "ConfuseTarget" - Teeter Dance (5), Supersonic (10),
|
||||
# Sweet Kiss (20), Confuse Ray (25)
|
||||
# "RaiseUserAttack1" - Howl (10), Sharpen (10), Medicate (15)
|
||||
# "RaiseUserSpeed2" - Agility (15), Rock Polish (25)
|
||||
# "LowerTargetAttack1" - Growl (10), Baby-Doll Eyes (15)
|
||||
# "LowerTargetAccuracy1" - Sand Attack (5), Flash (10), Kinesis (10), Smokescreen (10)
|
||||
# "LowerTargetAttack2" - Charm (10), Feather Dance (15)
|
||||
# "LowerTargetSpeed2" - String Shot (10), Cotton Spore (15), Scary Face (15)
|
||||
# "LowerTargetSpDef2" - Metal Sound (10), Fake Tears (15)
|
||||
case @move.move.function
|
||||
when "ConfuseTarget",
|
||||
"LowerTargetAccuracy1",
|
||||
"LowerTargetEvasion1RemoveSideEffects",
|
||||
"UserTargetSwapAtkSpAtkStages",
|
||||
"UserTargetSwapDefSpDefStages",
|
||||
"UserSwapBaseAtkDef",
|
||||
"UserTargetAverageBaseAtkSpAtk",
|
||||
"UserTargetAverageBaseDefSpDef",
|
||||
"SetUserTypesToUserMoveType",
|
||||
"SetTargetTypesToWater",
|
||||
"SetUserTypesToTargetTypes",
|
||||
"SetTargetAbilityToUserAbility",
|
||||
"UserTargetSwapAbilities",
|
||||
"PowerUpAllyMove",
|
||||
"StartWeakenElectricMoves",
|
||||
"StartWeakenFireMoves",
|
||||
"EnsureNextMoveAlwaysHits",
|
||||
"StartNegateTargetEvasionStatStageAndGhostImmunity",
|
||||
"StartNegateTargetEvasionStatStageAndDarkImmunity",
|
||||
"ProtectUserSideFromPriorityMoves",
|
||||
"ProtectUserSideFromMultiTargetDamagingMoves",
|
||||
"BounceBackProblemCausingStatusMoves",
|
||||
"StealAndUseBeneficialStatusMove",
|
||||
"DisableTargetMovesKnownByUser",
|
||||
"DisableTargetHealingMoves",
|
||||
"SetAttackerMovePPTo0IfUserFaints",
|
||||
"UserEnduresFaintingThisTurn",
|
||||
"RestoreUserConsumedItem",
|
||||
"StartNegateHeldItems",
|
||||
"StartDamageTargetEachTurnIfTargetAsleep",
|
||||
"HealUserDependingOnUserStockpile",
|
||||
"StartGravity",
|
||||
"StartUserAirborne",
|
||||
"UserSwapsPositionsWithAlly",
|
||||
"StartSwapAllBattlersBaseDefensiveStats",
|
||||
"RaiseTargetSpDef1",
|
||||
"RaiseGroundedGrassBattlersAtkSpAtk1",
|
||||
"RaiseGrassBattlersDef1",
|
||||
"AddGrassTypeToTarget",
|
||||
"TrapAllBattlersInBattleForOneTurn",
|
||||
"EnsureNextCriticalHit",
|
||||
"UserTargetSwapBaseSpeed",
|
||||
"RedirectAllMovesToTarget",
|
||||
"TargetUsesItsLastUsedMoveAgain"
|
||||
return 55
|
||||
when "RaiseUserAttack1",
|
||||
"RaiseUserDefense1",
|
||||
"RaiseUserDefense1CurlUpUser",
|
||||
"RaiseUserCriticalHitRate2",
|
||||
"RaiseUserAtkSpAtk1",
|
||||
"RaiseUserAtkSpAtk1Or2InSun",
|
||||
"RaiseUserAtkAcc1",
|
||||
"RaiseTargetRandomStat2",
|
||||
"LowerTargetAttack1",
|
||||
"LowerTargetDefense1",
|
||||
"LowerTargetAccuracy1",
|
||||
"LowerTargetAttack2",
|
||||
"LowerTargetSpeed2",
|
||||
"LowerTargetSpDef2",
|
||||
"ResetAllBattlersStatStages",
|
||||
"UserCopyTargetStatStages",
|
||||
"SetUserTypesBasedOnEnvironment",
|
||||
"DisableTargetUsingSameMoveConsecutively",
|
||||
"StartTargetCannotUseItem",
|
||||
"LowerTargetAttack1BypassSubstitute",
|
||||
"LowerTargetAtkSpAtk1",
|
||||
"LowerTargetSpAtk1",
|
||||
"TargetNextFireMoveDamagesTarget"
|
||||
return 60
|
||||
when "SleepTarget",
|
||||
"SleepTargetIfUserDarkrai",
|
||||
"SleepTargetChangeUserMeloettaForm",
|
||||
"PoisonTarget",
|
||||
"CureUserBurnPoisonParalysis",
|
||||
"RaiseUserAttack1",
|
||||
"RaiseUserSpDef1PowerUpElectricMove",
|
||||
"RaiseUserEvasion1",
|
||||
"RaiseUserSpeed2",
|
||||
"LowerTargetAttack1",
|
||||
"LowerTargetAtkDef1",
|
||||
"LowerTargetAttack2",
|
||||
"LowerTargetDefense2",
|
||||
"LowerTargetSpeed2",
|
||||
"LowerTargetSpAtk2IfCanAttract",
|
||||
"LowerTargetSpDef2",
|
||||
"ReplaceMoveThisBattleWithTargetLastMoveUsed",
|
||||
"ReplaceMoveWithTargetLastMoveUsed",
|
||||
"SetUserAbilityToTargetAbility",
|
||||
"UseMoveTargetIsAboutToUse",
|
||||
"UseRandomMoveFromUserParty",
|
||||
"StartHealUserEachTurnTrapUserInBattle",
|
||||
"HealTargetHalfOfTotalHP",
|
||||
"UserFaintsHealAndCureReplacement",
|
||||
"UserFaintsHealAndCureReplacementRestorePP",
|
||||
"StartSunWeather",
|
||||
"StartRainWeather",
|
||||
"StartSandstormWeather",
|
||||
"StartHailWeather",
|
||||
"RaisePlusMinusUserAndAlliesDefSpDef1",
|
||||
"LowerTargetSpAtk2",
|
||||
"LowerPoisonedTargetAtkSpAtkSpd1",
|
||||
"AddGhostTypeToTarget",
|
||||
"LowerTargetAtkSpAtk1SwitchOutUser",
|
||||
"RaisePlusMinusUserAndAlliesAtkSpAtk1",
|
||||
"HealTargetDependingOnGrassyTerrain"
|
||||
return 65
|
||||
when "SleepTarget",
|
||||
"SleepTargetChangeUserMeloettaForm",
|
||||
"SleepTargetNextTurn",
|
||||
"PoisonTarget",
|
||||
"ConfuseTarget",
|
||||
"RaiseTargetSpAtk1ConfuseTarget",
|
||||
"RaiseTargetAttack2ConfuseTarget",
|
||||
"UserTargetSwapStatStages",
|
||||
"StartUserSideImmunityToStatStageLowering",
|
||||
"SetUserTypesToResistLastAttack",
|
||||
"SetTargetAbilityToSimple",
|
||||
"SetTargetAbilityToInsomnia",
|
||||
"NegateTargetAbility",
|
||||
"TransformUserIntoTarget",
|
||||
"UseLastMoveUsedByTarget",
|
||||
"UseLastMoveUsed",
|
||||
"UseRandomMove",
|
||||
"HealUserFullyAndFallAsleep",
|
||||
"StartHealUserEachTurn",
|
||||
"StartPerishCountsForAllBattlers",
|
||||
"SwitchOutTargetStatusMove",
|
||||
"TrapTargetInBattle",
|
||||
"TargetMovesBecomeElectric",
|
||||
"NormalMovesBecomeElectric",
|
||||
"PoisonTargetLowerTargetSpeed1"
|
||||
return 70
|
||||
when "BadPoisonTarget",
|
||||
"ParalyzeTarget",
|
||||
"BurnTarget",
|
||||
"ConfuseTarget",
|
||||
"AttractTarget",
|
||||
"GiveUserStatusToTarget",
|
||||
"RaiseUserDefSpDef1",
|
||||
"RaiseUserDefense2",
|
||||
"RaiseUserSpeed2",
|
||||
"RaiseUserSpeed2LowerUserWeight",
|
||||
"RaiseUserSpDef2",
|
||||
"RaiseUserEvasion2MinimizeUser",
|
||||
"RaiseUserDefense3",
|
||||
"MaxUserAttackLoseHalfOfTotalHP",
|
||||
"UserTargetAverageHP",
|
||||
"ProtectUser",
|
||||
"DisableTargetLastMoveUsed",
|
||||
"DisableTargetStatusMoves",
|
||||
"HealUserHalfOfTotalHP",
|
||||
"HealUserHalfOfTotalHPLoseFlyingTypeThisTurn",
|
||||
"HealUserPositionNextTurn",
|
||||
"HealUserDependingOnWeather",
|
||||
"StartLeechSeedTarget",
|
||||
"AttackerFaintsIfUserFaints",
|
||||
"UserTargetSwapItems",
|
||||
"UserMakeSubstitute",
|
||||
"UserAddStockpileRaiseDefSpDef1",
|
||||
"RedirectAllMovesToUser",
|
||||
"InvertTargetStatStages",
|
||||
"HealUserByTargetAttackLowerTargetAttack1",
|
||||
"HealUserDependingOnSandstorm"
|
||||
return 75
|
||||
when "ParalyzeTarget",
|
||||
"ParalyzeTargetIfNotTypeImmune",
|
||||
"RaiseUserAtkDef1",
|
||||
"RaiseUserAtkDefAcc1",
|
||||
"RaiseUserSpAtkSpDef1",
|
||||
"UseMoveDependingOnEnvironment",
|
||||
"UseRandomUserMoveIfAsleep",
|
||||
"DisableTargetUsingDifferentMove",
|
||||
"SwitchOutUserPassOnEffects",
|
||||
"AddSpikesToFoeSide",
|
||||
"AddToxicSpikesToFoeSide",
|
||||
"AddStealthRocksToFoeSide",
|
||||
"CurseTargetOrLowerUserSpd1RaiseUserAtkDef1",
|
||||
"StartSlowerBattlersActFirst",
|
||||
"ProtectUserFromTargetingMovesSpikyShield",
|
||||
"StartElectricTerrain",
|
||||
"StartGrassyTerrain",
|
||||
"StartMistyTerrain",
|
||||
"StartPsychicTerrain",
|
||||
"CureTargetStatusHealUserHalfOfTotalHP"
|
||||
return 80
|
||||
when "CureUserPartyStatus",
|
||||
"RaiseUserAttack2",
|
||||
"RaiseUserSpAtk2",
|
||||
"RaiseUserSpAtk3",
|
||||
"StartUserSideDoubleSpeed",
|
||||
"StartWeakenPhysicalDamageAgainstUserSide",
|
||||
"StartWeakenSpecialDamageAgainstUserSide",
|
||||
"ProtectUserSideFromDamagingMovesIfUserFirstTurn",
|
||||
"ProtectUserFromDamagingMovesKingsShield",
|
||||
"ProtectUserBanefulBunker"
|
||||
return 85
|
||||
when "RaiseUserAtkSpd1",
|
||||
"RaiseUserSpAtkSpDefSpd1",
|
||||
"LowerUserDefSpDef1RaiseUserAtkSpAtkSpd2",
|
||||
"RaiseUserAtk1Spd2",
|
||||
"TwoTurnAttackRaiseUserSpAtkSpDefSpd2"
|
||||
return 90
|
||||
when "SleepTarget",
|
||||
"SleepTargetChangeUserMeloettaForm",
|
||||
"AddStickyWebToFoeSide",
|
||||
"StartWeakenDamageAgainstUserSideIfHail"
|
||||
return 100
|
||||
end
|
||||
# "DoesNothingUnusableInGravity",
|
||||
# "StartUserSideImmunityToInflictedStatus",
|
||||
# "LowerTargetEvasion1",
|
||||
# "LowerTargetEvasion2",
|
||||
# "StartPreventCriticalHitsAgainstUserSide",
|
||||
# "UserFaintsLowerTargetAtkSpAtk2",
|
||||
# "FleeFromBattle",
|
||||
# "SwitchOutUserStatusMove"
|
||||
# "TargetTakesUserItem",
|
||||
# "LowerPPOfTargetLastMoveBy4",
|
||||
# "StartTargetAirborneAndAlwaysHitByMoves",
|
||||
# "TargetActsNext",
|
||||
# "TargetActsLast",
|
||||
# "ProtectUserSideFromStatusMoves"
|
||||
return 100
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Make the final choice of which move to use depending on the calculated
|
||||
# scores for each move. Moves with higher scores are more likely to be chosen.
|
||||
@@ -662,6 +194,8 @@ class Battle::AI
|
||||
|
||||
# If there are no calculated choices, pick one at random
|
||||
if choices.length == 0
|
||||
# NOTE: Can only get here if no moves can be chosen, i.e. will auto-use a
|
||||
# move or struggle.
|
||||
user_battler.eachMoveWithIndex do |_m, i|
|
||||
next if !@battle.pbCanChooseMove?(user_battler.index, i, false)
|
||||
choices.push([i, 100, -1]) # Move index, score, target
|
||||
|
||||
Reference in New Issue
Block a user