mirror of
https://github.com/infinitefusion/infinitefusion-e18.git
synced 2025-12-10 06:34:59 +00:00
166 lines
6.0 KiB
Ruby
166 lines
6.0 KiB
Ruby
class PokeBattle_AI
|
|
#=============================================================================
|
|
#
|
|
#=============================================================================
|
|
# TODO: Reborn has the REVENGEKILLER role which compares mon's speed with
|
|
# opponent (only when deciding whether to switch mon in) - this
|
|
# comparison should be calculated when needed instead of being a role.
|
|
module BattleRole
|
|
PHAZER = 0
|
|
CLERIC = 1
|
|
STALLBREAKER = 2
|
|
STATUSABSORBER = 3
|
|
BATONPASSER = 4
|
|
SPINNER = 5
|
|
FIELDSETTER = 6
|
|
WEATHERSETTER = 7
|
|
SWEEPER = 8
|
|
PIVOT = 9
|
|
PHYSICALWALL = 10
|
|
SPECIALWALL = 11
|
|
TANK = 12
|
|
TRAPPER = 13
|
|
SCREENER = 14
|
|
ACE = 15
|
|
LEAD = 16
|
|
SECOND = 17
|
|
end
|
|
|
|
#=============================================================================
|
|
# Determine the roles filled by a Pokémon on a given side at a given party
|
|
# index.
|
|
#=============================================================================
|
|
def determine_roles(side, index)
|
|
pkmn = @battle.pbParty(side)[index]
|
|
ret = []
|
|
return ret if !pkmn || pkmn.egg?
|
|
|
|
# Check for moves indicative of particular roles
|
|
hasHealMove = false
|
|
hasPivotMove = false
|
|
pkmn.moves.each do |m|
|
|
next if !m
|
|
move = PokeBattle_Move.pbFromPBMove(@battle, m)
|
|
hasHealMove = true if !hasHealMove && move.healingMove?
|
|
case move.function
|
|
when "004", "0E5", "0EB", "0EC" # Yawn, Perish Song, Roar, Circle Throw
|
|
ret.push(BattleRole::PHAZER)
|
|
when "019" # Aromatherapy/Heal Bell
|
|
ret.push(BattleRole::CLERIC)
|
|
when "0BA" # Taunt
|
|
ret.push(BattleRole::STALLBREAKER)
|
|
when "0D7" # Wish
|
|
ret.push(BattleRole::CLERIC) if pkmn.ev[PBStats::HP] == PokeBattle_Pokemon::EV_STAT_LIMIT
|
|
when "0D9" # Rest
|
|
ret.push(BattleRole::STATUSABSORBER)
|
|
when "0ED" # Baton Pass
|
|
ret.push(BattleRole::BATONPASSER)
|
|
when "0EE" # U-turn
|
|
hasPivotMove = true
|
|
when "110" # Rapid Spin
|
|
ret.push(BattleRole::SPINNER)
|
|
when "154", "155", "156", "173" # Terrain moves
|
|
ret.push(BattleRole::FIELDSETTER)
|
|
else
|
|
ret.push(BattleRole::WEATHERSETTER) if move.is_a?(PokeBattle_WeatherMove)
|
|
end
|
|
end
|
|
|
|
# Check EVs, nature and moves for combinations indicative of particular roles
|
|
if pkmn.ev[PBStats::SPEED] == PokeBattle_Pokemon::EV_STAT_LIMIT
|
|
if [PBNatures::MODEST, PBNatures::ADAMANT, # SpAtk+ Atk-, Atk+ SpAtk-
|
|
PBNatures::TIMID, PBNatures::JOLLY].include?(pkmn.nature) # Spd+ Atk-, Spd+ SpAtk-
|
|
ret.push(BattleRole::SWEEPER)
|
|
end
|
|
end
|
|
if hasHealMove
|
|
ret.push(BattleRole::PIVOT) if hasPivotMove
|
|
if PBNatures.getStatRaised(pkmn.nature) == PBStats::DEFENSE &&
|
|
PBNatures.getStatLowered(pkmn.nature) != PBStats::DEFENSE
|
|
ret.push(BattleRole::PHYSICALWALL) if pkmn.ev[PBStats::DEFENSE] == PokeBattle_Pokemon::EV_STAT_LIMIT
|
|
elsif PBNatures.getStatRaised(pkmn.nature) == PBStats::SPDEF &&
|
|
PBNatures.getStatLowered(pkmn.nature) != PBStats::SPDEF
|
|
ret.push(BattleRole::SPECIALWALL) if pkmn.ev[PBStats::SPDEF] == PokeBattle_Pokemon::EV_STAT_LIMIT
|
|
end
|
|
else
|
|
ret.push(BattleRole::TANK) if pkmn.ev[PBStats::HP] == PokeBattle_Pokemon::EV_STAT_LIMIT
|
|
end
|
|
|
|
# Check for abilities indicative of particular roles
|
|
case pkmn.ability_id
|
|
when :REGENERATOR
|
|
ret.push(BattleRole::PIVOT)
|
|
when :GUTS, :QUICKFEET, :FLAREBOOST, :TOXICBOOST, :NATURALCURE, :MAGICGUARD,
|
|
:MAGICBOUNCE, :HYDRATION
|
|
ret.push(BattleRole::STATUSABSORBER)
|
|
when :SHADOWTAG, :ARENATRAP, :MAGNETPULL
|
|
ret.push(BattleRole::TRAPPER)
|
|
when :DROUGHT, :DRIZZLE, :SANDSTREAM, :SNOWWARNING, :PRIMORDIALSEA,
|
|
:DESOLATELAND, :DELTASTREAM
|
|
ret.push(BattleRole::WEATHERSETTER)
|
|
when :GRASSYSURGE, :ELECTRICSURGE, :MISTYSURGE, :PSYCHICSURGE
|
|
ret.push(BattleRole::FIELDSETTER)
|
|
end
|
|
|
|
# Check for items indicative of particular roles
|
|
case pkmn.item_id
|
|
when :LIGHTCLAY
|
|
ret.push(BattleRole::SCREENER)
|
|
when :ASSAULTVEST
|
|
ret.push(BattleRole::TANK)
|
|
when :CHOICEBAND, :CHOICESPECS
|
|
ret.push(BattleRole::STALLBREAKER)
|
|
ret.push(BattleRole::SWEEPER) if pkmn.ev[PBStats::SPEED] == PokeBattle_Pokemon::EV_STAT_LIMIT
|
|
when :CHOICESCARF
|
|
ret.push(BattleRole::SWEEPER) if pkmn.ev[PBStats::SPEED] == PokeBattle_Pokemon::EV_STAT_LIMIT
|
|
when :TOXICORB, :FLAMEORB
|
|
ret.push(BattleRole::STATUSABSORBER)
|
|
when :TERRAINEXTENDER
|
|
ret.push(BattleRole::FIELDSETTER)
|
|
end
|
|
|
|
# Check for position in team, level relative to other levels in team
|
|
partyStarts = @battle.pbPartyStarts(side)
|
|
if partyStarts.include?(index + 1) || index == @battle.pbParty(side).length - 1
|
|
ret.push(BattleRole::ACE)
|
|
else
|
|
ret.push(BattleRole::LEAD) if partyStarts.include?(index)
|
|
idxTrainer = @battle.pbGetOwnerIndexFromPartyIndex(side, index)
|
|
maxLevel = @battle.pbMaxLevelInTeam(side, idxTrainer)
|
|
if pkmn.level >= maxLevel
|
|
ret.push(BattleRole::SECOND)
|
|
else
|
|
secondHighest = true
|
|
seenHigherLevel = false
|
|
@battle.eachInTeam(side, @battle.pbGetOwnerIndexFromPartyIndex(side, index)).each do |p|
|
|
next if p.level < pkmn.level
|
|
if seenHigherLevel
|
|
secondHighest = false
|
|
break
|
|
end
|
|
seenHigherLevel = true
|
|
end
|
|
# NOTE: There can be multiple "second"s if all their levels are equal
|
|
# and the highest in the team (and none are the ace).
|
|
ret.push(BattleRole::SECOND) if secondHighest
|
|
end
|
|
end
|
|
|
|
return ret
|
|
end
|
|
|
|
def check_role(side, idxBattler, *roles)
|
|
role_array = @roles[side][idxBattler]
|
|
roles.each do |r|
|
|
return true if role_array.include?(r)
|
|
end
|
|
return false
|
|
end
|
|
|
|
def check_battler_role(battler, *roles)
|
|
side = idxParty.idxOwnSide
|
|
idxParty = idxParty.pokemonIndex
|
|
return check_role(side, idxParty, *roles)
|
|
end
|
|
end
|