Rewrote AI for move function codes for counters, protection removal, Wonder Room, Substitute. Fixed Counters working with damage absorbed by a substitute.

This commit is contained in:
Maruno17
2023-02-08 22:19:45 +00:00
parent 3f5c1f0974
commit 01e98c8f97
6 changed files with 154 additions and 83 deletions

View File

@@ -374,6 +374,7 @@ class Battle::Move
# code.
moveType = nil
moveType = :NORMAL if @function == "TypeDependsOnUserIVs" # Hidden Power
if !target.damageState.substitute
if physicalMove?(moveType)
target.effects[PBEffects::Counter] = damage
target.effects[PBEffects::CounterTarget] = user.index
@@ -381,6 +382,7 @@ class Battle::Move
target.effects[PBEffects::MirrorCoat] = damage
target.effects[PBEffects::MirrorCoatTarget] = user.index
end
end
if target.effects[PBEffects::Bide] > 0
target.effects[PBEffects::BideDamage] += damage
target.effects[PBEffects::BideTarget] = user.index

View File

@@ -991,20 +991,8 @@ end
#===============================================================================
# Ends target's protections immediately. (Hyperspace Hole)
#===============================================================================
class Battle::Move::RemoveProtectionsBypassSubstitute < Battle::Move
class Battle::Move::RemoveProtectionsBypassSubstitute < Battle::Move::RemoveProtections
def ignoresSubstitute?(user); return true; end
def pbEffectAgainstTarget(user, target)
target.effects[PBEffects::BanefulBunker] = false
target.effects[PBEffects::KingsShield] = false
target.effects[PBEffects::Obstruct] = false
target.effects[PBEffects::Protect] = false
target.effects[PBEffects::SpikyShield] = false
target.pbOwnSide.effects[PBEffects::CraftyShield] = false
target.pbOwnSide.effects[PBEffects::MatBlock] = false
target.pbOwnSide.effects[PBEffects::QuickGuard] = false
target.pbOwnSide.effects[PBEffects::WideGuard] = false
end
end
#===============================================================================

View File

