Some rearranging of AI script files/methods

This commit is contained in:
Maruno17
2023-02-10 21:47:04 +00:00
parent 7e4ef4247b
commit a8e024eb3e
15 changed files with 617 additions and 535 deletions

View File

@@ -25,10 +25,10 @@ class Battle::AI::AIBattler
def pokemon; return @battler.pokemon; end
def level; return @battler.level; end
def hp; return @battler.hp; end
def totalhp; return @battler.totalhp; end
def fainted?; return @battler.fainted?; end
def status; return @battler.status; end
def statusCount; return @battler.statusCount; end
def totalhp; return @battler.totalhp; end
def gender; return @battler.gender; end
def turnCount; return @battler.turnCount; end
def effects; return @battler.effects; end
@@ -307,6 +307,467 @@ class Battle::AI::AIBattler
#=============================================================================
# Returns a value indicating how beneficial the given item will be to this
# battler if it is holding it.
# Return values are typically -2, -1, 0, 1 or 2. 0 is indifferent, positive
# values mean this battler benefits, negative values mean this battler suffers.
def wants_item?(item = :NONE)
item == :NONE if item.nil?
# TODO: Add more items.
preferred_items = [
:CHOICESCARF,
:LEFTOVERS
]
preferred_items.push(:BLACKSLUDGE) if has_type?(:POISON)
preferred_items.push(:IRONBALL) if has_move_with_function?("ThrowUserItemAtTarget")
preferred_items.push(:CHOICEBAND) if check_for_move { |m| m.physicalMove?(m.type) }
preferred_items.push(:CHOICESPECS) if check_for_move { |m| m.specialMove?(m.type) }
unpreferred_items = [
:BLACKSLUDGE,
:FLAMEORB,
:IRONBALL,
:LAGGINGTAIL,
:STICKYBARB,
:TOXICORB
]
ret = 0
if preferred_items.include?(item)
ret = 2
elsif unpreferred_items.include?(item)
ret = -2
end
# Don't prefer if this battler knows Acrobatics
if has_move_with_function?("DoublePowerIfUserHasNoItem")
ret += (item == :NONE) ? 1 : -1
end
return ret
end
#=============================================================================
# Items can be consumed by Stuff Cheeks, Teatime, Bug Bite/Pluck and Fling.
def get_score_change_for_consuming_item(item)
ret = 0
case item
when :ORANBERRY, :BERRYJUICE, :ENIGMABERRY, :SITRUSBERRY
# Healing
ret += (hp > totalhp * 3 / 4) ? -8 : 8
ret = ret * 3 / 2 if GameData::Item.get(item).is_berry? && has_active_ability?(:RIPEN)
when :AGUAVBERRY, :FIGYBERRY, :IAPAPABERRY, :MAGOBERRY, :WIKIBERRY
# Healing with confusion
fraction_to_heal = 8 # Gens 6 and lower
if Settings::MECHANICS_GENERATION == 7
fraction_to_heal = 2
elsif Settings::MECHANICS_GENERATION >= 8
fraction_to_heal = 3
end
ret += (hp > totalhp * (1 - (1 / fraction_to_heal))) ? -8 : 8
ret = ret * 3 / 2 if GameData::Item.get(item).is_berry? && has_active_ability?(:RIPEN)
# TODO: Check whether the item will cause confusion?
when :ASPEARBERRY, :CHERIBERRY, :CHESTOBERRY, :PECHABERRY, :RAWSTBERRY
# Status cure
cured_status = {
:ASPEAR => :FROZEN,
:CHERIBERRY => :PARALYSIS,
:CHESTOBERRY => :SLEEP,
:PECHABERRY => :POISON,
:RAWSTBERRY => :BURN
}[item]
ret += (cured_status && status == cured_status) ? 8 : -8
when :PERSIMBERRY
# Confusion cure
ret += (effects[PBEffects::Confusion] > 1) ? 8 : -8
when :LUMBERRY
# Any status/confusion cure
ret += (status != :NONE || effects[PBEffects::Confusion] > 1) ? 8 : -8
when :MENTALHERB
# Cure mental effects
ret += 8 if effects[PBEffects::Attract] >= 0 ||
effects[PBEffects::Taunt] > 1 ||
effects[PBEffects::Encore] > 1 ||
effects[PBEffects::Torment] ||
effects[PBEffects::Disable] > 1 ||
effects[PBEffects::HealBlock] > 1
when :APICOTBERRY, :GANLONBERRY, :LIECHIBERRY, :PETAYABERRY, :SALACBERRY,
:KEEBERRY, :MARANGABERRY
# Stat raise
stat = {
:APICOTBERRY => :SPECIAL_DEFENSE,
:GANLONBERRY => :DEFENSE,
:LIECHIBERRY => :ATTACK,
:PETAYABERRY => :SPECIAL_ATTACK,
:SALACBERRY => :SPEED,
:KEEBERRY => :DEFENSE,
:MARANGABERRY => :SPECIAL_DEFENSE
}[item]
ret += 8 if stat && @ai.stat_raise_worthwhile?(self, stat)
ret = ret * 3 / 2 if GameData::Item.get(item).is_berry? && has_active_ability?(:RIPEN)
when :STARFBERRY
# Random stat raise
ret += 8
ret = ret * 3 / 2 if GameData::Item.get(item).is_berry? && has_active_ability?(:RIPEN)
when :WHITEHERB
# Resets lowered stats
reduced_stats = false
GameData::Stat.each_battle do |s|
next if stages[s.id] >= 0
reduced_stats = true
break
end
ret += 8 if reduced_stats
when :MICLEBERRY
# Raises accuracy of next move
ret += 8
when :LANSATBERRY
# Focus energy
ret += 8 if effects[PBEffects::FocusEnergy] < 2
when :LEPPABERRY
# Restore PP
ret += 8
ret = ret * 3 / 2 if GameData::Item.get(item).is_berry? && has_active_ability?(:RIPEN)
end
return ret
end
#=============================================================================
# These values are taken from the Complete-Fire-Red-Upgrade decomp here:
# https://github.com/Skeli789/Complete-Fire-Red-Upgrade/blob/f7f35becbd111c7e936b126f6328fc52d9af68c8/src/ability_battle_effects.c#L41
BASE_ABILITY_RATINGS = {
:ADAPTABILITY => 8,
:AERILATE => 8,
:AFTERMATH => 5,
:AIRLOCK => 5,
:ANALYTIC => 5,
:ANGERPOINT => 4,
:ANTICIPATION => 0,
:ARENATRAP => 9,
:AROMAVEIL => 3,
# :ASONECHILLINGNEIGH => 0,
# :ASONEGRIMNEIGH => 0,
:AURABREAK => 3,
:BADDREAMS => 4,
# :BALLFETCH => 0,
# :BATTERY => 0,
:BATTLEARMOR => 2,
:BATTLEBOND => 6,
:BEASTBOOST => 7,
:BERSERK => 5,
:BIGPECKS => 1,
:BLAZE => 5,
:BULLETPROOF => 7,
:CHEEKPOUCH => 4,
# :CHILLINGNEIGH => 0,
:CHLOROPHYLL => 6,
:CLEARBODY => 4,
:CLOUDNINE => 5,
:COLORCHANGE => 2,
:COMATOSE => 6,
:COMPETITIVE => 5,
:COMPOUNDEYES => 7,
:CONTRARY => 8,
:CORROSION => 5,
:COTTONDOWN => 3,
# :CURIOUSMEDICINE => 0,
:CURSEDBODY => 4,
:CUTECHARM => 2,
:DAMP => 2,
:DANCER => 5,
:DARKAURA => 6,
:DAUNTLESSSHIELD => 3,
:DAZZLING => 5,
:DEFEATIST => -1,
:DEFIANT => 5,
:DELTASTREAM => 10,
:DESOLATELAND => 10,
:DISGUISE => 8,
:DOWNLOAD => 7,
:DRAGONSMAW => 8,
:DRIZZLE => 9,
:DROUGHT => 9,
:DRYSKIN => 6,
:EARLYBIRD => 4,
:EFFECTSPORE => 4,
:ELECTRICSURGE => 8,
:EMERGENCYEXIT => 3,
:FAIRYAURA => 6,
:FILTER => 6,
:FLAMEBODY => 4,
:FLAREBOOST => 5,
:FLASHFIRE => 6,
:FLOWERGIFT => 4,
# :FLOWERVEIL => 0,
:FLUFFY => 5,
:FORECAST => 6,
:FOREWARN => 0,
# :FRIENDGUARD => 0,
:FRISK => 0,
:FULLMETALBODY => 4,
:FURCOAT => 7,
:GALEWINGS => 6,
:GALVANIZE => 8,
:GLUTTONY => 3,
:GOOEY => 5,
:GORILLATACTICS => 4,
:GRASSPELT => 2,
:GRASSYSURGE => 8,
# :GRIMNEIGH => 0,
:GULPMISSLE => 3,
:GUTS => 6,
:HARVEST => 5,
# :HEALER => 0,
:HEATPROOF => 5,
:HEAVYMETAL => -1,
# :HONEYGATHER => 0,
:HUGEPOWER => 10,
:HUNGERSWITCH => 2,
:HUSTLE => 7,
:HYDRATION => 4,
:HYPERCUTTER => 3,
:ICEBODY => 3,
:ICEFACE => 4,
:ICESCALES => 7,
# :ILLUMINATE => 0,
:ILLUSION => 8,
:IMMUNITY => 4,
:IMPOSTER => 9,
:INFILTRATOR => 6,
:INNARDSOUT => 5,
:INNERFOCUS => 2,
:INSOMNIA => 4,
:INTIMIDATE => 7,
:INTREPIDSWORD => 3,
:IRONBARBS => 6,
:IRONFIST => 6,
:JUSTIFIED => 4,
:KEENEYE => 1,
:KLUTZ => -1,
:LEAFGUARD => 2,
:LEVITATE => 7,
:LIBERO => 8,
:LIGHTMETAL => 2,
:LIGHTNINGROD => 7,
:LIMBER => 3,
:LIQUIDOOZE => 3,
:LIQUIDVOICE => 5,
:LONGREACH => 3,
:MAGICBOUNCE => 9,
:MAGICGUARD => 9,
:MAGICIAN => 3,
:MAGMAARMOR => 1,
:MAGNETPULL => 9,
:MARVELSCALE => 5,
:MEGALAUNCHER => 7,
:MERCILESS => 4,
:MIMICRY => 2,
# :MINUS => 0,
:MIRRORARMOR => 6,
:MISTYSURGE => 8,
:MOLDBREAKER => 7,
:MOODY => 10,
:MOTORDRIVE => 6,
:MOXIE => 7,
:MULTISCALE => 8,
:MULTITYPE => 8,
:MUMMY => 5,
:NATURALCURE => 7,
:NEUROFORCE => 6,
:NEUTRALIZINGGAS => 5,
:NOGUARD => 8,
:NORMALIZE => -1,
:OBLIVIOUS => 2,
:OVERCOAT => 5,
:OVERGROW => 5,
:OWNTEMPO => 3,
:PARENTALBOND => 10,
:PASTELVEIL => 4,
:PERISHBODY => -1,
:PICKPOCKET => 3,
:PICKUP => 1,
:PIXILATE => 8,
# :PLUS => 0,
:POISONHEAL => 8,
:POISONPOINT => 4,
:POISONTOUCH => 4,
:POWERCONSTRUCT => 10,
# :POWEROFALCHEMY => 0,
:POWERSPOT => 2,
:PRANKSTER => 8,
:PRESSURE => 5,
:PRIMORDIALSEA => 10,
:PRISMARMOR => 6,
:PROPELLORTAIL => 2,
:PROTEAN => 8,
:PSYCHICSURGE => 8,
:PUNKROCK => 2,
:PUREPOWER => 10,
:QUEENLYMAJESTY => 6,
# :QUICKDRAW => 0,
:QUICKFEET => 5,
:RAINDISH => 3,
:RATTLED => 3,
# :RECEIVER => 0,
:RECKLESS => 6,
:REFRIGERATE => 8,
:REGENERATOR => 8,
:RIPEN => 4,
:RIVALRY => 1,
:RKSSYSTEM => 8,
:ROCKHEAD => 5,
:ROUGHSKIN => 6,
# :RUNAWAY => 0,
:SANDFORCE => 4,
:SANDRUSH => 6,
:SANDSPIT => 5,
:SANDSTREAM => 9,
:SANDVEIL => 3,
:SAPSIPPER => 7,
:SCHOOLING => 6,
:SCRAPPY => 6,
:SCREENCLEANER => 3,
:SERENEGRACE => 8,
:SHADOWSHIELD => 8,
:SHADOWTAG => 10,
:SHEDSKIN => 7,
:SHEERFORCE => 8,
:SHELLARMOR => 2,
:SHIELDDUST => 5,
:SHIELDSDOWN => 6,
:SIMPLE => 8,
:SKILLLINK => 7,
:SLOWSTART => -2,
:SLUSHRUSH => 5,
:SNIPER => 3,
:SNOWCLOAK => 3,
:SNOWWARNING => 8,
:SOLARPOWER => 3,
:SOLIDROCK => 6,
:SOULHEART => 7,
:SOUNDPROOF => 4,
:SPEEDBOOST => 9,
:STAKEOUT => 6,
:STALL => -1,
:STALWART => 2,
:STAMINA => 6,
:STANCECHANGE => 10,
:STATIC => 4,
:STEADFAST => 2,
:STEAMENGINE => 3,
:STEELWORKER => 6,
:STEELYSPIRIT => 2,
:STENCH => 1,
:STICKYHOLD => 3,
:STORMDRAIN => 7,
:STRONGJAW => 6,
:STURDY => 6,
:SUCTIONCUPS => 2,
:SUPERLUCK => 3,
:SURGESURFER => 4,
:SWARM => 5,
:SWEETVEIL => 4,
:SWIFTSWIM => 6,
# :SYMBIOSIS => 0,
:SYNCHRONIZE => 4,
:TANGLEDFEET => 2,
:TANGLINGHAIR => 5,
:TECHNICIAN => 8,
# :TELEPATHY => 0,
:TERAVOLT => 7,
:THICKFAT => 7,
:TINTEDLENS => 7,
:TORRENT => 5,
:TOUGHCLAWS => 7,
:TOXICBOOST => 6,
:TRACE => 6,
:TRANSISTOR => 8,
:TRIAGE => 7,
:TRUANT => -2,
:TURBOBLAZE => 7,
:UNAWARE => 6,
:UNBURDEN => 7,
:UNNERVE => 3,
# :UNSEENFIST => 0,
:VICTORYSTAR => 6,
:VITALSPIRIT => 4,
:VOLTABSORB => 7,
:WANDERINGSPIRIT => 2,
:WATERABSORB => 7,
:WATERBUBBLE => 8,
:WATERCOMPACTION => 4,
:WATERVEIL => 4,
:WEAKARMOR => 2,
:WHITESMOKE => 4,
:WIMPOUT => 3,
:WONDERGUARD => 10,
:WONDERSKIN => 4,
:ZENMODE => -1
}
# Returns a value indicating how beneficial the given ability will be to this
# battler if it has it.
# Return values are typically between -10 and +10. 0 is indifferent, positive
# values mean this battler benefits, negative values mean this battler suffers.
# TODO: This method assumes the ability isn't being negated. Should it return
# 0 if it is? The calculations that call this method separately check
# for it being negated, because they need to do something special in
# that case, so I think it's okay for this method to ignore negation.
def wants_ability?(ability = :NONE)
ability = ability.id if !ability.is_a?(Symbol) && ability.respond_to?("id")
# TODO: Ideally replace the above list of ratings with context-sensitive
# calculations. Should they all go in this method, or should there be
# more handlers for each ability?
case ability
when :BLAZE
return 0 if !has_damaging_move_of_type?(:FIRE)
when :CUTECHARM, :RIVALRY
return 0 if gender == 2
when :FRIENDGUARD, :HEALER, :SYMBOISIS, :TELEPATHY
has_ally = false
each_ally(@side) { |b, i| has_ally = true }
return 0 if !has_ally
when :GALEWINGS
return 0 if !check_for_move { |m| m.type == :FLYING }
when :HUGEPOWER, :PUREPOWER
return 0 if !check_for_move { |m| m.physicalMove?(m.type) &&
m.function != "UseUserDefenseInsteadOfUserAttack" &&
m.function != "UseTargetAttackInsteadOfUserAttack" }
when :IRONFIST
return 0 if !check_for_move { |m| m.punchingMove? }
when :LIQUIDVOICE
return 0 if !check_for_move { |m| m.soundMove? }
when :MEGALAUNCHER
return 0 if !check_for_move { |m| m.pulseMove? }
when :OVERGROW
return 0 if !has_damaging_move_of_type?(:GRASS)
when :PRANKSTER
return 0 if !check_for_move { |m| m.statusMove? }
when :PUNKROCK
return 1 if !check_for_move { |m| m.damagingMove? && m.soundMove? }
when :RECKLESS
return 0 if !check_for_move { |m| m.recoilMove? }
when :ROCKHEAD
return 0 if !check_for_move { |m| m.recoilMove? && !m.is_a?(Battle::Move::CrashDamageIfFailsUnusableInGravity) }
when :RUNAWAY
return 0 if wild?
when :SANDFORCE
return 2 if !has_damaging_move_of_type?(:GROUND, :ROCK, :STEEL)
when :SKILLLINK
return 0 if !check_for_move { |m| m.is_a?(Battle::Move::HitTwoToFiveTimes) }
when :STEELWORKER
return 0 if !has_damaging_move_of_type?(:GRASS)
when :SWARM
return 0 if !has_damaging_move_of_type?(:BUG)
when :TORRENT
return 0 if !has_damaging_move_of_type?(:WATER)
when :TRIAGE
return 0 if !check_for_move { |m| m.healingMove? }
end
ret = BASE_ABILITY_RATINGS[ability] || 0
return ret
end
#=============================================================================
private
def effectiveness_of_type_against_single_battler_type(type, defend_type, user = nil)