@@ -601,7 +601,7 @@ Battle::AI::Handlers::MoveEffectScore.add("SwapSideEffects",
)
#===============================================================================
# TODO: Review score modifiers.
#
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.add("UserMakeSubstitute",
proc { |move, user, ai, battle|
@@ -612,7 +612,11 @@ Battle::AI::Handlers::MoveFailureCheck.add("UserMakeSubstitute",
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
score += (8 * user.hp.to_f / user.totalhp).round
# Prefer if foes don't know any moves that can bypass a substitute
ai.each_battler do |b, i|
score += 4 if !b.check_for_move { |m| m.ignoresSubstitute?(b.battler) }
end
# TODO: Predict incoming damage, and prefer if it's greater than
# user.totalhp / 4?
next score

View File

@@ -1323,7 +1323,6 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("UserCopyTargetStatStages
)
#===============================================================================
# TODO: Review score modifiers.
# TODO: Account for stat theft before damage calculation. This would be complex,
# involving pbCanRaiseStatStage? and Contrary and Simple; do I want to
# account for all that or simplify things?
@@ -1507,57 +1506,56 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("UserTargetAverageBaseAtk
target_atk = target.base_stat(:ATTACK)
target_spatk = target.base_stat(:SPECIAL_ATTACK)
next Battle::AI::MOVE_USELESS_SCORE if user_atk >= target_atk && user_spatk >= target_spatk
change_matters = false
# Score based on changes to Attack
atk_change_matters = false
if target_atk > user_atk
# User's Attack will be raised
if ai.stat_raise_worthwhile?(user, :ATTACK, true)
score += (20 * ((target_atk.to_f / user_atk) - 1)).to_i
atk_change_matters = true
change_matters = true
end
# Target's Attack will be lowered
if ai.stat_drop_worthwhile?(target, :ATTACK, true)
score += (20 * ((target_atk.to_f / user_atk) - 1)).to_i
atk_change_matters = true
change_matters = true
end
elsif target_atk < user_atk
# User's Attack will be lowered
if ai.stat_drop_worthwhile?(user, :ATTACK, true)
score -= (20 * ((user_atk.to_f / target_atk) - 1)).to_i
atk_change_matters = true
change_matters = true
end
# Target's Attack will be raised
if ai.stat_raise_worthwhile?(target, :ATTACK, true)
score -= (20 * ((user_atk.to_f / target_atk) - 1)).to_i
atk_change_matters = true
change_matters = true
end
end
# Score based on changes to Special Attack
spatk_change_matters = false
if target_spatk > user_spatk
# User's Special Attack will be raised
if ai.stat_raise_worthwhile?(user, :SPECIAL_ATTACK, true)
score += (20 * ((target_spatk.to_f / user_spatk) - 1)).to_i
spatk_change_matters = true
change_matters = true
end
# Target's Special Attack will be lowered
if ai.stat_drop_worthwhile?(target, :SPECIAL_ATTACK, true)
score += (20 * ((target_spatk.to_f / user_spatk) - 1)).to_i
spatk_change_matters = true
change_matters = true
end
elsif target_spatk < user_spatk
# User's Special Attack will be lowered
if ai.stat_drop_worthwhile?(user, :SPECIAL_ATTACK, true)
score -= (20 * ((user_spatk.to_f / target_spatk) - 1)).to_i
spatk_change_matters = true
change_matters = true
end
# Target's Special Attack will be raised
if ai.stat_raise_worthwhile?(target, :SPECIAL_ATTACK, true)
score -= (20 * ((user_spatk.to_f / target_spatk) - 1)).to_i
spatk_change_matters = true
change_matters = true
end
end
next Battle::AI::MOVE_USELESS_SCORE if !atk_change_matters && !spatk_change_matters
next Battle::AI::MOVE_USELESS_SCORE if !change_matters
next score
}
)
@@ -1572,57 +1570,56 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("UserTargetAverageBaseDef
target_def = target.base_stat(:DEFENSE)
target_spdef = target.base_stat(:SPECIAL_DEFENSE)
next Battle::AI::MOVE_USELESS_SCORE if user_def >= target_def && user_spdef >= target_spdef
change_matters = false
# Score based on changes to Defense
def_change_matters = false
if target_def > user_def
# User's Defense will be raised
if ai.stat_raise_worthwhile?(user, :ATTACK, true)
if ai.stat_raise_worthwhile?(user, :DEFENSE, true)
score += (20 * ((target_def.to_f / user_def) - 1)).to_i
def_change_matters = true
change_matters = true
end
# Target's Defense will be lowered
if ai.stat_drop_worthwhile?(target, :ATTACK, true)
if ai.stat_drop_worthwhile?(target, :DEFENSE, true)
score += (20 * ((target_def.to_f / user_def) - 1)).to_i
def_change_matters = true
change_matters = true
end
elsif target_def < user_def
# User's Defense will be lowered
if ai.stat_drop_worthwhile?(user, :ATTACK, true)
if ai.stat_drop_worthwhile?(user, :DEFENSE, true)
score -= (20 * ((user_def.to_f / target_def) - 1)).to_i
def_change_matters = true
change_matters = true
end
# Target's Defense will be raised
if ai.stat_raise_worthwhile?(target, :ATTACK, true)
if ai.stat_raise_worthwhile?(target, :DEFENSE, true)
score -= (20 * ((user_def.to_f / target_def) - 1)).to_i
def_change_matters = true
change_matters = true
end
end
# Score based on changes to Special Defense
spdef_change_matters = false
if target_spdef > user_spdef
# User's Special Defense will be raised
if ai.stat_raise_worthwhile?(user, :SPECIAL_ATTACK, true)
if ai.stat_raise_worthwhile?(user, :SPECIAL_DEFENSE, true)
score += (20 * ((target_spdef.to_f / user_spdef) - 1)).to_i
spdef_change_matters = true
change_matters = true
end
# Target's Special Defense will be lowered
if ai.stat_drop_worthwhile?(target, :SPECIAL_ATTACK, true)
if ai.stat_drop_worthwhile?(target, :SPECIAL_DEFENSE, true)
score += (20 * ((target_spdef.to_f / user_spdef) - 1)).to_i
spdef_change_matters = true
change_matters = true
end
elsif target_spdef < user_spdef
# User's Special Defense will be lowered
if ai.stat_drop_worthwhile?(user, :SPECIAL_ATTACK, true)
if ai.stat_drop_worthwhile?(user, :SPECIAL_DEFENSE, true)
score -= (20 * ((user_spdef.to_f / target_spdef) - 1)).to_i
spdef_change_matters = true
change_matters = true
end
# Target's Special Defense will be raised
if ai.stat_raise_worthwhile?(target, :SPECIAL_ATTACK, true)
if ai.stat_raise_worthwhile?(target, :SPECIAL_DEFENSE, true)
score -= (20 * ((user_spdef.to_f / target_spdef) - 1)).to_i
spdef_change_matters = true
change_matters = true
end
end
next Battle::AI::MOVE_USELESS_SCORE if !def_change_matters && !spdef_change_matters
next Battle::AI::MOVE_USELESS_SCORE if !change_matters
next score
}
)
@@ -1673,7 +1670,43 @@ Battle::AI::Handlers::MoveEffectScore.add("StartUserSideDoubleSpeed",
)
#===============================================================================
# TODO: Review score modifiers.
# TODO: This code shouldn't make use of target.
#
#===============================================================================
# StartSwapAllBattlersBaseDefensiveStats
Battle::AI::Handlers::MoveEffectScore.add("StartSwapAllBattlersBaseDefensiveStats",
proc { |score, move, user, ai, battle|
any_change_matters = false
ai.each_battler do |b, i|
b_def = b.base_stat(:DEFENSE)
b_spdef = b.base_stat(:SPECIAL_DEFENSE)
next if b_def == b_spdef
score_change = 0
if b_def > b_spdef
# Battler's Defense will be lowered
if ai.stat_drop_worthwhile?(b, :DEFENSE, true)
score_change -= (20 * ((b_def.to_f / b_spdef) - 1)).to_i
any_change_matters = true
end
# Battler's Special Defense will be raised
if ai.stat_raise_worthwhile?(b, :SPECIAL_DEFENSE, true)
score_change += (20 * ((b_def.to_f / b_spdef) - 1)).to_i
any_change_matters = true
end
else
# Battler's Special Defense will be lowered
if ai.stat_drop_worthwhile?(b, :SPECIAL_DEFENSE, true)
score_change -= (20 * ((b_spdef.to_f / b_def) - 1)).to_i
any_change_matters = true
end
# Battler's Defense will be raised
if ai.stat_raise_worthwhile?(b, :DEFENSE, true)
score_change += (20 * ((b_spdef.to_f / b_def) - 1)).to_i
any_change_matters = true
end
end
score += (b.opposes?(user)) ? -score_change : score_change
end
next Battle::AI::MOVE_USELESS_SCORE if !any_change_matters
next Battle::AI::MOVE_USELESS_SCORE if score <= Battle::AI::MOVE_BASE_SCORE
next score
}
)

View File

@@ -1138,17 +1138,28 @@ Battle::AI::Handlers::MoveEffectScore.add("ProtectUserSideFromMultiTargetDamagin
)
#===============================================================================
# TODO: Review score modifiers.
#
#===============================================================================
# RemoveProtections
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("RemoveProtections",
proc { |score, move, user, target, ai, battle|
if target.check_for_move { |m| (m.is_a?(Battle::Move::ProtectMove) ||
m.is_a?(Battle::Move::ProtectUserSideFromStatusMoves) ||
m.is_a?(Battle::Move::ProtectUserSideFromDamagingMovesIfUserFirstTurn)) &&
!m.is_a?(Battle::Move::UserEnduresFaintingThisTurn) }
score += 5
end
next score
}
)
#===============================================================================
# TODO: Review score modifiers.
#
#===============================================================================
# RemoveProtectionsBypassSubstitute
Battle::AI::Handlers::MoveEffectAgainstTargetScore.copy("RemoveProtectionsBypassSubstitute",
"RemoveProtections")
#===============================================================================
# TODO: Review score modifiers.
#
#===============================================================================
Battle::AI::Handlers::MoveFailureCheck.add("HoopaRemoveProtectionsBypassSubstituteLowerUserDef1",
proc { |move, user, ai, battle|
@@ -1157,6 +1168,8 @@ Battle::AI::Handlers::MoveFailureCheck.add("HoopaRemoveProtectionsBypassSubstitu
)
Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("HoopaRemoveProtectionsBypassSubstituteLowerUserDef1",
proc { |score, move, user, target, ai, battle|
score = Battle::AI::Handlers.apply_move_effect_against_target_score("RemoveProtections",
score, move, user, target, ai, battle)
next ai.get_score_for_target_stat_drop(score, user, move.move.statDown, false)
}
)

View File

@@ -241,8 +241,7 @@ Battle::AI::Handlers::MoveEffectAgainstTargetScore.add("PowerUpAllyMove",
)
#===============================================================================
# TODO: Review score modifiers.
# TODO: This code shouldn't make use of target.
#
#===============================================================================
Battle::AI::Handlers::MoveBasePower.add("CounterPhysicalDamage",
proc { |power, move, user, target, ai, battle|
@@ -251,22 +250,30 @@ Battle::AI::Handlers::MoveBasePower.add("CounterPhysicalDamage",
)
Battle::AI::Handlers::MoveEffectScore.add("CounterPhysicalDamage",
proc { |score, move, user, ai, battle|
# next Battle::AI::MOVE_USELESS_SCORE if target.effects[PBEffects::HyperBeam] > 0
attack = user.rough_stat(:ATTACK)
spatk = user.rough_stat(:SPECIAL_ATTACK)
if attack * 1.5 < spatk
score -= 60
# elsif ai.trainer.medium_skill? && target.battler.lastMoveUsed
# moveData = GameData::Move.get(target.battler.lastMoveUsed)
# score += 60 if moveData.physical?
has_physical_move = false
ai.each_foe_battler(user.side) do |b, i|
next if !b.can_attack?
next if !b.check_for_move { |m| m.physicalMove?(m.type) &&
(user.effects[PBEffects::Substitute] == 0 ||
m.ignoresSubstitute?(b.battler)) }
has_physical_move = true
# Prefer if foe has a higher Attack than Special Attack
score += 5 if b.rough_stat(:ATTACK) > b.rough_stat(:SPECIAL_ATTACK)
# Prefer if the last move the foe used was physical
if ai.trainer.medium_skill? && b.battler.lastMoveUsed
score += 5 if GameData::Move.get(b.battler.lastMoveUsed).physical?
end
# Prefer if the foe is taunted into using a damaging move
score += 4 if b.effects[PBEffects::Taunt] > 0
end
# Useless if no foes have a physical move to counter
next Battle::AI::MOVE_USELESS_SCORE if !has_physical_move
next score
}
)
#===============================================================================
# TODO: Review score modifiers.
# TODO: This code shouldn't make use of target.
#
#===============================================================================
Battle::AI::Handlers::MoveBasePower.add("CounterSpecialDamage",
proc { |power, move, user, target, ai, battle|
@@ -275,22 +282,30 @@ Battle::AI::Handlers::MoveBasePower.add("CounterSpecialDamage",
)
Battle::AI::Handlers::MoveEffectScore.add("CounterSpecialDamage",
proc { |score, move, user, ai, battle|
# next Battle::AI::MOVE_USELESS_SCORE if target.effects[PBEffects::HyperBeam] > 0
attack = user.rough_stat(:ATTACK)
spatk = user.rough_stat(:SPECIAL_ATTACK)
if attack > spatk * 1.5
score -= 60
# elsif ai.trainer.medium_skill? && target.battler.lastMoveUsed
# moveData = GameData::Move.get(target.battler.lastMoveUsed)
# score += 60 if moveData.special?
has_special_move = false
ai.each_foe_battler(user.side) do |b, i|
next if !b.can_attack?
next if !b.check_for_move { |m| m.specialMove?(m.type) &&
(user.effects[PBEffects::Substitute] == 0 ||
m.ignoresSubstitute?(b.battler)) }
has_special_move = true
# Prefer if foe has a higher Special Attack than Attack
score += 5 if b.rough_stat(:SPECIAL_ATTACK) > b.rough_stat(:ATTACK)
# Prefer if the last move the foe used was special
if ai.trainer.medium_skill? && b.battler.lastMoveUsed
score += 5 if GameData::Move.get(b.battler.lastMoveUsed).special?
end
# Prefer if the foe is taunted into using a damaging move
score += 4 if b.effects[PBEffects::Taunt] > 0
end
# Useless if no foes have a special move to counter
next Battle::AI::MOVE_USELESS_SCORE if !has_special_move
next score
}
)
#===============================================================================
# TODO: Review score modifiers.
# TODO: This code shouldn't make use of target.
#
#===============================================================================
Battle::AI::Handlers::MoveBasePower.add("CounterDamagePlusHalf",
proc { |power, move, user, target, ai, battle|
@@ -299,7 +314,23 @@ Battle::AI::Handlers::MoveBasePower.add("CounterDamagePlusHalf",
)
Battle::AI::Handlers::MoveEffectScore.add("CounterDamagePlusHalf",
proc { |score, move, user, ai, battle|
# next Battle::AI::MOVE_USELESS_SCORE if target.effects[PBEffects::HyperBeam] > 0
has_damaging_move = false
ai.each_foe_battler(user.side) do |b, i|
next if !b.can_attack? || user.faster_than?(b)
next if !b.check_for_move { |m| m.damagingMove? &&
(user.effects[PBEffects::Substitute] == 0 ||
m.ignoresSubstitute?(b.battler)) }
has_damaging_move = true
# Prefer if the last move the foe used was damaging
if ai.trainer.medium_skill? && b.battler.lastMoveUsed
score += 5 if GameData::Move.get(b.battler.lastMoveUsed).damaging?
end
# Prefer if the foe is taunted into using a damaging move
score += 6 if b.effects[PBEffects::Taunt] > 0
end
# Useless if no foes have a damaging move to counter
next Battle::AI::MOVE_USELESS_SCORE if !has_damaging_move
next score
}
)