mirror of
https://github.com/infinitefusion/infinitefusion-e18.git
synced 2025-12-12 15:44:57 +00:00
Initial commit
This commit is contained in:
665
Data/Scripts/011_Battle/001_Battler/001_PokeBattle_Battler.rb
Normal file
665
Data/Scripts/011_Battle/001_Battler/001_PokeBattle_Battler.rb
Normal file
@@ -0,0 +1,665 @@
|
||||
class PokeBattle_Battler
|
||||
# Fundamental to this object
|
||||
attr_reader :battle
|
||||
attr_accessor :index
|
||||
# The Pokémon and its properties
|
||||
attr_reader :pokemon
|
||||
attr_accessor :pokemonIndex
|
||||
attr_accessor :species
|
||||
attr_accessor :type1
|
||||
attr_accessor :type2
|
||||
attr_accessor :ability
|
||||
attr_accessor :moves
|
||||
attr_accessor :gender
|
||||
attr_accessor :iv
|
||||
attr_accessor :attack
|
||||
attr_accessor :spatk
|
||||
attr_accessor :speed
|
||||
attr_accessor :stages
|
||||
attr_reader :totalhp
|
||||
attr_reader :fainted # Boolean to mark whether self has fainted properly
|
||||
attr_accessor :captured # Boolean to mark whether self was captured
|
||||
attr_reader :dummy
|
||||
attr_accessor :effects
|
||||
# Things the battler has done in battle
|
||||
attr_accessor :turnCount
|
||||
attr_accessor :participants
|
||||
attr_accessor :lastAttacker
|
||||
attr_accessor :lastFoeAttacker
|
||||
attr_accessor :lastHPLost
|
||||
attr_accessor :lastHPLostFromFoe
|
||||
attr_accessor :lastMoveUsed
|
||||
attr_accessor :lastMoveUsedType
|
||||
attr_accessor :lastRegularMoveUsed
|
||||
attr_accessor :lastRegularMoveTarget # For Instruct
|
||||
attr_accessor :lastRoundMoved
|
||||
attr_accessor :lastMoveFailed # For Stomping Tantrum
|
||||
attr_accessor :lastRoundMoveFailed # For Stomping Tantrum
|
||||
attr_accessor :movesUsed
|
||||
attr_accessor :currentMove # ID of multi-turn move currently being used
|
||||
attr_accessor :tookDamage # Boolean for whether self took damage this round
|
||||
attr_accessor :tookPhysicalHit
|
||||
attr_accessor :damageState
|
||||
attr_accessor :initialHP # Set at the start of each move's usage
|
||||
|
||||
#=============================================================================
|
||||
# Complex accessors
|
||||
#=============================================================================
|
||||
attr_reader :level
|
||||
|
||||
def level=(value)
|
||||
@level = value
|
||||
@pokemon.level = value if @pokemon
|
||||
end
|
||||
|
||||
attr_reader :form
|
||||
|
||||
def form=(value)
|
||||
@form = value
|
||||
@pokemon.form = value if @pokemon
|
||||
end
|
||||
|
||||
attr_reader :item
|
||||
|
||||
def item=(value)
|
||||
@item = value
|
||||
@pokemon.setItem(value) if @pokemon
|
||||
end
|
||||
|
||||
def defense
|
||||
return @spdef if @battle.field.effects[PBEffects::WonderRoom]>0
|
||||
return @defense
|
||||
end
|
||||
|
||||
attr_writer :defense
|
||||
|
||||
def spdef
|
||||
return @defense if @battle.field.effects[PBEffects::WonderRoom]>0
|
||||
return @spdef
|
||||
end
|
||||
|
||||
attr_writer :spdef
|
||||
|
||||
attr_reader :hp
|
||||
|
||||
def hp=(value)
|
||||
@hp = value.to_i
|
||||
@pokemon.hp = value.to_i if @pokemon
|
||||
end
|
||||
|
||||
def fainted?; return @hp<=0; end
|
||||
alias isFainted? fainted?
|
||||
|
||||
attr_reader :status
|
||||
|
||||
def status=(value)
|
||||
@effects[PBEffects::Truant] = false if @status==PBStatuses::SLEEP && value!=PBStatuses::SLEEP
|
||||
@effects[PBEffects::Toxic] = 0 if value!=PBStatuses::POISON
|
||||
@status = value
|
||||
@pokemon.status = value if @pokemon
|
||||
self.statusCount = 0 if value!=PBStatuses::POISON && value!=PBStatuses::SLEEP
|
||||
@battle.scene.pbRefreshOne(@index)
|
||||
end
|
||||
|
||||
attr_reader :statusCount
|
||||
|
||||
def statusCount=(value)
|
||||
@statusCount = value
|
||||
@pokemon.statusCount = value if @pokemon
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Properties from Pokémon
|
||||
#=============================================================================
|
||||
def happiness; return @pokemon ? @pokemon.happiness : 0; end
|
||||
def nature; return @pokemon ? @pokemon.nature : 0; end
|
||||
def pokerusStage; return @pokemon ? @pokemon.pokerusStage : 0; end
|
||||
|
||||
#=============================================================================
|
||||
# Mega Evolution, Primal Reversion, Shadow Pokémon
|
||||
#=============================================================================
|
||||
def hasMega?
|
||||
return false if @effects[PBEffects::Transform]
|
||||
return @pokemon && @pokemon.hasMegaForm?
|
||||
end
|
||||
|
||||
def mega?; return @pokemon && @pokemon.mega?; end
|
||||
alias isMega? mega?
|
||||
|
||||
def hasPrimal?
|
||||
return false if @effects[PBEffects::Transform]
|
||||
return @pokemon && @pokemon.hasPrimalForm?
|
||||
end
|
||||
|
||||
def primal?; return @pokemon && @pokemon.primal?; end
|
||||
alias isPrimal? primal?
|
||||
|
||||
def shadowPokemon?; return false; end
|
||||
alias isShadow? shadowPokemon?
|
||||
|
||||
def inHyperMode?; return false; end
|
||||
|
||||
#=============================================================================
|
||||
# Display-only properties
|
||||
#=============================================================================
|
||||
def name
|
||||
return @effects[PBEffects::Illusion].name if @effects[PBEffects::Illusion]
|
||||
return @name
|
||||
end
|
||||
|
||||
attr_writer :name
|
||||
|
||||
def displayPokemon
|
||||
return @effects[PBEffects::Illusion] if @effects[PBEffects::Illusion]
|
||||
return self.pokemon
|
||||
end
|
||||
|
||||
def displaySpecies
|
||||
return @effects[PBEffects::Illusion].species if @effects[PBEffects::Illusion]
|
||||
return self.species
|
||||
end
|
||||
|
||||
def displayGender
|
||||
return @effects[PBEffects::Illusion].gender if @effects[PBEffects::Illusion]
|
||||
return self.gender
|
||||
end
|
||||
|
||||
def displayForm
|
||||
return @effects[PBEffects::Illusion].form if @effects[PBEffects::Illusion]
|
||||
return self.form
|
||||
end
|
||||
|
||||
def shiny?
|
||||
return @effects[PBEffects::Illusion].shiny? if @effects[PBEffects::Illusion]
|
||||
return @pokemon && @pokemon.shiny?
|
||||
end
|
||||
alias isShiny? shiny?
|
||||
|
||||
def owned?
|
||||
return false if !@battle.wildBattle?
|
||||
return $Trainer.owned[displaySpecies]
|
||||
end
|
||||
alias owned owned?
|
||||
|
||||
def abilityName; return PBAbilities.getName(@ability); end
|
||||
def itemName; return PBItems.getName(@item); end
|
||||
|
||||
def pbThis(lowerCase=false)
|
||||
if opposes?
|
||||
if @battle.trainerBattle?
|
||||
return lowerCase ? _INTL("the opposing {1}",name) : _INTL("The opposing {1}",name)
|
||||
else
|
||||
return lowerCase ? _INTL("the wild {1}",name) : _INTL("The wild {1}",name)
|
||||
end
|
||||
elsif !pbOwnedByPlayer?
|
||||
return lowerCase ? _INTL("the ally {1}",name) : _INTL("The ally {1}",name)
|
||||
end
|
||||
return name
|
||||
end
|
||||
|
||||
def pbTeam(lowerCase=false)
|
||||
if opposes?
|
||||
return lowerCase ? _INTL("the opposing team") : _INTL("The opposing team")
|
||||
end
|
||||
return lowerCase ? _INTL("your team") : _INTL("Your team")
|
||||
end
|
||||
|
||||
def pbOpposingTeam(lowerCase=false)
|
||||
if opposes?
|
||||
return lowerCase ? _INTL("your team") : _INTL("Your team")
|
||||
end
|
||||
return lowerCase ? _INTL("the opposing team") : _INTL("The opposing team")
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Calculated properties
|
||||
#=============================================================================
|
||||
def pbSpeed
|
||||
return 1 if fainted?
|
||||
stageMul = [2,2,2,2,2,2, 2, 3,4,5,6,7,8]
|
||||
stageDiv = [8,7,6,5,4,3, 2, 2,2,2,2,2,2]
|
||||
stage = @stages[PBStats::SPEED] + 6
|
||||
speed = @speed*stageMul[stage]/stageDiv[stage]
|
||||
speedMult = 0x1000
|
||||
# Ability effects that alter calculated Speed
|
||||
if abilityActive?
|
||||
speedMult = BattleHandlers.triggerSpeedCalcAbility(@ability,self,speedMult)
|
||||
end
|
||||
# Item effects that alter calculated Speed
|
||||
if itemActive?
|
||||
speedMult = BattleHandlers.triggerSpeedCalcItem(@item,self,speedMult)
|
||||
end
|
||||
# Other effects
|
||||
speedMult *= 2 if pbOwnSide.effects[PBEffects::Tailwind]>0
|
||||
speedMult /= 2 if pbOwnSide.effects[PBEffects::Swamp]>0
|
||||
# Paralysis
|
||||
if status==PBStatuses::PARALYSIS && !hasActiveAbility?(:QUICKFEET)
|
||||
speedMult /= (NEWEST_BATTLE_MECHANICS) ? 2 : 4
|
||||
end
|
||||
# Badge multiplier
|
||||
if @battle.internalBattle && pbOwnedByPlayer? &&
|
||||
@battle.pbPlayer.numbadges>=NUM_BADGES_BOOST_SPEED
|
||||
speedMult *= 1.1
|
||||
end
|
||||
# Calculation
|
||||
return [(speed.to_f*speedMult/0x1000).round,1].max
|
||||
end
|
||||
|
||||
def pbWeight
|
||||
ret = (@pokemon) ? @pokemon.weight : 500
|
||||
ret += @effects[PBEffects::WeightChange]
|
||||
ret = 1 if ret<1
|
||||
if abilityActive? && !@battle.moldBreaker
|
||||
ret = BattleHandlers.triggerWeightCalcAbility(@ability,self,ret)
|
||||
end
|
||||
if itemActive?
|
||||
ret = BattleHandlers.triggerWeightCalcItem(@item,self,ret)
|
||||
end
|
||||
return [ret,1].max
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Queries about what the battler has
|
||||
#=============================================================================
|
||||
def plainStats
|
||||
ret = []
|
||||
ret[PBStats::ATTACK] = self.attack
|
||||
ret[PBStats::DEFENSE] = self.defense
|
||||
ret[PBStats::SPATK] = self.spatk
|
||||
ret[PBStats::SPDEF] = self.spdef
|
||||
ret[PBStats::SPEED] = self.speed
|
||||
return ret
|
||||
end
|
||||
|
||||
# Returns the active types of this Pokémon. The array should not include the
|
||||
# same type more than once, and should not include any invalid type numbers
|
||||
# (e.g. -1).
|
||||
def pbTypes(withType3=false)
|
||||
ret = [@type1]
|
||||
ret.push(@type2) if @type2!=@type1
|
||||
# Burn Up erases the Fire-type.
|
||||
if @effects[PBEffects::BurnUp]
|
||||
ret.reject! { |type| isConst?(type,PBTypes,:FIRE) }
|
||||
end
|
||||
# Roost erases the Flying-type. If there are no types left, adds the Normal-
|
||||
# type.
|
||||
if @effects[PBEffects::Roost]
|
||||
ret.reject! { |type| isConst?(type,PBTypes,:FLYING) }
|
||||
ret.push(getConst(PBTypes,:NORMAL) || 0) if ret.length==0
|
||||
end
|
||||
# Add the third type specially.
|
||||
if withType3 && @effects[PBEffects::Type3]>=0
|
||||
ret.push(@effects[PBEffects::Type3]) if !ret.include?(@effects[PBEffects::Type3])
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
def pbHasType?(type)
|
||||
type = getConst(PBTypes,type) if type.is_a?(Symbol) || type.is_a?(String)
|
||||
return false if !type || type<0
|
||||
activeTypes = pbTypes(true)
|
||||
return activeTypes.include?(type)
|
||||
end
|
||||
|
||||
def pbHasOtherType?(type)
|
||||
type = getConst(PBTypes,type) if type.is_a?(Symbol) || type.is_a?(String)
|
||||
return false if !type || type<0
|
||||
activeTypes = pbTypes(true)
|
||||
activeTypes.reject! { |t| t==type }
|
||||
return activeTypes.length>0
|
||||
end
|
||||
|
||||
# NOTE: Do not create any held item which affects whether a Pokémon's ability
|
||||
# is active. The ability Klutz affects whether a Pokémon's item is
|
||||
# active, and the code for the two combined would cause an infinite loop
|
||||
# (regardless of whether any Pokémon actualy has either the ability or
|
||||
# the item - the code existing is enough to cause the loop).
|
||||
def abilityActive?(ignoreFainted=false)
|
||||
return false if fainted? && !ignoreFainted
|
||||
return false if @effects[PBEffects::GastroAcid]
|
||||
return true
|
||||
end
|
||||
|
||||
def hasActiveAbility?(ability,ignoreFainted=false)
|
||||
return false if !abilityActive?(ignoreFainted)
|
||||
if ability.is_a?(Array)
|
||||
ability.each do |a|
|
||||
a = getID(PBAbilities,a)
|
||||
return true if a!=0 && a==@ability
|
||||
end
|
||||
return false
|
||||
end
|
||||
ability = getID(PBAbilities,ability)
|
||||
return ability!=0 && ability==@ability
|
||||
end
|
||||
alias hasWorkingAbility hasActiveAbility?
|
||||
|
||||
def nonNegatableAbility?
|
||||
abilityBlacklist = [
|
||||
# Form-changing abilities
|
||||
:BATTLEBOND,
|
||||
:DISGUISE,
|
||||
# :FLOWERGIFT, # This can be negated
|
||||
# :FORECAST, # This can be negated
|
||||
:MULTITYPE,
|
||||
:POWERCONSTRUCT,
|
||||
:SCHOOLING,
|
||||
:SHIELDSDOWN,
|
||||
:STANCECHANGE,
|
||||
:ZENMODE,
|
||||
# Abilities intended to be inherent properties of a certain species
|
||||
:COMATOSE,
|
||||
:RKSSYSTEM
|
||||
]
|
||||
failed = false
|
||||
abilityBlacklist.each do |abil|
|
||||
return true if isConst?(@ability,PBAbilities,abil)
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
def itemActive?(ignoreFainted=false)
|
||||
return false if fainted? && !ignoreFainted
|
||||
return false if @effects[PBEffects::Embargo]>0
|
||||
return false if @battle.field.effects[PBEffects::MagicRoom]>0
|
||||
return false if hasActiveAbility?(:KLUTZ,ignoreFainted)
|
||||
return true
|
||||
end
|
||||
|
||||
def hasActiveItem?(item,ignoreFainted=false)
|
||||
return false if !itemActive?(ignoreFainted)
|
||||
if item.is_a?(Array)
|
||||
item.each do |i|
|
||||
i = getID(PBItems,i)
|
||||
return true if i!=0 && i==@item
|
||||
end
|
||||
return false
|
||||
end
|
||||
item = getID(PBItems,item)
|
||||
return item!=0 && item==@item
|
||||
end
|
||||
alias hasWorkingItem hasActiveItem?
|
||||
|
||||
# Returns whether the specified item will be unlosable for this Pokémon.
|
||||
def unlosableItem?(item)
|
||||
return false if item<=0
|
||||
return true if pbIsMail?(item)
|
||||
return false if @effects[PBEffects::Transform]
|
||||
# Items that change a Pokémon's form
|
||||
return true if @pokemon && @pokemon.getMegaForm(true)>0 # Mega Stone
|
||||
return pbIsUnlosableItem?(item,@species,@ability)
|
||||
end
|
||||
|
||||
def eachMove
|
||||
@moves.each { |m| yield m if m && m.id!=0 }
|
||||
end
|
||||
|
||||
def eachMoveWithIndex
|
||||
@moves.each_with_index { |m,i| yield m,i if m && m.id!=0 }
|
||||
end
|
||||
|
||||
def pbHasMove?(id)
|
||||
id = getID(PBMoves,id)
|
||||
return false if !id || id<=0
|
||||
eachMove { |m| return true if m.id==id }
|
||||
return false
|
||||
end
|
||||
|
||||
def pbHasMoveType?(type)
|
||||
type = getConst(PBTypes,type)
|
||||
return false if !type || type<0
|
||||
eachMove { |m| return true if m.type==type }
|
||||
return false
|
||||
end
|
||||
|
||||
def pbHasMoveFunction?(*arg)
|
||||
return false if !code
|
||||
eachMove do |m|
|
||||
arg.each { |code| return true if m.function==code }
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
def hasMoldBreaker?
|
||||
return hasActiveAbility?([:MOLDBREAKER,:TERAVOLT,:TURBOBLAZE])
|
||||
end
|
||||
|
||||
def canChangeType?
|
||||
return false if isConst?(@ability,PBAbilities,:MULTITYPE) ||
|
||||
isConst?(@ability,PBAbilities,:RKSSYSTEM)
|
||||
return true
|
||||
end
|
||||
|
||||
def airborne?
|
||||
return false if hasActiveItem?(:IRONBALL)
|
||||
return false if @effects[PBEffects::Ingrain]
|
||||
return false if @effects[PBEffects::SmackDown]
|
||||
return false if @battle.field.effects[PBEffects::Gravity]>0
|
||||
return true if pbHasType?(:FLYING)
|
||||
return true if hasActiveAbility?(:LEVITATE) && !@battle.moldBreaker
|
||||
return true if hasActiveItem?(:AIRBALLOON)
|
||||
return true if @effects[PBEffects::MagnetRise]>0
|
||||
return true if @effects[PBEffects::Telekinesis]>0
|
||||
return false
|
||||
end
|
||||
|
||||
def affectedByTerrain?
|
||||
return false if airborne?
|
||||
return false if semiInvulnerable?
|
||||
return true
|
||||
end
|
||||
|
||||
def takesIndirectDamage?(showMsg=false)
|
||||
return false if fainted?
|
||||
if hasActiveAbility?(:MAGICGUARD)
|
||||
if showMsg
|
||||
@battle.pbShowAbilitySplash(self)
|
||||
if PokeBattle_SceneConstants::USE_ABILITY_SPLASH
|
||||
@battle.pbDisplay(_INTL("{1} is unaffected!",pbThis))
|
||||
else
|
||||
@battle.pbDisplay(_INTL("{1} is unaffected because of its {2}!",pbThis,abilityName))
|
||||
end
|
||||
@battle.pbHideAbilitySplash(self)
|
||||
end
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
def takesSandstormDamage?
|
||||
return false if !takesIndirectDamage?
|
||||
return false if pbHasType?(:GROUND) || pbHasType?(:ROCK) || pbHasType?(:STEEL)
|
||||
return false if inTwoTurnAttack?("0CA","0CB") # Dig, Dive
|
||||
return false if hasActiveAbility?([:OVERCOAT,:SANDFORCE,:SANDRUSH,:SANDVEIL])
|
||||
return false if hasActiveItem?(:SAFETYGOGGLES)
|
||||
return true
|
||||
end
|
||||
|
||||
def takesHailDamage?
|
||||
return false if !takesIndirectDamage?
|
||||
return false if pbHasType?(:ICE)
|
||||
return false if inTwoTurnAttack?("0CA","0CB") # Dig, Dive
|
||||
return false if hasActiveAbility?([:OVERCOAT,:ICEBODY,:SNOWCLOAK])
|
||||
return false if hasActiveItem?(:SAFETYGOGGLES)
|
||||
return true
|
||||
end
|
||||
|
||||
def takesShadowSkyDamage?
|
||||
return false if fainted?
|
||||
return false if shadowPokemon?
|
||||
return true
|
||||
end
|
||||
|
||||
def affectedByPowder?(showMsg=false)
|
||||
return false if fainted?
|
||||
return true if !NEWEST_BATTLE_MECHANICS
|
||||
if pbHasType?(:GRASS)
|
||||
@battle.pbDisplay(_INTL("{1} is unaffected!",pbThis)) if showMsg
|
||||
return false
|
||||
end
|
||||
if hasActiveAbility?(:OVERCOAT) && !@battle.moldBreaker
|
||||
if showMsg
|
||||
@battle.pbShowAbilitySplash(self)
|
||||
if PokeBattle_SceneConstants::USE_ABILITY_SPLASH
|
||||
@battle.pbDisplay(_INTL("{1} is unaffected!",pbThis))
|
||||
else
|
||||
@battle.pbDisplay(_INTL("{1} is unaffected because of its {2}!",pbThis,abilityName))
|
||||
end
|
||||
@battle.pbHideAbilitySplash(self)
|
||||
end
|
||||
return false
|
||||
end
|
||||
if hasActiveItem?(:SAFETYGOGGLES)
|
||||
if showMsg
|
||||
@battle.pbDisplay(_INTL("{1} is unaffected because of its {2}!",pbThis,itemName))
|
||||
end
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
def canHeal?
|
||||
return false if fainted? || @hp>=@totalhp
|
||||
return false if @effects[PBEffects::HealBlock]>0
|
||||
return true
|
||||
end
|
||||
|
||||
def affectedByContactEffect?(showMsg=false)
|
||||
return false if fainted?
|
||||
if hasActiveItem?(:PROTECTIVEPADS)
|
||||
@battle.pbDisplay(_INTL("{1} protected itself with the {2}!",pbThis,itemName)) if showMsg
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
def movedThisRound?
|
||||
return @lastRoundMoved && @lastRoundMoved==@battle.turnCount
|
||||
end
|
||||
|
||||
def usingMultiTurnAttack?
|
||||
return true if @effects[PBEffects::TwoTurnAttack]>0
|
||||
return true if @effects[PBEffects::HyperBeam]>0
|
||||
return true if @effects[PBEffects::Rollout]>0
|
||||
return true if @effects[PBEffects::Outrage]>0
|
||||
return true if @effects[PBEffects::Uproar]>0
|
||||
return true if @effects[PBEffects::Bide]>0
|
||||
return false
|
||||
end
|
||||
|
||||
def inTwoTurnAttack?(*arg)
|
||||
return false if @effects[PBEffects::TwoTurnAttack]==0
|
||||
ttaFunction = pbGetMoveData(@effects[PBEffects::TwoTurnAttack],MOVE_FUNCTION_CODE)
|
||||
arg.each { |a| return true if a==ttaFunction }
|
||||
return false
|
||||
end
|
||||
|
||||
def semiInvulnerable?
|
||||
return inTwoTurnAttack?("0C9","0CA","0CB","0CC","0CD","0CE","14D")
|
||||
end
|
||||
|
||||
def pbEncoredMoveIndex
|
||||
return -1 if @effects[PBEffects::Encore]==0 || @effects[PBEffects::EncoreMove]==0
|
||||
ret = -1
|
||||
eachMoveWithIndex do |m,i|
|
||||
next if m.id!=@effects[PBEffects::EncoreMove]
|
||||
ret = i
|
||||
break
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
def initialItem
|
||||
return @battle.initialItems[@index&1][@pokemonIndex]
|
||||
end
|
||||
|
||||
def setInitialItem(newItem)
|
||||
@battle.initialItems[@index&1][@pokemonIndex] = newItem
|
||||
end
|
||||
|
||||
def recycleItem
|
||||
return @battle.recycleItems[@index&1][@pokemonIndex]
|
||||
end
|
||||
|
||||
def setRecycleItem(newItem)
|
||||
@battle.recycleItems[@index&1][@pokemonIndex] = newItem
|
||||
end
|
||||
|
||||
def belched?
|
||||
return @battle.belch[@index&1][@pokemonIndex]
|
||||
end
|
||||
|
||||
def setBelched
|
||||
@battle.belch[@index&1][@pokemonIndex] = true
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Methods relating to this battler's position on the battlefield
|
||||
#=============================================================================
|
||||
# Returns whether the given position belongs to the opposing Pokémon's side.
|
||||
def opposes?(i=0)
|
||||
i = i.index if i.respond_to?("index")
|
||||
return (@index&1)!=(i&1)
|
||||
end
|
||||
|
||||
# Returns whether the given position/battler is near to self.
|
||||
def near?(i)
|
||||
i = i.index if i.respond_to?("index")
|
||||
return @battle.nearBattlers?(@index,i)
|
||||
end
|
||||
|
||||
# Returns whether self is owned by the player.
|
||||
def pbOwnedByPlayer?
|
||||
return @battle.pbOwnedByPlayer?(@index)
|
||||
end
|
||||
|
||||
# Returns 0 if self is on the player's side, or 1 if self is on the opposing
|
||||
# side.
|
||||
def idxOwnSide
|
||||
return @index&1
|
||||
end
|
||||
|
||||
# Returns 1 if self is on the player's side, or 0 if self is on the opposing
|
||||
# side.
|
||||
def idxOpposingSide
|
||||
return (@index&1)^1
|
||||
end
|
||||
|
||||
# Returns the data structure for this battler's side.
|
||||
def pbOwnSide
|
||||
return @battle.sides[idxOwnSide]
|
||||
end
|
||||
|
||||
# Returns the data structure for the opposing Pokémon's side.
|
||||
def pbOpposingSide
|
||||
return @battle.sides[idxOpposingSide]
|
||||
end
|
||||
|
||||
# Yields each unfainted ally Pokémon.
|
||||
def eachAlly
|
||||
@battle.battlers.each do |b|
|
||||
yield b if b && !b.fainted? && !b.opposes?(@index) && b.index!=@index
|
||||
end
|
||||
end
|
||||
|
||||
# Yields each unfainted opposing Pokémon.
|
||||
def eachOpposing
|
||||
@battle.battlers.each { |b| yield b if b && !b.fainted? && b.opposes?(@index) }
|
||||
end
|
||||
|
||||
# Returns the battler that is most directly opposite to self. unfaintedOnly is
|
||||
# whether it should prefer to return a non-fainted battler.
|
||||
def pbDirectOpposing(unfaintedOnly=false)
|
||||
@battle.pbGetOpposingIndicesInOrder(@index).each do |i|
|
||||
next if !@battle.battlers[i]
|
||||
break if unfaintedOnly && @battle.battlers[i].fainted?
|
||||
return @battle.battlers[i]
|
||||
end
|
||||
# Wanted an unfainted battler but couldn't find one; make do with a fainted
|
||||
# battler
|
||||
@battle.pbGetOpposingIndicesInOrder(@index).each do |i|
|
||||
return @battle.battlers[i] if @battle.battlers[i]
|
||||
end
|
||||
return @battle.battlers[(@index^1)]
|
||||
end
|
||||
end
|
||||
326
Data/Scripts/011_Battle/001_Battler/002_Battler_Initialize.rb
Normal file
326
Data/Scripts/011_Battle/001_Battler/002_Battler_Initialize.rb
Normal file
@@ -0,0 +1,326 @@
|
||||
class PokeBattle_Battler
|
||||
#=============================================================================
|
||||
# Creating a battler
|
||||
#=============================================================================
|
||||
def initialize(btl,idxBattler)
|
||||
@battle = btl
|
||||
@index = idxBattler
|
||||
@captured = false
|
||||
@dummy = false
|
||||
@stages = []
|
||||
@effects = []
|
||||
@damageState = PokeBattle_DamageState.new
|
||||
pbInitBlank
|
||||
pbInitEffects(false)
|
||||
end
|
||||
|
||||
def pbInitBlank
|
||||
@name = ""
|
||||
@species = 0
|
||||
@form = 0
|
||||
@level = 0
|
||||
@hp = @totalhp = 0
|
||||
@type1 = @type2 = 0
|
||||
@ability = 0
|
||||
@item = 0
|
||||
@gender = 0
|
||||
@attack = @defense = @spatk = @spdef = @speed = 0
|
||||
@status = PBStatuses::NONE
|
||||
@statusCount = 0
|
||||
@pokemon = nil
|
||||
@pokemonIndex = -1
|
||||
@participants = []
|
||||
@moves = []
|
||||
@iv = [0,0,0,0,0,0]
|
||||
end
|
||||
|
||||
# Used by Future Sight only, when Future Sight's user is no longer in battle.
|
||||
def pbInitDummyPokemon(pkmn,idxParty)
|
||||
raise _INTL("An egg can't be an active Pokémon.") if pkmn.egg?
|
||||
@name = pkmn.name
|
||||
@species = pkmn.species
|
||||
@form = pkmn.form
|
||||
@level = pkmn.level
|
||||
@hp = pkmn.hp
|
||||
@totalhp = pkmn.totalhp
|
||||
@type1 = pkmn.type1
|
||||
@type2 = pkmn.type2
|
||||
# ability and item intentionally not copied across here
|
||||
@gender = pkmn.gender
|
||||
@attack = pkmn.attack
|
||||
@defense = pkmn.defense
|
||||
@spatk = pkmn.spatk
|
||||
@spdef = pkmn.spdef
|
||||
@speed = pkmn.speed
|
||||
@status = pkmn.status
|
||||
@statusCount = pkmn.statusCount
|
||||
@pokemon = pkmn
|
||||
@pokemonIndex = idxParty
|
||||
@participants = []
|
||||
# moves intentionally not copied across here
|
||||
@iv = pkmn.iv.clone
|
||||
@dummy = true
|
||||
end
|
||||
|
||||
def pbInitialize(pkmn,idxParty,batonPass=false)
|
||||
pbInitPokemon(pkmn,idxParty)
|
||||
pbInitEffects(batonPass)
|
||||
end
|
||||
|
||||
def pbInitPokemon(pkmn,idxParty)
|
||||
raise _INTL("An egg can't be an active Pokémon.") if pkmn.egg?
|
||||
@name = pkmn.name
|
||||
@species = pkmn.species
|
||||
@form = pkmn.form
|
||||
@level = pkmn.level
|
||||
@hp = pkmn.hp
|
||||
@totalhp = pkmn.totalhp
|
||||
@type1 = pkmn.type1
|
||||
@type2 = pkmn.type2
|
||||
@ability = pkmn.ability
|
||||
@item = pkmn.item
|
||||
@gender = pkmn.gender
|
||||
@attack = pkmn.attack
|
||||
@defense = pkmn.defense
|
||||
@spatk = pkmn.spatk
|
||||
@spdef = pkmn.spdef
|
||||
@speed = pkmn.speed
|
||||
@status = pkmn.status
|
||||
@statusCount = pkmn.statusCount
|
||||
@pokemon = pkmn
|
||||
@pokemonIndex = idxParty
|
||||
@participants = [] # Participants earn Exp. if this battler is defeated
|
||||
@moves = []
|
||||
pkmn.moves.each_with_index do |m,i|
|
||||
@moves[i] = PokeBattle_Move.pbFromPBMove(@battle,m)
|
||||
end
|
||||
@iv = pkmn.iv.clone
|
||||
end
|
||||
|
||||
def pbInitEffects(batonPass)
|
||||
if batonPass
|
||||
# These effects are passed on if Baton Pass is used, but they need to be
|
||||
# reapplied
|
||||
@effects[PBEffects::LaserFocus] = (@effects[PBEffects::LaserFocus]>0) ? 2 : 0
|
||||
@effects[PBEffects::LockOn] = (@effects[PBEffects::LockOn]>0) ? 2 : 0
|
||||
if @effects[PBEffects::PowerTrick]
|
||||
@attack,@defense = @defense,@attack
|
||||
end
|
||||
# These effects are passed on if Baton Pass is used, but they need to be
|
||||
# cancelled in certain circumstances anyway
|
||||
@effects[PBEffects::Telekinesis] = 0 if isConst?(@species,PBSpecies,:GENGAR) && mega?
|
||||
@effects[PBEffects::GastroAcid] = false if nonNegatableAbility?
|
||||
else
|
||||
# These effects are passed on if Baton Pass is used
|
||||
@stages[PBStats::ATTACK] = 0
|
||||
@stages[PBStats::DEFENSE] = 0
|
||||
@stages[PBStats::SPEED] = 0
|
||||
@stages[PBStats::SPATK] = 0
|
||||
@stages[PBStats::SPDEF] = 0
|
||||
@stages[PBStats::EVASION] = 0
|
||||
@stages[PBStats::ACCURACY] = 0
|
||||
@effects[PBEffects::AquaRing] = false
|
||||
@effects[PBEffects::Confusion] = 0
|
||||
@effects[PBEffects::Curse] = false
|
||||
@effects[PBEffects::Embargo] = 0
|
||||
@effects[PBEffects::FocusEnergy] = 0
|
||||
@effects[PBEffects::GastroAcid] = false
|
||||
@effects[PBEffects::HealBlock] = 0
|
||||
@effects[PBEffects::Ingrain] = false
|
||||
@effects[PBEffects::LaserFocus] = 0
|
||||
@effects[PBEffects::LeechSeed] = -1
|
||||
@effects[PBEffects::LockOn] = 0
|
||||
@effects[PBEffects::LockOnPos] = -1
|
||||
@effects[PBEffects::MagnetRise] = 0
|
||||
@effects[PBEffects::PerishSong] = 0
|
||||
@effects[PBEffects::PerishSongUser] = -1
|
||||
@effects[PBEffects::PowerTrick] = false
|
||||
@effects[PBEffects::Substitute] = 0
|
||||
@effects[PBEffects::Telekinesis] = 0
|
||||
end
|
||||
@damageState.reset
|
||||
@fainted = (@hp==0)
|
||||
@initialHP = 0
|
||||
@lastAttacker = []
|
||||
@lastFoeAttacker = []
|
||||
@lastHPLost = 0
|
||||
@lastHPLostFromFoe = 0
|
||||
@tookDamage = false
|
||||
@tookPhysicalHit = false
|
||||
@lastMoveUsed = -1
|
||||
@lastMoveUsedType = -1
|
||||
@lastRegularMoveUsed = -1
|
||||
@lastRegularMoveTarget = -1
|
||||
@lastRoundMoved = -1
|
||||
@lastMoveFailed = false
|
||||
@lastRoundMoveFailed = false
|
||||
@movesUsed = []
|
||||
@turnCount = 0
|
||||
@effects[PBEffects::Attract] = -1
|
||||
@battle.eachBattler do |b| # Other battlers no longer attracted to self
|
||||
b.effects[PBEffects::Attract] = -1 if b.effects[PBEffects::Attract]==@index
|
||||
end
|
||||
@effects[PBEffects::BanefulBunker] = false
|
||||
@effects[PBEffects::BeakBlast] = false
|
||||
@effects[PBEffects::Bide] = 0
|
||||
@effects[PBEffects::BideDamage] = 0
|
||||
@effects[PBEffects::BideTarget] = -1
|
||||
@effects[PBEffects::BurnUp] = false
|
||||
@effects[PBEffects::Charge] = 0
|
||||
@effects[PBEffects::ChoiceBand] = -1
|
||||
@effects[PBEffects::Counter] = -1
|
||||
@effects[PBEffects::CounterTarget] = -1
|
||||
@effects[PBEffects::Dancer] = false
|
||||
@effects[PBEffects::DefenseCurl] = false
|
||||
@effects[PBEffects::DestinyBond] = false
|
||||
@effects[PBEffects::DestinyBondPrevious] = false
|
||||
@effects[PBEffects::DestinyBondTarget] = -1
|
||||
@effects[PBEffects::Disable] = 0
|
||||
@effects[PBEffects::DisableMove] = 0
|
||||
@effects[PBEffects::Electrify] = false
|
||||
@effects[PBEffects::Encore] = 0
|
||||
@effects[PBEffects::EncoreMove] = 0
|
||||
@effects[PBEffects::Endure] = false
|
||||
@effects[PBEffects::FirstPledge] = 0
|
||||
@effects[PBEffects::FlashFire] = false
|
||||
@effects[PBEffects::Flinch] = false
|
||||
@effects[PBEffects::FocusPunch] = false
|
||||
@effects[PBEffects::FollowMe] = 0
|
||||
@effects[PBEffects::Foresight] = false
|
||||
@effects[PBEffects::FuryCutter] = 0
|
||||
@effects[PBEffects::GemConsumed] = 0
|
||||
@effects[PBEffects::Grudge] = false
|
||||
@effects[PBEffects::HelpingHand] = false
|
||||
@effects[PBEffects::HyperBeam] = 0
|
||||
@effects[PBEffects::Illusion] = nil
|
||||
if hasActiveAbility?(:ILLUSION)
|
||||
idxLastParty = @battle.pbLastInTeam(@index)
|
||||
if idxLastParty!=@pokemonIndex
|
||||
@effects[PBEffects::Illusion] = @battle.pbParty(@index)[idxLastParty]
|
||||
end
|
||||
end
|
||||
@effects[PBEffects::Imprison] = false
|
||||
@effects[PBEffects::Instruct] = false
|
||||
@effects[PBEffects::Instructed] = false
|
||||
@effects[PBEffects::KingsShield] = false
|
||||
@battle.eachBattler do |b| # Other battlers lose their lock-on against self
|
||||
next if b.effects[PBEffects::LockOn]==0
|
||||
next if b.effects[PBEffects::LockOnPos]!=@index
|
||||
b.effects[PBEffects::LockOn] = 0
|
||||
b.effects[PBEffects::LockOnPos] = -1
|
||||
end
|
||||
@effects[PBEffects::MagicBounce] = false
|
||||
@effects[PBEffects::MagicCoat] = false
|
||||
@effects[PBEffects::MeanLook] = -1
|
||||
@battle.eachBattler do |b| # Other battlers no longer blocked by self
|
||||
b.effects[PBEffects::MeanLook] = -1 if b.effects[PBEffects::MeanLook]==@index
|
||||
end
|
||||
@effects[PBEffects::MeFirst] = false
|
||||
@effects[PBEffects::Metronome] = 0
|
||||
@effects[PBEffects::MicleBerry] = false
|
||||
@effects[PBEffects::Minimize] = false
|
||||
@effects[PBEffects::MiracleEye] = false
|
||||
@effects[PBEffects::MirrorCoat] = -1
|
||||
@effects[PBEffects::MirrorCoatTarget] = -1
|
||||
@effects[PBEffects::MoveNext] = false
|
||||
@effects[PBEffects::MudSport] = false
|
||||
@effects[PBEffects::Nightmare] = false
|
||||
@effects[PBEffects::Outrage] = 0
|
||||
@effects[PBEffects::ParentalBond] = 0
|
||||
@effects[PBEffects::PickupItem] = 0
|
||||
@effects[PBEffects::PickupUse] = 0
|
||||
@effects[PBEffects::Pinch] = false
|
||||
@effects[PBEffects::Powder] = false
|
||||
@effects[PBEffects::Prankster] = false
|
||||
@effects[PBEffects::PriorityAbility] = false
|
||||
@effects[PBEffects::PriorityItem] = false
|
||||
@effects[PBEffects::Protect] = false
|
||||
@effects[PBEffects::ProtectRate] = 1
|
||||
@effects[PBEffects::Pursuit] = false
|
||||
@effects[PBEffects::Quash] = 0
|
||||
@effects[PBEffects::Rage] = false
|
||||
@effects[PBEffects::RagePowder] = false
|
||||
@effects[PBEffects::Revenge] = 0
|
||||
@effects[PBEffects::Rollout] = 0
|
||||
@effects[PBEffects::Roost] = false
|
||||
@effects[PBEffects::SkyDrop] = -1
|
||||
@battle.eachBattler do |b| # Other battlers no longer Sky Dropped by self
|
||||
b.effects[PBEffects::SkyDrop] = -1 if b.effects[PBEffects::SkyDrop]==@index
|
||||
end
|
||||
@effects[PBEffects::SlowStart] = 0
|
||||
@effects[PBEffects::SmackDown] = false
|
||||
@effects[PBEffects::Snatch] = 0
|
||||
@effects[PBEffects::SpikyShield] = false
|
||||
@effects[PBEffects::Spotlight] = 0
|
||||
@effects[PBEffects::Stockpile] = 0
|
||||
@effects[PBEffects::StockpileDef] = 0
|
||||
@effects[PBEffects::StockpileSpDef] = 0
|
||||
@effects[PBEffects::Taunt] = 0
|
||||
@effects[PBEffects::ThroatChop] = 0
|
||||
@effects[PBEffects::Torment] = false
|
||||
@effects[PBEffects::Toxic] = 0
|
||||
@effects[PBEffects::Transform] = false
|
||||
@effects[PBEffects::TransformSpecies] = 0
|
||||
@effects[PBEffects::Trapping] = 0
|
||||
@effects[PBEffects::TrappingMove] = 0
|
||||
@effects[PBEffects::TrappingUser] = -1
|
||||
@battle.eachBattler do |b| # Other battlers no longer trapped by self
|
||||
next if b.effects[PBEffects::TrappingUser]!=@index
|
||||
b.effects[PBEffects::Trapping] = 0
|
||||
b.effects[PBEffects::TrappingUser] = -1
|
||||
end
|
||||
@effects[PBEffects::Truant] = false
|
||||
@effects[PBEffects::TwoTurnAttack] = 0
|
||||
@effects[PBEffects::Type3] = -1
|
||||
@effects[PBEffects::Unburden] = false
|
||||
@effects[PBEffects::Uproar] = 0
|
||||
@effects[PBEffects::WaterSport] = false
|
||||
@effects[PBEffects::WeightChange] = 0
|
||||
@effects[PBEffects::Yawn] = 0
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Refreshing a battler's properties
|
||||
#=============================================================================
|
||||
def pbUpdate(fullChange=false)
|
||||
return if !@pokemon
|
||||
@pokemon.calcStats
|
||||
@level = @pokemon.level
|
||||
@hp = @pokemon.hp
|
||||
@totalhp = @pokemon.totalhp
|
||||
if !@effects[PBEffects::Transform]
|
||||
@attack = @pokemon.attack
|
||||
@defense = @pokemon.defense
|
||||
@spatk = @pokemon.spatk
|
||||
@spdef = @pokemon.spdef
|
||||
@speed = @pokemon.speed
|
||||
if fullChange
|
||||
@type1 = @pokemon.type1
|
||||
@type2 = @pokemon.type2
|
||||
@ability = @pokemon.ability
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Used only to erase the battler of a Shadow Pokémon that has been snagged.
|
||||
def pbReset
|
||||
@pokemon = nil
|
||||
@pokemonIndex = -1
|
||||
@hp = 0
|
||||
pbInitEffects(false)
|
||||
@participants = []
|
||||
# Reset status
|
||||
@status = PBStatuses::NONE
|
||||
@statusCount = 0
|
||||
# Reset choice
|
||||
@battle.pbClearChoice(@index)
|
||||
end
|
||||
|
||||
# Update which Pokémon will gain Exp if this battler is defeated.
|
||||
def pbUpdateParticipants
|
||||
return if fainted? || !@battle.opposes?(@index)
|
||||
eachOpposing do |b|
|
||||
@participants.push(b.pokemonIndex) if !@participants.include?(b.pokemonIndex)
|
||||
end
|
||||
end
|
||||
end
|
||||
301
Data/Scripts/011_Battle/001_Battler/003_Battler_ChangeSelf.rb
Normal file
301
Data/Scripts/011_Battle/001_Battler/003_Battler_ChangeSelf.rb
Normal file
@@ -0,0 +1,301 @@
|
||||
class PokeBattle_Battler
|
||||
#=============================================================================
|
||||
# Change HP
|
||||
#=============================================================================
|
||||
def pbReduceHP(amt,anim=true,registerDamage=true,anyAnim=true)
|
||||
amt = amt.round
|
||||
amt = @hp if amt>@hp
|
||||
amt = 1 if amt<1 && !fainted?
|
||||
oldHP = @hp
|
||||
self.hp -= amt
|
||||
PBDebug.log("[HP change] #{pbThis} lost #{amt} HP (#{oldHP}=>#{@hp})")
|
||||
raise _INTL("HP less than 0") if @hp<0
|
||||
raise _INTL("HP greater than total HP") if @hp>@totalhp
|
||||
@battle.scene.pbHPChanged(self,oldHP,anim) if anyAnim && amt>0
|
||||
@tookDamage = true if amt>0 && registerDamage
|
||||
return amt
|
||||
end
|
||||
|
||||
def pbRecoverHP(amt,anim=true,anyAnim=true)
|
||||
amt = amt.round
|
||||
amt = @totalhp-@hp if amt>@totalhp-@hp
|
||||
amt = 1 if amt<1 && @hp<@totalhp
|
||||
oldHP = @hp
|
||||
self.hp += amt
|
||||
PBDebug.log("[HP change] #{pbThis} gained #{amt} HP (#{oldHP}=>#{@hp})")
|
||||
raise _INTL("HP less than 0") if @hp<0
|
||||
raise _INTL("HP greater than total HP") if @hp>@totalhp
|
||||
@battle.scene.pbHPChanged(self,oldHP,anim) if anyAnim && amt>0
|
||||
return amt
|
||||
end
|
||||
|
||||
def pbRecoverHPFromDrain(amt,target,msg=nil)
|
||||
if target.hasActiveAbility?(:LIQUIDOOZE)
|
||||
oldHP = @hp
|
||||
@battle.pbShowAbilitySplash(target)
|
||||
pbReduceHP(amt)
|
||||
@battle.pbDisplay(_INTL("{1} sucked up the liquid ooze!",pbThis))
|
||||
@battle.pbHideAbilitySplash(target)
|
||||
pbItemHPHealCheck
|
||||
else
|
||||
msg = _INTL("{1} had its energy drained!",target.pbThis) if !msg || msg==""
|
||||
@battle.pbDisplay(msg)
|
||||
if canHeal?
|
||||
amt = (amt*1.3).floor if hasActiveItem?(:BIGROOT)
|
||||
pbRecoverHP(amt)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def pbFaint(showMessage=true)
|
||||
if !fainted?
|
||||
PBDebug.log("!!!***Can't faint with HP greater than 0")
|
||||
return
|
||||
end
|
||||
return if @fainted # Has already fainted properly
|
||||
@battle.pbDisplayBrief(_INTL("{1} fainted!",pbThis)) if showMessage
|
||||
PBDebug.log("[Pokémon fainted] #{pbThis} (#{@index})") if !showMessage
|
||||
@battle.scene.pbFaintBattler(self)
|
||||
pbInitEffects(false)
|
||||
# Reset status
|
||||
self.status = PBStatuses::NONE
|
||||
self.statusCount = 0
|
||||
# Lose happiness
|
||||
if @pokemon && @battle.internalBattle
|
||||
badLoss = false
|
||||
@battle.eachOtherSideBattler(@index) do |b|
|
||||
badLoss = true if b.level>=self.level+30
|
||||
end
|
||||
@pokemon.changeHappiness((badLoss) ? "faintbad" : "faint")
|
||||
end
|
||||
# Reset form
|
||||
@battle.peer.pbOnLeavingBattle(@battle,@pokemon,@battle.usedInBattle[idxOwnSide][@index/2])
|
||||
@pokemon.makeUnmega if mega?
|
||||
@pokemon.makeUnprimal if primal?
|
||||
# Do other things
|
||||
@battle.pbClearChoice(@index) # Reset choice
|
||||
pbOwnSide.effects[PBEffects::LastRoundFainted] = @battle.turnCount
|
||||
# Check other battlers' abilities that trigger upon a battler fainting
|
||||
pbAbilitiesOnFainting
|
||||
# Check for end of primordial weather
|
||||
@battle.pbEndPrimordialWeather
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Move PP
|
||||
#=============================================================================
|
||||
def pbSetPP(move,pp)
|
||||
move.pp = pp
|
||||
# No need to care about @effects[PBEffects::Mimic], since Mimic can't copy
|
||||
# Mimic
|
||||
if move.realMove && move.id==move.realMove.id && !@effects[PBEffects::Transform]
|
||||
move.realMove.pp = pp
|
||||
end
|
||||
end
|
||||
|
||||
def pbReducePP(move)
|
||||
return true if usingMultiTurnAttack?
|
||||
return true if move.pp<0 # Don't reduce PP for special calls of moves
|
||||
return true if move.totalpp<=0 # Infinite PP, can always be used
|
||||
return false if move.pp==0 # Ran out of PP, couldn't reduce
|
||||
pbSetPP(move,move.pp-1) if move.pp>0
|
||||
return true
|
||||
end
|
||||
|
||||
def pbReducePPOther(move)
|
||||
pbSetPP(move,move.pp-1) if move.pp>0
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Change type
|
||||
#=============================================================================
|
||||
def pbChangeTypes(newType)
|
||||
if newType.is_a?(PokeBattle_Battler)
|
||||
newTypes = newType.pbTypes
|
||||
newTypes.push(getConst(PBTypes,:NORMAL) || 0) if newTypes.length==0
|
||||
newType3 = newType.effects[PBEffects::Type3]
|
||||
newType3 = -1 if newTypes.include?(newType3)
|
||||
@type1 = newTypes[0]
|
||||
@type2 = (newTypes.length==1) ? newTypes[0] : newTypes[1]
|
||||
@effects[PBEffects::Type3] = newType3
|
||||
else
|
||||
newType = getConst(PBTypes,newType) if newType.is_a?(Symbol) || newType.is_a?(String)
|
||||
@type1 = newType
|
||||
@type2 = newType
|
||||
@effects[PBEffects::Type3] = -1
|
||||
end
|
||||
@effects[PBEffects::BurnUp] = false
|
||||
@effects[PBEffects::Roost] = false
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Forms
|
||||
#=============================================================================
|
||||
def pbChangeForm(newForm,msg)
|
||||
return if fainted? || @effects[PBEffects::Transform] || @form==newForm
|
||||
oldForm = @form
|
||||
oldDmg = @totalhp-@hp
|
||||
self.form = newForm
|
||||
pbUpdate(true)
|
||||
@hp = @totalhp-oldDmg
|
||||
@effects[PBEffects::WeightChange] = 0 if NEWEST_BATTLE_MECHANICS
|
||||
@battle.scene.pbChangePokemon(self,@pokemon)
|
||||
@battle.scene.pbRefreshOne(@index)
|
||||
@battle.pbDisplay(msg) if msg && msg!=""
|
||||
PBDebug.log("[Form changed] #{pbThis} changed from form #{oldForm} to form #{newForm}")
|
||||
@battle.pbSetSeen(self)
|
||||
end
|
||||
|
||||
def pbCheckFormOnStatusChange
|
||||
return if fainted? || @effects[PBEffects::Transform]
|
||||
# Shaymin - reverts if frozen
|
||||
if isConst?(@species,PBSpecies,:SHAYMIN) && frozen?
|
||||
pbChangeForm(0,_INTL("{1} transformed!",pbThis))
|
||||
end
|
||||
end
|
||||
|
||||
def pbCheckFormOnMovesetChange
|
||||
return if fainted? || @effects[PBEffects::Transform]
|
||||
# Keldeo - knowing Secret Sword
|
||||
if isConst?(@species,PBSpecies,:KELDEO)
|
||||
newForm = 0
|
||||
newForm = 1 if pbHasMove?(:SECRETSWORD)
|
||||
pbChangeForm(newForm,_INTL("{1} transformed!",pbThis))
|
||||
end
|
||||
end
|
||||
|
||||
def pbCheckFormOnWeatherChange
|
||||
return if fainted? || @effects[PBEffects::Transform]
|
||||
# Castform - Forecast
|
||||
if isConst?(@species,PBSpecies,:CASTFORM)
|
||||
if hasActiveAbility?(:FORECAST)
|
||||
newForm = 0
|
||||
case @battle.pbWeather
|
||||
when PBWeather::Sun, PBWeather::HarshSun; newForm = 1
|
||||
when PBWeather::Rain, PBWeather::HeavyRain; newForm = 2
|
||||
when PBWeather::Hail; newForm = 3
|
||||
end
|
||||
if @form!=newForm
|
||||
@battle.pbShowAbilitySplash(self,true)
|
||||
@battle.pbHideAbilitySplash(self)
|
||||
pbChangeForm(newForm,_INTL("{1} transformed!",pbThis))
|
||||
end
|
||||
else
|
||||
pbChangeForm(0,_INTL("{1} transformed!",pbThis))
|
||||
end
|
||||
end
|
||||
# Cherrim - Flower Gift
|
||||
if isConst?(@species,PBSpecies,:CHERRIM)
|
||||
if hasActiveAbility?(:FLOWERGIFT)
|
||||
newForm = 0
|
||||
case @battle.pbWeather
|
||||
when PBWeather::Sun, PBWeather::HarshSun; newForm = 1
|
||||
end
|
||||
if @form!=newForm
|
||||
@battle.pbShowAbilitySplash(self,true)
|
||||
@battle.pbHideAbilitySplash(self)
|
||||
pbChangeForm(newForm,_INTL("{1} transformed!",pbThis))
|
||||
end
|
||||
else
|
||||
pbChangeForm(0,_INTL("{1} transformed!",pbThis))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Checks the Pokémon's form and updates it if necessary. Used for when a
|
||||
# Pokémon enters battle (endOfRound=false) and at the end of each round
|
||||
# (endOfRound=true).
|
||||
def pbCheckForm(endOfRound=false)
|
||||
return if fainted? || @effects[PBEffects::Transform]
|
||||
# Form changes upon entering battle and when the weather changes
|
||||
pbCheckFormOnWeatherChange if !endOfRound
|
||||
# Darmanitan - Zen Mode
|
||||
if isConst?(@species,PBSpecies,:DARMANITAN) && isConst?(@ability,PBAbilities,:ZENMODE)
|
||||
if @hp<=@totalhp/2
|
||||
if @form!=1
|
||||
@battle.pbShowAbilitySplash(self,true)
|
||||
@battle.pbHideAbilitySplash(self)
|
||||
pbChangeForm(1,_INTL("{1} triggered!",abilityName))
|
||||
end
|
||||
elsif @form!=0
|
||||
@battle.pbShowAbilitySplash(self,true)
|
||||
@battle.pbHideAbilitySplash(self)
|
||||
pbChangeForm(0,_INTL("{1} triggered!",abilityName))
|
||||
end
|
||||
end
|
||||
# Minior - Shields Down
|
||||
if isConst?(@species,PBSpecies,:MINIOR) && isConst?(@ability,PBAbilities,:SHIELDSDOWN)
|
||||
if @hp>@totalhp/2 # Turn into Meteor form
|
||||
newForm = (@form>=7) ? @form-7 : @form
|
||||
if @form!=newForm
|
||||
@battle.pbShowAbilitySplash(self,true)
|
||||
@battle.pbHideAbilitySplash(self)
|
||||
pbChangeForm(newForm,_INTL("{1} deactivated!",abilityName))
|
||||
elsif !endOfRound
|
||||
@battle.pbDisplay(_INTL("{1} deactivated!",abilityName))
|
||||
end
|
||||
elsif @form<7 # Turn into Core form
|
||||
@battle.pbShowAbilitySplash(self,true)
|
||||
@battle.pbHideAbilitySplash(self)
|
||||
pbChangeForm(@form+7,_INTL("{1} activated!",abilityName))
|
||||
end
|
||||
end
|
||||
# Wishiwashi - Schooling
|
||||
if isConst?(@species,PBSpecies,:WISHIWASHI) && isConst?(@ability,PBAbilities,:SCHOOLING)
|
||||
if @level>=20 && @hp>@totalhp/4
|
||||
if @form!=1
|
||||
@battle.pbShowAbilitySplash(self,true)
|
||||
@battle.pbHideAbilitySplash(self)
|
||||
pbChangeForm(1,_INTL("{1} formed a school!",pbThis))
|
||||
end
|
||||
elsif @form!=0
|
||||
@battle.pbShowAbilitySplash(self,true)
|
||||
@battle.pbHideAbilitySplash(self)
|
||||
pbChangeForm(0,_INTL("{1} stopped schooling!",pbThis))
|
||||
end
|
||||
end
|
||||
# Zygarde - Power Construct
|
||||
if isConst?(@species,PBSpecies,:ZYGARDE) && isConst?(@ability,PBAbilities,:POWERCONSTRUCT) &&
|
||||
endOfRound
|
||||
if @hp<=@totalhp/2 && @form<2 # Turn into Complete Forme
|
||||
newForm = @form+2
|
||||
@battle.pbDisplay(_INTL("You sense the presence of many!"))
|
||||
@battle.pbShowAbilitySplash(self,true)
|
||||
@battle.pbHideAbilitySplash(self)
|
||||
pbChangeForm(newForm,_INTL("{1} transformed into its Complete Forme!",pbThis))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def pbTransform(target)
|
||||
oldAbil = @ability
|
||||
@effects[PBEffects::Transform] = true
|
||||
@effects[PBEffects::TransformSpecies] = target.species
|
||||
pbChangeTypes(target)
|
||||
@ability = target.ability
|
||||
@attack = target.attack
|
||||
@defense = target.defense
|
||||
@spatk = target.spatk
|
||||
@spdef = target.spdef
|
||||
@speed = target.speed
|
||||
PBStats.eachBattleStat { |s| @stages[s] = target.stages[s] }
|
||||
if NEWEST_BATTLE_MECHANICS
|
||||
@effects[PBEffects::FocusEnergy] = target.effects[PBEffects::FocusEnergy]
|
||||
@effects[PBEffects::LaserFocus] = target.effects[PBEffects::LaserFocus]
|
||||
end
|
||||
@moves.clear
|
||||
target.moves.each_with_index do |m,i|
|
||||
@moves[i] = PokeBattle_Move.pbFromPBMove(@battle,PBMove.new(m.id))
|
||||
@moves[i].pp = 5
|
||||
@moves[i].totalpp = 5
|
||||
end
|
||||
@effects[PBEffects::Disable] = 0
|
||||
@effects[PBEffects::DisableMove] = 0
|
||||
@effects[PBEffects::WeightChange] = target.effects[PBEffects::WeightChange]
|
||||
@battle.scene.pbRefreshOne(@index)
|
||||
@battle.pbDisplay(_INTL("{1} transformed into {2}!",pbThis,target.pbThis(true)))
|
||||
pbOnAbilityChanged(oldAbil)
|
||||
end
|
||||
|
||||
def pbHyperMode; end
|
||||
end
|
||||
573
Data/Scripts/011_Battle/001_Battler/004_Battler_Statuses.rb
Normal file
573
Data/Scripts/011_Battle/001_Battler/004_Battler_Statuses.rb
Normal file
@@ -0,0 +1,573 @@
|
||||
class PokeBattle_Battler
|
||||
#=============================================================================
|
||||
# Generalised checks for whether a status problem can be inflicted
|
||||
#=============================================================================
|
||||
# NOTE: Not all "does it have this status?" checks use this method. If the
|
||||
# check is leading up to curing self of that status condition, then it
|
||||
# will look at the value of @status directly instead - if it is that
|
||||
# PBStatuses value then it is curable. This method only checks for
|
||||
# "counts as having that status", which includes Comatose which can't be
|
||||
# cured.
|
||||
def pbHasStatus?(checkStatus)
|
||||
if BattleHandlers.triggerStatusCheckAbilityNonIgnorable(@ability,self,checkStatus)
|
||||
return true
|
||||
end
|
||||
return @status==checkStatus
|
||||
end
|
||||
|
||||
def pbHasAnyStatus?
|
||||
if BattleHandlers.triggerStatusCheckAbilityNonIgnorable(@ability,self,nil)
|
||||
return true
|
||||
end
|
||||
return @status!=PBStatuses::NONE
|
||||
end
|
||||
|
||||
def pbCanInflictStatus?(newStatus,user,showMessages,move=nil,ignoreStatus=false)
|
||||
return false if fainted?
|
||||
selfInflicted = (user && user.index==@index)
|
||||
# Already have that status problem
|
||||
if self.status==newStatus && !ignoreStatus
|
||||
if showMessages
|
||||
msg = ""
|
||||
case self.status
|
||||
when PBStatuses::SLEEP; msg = _INTL("{1} is already asleep!",pbThis)
|
||||
when PBStatuses::POISON; msg = _INTL("{1} is already poisoned!",pbThis)
|
||||
when PBStatuses::BURN; msg = _INTL("{1} already has a burn!",pbThis)
|
||||
when PBStatuses::PARALYSIS; msg = _INTL("{1} is already paralyzed!",pbThis)
|
||||
when PBStatuses::FROZEN; msg = _INTL("{1} is already frozen solid!",pbThis)
|
||||
end
|
||||
@battle.pbDisplay(msg)
|
||||
end
|
||||
return false
|
||||
end
|
||||
# Trying to replace a status problem with another one
|
||||
if self.status!=PBStatuses::NONE && !ignoreStatus && !selfInflicted
|
||||
@battle.pbDisplay(_INTL("It doesn't affect {1}...",pbThis(true))) if showMessages
|
||||
return false
|
||||
end
|
||||
# Trying to inflict a status problem on a Pokémon behind a substitute
|
||||
if @effects[PBEffects::Substitute]>0 && !(move && move.ignoresSubstitute?(user)) &&
|
||||
!selfInflicted
|
||||
@battle.pbDisplay(_INTL("It doesn't affect {1}...",pbThis(true))) if showMessages
|
||||
return false
|
||||
end
|
||||
# Weather immunity
|
||||
if newStatus==PBStatuses::FROZEN &&
|
||||
(@battle.pbWeather==PBWeather::Sun || @battle.pbWeather==PBWeather::HarshSun)
|
||||
@battle.pbDisplay(_INTL("It doesn't affect {1}...",pbThis(true))) if showMessages
|
||||
return false
|
||||
end
|
||||
# Terrains immunity
|
||||
if affectedByTerrain?
|
||||
case @battle.field.terrain
|
||||
when PBBattleTerrains::Electric
|
||||
if newStatus==PBStatuses::SLEEP
|
||||
@battle.pbDisplay(_INTL("{1} surrounds itself with electrified terrain!",
|
||||
pbThis(true))) if showMessages
|
||||
return false
|
||||
end
|
||||
when PBBattleTerrains::Misty
|
||||
@battle.pbDisplay(_INTL("{1} surrounds itself with misty terrain!",pbThis(true))) if showMessages
|
||||
return false
|
||||
end
|
||||
end
|
||||
# Uproar immunity
|
||||
if newStatus==PBStatuses::SLEEP &&
|
||||
!(hasActiveAbility?(:SOUNDPROOF) && !@battle.moldBreaker)
|
||||
@battle.eachBattler do |b|
|
||||
next if b.effects[PBEffects::Uproar]==0
|
||||
@battle.pbDisplay(_INTL("But the uproar kept {1} awake!",pbThis(true))) if showMessages
|
||||
return false
|
||||
end
|
||||
end
|
||||
# Type immunities
|
||||
hasImmuneType = false
|
||||
case newStatus
|
||||
when PBStatuses::SLEEP
|
||||
# No type is immune to sleep
|
||||
when PBStatuses::POISON
|
||||
if !(user && user.hasActiveAbility?(:CORROSION))
|
||||
hasImmuneType |= pbHasType?(:POISON)
|
||||
hasImmuneType |= pbHasType?(:STEEL)
|
||||
end
|
||||
when PBStatuses::BURN
|
||||
hasImmuneType |= pbHasType?(:FIRE)
|
||||
when PBStatuses::PARALYSIS
|
||||
hasImmuneType |= pbHasType?(:ELECTRIC) && NEWEST_BATTLE_MECHANICS
|
||||
when PBStatuses::FROZEN
|
||||
hasImmuneType |= pbHasType?(:ICE)
|
||||
end
|
||||
if hasImmuneType
|
||||
@battle.pbDisplay(_INTL("It doesn't affect {1}...",pbThis(true))) if showMessages
|
||||
return false
|
||||
end
|
||||
# Ability immunity
|
||||
immuneByAbility = false; immAlly = nil
|
||||
if BattleHandlers.triggerStatusImmunityAbilityNonIgnorable(@ability,self,newStatus)
|
||||
immuneByAbility = true
|
||||
elsif selfInflicted || !@battle.moldBreaker
|
||||
if abilityActive? && BattleHandlers.triggerStatusImmunityAbility(@ability,self,newStatus)
|
||||
immuneByAbility = true
|
||||
else
|
||||
eachAlly do |b|
|
||||
next if !b.abilityActive?
|
||||
next if !BattleHandlers.triggerStatusImmunityAllyAbility(b.ability,self,newStatus)
|
||||
immuneByAbility = true
|
||||
immAlly = b
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
if immuneByAbility
|
||||
if showMessages
|
||||
@battle.pbShowAbilitySplash(immAlly || self)
|
||||
msg = ""
|
||||
if PokeBattle_SceneConstants::USE_ABILITY_SPLASH
|
||||
case newStatus
|
||||
when PBStatuses::SLEEP; msg = _INTL("{1} stays awake!",pbThis)
|
||||
when PBStatuses::POISON; msg = _INTL("{1} cannot be poisoned!",pbThis)
|
||||
when PBStatuses::BURN; msg = _INTL("{1} cannot be burned!",pbThis)
|
||||
when PBStatuses::PARALYSIS; msg = _INTL("{1} cannot be paralyzed!",pbThis)
|
||||
when PBStatuses::FROZEN; msg = _INTL("{1} cannot be frozen solid!",pbThis)
|
||||
end
|
||||
elsif immAlly
|
||||
case newStatus
|
||||
when PBStatuses::SLEEP
|
||||
msg = _INTL("{1} stays awake because of {2}'s {3}!",
|
||||
pbThis,immAlly.pbThis(true),immAlly.abilityName)
|
||||
when PBStatuses::POISON
|
||||
msg = _INTL("{1} cannot be poisoned because of {2}'s {3}!",
|
||||
pbThis,immAlly.pbThis(true),immAlly.abilityName)
|
||||
when PBStatuses::BURN
|
||||
msg = _INTL("{1} cannot be burned because of {2}'s {3}!",
|
||||
pbThis,immAlly.pbThis(true),immAlly.abilityName)
|
||||
when PBStatuses::PARALYSIS
|
||||
msg = _INTL("{1} cannot be paralyzed because of {2}'s {3}!",
|
||||
pbThis,immAlly.pbThis(true),immAlly.abilityName)
|
||||
when PBStatuses::FROZEN
|
||||
msg = _INTL("{1} cannot be frozen solid because of {2}'s {3}!",
|
||||
pbThis,immAlly.pbThis(true),immAlly.abilityName)
|
||||
end
|
||||
else
|
||||
case newStatus
|
||||
when PBStatuses::SLEEP; msg = _INTL("{1} stays awake because of its {2}!",pbThis,abilityName)
|
||||
when PBStatuses::POISON; msg = _INTL("{1}'s {2} prevents poisoning!",pbThis,abilityName)
|
||||
when PBStatuses::BURN; msg = _INTL("{1}'s {2} prevents burns!",pbThis,abilityName)
|
||||
when PBStatuses::PARALYSIS; msg = _INTL("{1}'s {2} prevents paralysis!",pbThis,abilityName)
|
||||
when PBStatuses::FROZEN; msg = _INTL("{1}'s {2} prevents freezing!",pbThis,abilityName)
|
||||
end
|
||||
end
|
||||
@battle.pbDisplay(msg)
|
||||
@battle.pbHideAbilitySplash(immAlly || self)
|
||||
end
|
||||
return false
|
||||
end
|
||||
# Safeguard immunity
|
||||
if pbOwnSide.effects[PBEffects::Safeguard]>0 && !selfInflicted && move &&
|
||||
!(user && user.hasActiveAbility?(:INFILTRATOR))
|
||||
@battle.pbDisplay(_INTL("{1}'s team is protected by Safeguard!",pbThis)) if showMessages
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
def pbCanSynchronizeStatus?(status,target)
|
||||
return false if fainted?
|
||||
# Trying to replace a status problem with another one
|
||||
return false if self.status!=PBStatuses::NONE
|
||||
# Terrain immunity
|
||||
return false if @battle.field.terrain==PBBattleTerrains::Misty && affectedByTerrain?
|
||||
# Type immunities
|
||||
hasImmuneType = false
|
||||
case self.status
|
||||
when PBStatuses::POISON
|
||||
# NOTE: target will have Synchronize, so it can't have Corrosion.
|
||||
if !(target && target.hasActiveAbility?(:CORROSION))
|
||||
hasImmuneType |= pbHasType?(:POISON)
|
||||
hasImmuneType |= pbHasType?(:STEEL)
|
||||
end
|
||||
when PBStatuses::BURN
|
||||
hasImmuneType |= pbHasType?(:FIRE)
|
||||
when PBStatuses::PARALYSIS
|
||||
hasImmuneType |= pbHasType?(:ELECTRIC) && NEWEST_BATTLE_MECHANICS
|
||||
end
|
||||
return false if hasImmuneType
|
||||
# Ability immunity
|
||||
if BattleHandlers.triggerStatusImmunityAbilityNonIgnorable(@ability,self,status)
|
||||
return false
|
||||
end
|
||||
if abilityActive? && BattleHandlers.triggerStatusImmunityAbility(@ability,self,status)
|
||||
return false
|
||||
end
|
||||
eachAlly do |b|
|
||||
next if !b.abilityActive?
|
||||
next if !BattleHandlers.triggerStatusImmunityAllyAbility(b.ability,self,status)
|
||||
return false
|
||||
end
|
||||
# Safeguard immunity
|
||||
if pbOwnSide.effects[PBEffects::Safeguard]>0 &&
|
||||
!(user && user.hasActiveAbility?(:INFILTRATOR))
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Generalised infliction of status problem
|
||||
#=============================================================================
|
||||
def pbInflictStatus(newStatus,newStatusCount=0,msg=nil,user=nil)
|
||||
# Inflict the new status
|
||||
self.status = newStatus
|
||||
self.statusCount = newStatusCount
|
||||
@effects[PBEffects::Toxic] = 0
|
||||
# Record status change in debug log, generate default message, show animation
|
||||
case newStatus
|
||||
when PBStatuses::SLEEP
|
||||
@battle.pbCommonAnimation("Sleep",self)
|
||||
msg = _INTL("{1} fell asleep!",pbThis) if !msg || msg==""
|
||||
when PBStatuses::POISON
|
||||
if newStatusCount>0
|
||||
@battle.pbCommonAnimation("Toxic",self)
|
||||
msg = _INTL("{1} was badly poisoned!",pbThis) if !msg || msg==""
|
||||
else
|
||||
@battle.pbCommonAnimation("Poison",self)
|
||||
msg = _INTL("{1} was poisoned!",pbThis) if !msg || msg==""
|
||||
end
|
||||
when PBStatuses::BURN
|
||||
@battle.pbCommonAnimation("Burn",self)
|
||||
msg = _INTL("{1} was burned!",pbThis) if !msg || msg==""
|
||||
when PBStatuses::PARALYSIS
|
||||
@battle.pbCommonAnimation("Paralysis",self)
|
||||
msg = _INTL("{1} is paralyzed! It may be unable to move!",pbThis) if !msg || msg==""
|
||||
when PBStatuses::FROZEN
|
||||
@battle.pbCommonAnimation("Frozen",self)
|
||||
msg = _INTL("{1} was frozen solid!",pbThis) if !msg || msg==""
|
||||
end
|
||||
# Show message
|
||||
@battle.pbDisplay(msg) if msg && msg!=""
|
||||
PBDebug.log("[Status change] #{pbThis}'s sleep count is #{newStatusCount}") if newStatus==PBStatuses::SLEEP
|
||||
pbCheckFormOnStatusChange
|
||||
# Synchronize
|
||||
if abilityActive?
|
||||
BattleHandlers.triggerAbilityOnStatusInflicted(@ability,self,user,newStatus)
|
||||
end
|
||||
# Status cures
|
||||
pbItemStatusCureCheck
|
||||
pbAbilityStatusCureCheck
|
||||
# Petal Dance/Outrage/Thrash get cancelled immediately by falling asleep
|
||||
# NOTE: I don't know why this applies only to Outrage and only to falling
|
||||
# asleep (i.e. it doesn't cancel Rollout/Uproar/other multi-turn
|
||||
# moves, and it doesn't cancel any moves if self becomes frozen/
|
||||
# disabled/anything else). This behaviour was tested in Gen 5.
|
||||
if @status==PBStatuses::SLEEP && @effects[PBEffects::Outrage]>0
|
||||
@effects[PBEffects::Outrage] = 0
|
||||
@currentMove = 0
|
||||
end
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Sleep
|
||||
#=============================================================================
|
||||
def asleep?
|
||||
return pbHasStatus?(PBStatuses::SLEEP)
|
||||
end
|
||||
|
||||
def pbCanSleep?(user,showMessages,move=nil,ignoreStatus=false)
|
||||
return pbCanInflictStatus?(PBStatuses::SLEEP,user,showMessages,move,ignoreStatus)
|
||||
end
|
||||
|
||||
def pbCanSleepYawn?
|
||||
return false if self.status!=PBStatuses::NONE
|
||||
if affectedByTerrain?
|
||||
return false if @battle.field.terrain==PBBattleTerrains::Electric
|
||||
return false if @battle.field.terrain==PBBattleTerrains::Misty
|
||||
end
|
||||
if !hasActiveAbility?(:SOUNDPROOF)
|
||||
@battle.eachBattler do |b|
|
||||
return false if b.effects[PBEffects::Uproar]>0
|
||||
end
|
||||
end
|
||||
if BattleHandlers.triggerStatusImmunityAbilityNonIgnorable(@ability,self,PBStatuses::SLEEP)
|
||||
return false
|
||||
end
|
||||
# NOTE: Bulbapedia claims that Flower Veil shouldn't prevent sleep due to
|
||||
# drowsiness, but I disagree because that makes no sense. Also, the
|
||||
# comparable Sweet Veil does prevent sleep due to drowsiness.
|
||||
if abilityActive? && BattleHandlers.triggerStatusImmunityAbility(@ability,self,PBStatuses::SLEEP)
|
||||
return false
|
||||
end
|
||||
eachAlly do |b|
|
||||
next if !b.abilityActive?
|
||||
next if !BattleHandlers.triggerStatusImmunityAllyAbility(b.ability,self,PBStatuses::SLEEP)
|
||||
return false
|
||||
end
|
||||
# NOTE: Bulbapedia claims that Safeguard shouldn't prevent sleep due to
|
||||
# drowsiness. I disagree with this too. Compare with the other sided
|
||||
# effects Misty/Electric Terrain, which do prevent it.
|
||||
return false if pbOwnSide.effects[PBEffects::Safeguard]>0
|
||||
return true
|
||||
end
|
||||
|
||||
def pbSleep(msg=nil)
|
||||
pbInflictStatus(PBStatuses::SLEEP,pbSleepDuration,msg)
|
||||
end
|
||||
|
||||
def pbSleepSelf(msg=nil,duration=-1)
|
||||
pbInflictStatus(PBStatuses::SLEEP,pbSleepDuration(duration),msg)
|
||||
end
|
||||
|
||||
def pbSleepDuration(duration=-1)
|
||||
duration = 2+@battle.pbRandom(3) if duration<=0
|
||||
duration = (duration/2).floor if hasActiveAbility?(:EARLYBIRD)
|
||||
return duration
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Poison
|
||||
#=============================================================================
|
||||
def poisoned?
|
||||
return pbHasStatus?(PBStatuses::POISON)
|
||||
end
|
||||
|
||||
def pbCanPoison?(user,showMessages,move=nil)
|
||||
return pbCanInflictStatus?(PBStatuses::POISON,user,showMessages,move)
|
||||
end
|
||||
|
||||
def pbCanPoisonSynchronize?(target)
|
||||
return pbCanSynchronizeStatus?(PBStatuses::POISON,target)
|
||||
end
|
||||
|
||||
def pbPoison(user=nil,msg=nil,toxic=false)
|
||||
pbInflictStatus(PBStatuses::POISON,(toxic) ? 1 : 0,msg,user)
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Burn
|
||||
#=============================================================================
|
||||
def burned?
|
||||
return pbHasStatus?(PBStatuses::BURN)
|
||||
end
|
||||
|
||||
def pbCanBurn?(user,showMessages,move=nil)
|
||||
return pbCanInflictStatus?(PBStatuses::BURN,user,showMessages,move)
|
||||
end
|
||||
|
||||
def pbCanBurnSynchronize?(target)
|
||||
return pbCanSynchronizeStatus?(PBStatuses::BURN,target)
|
||||
end
|
||||
|
||||
def pbBurn(user=nil,msg=nil)
|
||||
pbInflictStatus(PBStatuses::BURN,0,msg,user)
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Paralyze
|
||||
#=============================================================================
|
||||
def paralyzed?
|
||||
return pbHasStatus?(PBStatuses::PARALYSIS)
|
||||
end
|
||||
|
||||
def pbCanParalyze?(user,showMessages,move=nil)
|
||||
return pbCanInflictStatus?(PBStatuses::PARALYSIS,user,showMessages,move)
|
||||
end
|
||||
|
||||
def pbCanParalyzeSynchronize?(target)
|
||||
return pbCanSynchronizeStatus?(PBStatuses::PARALYSIS,target)
|
||||
end
|
||||
|
||||
def pbParalyze(user=nil,msg=nil)
|
||||
pbInflictStatus(PBStatuses::PARALYSIS,0,msg,user)
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Freeze
|
||||
#=============================================================================
|
||||
def frozen?
|
||||
return pbHasStatus?(PBStatuses::FROZEN)
|
||||
end
|
||||
|
||||
def pbCanFreeze?(user,showMessages,move=nil)
|
||||
return pbCanInflictStatus?(PBStatuses::FROZEN,user,showMessages,move)
|
||||
end
|
||||
|
||||
def pbFreeze(msg=nil)
|
||||
pbInflictStatus(PBStatuses::FROZEN,0,msg)
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Generalised status displays
|
||||
#=============================================================================
|
||||
def pbContinueStatus
|
||||
anim = ""; msg = ""
|
||||
case self.status
|
||||
when PBStatuses::SLEEP
|
||||
anim = "Sleep"; msg = _INTL("{1} is fast asleep.",pbThis)
|
||||
when PBStatuses::POISON
|
||||
anim = (@statusCount>0) ? "Toxic" : "Poison"
|
||||
msg = _INTL("{1} was hurt by poison!",pbThis)
|
||||
when PBStatuses::BURN
|
||||
anim = "Burn"; msg = _INTL("{1} was hurt by its burn!",pbThis)
|
||||
when PBStatuses::PARALYSIS
|
||||
anim = "Paralysis"; msg = _INTL("{1} is paralyzed! It can't move!",pbThis)
|
||||
when PBStatuses::FROZEN
|
||||
anim = "Frozen"; msg = _INTL("{1} is frozen solid!",pbThis)
|
||||
end
|
||||
@battle.pbCommonAnimation(anim,self) if anim!=""
|
||||
yield if block_given?
|
||||
@battle.pbDisplay(msg) if msg!=""
|
||||
PBDebug.log("[Status continues] #{pbThis}'s sleep count is #{@statusCount}") if self.status==PBStatuses::SLEEP
|
||||
end
|
||||
|
||||
def pbCureStatus(showMessages=true)
|
||||
oldStatus = status
|
||||
self.status = PBStatuses::NONE
|
||||
if showMessages
|
||||
case oldStatus
|
||||
when PBStatuses::SLEEP; @battle.pbDisplay(_INTL("{1} woke up!",pbThis))
|
||||
when PBStatuses::POISON; @battle.pbDisplay(_INTL("{1} was cured of its poisoning.",pbThis))
|
||||
when PBStatuses::BURN; @battle.pbDisplay(_INTL("{1}'s burn was healed.",pbThis))
|
||||
when PBStatuses::PARALYSIS; @battle.pbDisplay(_INTL("{1} was cured of paralysis.",pbThis))
|
||||
when PBStatuses::FROZEN; @battle.pbDisplay(_INTL("{1} thawed out!",pbThis))
|
||||
end
|
||||
end
|
||||
PBDebug.log("[Status change] #{pbThis}'s status was cured") if !showMessages
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Confusion
|
||||
#=============================================================================
|
||||
def pbCanConfuse?(user=nil,showMessages=true,move=nil,selfInflicted=false)
|
||||
return false if fainted?
|
||||
if @effects[PBEffects::Confusion]>0
|
||||
@battle.pbDisplay(_INTL("{1} is already confused.",pbThis)) if showMessages
|
||||
return false
|
||||
end
|
||||
if @effects[PBEffects::Substitute]>0 && !(move && move.ignoresSubstitute?(user)) &&
|
||||
!selfInflicted
|
||||
@battle.pbDisplay(_INTL("But it failed!")) if showMessages
|
||||
return false
|
||||
end
|
||||
# Terrains immunity
|
||||
if affectedByTerrain? && @battle.field.terrain==PBBattleTerrains::Misty
|
||||
@battle.pbDisplay(_INTL("{1} surrounds itself with misty terrain!",pbThis(true))) if showMessages
|
||||
return false
|
||||
end
|
||||
if selfInflicted || !@battle.moldBreaker
|
||||
if hasActiveAbility?(:OWNTEMPO)
|
||||
if showMessages
|
||||
@battle.pbShowAbilitySplash(self)
|
||||
if PokeBattle_SceneConstants::USE_ABILITY_SPLASH
|
||||
@battle.pbDisplay(_INTL("{1} doesn't become confused!",pbThis))
|
||||
else
|
||||
@battle.pbDisplay(_INTL("{1}'s {2} prevents confusion!",pbThis,abilityName))
|
||||
end
|
||||
@battle.pbHideAbilitySplash(self)
|
||||
end
|
||||
return false
|
||||
end
|
||||
end
|
||||
if pbOwnSide.effects[PBEffects::Safeguard]>0 && !selfInflicted &&
|
||||
!(user && user.hasActiveAbility?(:INFILTRATOR))
|
||||
@battle.pbDisplay(_INTL("{1}'s team is protected by Safeguard!",pbThis)) if showMessages
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
def pbCanConfuseSelf?(showMessages)
|
||||
return pbCanConfuse?(nil,showMessages,nil,true)
|
||||
end
|
||||
|
||||
def pbConfuse(msg=nil)
|
||||
@effects[PBEffects::Confusion] = pbConfusionDuration
|
||||
@battle.pbCommonAnimation("Confusion",self)
|
||||
msg = _INTL("{1} became confused!",pbThis) if !msg || msg==""
|
||||
@battle.pbDisplay(msg)
|
||||
PBDebug.log("[Lingering effect] #{pbThis}'s confusion count is #{@effects[PBEffects::Confusion]}")
|
||||
# Confusion cures
|
||||
pbItemStatusCureCheck
|
||||
pbAbilityStatusCureCheck
|
||||
end
|
||||
|
||||
def pbConfusionDuration(duration=-1)
|
||||
duration = 2+@battle.pbRandom(4) if duration<=0
|
||||
return duration
|
||||
end
|
||||
|
||||
def pbCureConfusion
|
||||
@effects[PBEffects::Confusion] = 0
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Attraction
|
||||
#=============================================================================
|
||||
def pbCanAttract?(user,showMessages=true)
|
||||
return false if fainted?
|
||||
return false if !user || user.fainted?
|
||||
if @effects[PBEffects::Attract]>=0
|
||||
@battle.pbDisplay(_INTL("{1} is unaffected!",pbThis)) if showMessages
|
||||
return false
|
||||
end
|
||||
agender = user.gender
|
||||
ogender = gender
|
||||
if agender==2 || ogender==2 || agender==ogender
|
||||
@battle.pbDisplay(_INTL("{1} is unaffected!",pbThis)) if showMessages
|
||||
return false
|
||||
end
|
||||
if !@battle.moldBreaker
|
||||
if hasActiveAbility?([:AROMAVEIL,:OBLIVIOUS])
|
||||
if showMessages
|
||||
@battle.pbShowAbilitySplash(self)
|
||||
if PokeBattle_SceneConstants::USE_ABILITY_SPLASH
|
||||
@battle.pbDisplay(_INTL("{1} is unaffected!",pbThis))
|
||||
else
|
||||
@battle.pbDisplay(_INTL("{1}'s {2} prevents romance!",pbThis,abilityName))
|
||||
end
|
||||
@battle.pbHideAbilitySplash(self)
|
||||
end
|
||||
return false
|
||||
else
|
||||
eachAlly do |b|
|
||||
next if !b.hasActiveAbility?(:AROMAVEIL)
|
||||
if showMessages
|
||||
@battle.pbShowAbilitySplash(self)
|
||||
if PokeBattle_SceneConstants::USE_ABILITY_SPLASH
|
||||
@battle.pbDisplay(_INTL("{1} is unaffected!",pbThis))
|
||||
else
|
||||
@battle.pbDisplay(_INTL("{1}'s {2} prevents romance!",b.pbThis,b.abilityName))
|
||||
end
|
||||
@battle.pbHideAbilitySplash(self)
|
||||
end
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
def pbAttract(user,msg=nil)
|
||||
@effects[PBEffects::Attract] = user.index
|
||||
@battle.pbCommonAnimation("Attract",self)
|
||||
msg = _INTL("{1} fell in love!",pbThis) if !msg || msg==""
|
||||
@battle.pbDisplay(msg)
|
||||
# Destiny Knot
|
||||
if hasActiveItem?(:DESTINYKNOT) && user.pbCanAttract?(self,false)
|
||||
user.pbAttract(self,_INTL("{1} fell in love from the {2}!",user.pbThis(true),itemName))
|
||||
end
|
||||
# Attraction cures
|
||||
pbItemStatusCureCheck
|
||||
pbAbilityStatusCureCheck
|
||||
end
|
||||
|
||||
def pbCureAttract
|
||||
@effects[PBEffects::Attract] = -1
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Flinching
|
||||
#=============================================================================
|
||||
def pbFlinch(user=nil)
|
||||
return if hasActiveAbility?(:INNERFOCUS) && !@battle.moldBreaker
|
||||
@effects[PBEffects::Flinch] = true
|
||||
end
|
||||
end
|
||||
310
Data/Scripts/011_Battle/001_Battler/005_Battler_StatStages.rb
Normal file
310
Data/Scripts/011_Battle/001_Battler/005_Battler_StatStages.rb
Normal file
@@ -0,0 +1,310 @@
|
||||
class PokeBattle_Battler
|
||||
#=============================================================================
|
||||
# Increase stat stages
|
||||
#=============================================================================
|
||||
def statStageAtMax?(stat)
|
||||
return @stages[stat]>=6
|
||||
end
|
||||
|
||||
def pbCanRaiseStatStage?(stat,user=nil,move=nil,showFailMsg=false,ignoreContrary=false)
|
||||
return false if fainted?
|
||||
# Contrary
|
||||
if hasActiveAbility?(:CONTRARY) && !ignoreContrary && !@battle.moldBreaker
|
||||
return pbCanLowerStatStage?(stat,user,move,showFailMsg,true)
|
||||
end
|
||||
# Check the stat stage
|
||||
if statStageAtMax?(stat)
|
||||
@battle.pbDisplay(_INTL("{1}'s {2} won't go any higher!",
|
||||
pbThis,PBStats.getName(stat))) if showFailMsg
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
def pbRaiseStatStageBasic(stat,increment,ignoreContrary=false)
|
||||
if !@battle.moldBreaker
|
||||
# Contrary
|
||||
if hasActiveAbility?(:CONTRARY) && !ignoreContrary
|
||||
return pbLowerStatStageBasic(stat,increment,true)
|
||||
end
|
||||
# Simple
|
||||
increment *= 2 if hasActiveAbility?(:SIMPLE)
|
||||
end
|
||||
# Change the stat stage
|
||||
increment = [increment,6-@stages[stat]].min
|
||||
if increment>0
|
||||
s = PBStats.getName(stat); new = @stages[stat]+increment
|
||||
PBDebug.log("[Stat change] #{pbThis}'s #{s}: #{@stages[stat]} -> #{new} (+#{increment})")
|
||||
@stages[stat] += increment
|
||||
end
|
||||
return increment
|
||||
end
|
||||
|
||||
def pbRaiseStatStage(stat,increment,user,showAnim=true,ignoreContrary=false)
|
||||
return false if !PBStats.validBattleStat?(stat)
|
||||
# Contrary
|
||||
if hasActiveAbility?(:CONTRARY) && !ignoreContrary && !@battle.moldBreaker
|
||||
return pbLowerStatStage(stat,increment,user,showAnim,true)
|
||||
end
|
||||
# Perform the stat stage change
|
||||
increment = pbRaiseStatStageBasic(stat,increment,ignoreContrary)
|
||||
return false if increment<=0
|
||||
# Stat up animation and message
|
||||
@battle.pbCommonAnimation("StatUp",self) if showAnim
|
||||
arrStatTexts = [
|
||||
_INTL("{1}'s {2} rose!",pbThis,PBStats.getName(stat)),
|
||||
_INTL("{1}'s {2} rose sharply!",pbThis,PBStats.getName(stat)),
|
||||
_INTL("{1}'s {2} rose drastically!",pbThis,PBStats.getName(stat))]
|
||||
@battle.pbDisplay(arrStatTexts[[increment-1,2].min])
|
||||
# Trigger abilities upon stat gain
|
||||
if abilityActive?
|
||||
BattleHandlers.triggerAbilityOnStatGain(@ability,self,stat,user)
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
def pbRaiseStatStageByCause(stat,increment,user,cause,showAnim=true,ignoreContrary=false)
|
||||
return false if !PBStats.validBattleStat?(stat)
|
||||
# Contrary
|
||||
if hasActiveAbility?(:CONTRARY) && !ignoreContrary && !@battle.moldBreaker
|
||||
return pbLowerStatStageByCause(stat,increment,user,cause,showAnim,true)
|
||||
end
|
||||
# Perform the stat stage change
|
||||
increment = pbRaiseStatStageBasic(stat,increment,ignoreContrary)
|
||||
return false if increment<=0
|
||||
# Stat up animation and message
|
||||
@battle.pbCommonAnimation("StatUp",self) if showAnim
|
||||
if user.index==@index
|
||||
arrStatTexts = [
|
||||
_INTL("{1}'s {2} raised its {3}!",pbThis,cause,PBStats.getName(stat)),
|
||||
_INTL("{1}'s {2} sharply raised its {3}!",pbThis,cause,PBStats.getName(stat)),
|
||||
_INTL("{1}'s {2} drastically raised its {3}!",pbThis,cause,PBStats.getName(stat))]
|
||||
else
|
||||
arrStatTexts = [
|
||||
_INTL("{1}'s {2} raised {3}'s {4}!",user.pbThis,cause,pbThis(true),PBStats.getName(stat)),
|
||||
_INTL("{1}'s {2} sharply raised {3}'s {4}!",user.pbThis,cause,pbThis(true),PBStats.getName(stat)),
|
||||
_INTL("{1}'s {2} drastically raised {3}'s {4}!",user.pbThis,cause,pbThis(true),PBStats.getName(stat))]
|
||||
end
|
||||
@battle.pbDisplay(arrStatTexts[[increment-1,2].min])
|
||||
# Trigger abilities upon stat gain
|
||||
if abilityActive?
|
||||
BattleHandlers.triggerAbilityOnStatGain(@ability,self,stat,user)
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
def pbRaiseStatStageByAbility(stat,increment,user,splashAnim=true)
|
||||
return false if fainted?
|
||||
ret = false
|
||||
@battle.pbShowAbilitySplash(user) if splashAnim
|
||||
if pbCanRaiseStatStage?(stat,user,nil,PokeBattle_SceneConstants::USE_ABILITY_SPLASH)
|
||||
if PokeBattle_SceneConstants::USE_ABILITY_SPLASH
|
||||
ret = pbRaiseStatStage(stat,increment,user)
|
||||
else
|
||||
ret = pbRaiseStatStageByCause(stat,increment,user,user.abilityName)
|
||||
end
|
||||
end
|
||||
@battle.pbHideAbilitySplash(user) if splashAnim
|
||||
return ret
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Decrease stat stages
|
||||
#=============================================================================
|
||||
def statStageAtMin?(stat)
|
||||
return @stages[stat]<=-6
|
||||
end
|
||||
|
||||
def pbCanLowerStatStage?(stat,user=nil,move=nil,showFailMsg=false,ignoreContrary=false)
|
||||
return false if fainted?
|
||||
# Contrary
|
||||
if hasActiveAbility?(:CONTRARY) && !ignoreContrary && !@battle.moldBreaker
|
||||
return pbCanRaiseStatStage?(stat,user,move,showFailMsg,true)
|
||||
end
|
||||
if !user || user.index!=@index # Not self-inflicted
|
||||
if @effects[PBEffects::Substitute]>0 && !(move && move.ignoresSubstitute?(user))
|
||||
@battle.pbDisplay(_INTL("{1} is protected by its substitute!",pbThis)) if showFailMsg
|
||||
return false
|
||||
end
|
||||
if pbOwnSide.effects[PBEffects::Mist]>0 &&
|
||||
!(user && user.hasActiveAbility?(:INFILTRATOR))
|
||||
@battle.pbDisplay(_INTL("{1} is protected by Mist!",pbThis)) if showFailMsg
|
||||
return false
|
||||
end
|
||||
if abilityActive?
|
||||
return false if BattleHandlers.triggerStatLossImmunityAbility(
|
||||
@ability,self,stat,@battle,showFailMsg) if !@battle.moldBreaker
|
||||
return false if BattleHandlers.triggerStatLossImmunityAbilityNonIgnorable(
|
||||
@ability,self,stat,@battle,showFailMsg)
|
||||
end
|
||||
if !@battle.moldBreaker
|
||||
eachAlly do |b|
|
||||
next if !b.abilityActive?
|
||||
return false if BattleHandlers.triggerStatLossImmunityAllyAbility(
|
||||
b.ability,b,self,stat,@battle,showFailMsg)
|
||||
end
|
||||
end
|
||||
end
|
||||
# Check the stat stage
|
||||
if statStageAtMin?(stat)
|
||||
@battle.pbDisplay(_INTL("{1}'s {2} won't go any lower!",
|
||||
pbThis,PBStats.getName(stat))) if showFailMsg
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
def pbLowerStatStageBasic(stat,increment,ignoreContrary=false)
|
||||
if !@battle.moldBreaker
|
||||
# Contrary
|
||||
if hasActiveAbility?(:CONTRARY) && !ignoreContrary
|
||||
return pbRaiseStatStageBasic(stat,increment,true)
|
||||
end
|
||||
# Simple
|
||||
increment *= 2 if hasActiveAbility?(:SIMPLE)
|
||||
end
|
||||
# Change the stat stage
|
||||
increment = [increment,6+@stages[stat]].min
|
||||
if increment>0
|
||||
s = PBStats.getName(stat); new = @stages[stat]-increment
|
||||
PBDebug.log("[Stat change] #{pbThis}'s #{s}: #{@stages[stat]} -> #{new} (-#{increment})")
|
||||
@stages[stat] -= increment
|
||||
end
|
||||
return increment
|
||||
end
|
||||
|
||||
def pbLowerStatStage(stat,increment,user,showAnim=true,ignoreContrary=false)
|
||||
return false if !PBStats.validBattleStat?(stat)
|
||||
# Contrary
|
||||
if hasActiveAbility?(:CONTRARY) && !ignoreContrary && !@battle.moldBreaker
|
||||
return pbRaiseStatStage(stat,increment,user,showAnim,true)
|
||||
end
|
||||
# Perform the stat stage change
|
||||
increment = pbLowerStatStageBasic(stat,increment,ignoreContrary)
|
||||
return false if increment<=0
|
||||
# Stat down animation and message
|
||||
@battle.pbCommonAnimation("StatDown",self) if showAnim
|
||||
arrStatTexts = [
|
||||
_INTL("{1}'s {2} fell!",pbThis,PBStats.getName(stat)),
|
||||
_INTL("{1}'s {2} harshly fell!",pbThis,PBStats.getName(stat)),
|
||||
_INTL("{1}'s {2} severely fell!",pbThis,PBStats.getName(stat))]
|
||||
@battle.pbDisplay(arrStatTexts[[increment-1,2].min])
|
||||
# Trigger abilities upon stat loss
|
||||
if abilityActive?
|
||||
BattleHandlers.triggerAbilityOnStatLoss(@ability,self,stat,user)
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
def pbLowerStatStageByCause(stat,increment,user,cause,showAnim=true,ignoreContrary=false)
|
||||
return false if !PBStats.validBattleStat?(stat)
|
||||
# Contrary
|
||||
if hasActiveAbility?(:CONTRARY) && !ignoreContrary && !@battle.moldBreaker
|
||||
return pbRaiseStatStageByCause(stat,increment,user,cause,showAnim,true)
|
||||
end
|
||||
# Perform the stat stage change
|
||||
increment = pbLowerStatStageBasic(stat,increment,ignoreContrary)
|
||||
return false if increment<=0
|
||||
# Stat down animation and message
|
||||
@battle.pbCommonAnimation("StatDown",self) if showAnim
|
||||
if user.index==@index
|
||||
arrStatTexts = [
|
||||
_INTL("{1}'s {2} lowered its {3}!",pbThis,cause,PBStats.getName(stat)),
|
||||
_INTL("{1}'s {2} harshly lowered its {3}!",pbThis,cause,PBStats.getName(stat)),
|
||||
_INTL("{1}'s {2} severely lowered its {3}!",pbThis,cause,PBStats.getName(stat))]
|
||||
else
|
||||
arrStatTexts = [
|
||||
_INTL("{1}'s {2} lowered {3}'s {4}!",user.pbThis,cause,pbThis(true),PBStats.getName(stat)),
|
||||
_INTL("{1}'s {2} harshly lowered {3}'s {4}!",user.pbThis,cause,pbThis(true),PBStats.getName(stat)),
|
||||
_INTL("{1}'s {2} severely lowered {3}'s {4}!",user.pbThis,cause,pbThis(true),PBStats.getName(stat))]
|
||||
end
|
||||
@battle.pbDisplay(arrStatTexts[[increment-1,2].min])
|
||||
# Trigger abilities upon stat loss
|
||||
if abilityActive?
|
||||
BattleHandlers.triggerAbilityOnStatLoss(@ability,self,stat,user)
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
def pbLowerStatStageByAbility(stat,increment,user,splashAnim=true,checkContact=false)
|
||||
ret = false
|
||||
@battle.pbShowAbilitySplash(user) if splashAnim
|
||||
if pbCanLowerStatStage?(stat,user,nil,PokeBattle_SceneConstants::USE_ABILITY_SPLASH) &&
|
||||
(!checkContact || affectedByContactEffect?(PokeBattle_SceneConstants::USE_ABILITY_SPLASH))
|
||||
if PokeBattle_SceneConstants::USE_ABILITY_SPLASH
|
||||
ret = pbLowerStatStage(stat,increment,user)
|
||||
else
|
||||
ret = pbLowerStatStageByCause(stat,increment,user,user.abilityName)
|
||||
end
|
||||
end
|
||||
@battle.pbHideAbilitySplash(user) if splashAnim
|
||||
return ret
|
||||
end
|
||||
|
||||
def pbLowerAttackStatStageIntimidate(user)
|
||||
return false if fainted?
|
||||
# NOTE: Substitute intentially blocks Intimidate even if self has Contrary.
|
||||
if @effects[PBEffects::Substitute]>0
|
||||
if PokeBattle_SceneConstants::USE_ABILITY_SPLASH
|
||||
@battle.pbDisplay(_INTL("{1} is protected by its substitute!",pbThis))
|
||||
else
|
||||
@battle.pbDisplay(_INTL("{1}'s substitute protected it from {2}'s {3}!",
|
||||
pbThis,user.pbThis(true),user.abilityName))
|
||||
end
|
||||
return false
|
||||
end
|
||||
if PokeBattle_SceneConstants::USE_ABILITY_SPLASH
|
||||
return pbLowerStatStageByAbility(PBStats::ATTACK,1,user,false)
|
||||
end
|
||||
# NOTE: These checks exist to ensure appropriate messages are shown if
|
||||
# Intimidate is blocked somehow (i.e. the messages should mention the
|
||||
# Intimidate ability by name).
|
||||
if !hasActiveAbility?(:CONTRARY)
|
||||
if pbOwnSide.effects[PBEffects::Mist]>0
|
||||
@battle.pbDisplay(_INTL("{1} is protected from {2}'s {3} by Mist!",
|
||||
pbThis,user.pbThis(true),user.abilityName))
|
||||
return false
|
||||
end
|
||||
if abilityActive?
|
||||
if BattleHandlers.triggerStatLossImmunityAbility(@ability,self,PBStats::ATTACK,@battle,false) ||
|
||||
BattleHandlers.triggerStatLossImmunityAbilityNonIgnorable(@ability,self,PBStats::ATTACK,@battle,false)
|
||||
@battle.pbDisplay(_INTL("{1}'s {2} prevented {3}'s {4} from working!",
|
||||
pbThis,abilityName,user.pbThis(true),user.abilityName))
|
||||
return false
|
||||
end
|
||||
end
|
||||
eachAlly do |b|
|
||||
next if !b.abilityActive?
|
||||
if BattleHandlers.triggerStatLossImmunityAllyAbility(b.ability,b,self,PBStats::ATTACK,@battle,false)
|
||||
@battle.pbDisplay(_INTL("{1} is protected from {2}'s {3} by {4}'s {5}!",
|
||||
pbThis,user.pbThis(true),user.abilityName,b.pbThis(true),b.abilityName))
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
return false if !pbCanLowerStatStage?(PBStats::ATTACK,user)
|
||||
return pbLowerStatStageByCause(PBStats::ATTACK,1,user,user.abilityName)
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Reset stat stages
|
||||
#=============================================================================
|
||||
def hasAlteredStatStages?
|
||||
PBStats.eachBattleStat { |s| return true if @stages[s]!=0 }
|
||||
return false
|
||||
end
|
||||
|
||||
def hasRaisedStatStages?
|
||||
PBStats.eachBattleStat { |s| return true if @stages[s]>0 }
|
||||
return false
|
||||
end
|
||||
|
||||
def hasLoweredStatStages?
|
||||
PBStats.eachBattleStat { |s| return true if @stages[s]<0 }
|
||||
return false
|
||||
end
|
||||
|
||||
def pbResetStatStages
|
||||
PBStats.eachBattleStat { |s| @stages[s] = 0 }
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,322 @@
|
||||
class PokeBattle_Battler
|
||||
#=============================================================================
|
||||
# Called when a Pokémon (self) is sent into battle or its ability changes.
|
||||
#=============================================================================
|
||||
def pbEffectsOnSwitchIn(switchIn=false)
|
||||
# Healing Wish/Lunar Dance/entry hazards
|
||||
@battle.pbOnActiveOne(self) if switchIn
|
||||
# Primal Revert upon entering battle
|
||||
@battle.pbPrimalReversion(@index) if !fainted?
|
||||
# Ending primordial weather, checking Trace
|
||||
pbContinualAbilityChecks(true)
|
||||
# Abilities that trigger upon switching in
|
||||
if (!fainted? && nonNegatableAbility?) || abilityActive?
|
||||
BattleHandlers.triggerAbilityOnSwitchIn(@ability,self,@battle)
|
||||
end
|
||||
# Check for end of primordial weather
|
||||
@battle.pbEndPrimordialWeather
|
||||
# Items that trigger upon switching in (Air Balloon message)
|
||||
if switchIn && itemActive?
|
||||
BattleHandlers.triggerItemOnSwitchIn(@item,self,@battle)
|
||||
end
|
||||
# Berry check, status-curing ability check
|
||||
pbHeldItemTriggerCheck if switchIn
|
||||
pbAbilityStatusCureCheck
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Ability effects
|
||||
#=============================================================================
|
||||
def pbAbilitiesOnSwitchOut
|
||||
if abilityActive?
|
||||
BattleHandlers.triggerAbilityOnSwitchOut(@ability,self,false)
|
||||
end
|
||||
# Reset form
|
||||
@battle.peer.pbOnLeavingBattle(@battle,@pokemon,@battle.usedInBattle[idxOwnSide][@index/2])
|
||||
# Treat self as fainted
|
||||
@hp = 0
|
||||
@fainted = true
|
||||
# Check for end of primordial weather
|
||||
@battle.pbEndPrimordialWeather
|
||||
end
|
||||
|
||||
def pbAbilitiesOnFainting
|
||||
# Self fainted; check all other battlers to see if their abilities trigger
|
||||
@battle.pbPriority(true).each do |b|
|
||||
next if !b || !b.abilityActive?
|
||||
BattleHandlers.triggerAbilityChangeOnBattlerFainting(b.ability,b,self,@battle)
|
||||
end
|
||||
@battle.pbPriority(true).each do |b|
|
||||
next if !b || !b.abilityActive?
|
||||
BattleHandlers.triggerAbilityOnBattlerFainting(b.ability,b,self,@battle)
|
||||
end
|
||||
end
|
||||
|
||||
# Used for Emergency Exit/Wimp Out.
|
||||
def pbAbilitiesOnDamageTaken(oldHP,newHP=-1)
|
||||
return false if !abilityActive?
|
||||
newHP = @hp if newHP<0
|
||||
return false if oldHP<@totalhp/2 || newHP>=@totalhp/2 # Didn't drop below half
|
||||
ret = BattleHandlers.triggerAbilityOnHPDroppedBelowHalf(@ability,self,@battle)
|
||||
return ret # Whether self has switched out
|
||||
end
|
||||
|
||||
# Called when a Pokémon (self) enters battle, at the end of each move used,
|
||||
# and at the end of each round.
|
||||
def pbContinualAbilityChecks(onSwitchIn=false)
|
||||
# Check for end of primordial weather
|
||||
@battle.pbEndPrimordialWeather
|
||||
# Trace
|
||||
if hasActiveAbility?(:TRACE)
|
||||
# NOTE: In Gen 5 only, Trace only triggers upon the Trace bearer switching
|
||||
# in and not at any later times, even if a traceable ability turns
|
||||
# up later. Essentials ignores this, and allows Trace to trigger
|
||||
# whenever it can even in the old battle mechanics.
|
||||
abilityBlacklist = [
|
||||
# Replaces self with another ability
|
||||
:POWEROFALCHEMY,
|
||||
:RECEIVER,
|
||||
:TRACE,
|
||||
# Form-changing abilities
|
||||
:BATTLEBOND,
|
||||
:DISGUISE,
|
||||
:FLOWERGIFT,
|
||||
:FORECAST,
|
||||
:MULTITYPE,
|
||||
:POWERCONSTRUCT,
|
||||
:SCHOOLING,
|
||||
:SHIELDSDOWN,
|
||||
:STANCECHANGE,
|
||||
:ZENMODE,
|
||||
# Appearance-changing abilities
|
||||
:ILLUSION,
|
||||
:IMPOSTER,
|
||||
# Abilities intended to be inherent properties of a certain species
|
||||
:COMATOSE,
|
||||
:RKSSYSTEM
|
||||
]
|
||||
choices = []
|
||||
@battle.eachOtherSideBattler(@index) do |b|
|
||||
abilityBlacklist.each do |abil|
|
||||
next if !isConst?(b.ability,PBAbilities,abil)
|
||||
choices.push(b)
|
||||
break
|
||||
end
|
||||
end
|
||||
if choices.length>0
|
||||
choice = choices[@battle.pbRandom(choices.length)]
|
||||
@battle.pbShowAbilitySplash(self)
|
||||
@ability = choice.ability
|
||||
@battle.pbDisplay(_INTL("{1} traced {2}'s {3}!",pbThis,choice.pbThis(true),choice.abilityName))
|
||||
@battle.pbHideAbilitySplash(self)
|
||||
if !onSwitchIn && (nonNegatableAbility? || abilityActive?)
|
||||
BattleHandlers.triggerAbilityOnSwitchIn(@ability,self,@battle)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Ability curing
|
||||
#=============================================================================
|
||||
# Cures status conditions, confusion and infatuation.
|
||||
def pbAbilityStatusCureCheck
|
||||
if abilityActive?
|
||||
BattleHandlers.triggerStatusCureAbility(@ability,self)
|
||||
end
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Ability change
|
||||
#=============================================================================
|
||||
def pbOnAbilityChanged(oldAbil)
|
||||
if @effects[PBEffects::Illusion] && isConst?(oldAbil,PBAbilities,:ILLUSION)
|
||||
@effects[PBEffects::Illusion] = nil
|
||||
if !@effects[PBEffects::Transform]
|
||||
@battle.scene.pbChangePokemon(self,@pokemon)
|
||||
@battle.pbDisplay(_INTL("{1}'s {2} wore off!",pbThis,PBAbilities.getName(oldAbil)))
|
||||
@battle.pbSetSeen(self)
|
||||
end
|
||||
end
|
||||
@effects[PBEffects::GastroAcid] = false if nonNegatableAbility?
|
||||
@effects[PBEffects::SlowStart] = 0 if !isConst?(@ability,PBAbilities,:SLOWSTART)
|
||||
# Revert form if Flower Gift/Forecast was lost
|
||||
pbCheckFormOnWeatherChange
|
||||
# Check for end of primordial weather
|
||||
@battle.pbEndPrimordialWeather
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Held item consuming/removing
|
||||
#=============================================================================
|
||||
def pbCanConsumeBerry?(item,alwaysCheckGluttony=true)
|
||||
return false if @battle.pbCheckOpposingAbility(:UNNERVE,@index)
|
||||
return true if @hp<=@totalhp/4
|
||||
if alwaysCheckGluttony || NEWEST_BATTLE_MECHANICS
|
||||
return true if @hp<=@totalhp/2 && hasActiveAbility?(:GLUTTONY)
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
# permanent is whether the item is lost even after battle. Is false for Knock
|
||||
# Off.
|
||||
def pbRemoveItem(permanent=true)
|
||||
@effects[PBEffects::ChoiceBand] = -1
|
||||
@effects[PBEffects::Unburden] = true if @item>0
|
||||
setInitialItem(0) if self.initialItem==@item && permanent
|
||||
self.item = 0
|
||||
end
|
||||
|
||||
def pbConsumeItem(recoverable=true,symbiosis=true,belch=true)
|
||||
PBDebug.log("[Item consumed] #{pbThis} consumed its held #{PBItems.getName(@item)}")
|
||||
if recoverable
|
||||
setRecycleItem(@item)
|
||||
@effects[PBEffects::PickupItem] = @item
|
||||
@effects[PBEffects::PickupUse] = @battle.nextPickupUse
|
||||
end
|
||||
setBelched if belch && pbIsBerry?(@item)
|
||||
pbRemoveItem
|
||||
pbSymbiosis if symbiosis
|
||||
end
|
||||
|
||||
def pbSymbiosis
|
||||
return if fainted?
|
||||
return if @item!=0
|
||||
@battle.pbPriority(true).each do |b|
|
||||
next if b.opposes?
|
||||
next if !b.hasActiveAbility?(:SYMBIOSIS)
|
||||
next if b.item==0 || b.unlosableItem?(b.item)
|
||||
next if unlosableItem?(b.item)
|
||||
@battle.pbShowAbilitySplash(b)
|
||||
if PokeBattle_SceneConstants::USE_ABILITY_SPLASH
|
||||
@battle.pbDisplay(_INTL("{1} shared its {2} with {3}!",
|
||||
b.pbThis,b.itemName,pbThis(true)))
|
||||
else
|
||||
@battle.pbDisplay(_INTL("{1}'s {2} let it share its {3} with {4}!",
|
||||
b.pbThis,b.abilityName,b.itemName,pbThis(true)))
|
||||
end
|
||||
self.item = b.item
|
||||
b.item = 0
|
||||
b.effects[PBEffects::Unburden] = true
|
||||
@battle.pbHideAbilitySplash(b)
|
||||
pbHeldItemTriggerCheck
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
def pbHeldItemTriggered(thisItem,forcedItem=0,fling=false)
|
||||
# Cheek Pouch
|
||||
if hasActiveAbility?(:CHEEKPOUCH) && pbIsBerry?(thisItem) && canHeal?
|
||||
@battle.pbShowAbilitySplash(self)
|
||||
pbRecoverHP(@totalhp/3)
|
||||
if PokeBattle_SceneConstants::USE_ABILITY_SPLASH
|
||||
@battle.pbDisplay(_INTL("{1}'s HP was restored.",pbThis))
|
||||
else
|
||||
@battle.pbDisplay(_INTL("{1}'s {2} restored its HP.",pbThis,abilityName))
|
||||
end
|
||||
@battle.pbHideAbilitySplash(self)
|
||||
end
|
||||
pbConsumeItem if forcedItem<=0
|
||||
pbSymbiosis if forcedItem>0 && !fling # Bug Bite/Pluck users trigger Symbiosis
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Held item trigger checks
|
||||
#=============================================================================
|
||||
# NOTE: A Pokémon using Bug Bite/Pluck, and a Pokémon having an item thrown at
|
||||
# it via Fling, will gain the effect of the item even if the Pokémon is
|
||||
# affected by item-negating effects.
|
||||
# If forcedItem is -1, the Pokémon's held item is forced to be consumed. If it
|
||||
# is greater than 0, a different item (of that ID) is forced to be consumed
|
||||
# (not the Pokémon's held one).
|
||||
def pbHeldItemTriggerCheck(forcedItem=0,fling=false)
|
||||
return if fainted?
|
||||
return if forcedItem==0 && !itemActive?
|
||||
pbItemHPHealCheck(forcedItem,fling)
|
||||
pbItemStatusCureCheck(forcedItem,fling)
|
||||
pbItemEndOfMoveCheck(forcedItem,fling)
|
||||
# For Enigma Berry, Kee Berry and Maranga Berry, which have their effects
|
||||
# when forcibly consumed by Pluck/Fling.
|
||||
if forcedItem!=0
|
||||
thisItem = (forcedItem>0) ? forcedItem : @item
|
||||
if BattleHandlers.triggerTargetItemOnHitPositiveBerry(thisItem,self,@battle,true)
|
||||
pbHeldItemTriggered(thisItem,forcedItem,fling)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# forcedItem is an item ID for Pluck/Fling, and 0 otherwise. fling is for
|
||||
# Fling only.
|
||||
def pbItemHPHealCheck(forcedItem=0,fling=false)
|
||||
return if !canHeal?
|
||||
return if forcedItem==0 && !itemActive?
|
||||
thisItem = (forcedItem>0) ? forcedItem : @item
|
||||
if BattleHandlers.triggerHPHealItem(thisItem,self,@battle,(forcedItem!=0))
|
||||
pbHeldItemTriggered(thisItem,forcedItem,fling)
|
||||
elsif forcedItem==0
|
||||
pbItemTerrainStatBoostCheck
|
||||
end
|
||||
end
|
||||
|
||||
# Cures status conditions, confusion, infatuation and the other effects cured
|
||||
# by Mental Herb.
|
||||
# forcedItem is an item ID for Pluck/Fling, and 0 otherwise. fling is for
|
||||
# Fling only.
|
||||
def pbItemStatusCureCheck(forcedItem=0,fling=false)
|
||||
return if fainted?
|
||||
return if forcedItem==0 && !itemActive?
|
||||
thisItem = (forcedItem>0) ? forcedItem : @item
|
||||
if BattleHandlers.triggerStatusCureItem(thisItem,self,@battle,(forcedItem!=0))
|
||||
pbHeldItemTriggered(thisItem,forcedItem,fling)
|
||||
end
|
||||
end
|
||||
|
||||
# Called at the end of using a move.
|
||||
# forcedItem is an item ID for Pluck/Fling, and 0 otherwise. fling is for
|
||||
# Fling only.
|
||||
def pbItemEndOfMoveCheck(forcedItem=0,fling=false)
|
||||
return if fainted?
|
||||
return if forcedItem==0 && !itemActive?
|
||||
thisItem = (forcedItem>0) ? forcedItem : @item
|
||||
if BattleHandlers.triggerEndOfMoveItem(thisItem,self,@battle,(forcedItem!=0))
|
||||
pbHeldItemTriggered(thisItem,forcedItem,fling)
|
||||
elsif BattleHandlers.triggerEndOfMoveStatRestoreItem(thisItem,self,@battle,(forcedItem!=0))
|
||||
pbHeldItemTriggered(thisItem,forcedItem,fling)
|
||||
end
|
||||
end
|
||||
|
||||
# Used for White Herb (restore lowered stats). Only called by Moody and Sticky
|
||||
# Web, as all other stat reduction happens because of/during move usage and
|
||||
# this handler is also called at the end of each move's usage.
|
||||
# forcedItem is an item ID for Pluck/Fling, and 0 otherwise. fling is for
|
||||
# Fling only.
|
||||
def pbItemStatRestoreCheck(forcedItem=0,fling=false)
|
||||
return if fainted?
|
||||
return if forcedItem==0 && !itemActive?
|
||||
thisItem = (forcedItem>0) ? forcedItem : @item
|
||||
if BattleHandlers.triggerEndOfMoveStatRestoreItem(thisItem,self,@battle,(forcedItem!=0))
|
||||
pbHeldItemTriggered(thisItem,forcedItem,fling)
|
||||
end
|
||||
end
|
||||
|
||||
# Called when the battle terrain changes and when a Pokémon loses HP.
|
||||
# forcedItem is an item ID for Pluck/Fling, and 0 otherwise. fling is for
|
||||
# Fling only.
|
||||
def pbItemTerrainStatBoostCheck
|
||||
return if !itemActive?
|
||||
if BattleHandlers.triggerTerrainStatBoostItem(@item,self,@battle)
|
||||
pbHeldItemTriggered(@item)
|
||||
end
|
||||
end
|
||||
|
||||
# Used for Adrenaline Orb. Called when Intimidate is triggered (even if
|
||||
# Intimidate has no effect on the Pokémon).
|
||||
# forcedItem is an item ID for Pluck/Fling, and 0 otherwise. fling is for
|
||||
# Fling only.
|
||||
def pbItemOnIntimidatedCheck
|
||||
return if !itemActive?
|
||||
if BattleHandlers.triggerItemOnIntimidated(@item,self,@battle)
|
||||
pbHeldItemTriggered(@item)
|
||||
end
|
||||
end
|
||||
end
|
||||
729
Data/Scripts/011_Battle/001_Battler/007_Battler_UseMove.rb
Normal file
729
Data/Scripts/011_Battle/001_Battler/007_Battler_UseMove.rb
Normal file
@@ -0,0 +1,729 @@
|
||||
class PokeBattle_Battler
|
||||
#=============================================================================
|
||||
# Turn processing
|
||||
#=============================================================================
|
||||
def pbProcessTurn(choice,tryFlee=true)
|
||||
return false if fainted?
|
||||
# Wild roaming Pokémon always flee if possible
|
||||
if tryFlee && @battle.wildBattle? && opposes? &&
|
||||
@battle.rules["alwaysflee"] && @battle.pbCanRun?(@index)
|
||||
pbBeginTurn(choice)
|
||||
@battle.pbDisplay(_INTL("{1} fled from battle!",pbThis)) { pbSEPlay("Battle flee") }
|
||||
@battle.decision = 3
|
||||
pbEndTurn(choice)
|
||||
return true
|
||||
end
|
||||
# Shift with the battler next to this one
|
||||
if choice[0]==:Shift
|
||||
idxOther = -1
|
||||
case @battle.pbSideSize(@index)
|
||||
when 2
|
||||
idxOther = (@index+2)%4
|
||||
when 3
|
||||
if @index!=2 && @index!=3 # If not in middle spot already
|
||||
idxOther = ((@index%2)==0) ? 2 : 3
|
||||
end
|
||||
end
|
||||
if idxOther>=0
|
||||
@battle.pbSwapBattlers(@index,idxOther)
|
||||
case @battle.pbSideSize(@index)
|
||||
when 2
|
||||
@battle.pbDisplay(_INTL("{1} moved across!",pbThis))
|
||||
when 3
|
||||
@battle.pbDisplay(_INTL("{1} moved to the center!",pbThis))
|
||||
end
|
||||
end
|
||||
pbBeginTurn(choice)
|
||||
pbCancelMoves
|
||||
@lastRoundMoved = @battle.turnCount # Done something this round
|
||||
return true
|
||||
end
|
||||
# If this battler's action for this round wasn't "use a move"
|
||||
if choice[0]!=:UseMove
|
||||
# Clean up effects that end at battler's turn
|
||||
pbBeginTurn(choice)
|
||||
pbEndTurn(choice)
|
||||
return false
|
||||
end
|
||||
# Turn is skipped if Pursuit was used during switch
|
||||
if @effects[PBEffects::Pursuit]
|
||||
@effects[PBEffects::Pursuit] = false
|
||||
pbCancelMoves
|
||||
pbEndTurn(choice)
|
||||
@battle.pbJudge
|
||||
return false
|
||||
end
|
||||
# Use the move
|
||||
PBDebug.log("[Move usage] #{pbThis} started using #{choice[2].name}")
|
||||
PBDebug.logonerr{
|
||||
pbUseMove(choice,choice[2]==@battle.struggle)
|
||||
}
|
||||
@battle.pbJudge
|
||||
# Update priority order
|
||||
# @battle.pbCalculatePriority if NEWEST_BATTLE_MECHANICS
|
||||
return true
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
#
|
||||
#=============================================================================
|
||||
def pbBeginTurn(choice)
|
||||
# Cancel some lingering effects which only apply until the user next moves
|
||||
@effects[PBEffects::BeakBlast] = false
|
||||
@effects[PBEffects::DestinyBondPrevious] = @effects[PBEffects::DestinyBond]
|
||||
@effects[PBEffects::DestinyBond] = false
|
||||
@effects[PBEffects::Grudge] = false
|
||||
@effects[PBEffects::MoveNext] = false
|
||||
@effects[PBEffects::Quash] = 0
|
||||
@effects[PBEffects::ShellTrap] = false
|
||||
# Encore's effect ends if the encored move is no longer available
|
||||
if @effects[PBEffects::Encore]>0 && pbEncoredMoveIndex<0
|
||||
@effects[PBEffects::Encore] = 0
|
||||
@effects[PBEffects::EncoreMove] = 0
|
||||
end
|
||||
end
|
||||
|
||||
# Called when the usage of various multi-turn moves is disrupted due to
|
||||
# failing pbTryUseMove, being ineffective against all targets, or because
|
||||
# Pursuit was used specially to intercept a switching foe.
|
||||
# Cancels the use of multi-turn moves and counters thereof. Note that Hyper
|
||||
# Beam's effect is NOT cancelled.
|
||||
def pbCancelMoves
|
||||
# Outragers get confused anyway if they are disrupted during their final
|
||||
# turn of using the move
|
||||
if @effects[PBEffects::Outrage]==1 && pbCanConfuseSelf?(false)
|
||||
pbConfuse(_INTL("{1} became confused due to fatigue!",pbThis))
|
||||
end
|
||||
# Cancel usage of most multi-turn moves
|
||||
@effects[PBEffects::TwoTurnAttack] = 0
|
||||
@effects[PBEffects::Rollout] = 0
|
||||
@effects[PBEffects::Outrage] = 0
|
||||
@effects[PBEffects::Uproar] = 0
|
||||
@effects[PBEffects::Bide] = 0
|
||||
@currentMove = 0
|
||||
# Reset counters for moves which increase them when used in succession
|
||||
@effects[PBEffects::FuryCutter] = 0
|
||||
end
|
||||
|
||||
def pbEndTurn(choice)
|
||||
@lastRoundMoved = @battle.turnCount # Done something this round
|
||||
if @effects[PBEffects::ChoiceBand]<0 &&
|
||||
hasActiveItem?([:CHOICEBAND,:CHOICESPECS,:CHOICESCARF])
|
||||
if @lastMoveUsed>=0 && pbHasMove?(@lastMoveUsed)
|
||||
@effects[PBEffects::ChoiceBand] = @lastMoveUsed
|
||||
elsif @lastRegularMoveUsed>=0 && pbHasMove?(@lastRegularMoveUsed)
|
||||
@effects[PBEffects::ChoiceBand] = @lastRegularMoveUsed
|
||||
end
|
||||
end
|
||||
@effects[PBEffects::Charge] = 0 if @effects[PBEffects::Charge]==1
|
||||
@effects[PBEffects::GemConsumed] = 0
|
||||
@battle.eachBattler { |b| b.pbContinualAbilityChecks } # Trace, end primordial weathers
|
||||
end
|
||||
|
||||
def pbConfusionDamage(msg)
|
||||
@damageState.reset
|
||||
@damageState.initialHP = @hp
|
||||
confusionMove = PokeBattle_Confusion.new(@battle,nil)
|
||||
confusionMove.calcType = confusionMove.pbCalcType(self) # -1
|
||||
@damageState.typeMod = confusionMove.pbCalcTypeMod(confusionMove.calcType,self,self) # 8
|
||||
confusionMove.pbCheckDamageAbsorption(self,self)
|
||||
confusionMove.pbCalcDamage(self,self)
|
||||
confusionMove.pbReduceDamage(self,self)
|
||||
self.hp -= @damageState.hpLost
|
||||
confusionMove.pbAnimateHitAndHPLost(self,[self])
|
||||
@battle.pbDisplay(msg) # "It hurt itself in its confusion!"
|
||||
confusionMove.pbRecordDamageLost(self,self)
|
||||
confusionMove.pbEndureKOMessage(self)
|
||||
pbFaint if fainted?
|
||||
pbItemHPHealCheck
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Simple "use move" method, used when a move calls another move and for Future
|
||||
# Sight's attack
|
||||
#=============================================================================
|
||||
def pbUseMoveSimple(moveID,target=-1,idxMove=-1,specialUsage=true)
|
||||
choice = []
|
||||
choice[0] = :UseMove # "Use move"
|
||||
choice[1] = idxMove # Index of move to be used in user's moveset
|
||||
if idxMove>=0
|
||||
choice[2] = @moves[idxMove]
|
||||
else
|
||||
choice[2] = PokeBattle_Move.pbFromPBMove(@battle,PBMove.new(moveID)) # PokeBattle_Move object
|
||||
choice[2].pp = -1
|
||||
end
|
||||
choice[3] = target # Target (-1 means no target yet)
|
||||
PBDebug.log("[Move usage] #{pbThis} started using the called/simple move #{choice[2].name}")
|
||||
pbUseMove(choice,specialUsage)
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Master "use move" method
|
||||
#=============================================================================
|
||||
def pbUseMove(choice,specialUsage=false)
|
||||
# NOTE: This is intentionally determined before a multi-turn attack can
|
||||
# set specialUsage to true.
|
||||
skipAccuracyCheck = (specialUsage && choice[2]!=@battle.struggle)
|
||||
# Start using the move
|
||||
pbBeginTurn(choice)
|
||||
# Force the use of certain moves if they're already being used
|
||||
if usingMultiTurnAttack?
|
||||
choice[2] = PokeBattle_Move.pbFromPBMove(@battle,PBMove.new(@currentMove))
|
||||
specialUsage = true
|
||||
elsif @effects[PBEffects::Encore]>0 && choice[1]>=0 &&
|
||||
@battle.pbCanShowCommands?(@index)
|
||||
idxEncoredMove = pbEncoredMoveIndex
|
||||
if idxEncoredMove>=0 && @battle.pbCanChooseMove?(@index,idxEncoredMove,false)
|
||||
if choice[1]!=idxEncoredMove # Change move if battler was Encored mid-round
|
||||
choice[1] = idxEncoredMove
|
||||
choice[2] = @moves[idxEncoredMove]
|
||||
choice[3] = -1 # No target chosen
|
||||
end
|
||||
end
|
||||
end
|
||||
# Labels the move being used as "move"
|
||||
move = choice[2]
|
||||
return if !move || move.id==0 # if move was not chosen somehow
|
||||
# Try to use the move (inc. disobedience)
|
||||
@lastMoveFailed = false
|
||||
if !pbTryUseMove(choice,move,specialUsage,skipAccuracyCheck)
|
||||
@lastMoveUsed = -1
|
||||
@lastMoveUsedType = -1
|
||||
if !specialUsage
|
||||
@lastRegularMoveUsed = -1
|
||||
@lastRegularMoveTarget = -1
|
||||
end
|
||||
@battle.pbGainExp # In case self is KO'd due to confusion
|
||||
pbCancelMoves
|
||||
pbEndTurn(choice)
|
||||
return
|
||||
end
|
||||
move = choice[2] # In case disobedience changed the move to be used
|
||||
return if !move || move.id==0 # if move was not chosen somehow
|
||||
# Subtract PP
|
||||
if !specialUsage
|
||||
if !pbReducePP(move)
|
||||
@battle.pbDisplay(_INTL("{1} used {2}!",pbThis,move.name))
|
||||
@battle.pbDisplay(_INTL("But there was no PP left for the move!"))
|
||||
@lastMoveUsed = -1
|
||||
@lastMoveUsedType = -1
|
||||
@lastRegularMoveUsed = -1
|
||||
@lastRegularMoveTarget = -1
|
||||
@lastMoveFailed = true
|
||||
pbCancelMoves
|
||||
pbEndTurn(choice)
|
||||
return
|
||||
end
|
||||
end
|
||||
# Stance Change
|
||||
if isConst?(@species,PBSpecies,:AEGISLASH) && isConst?(@ability,PBAbilities,:STANCECHANGE)
|
||||
if move.damagingMove?
|
||||
pbChangeForm(1,_INTL("{1} changed to Blade Forme!",pbThis))
|
||||
elsif isConst?(move.id,PBMoves,:KINGSSHIELD)
|
||||
pbChangeForm(0,_INTL("{1} changed to Shield Forme!",pbThis))
|
||||
end
|
||||
end
|
||||
# Calculate the move's type during this usage
|
||||
move.calcType = move.pbCalcType(self)
|
||||
# Start effect of Mold Breaker
|
||||
@battle.moldBreaker = hasMoldBreaker?
|
||||
# Remember that user chose a two-turn move
|
||||
if move.pbIsChargingTurn?(self)
|
||||
# Beginning the use of a two-turn attack
|
||||
@effects[PBEffects::TwoTurnAttack] = move.id
|
||||
@currentMove = move.id
|
||||
else
|
||||
@effects[PBEffects::TwoTurnAttack] = 0 # Cancel use of two-turn attack
|
||||
end
|
||||
# Add to counters for moves which increase them when used in succession
|
||||
move.pbChangeUsageCounters(self,specialUsage)
|
||||
# Charge up Metronome item
|
||||
if hasActiveItem?(:METRONOME) && !move.callsAnotherMove?
|
||||
if @lastMoveUsed==move.id && !@lastMoveFailed
|
||||
@effects[PBEffects::Metronome] += 1
|
||||
else
|
||||
@effects[PBEffects::Metronome] = 0
|
||||
end
|
||||
end
|
||||
# Record move as having been used
|
||||
@lastMoveUsed = move.id
|
||||
@lastMoveUsedType = move.calcType # For Conversion 2
|
||||
if !specialUsage
|
||||
@lastRegularMoveUsed = move.id # For Disable, Encore, Instruct, Mimic, Mirror Move, Sketch, Spite
|
||||
@lastRegularMoveTarget = choice[3] # For Instruct (remembering original target is fine)
|
||||
@movesUsed.push(move.id) if !@movesUsed.include?(move.id) # For Last Resort
|
||||
end
|
||||
@battle.lastMoveUsed = move.id # For Copycat
|
||||
@battle.lastMoveUser = @index # For "self KO" battle clause to avoid draws
|
||||
@battle.successStates[@index].useState = 1 # Battle Arena - assume failure
|
||||
# Find the default user (self or Snatcher) and target(s)
|
||||
user = pbFindUser(choice,move)
|
||||
user = pbChangeUser(choice,move,user)
|
||||
targets = pbFindTargets(choice,move,user)
|
||||
targets = pbChangeTargets(move,user,targets)
|
||||
# Pressure
|
||||
if !specialUsage
|
||||
targets.each do |b|
|
||||
next unless b.opposes?(user) && b.hasActiveAbility?(:PRESSURE)
|
||||
PBDebug.log("[Ability triggered] #{b.pbThis}'s #{b.abilityName}")
|
||||
user.pbReducePP(move)
|
||||
end
|
||||
if PBTargets.targetsFoeSide?(move.pbTarget(user))
|
||||
@battle.eachOtherSideBattler(user) do |b|
|
||||
next unless b.hasActiveAbility?(:PRESSURE)
|
||||
PBDebug.log("[Ability triggered] #{b.pbThis}'s #{b.abilityName}")
|
||||
user.pbReducePP(move)
|
||||
end
|
||||
end
|
||||
end
|
||||
# Dazzling/Queenly Majesty make the move fail here
|
||||
@battle.pbPriority(true).each do |b|
|
||||
next if !b || !b.abilityActive?
|
||||
if BattleHandlers.triggerMoveBlockingAbility(b.ability,b,user,targets,move,@battle)
|
||||
@battle.pbDisplayBrief(_INTL("{1} used {2}!",user.pbThis,move.name))
|
||||
@battle.pbShowAbilitySplash(b)
|
||||
@battle.pbDisplay(_INTL("{1} cannot use {2}!",user.pbThis,move.name))
|
||||
@battle.pbHideAbilitySplash(b)
|
||||
user.lastMoveFailed = true
|
||||
pbCancelMoves
|
||||
pbEndTurn(choice)
|
||||
return
|
||||
end
|
||||
end
|
||||
# "X used Y!" message
|
||||
# Can be different for Bide, Fling, Focus Punch and Future Sight
|
||||
# NOTE: This intentionally passes self rather than user. The user is always
|
||||
# self except if Snatched, but this message should state the original
|
||||
# user (self) even if the move is Snatched.
|
||||
move.pbDisplayUseMessage(self)
|
||||
# Snatch's message (user is the new user, self is the original user)
|
||||
if move.snatched
|
||||
@lastMoveFailed = true # Intentionally applies to self, not user
|
||||
@battle.pbDisplay(_INTL("{1} snatched {2}'s move!",user.pbThis,pbThis(true)))
|
||||
end
|
||||
# "But it failed!" checks
|
||||
if move.pbMoveFailed?(user,targets)
|
||||
PBDebug.log(sprintf("[Move failed] In function code %s's def pbMoveFailed?",move.function))
|
||||
user.lastMoveFailed = true
|
||||
pbCancelMoves
|
||||
pbEndTurn(choice)
|
||||
return
|
||||
end
|
||||
# Perform set-up actions and display messages
|
||||
# Messages include Magnitude's number and Pledge moves' "it's a combo!"
|
||||
move.pbOnStartUse(user,targets)
|
||||
# Self-thawing due to the move
|
||||
if user.status==PBStatuses::FROZEN && move.thawsUser?
|
||||
user.pbCureStatus(false)
|
||||
@battle.pbDisplay(_INTL("{1} melted the ice!",user.pbThis))
|
||||
end
|
||||
# Powder
|
||||
if user.effects[PBEffects::Powder] && isConst?(move.calcType,PBTypes,:FIRE)
|
||||
@battle.pbCommonAnimation("Powder",user)
|
||||
@battle.pbDisplay(_INTL("When the flame touched the powder on the Pokémon, it exploded!"))
|
||||
user.lastMoveFailed = true
|
||||
w = @battle.pbWeather
|
||||
if w!=PBWeather.RAINDANCE && w!=PBWeather.HEAVYRAIN && user.takesIndirectDamage?
|
||||
oldHP = user.hp
|
||||
user.pbReduceHP((user.totalhp/4.0).round,false)
|
||||
user.pbFaint if user.fainted?
|
||||
@battle.pbGainExp # In case user is KO'd by this
|
||||
user.pbItemHPHealCheck
|
||||
if user.pbAbilitiesOnDamageTaken(oldHP)
|
||||
user.pbEffectsOnSwitchIn(true)
|
||||
end
|
||||
end
|
||||
pbCancelMoves
|
||||
pbEndTurn(choice)
|
||||
return
|
||||
end
|
||||
# Primordial Sea, Desolate Land
|
||||
if move.damagingMove?
|
||||
case @battle.pbWeather
|
||||
when PBWeather::HeavyRain
|
||||
if isConst?(move.calcType,PBTypes,:FIRE)
|
||||
@battle.pbDisplay(_INTL("The Fire-type attack fizzled out in the heavy rain!"))
|
||||
user.lastMoveFailed = true
|
||||
pbCancelMoves
|
||||
pbEndTurn(choice)
|
||||
return
|
||||
end
|
||||
when PBWeather::HarshSun
|
||||
if isConst?(move.calcType,PBTypes,:WATER)
|
||||
@battle.pbDisplay(_INTL("The Water-type attack evaporated in the harsh sunlight!"))
|
||||
user.lastMoveFailed = true
|
||||
pbCancelMoves
|
||||
pbEndTurn(choice)
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
# Protean
|
||||
if user.hasActiveAbility?(:PROTEAN) && !move.callsAnotherMove? && !move.snatched
|
||||
if user.pbHasOtherType?(moveType) && !PBTypes.isPseudoType?(move.calcType)
|
||||
@battle.pbShowAbilitySplash(user)
|
||||
user.pbChangeTypes(move.calcType)
|
||||
typeName = PBTypes.getName(move.calcType)
|
||||
@battle.pbDisplay(_INTL("{1} transformed into the {2} type!",user.pbThis,typeName))
|
||||
@battle.pbHideAbilitySplash(user)
|
||||
# NOTE: The GF games say that if Curse is used by a non-Ghost-type
|
||||
# Pokémon which becomes Ghost-type because of Protean, it should
|
||||
# target and curse itself. I think this is silly, so I'm making it
|
||||
# choose a random opponent to curse instead.
|
||||
if move.function=="10D" && targets.length==0 # Curse
|
||||
choice[3] = -1
|
||||
targets = pbFindTargets(choice,move,user)
|
||||
end
|
||||
end
|
||||
end
|
||||
#---------------------------------------------------------------------------
|
||||
magicCoater = -1
|
||||
magicBouncer = -1
|
||||
if targets.length==0 && !PBTargets.noTargets?(move.pbTarget(user)) &&
|
||||
!move.worksWithNoTargets?
|
||||
# def pbFindTargets should have found a target(s), but it didn't because
|
||||
# they were all fainted
|
||||
# All target types except: None, User, UserSide, FoeSide, BothSides
|
||||
@battle.pbDisplay(_INTL("But there was no target..."))
|
||||
user.lastMoveFailed = true
|
||||
else # We have targets, or move doesn't use targets
|
||||
# Reset whole damage state, perform various success checks (not accuracy)
|
||||
user.initialHP = user.hp
|
||||
targets.each do |b|
|
||||
b.damageState.reset
|
||||
b.damageState.initialHP = b.hp
|
||||
if !pbSuccessCheckAgainstTarget(move,user,b)
|
||||
b.damageState.unaffected = true
|
||||
end
|
||||
end
|
||||
# Magic Coat/Magic Bounce checks (for moves which don't target Pokémon)
|
||||
if targets.length==0 && move.canMagicCoat?
|
||||
@battle.pbPriority(true).each do |b|
|
||||
next if b.fainted? || !b.opposes?(user)
|
||||
next if b.semiInvulnerable?
|
||||
if b.effects[PBEffects::MagicCoat]
|
||||
magicCoater = b.index
|
||||
b.effects[PBEffects::MagicCoat] = false
|
||||
break
|
||||
elsif b.hasActiveAbility?(:MAGICBOUNCE) && !@battle.moldBreaker &&
|
||||
!b.effects[PBEffects::MagicBounce]
|
||||
magicBouncer = b.index
|
||||
b.effects[PBEffects::MagicBounce] = true
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
# Get the number of hits
|
||||
numHits = move.pbNumHits(user,targets)
|
||||
# Process each hit in turn
|
||||
realNumHits = 0
|
||||
for i in 0...numHits
|
||||
break if magicCoater>=0 || magicBouncer>=0
|
||||
success = pbProcessMoveHit(move,user,targets,i,skipAccuracyCheck)
|
||||
if !success
|
||||
if i==0 && targets.length>0
|
||||
hasFailed = false
|
||||
targets.each do |t|
|
||||
next if t.damageState.protected
|
||||
hasFailed = t.damageState.unaffected
|
||||
break if !t.damageState.unaffected
|
||||
end
|
||||
user.lastMoveFailed = hasFailed
|
||||
end
|
||||
break
|
||||
end
|
||||
realNumHits += 1
|
||||
break if user.fainted?
|
||||
break if user.status==PBStatuses::SLEEP || user.status==PBStatuses::FROZEN
|
||||
# NOTE: If a multi-hit move becomes disabled partway through doing those
|
||||
# hits (e.g. by Cursed Body), the rest of the hits continue as
|
||||
# normal.
|
||||
notFainted = false
|
||||
break if !targets.any? { |t| !t.fainted? } # All targets are fainted
|
||||
end
|
||||
# Battle Arena only - attack is successful
|
||||
@battle.successStates[user.index].useState = 2
|
||||
if targets.length>0
|
||||
@battle.successStates[user.index].typeMod = 0
|
||||
targets.each do |b|
|
||||
next if b.damageState.unaffected
|
||||
@battle.successStates[user.index].typeMod += b.damageState.typeMod
|
||||
end
|
||||
end
|
||||
# Effectiveness message for multi-hit moves
|
||||
# NOTE: No move is both multi-hit and multi-target, and the messages below
|
||||
# aren't quite right for such a hypothetical move.
|
||||
if numHits>1
|
||||
if move.damagingMove?
|
||||
targets.each do |b|
|
||||
next if b.damageState.unaffected || b.damageState.substitute
|
||||
move.pbEffectivenessMessage(user,b,targets.length)
|
||||
end
|
||||
end
|
||||
if realNumHits==1
|
||||
@battle.pbDisplay(_INTL("Hit 1 time!"))
|
||||
elsif realNumHits>1
|
||||
@battle.pbDisplay(_INTL("Hit {1} times!",realNumHits))
|
||||
end
|
||||
end
|
||||
# Magic Coat's bouncing back (move has targets)
|
||||
targets.each do |b|
|
||||
next if b.fainted?
|
||||
next if !b.damageState.magicCoat && !b.damageState.magicBounce
|
||||
@battle.pbShowAbilitySplash(b) if b.damageState.magicBounce
|
||||
@battle.pbDisplay(_INTL("{1} bounced the {2} back!",b.pbThis,move.name))
|
||||
@battle.pbHideAbilitySplash(b) if b.damageState.magicBounce
|
||||
newChoice = choice.clone
|
||||
newChoice[3] = user.index
|
||||
newTargets = pbFindTargets(newChoice,move,b)
|
||||
newTargets = pbChangeTargets(move,b,newTargets)
|
||||
success = pbProcessMoveHit(move,b,newTargets,0,false)
|
||||
b.lastMoveFailed = true if !success
|
||||
targets.each { |b| b.pbFaint if b && b.fainted? }
|
||||
user.pbFaint if user.fainted?
|
||||
end
|
||||
# Magic Coat's bouncing back (move has no targets)
|
||||
if magicCoater>=0 || magicBouncer>=0
|
||||
mc = @battle.battlers[(magicCoater>=0) ? magicCoater : magicBouncer]
|
||||
if !mc.fainted?
|
||||
user.lastMoveFailed = true
|
||||
@battle.pbShowAbilitySplash(mc) if magicBouncer>=0
|
||||
@battle.pbDisplay(_INTL("{1} bounced the {2} back!",mc.pbThis,move.name))
|
||||
@battle.pbHideAbilitySplash(mc) if magicBouncer>=0
|
||||
success = pbProcessMoveHit(move,mc,[],0,false)
|
||||
mc.lastMoveFailed = true if !success
|
||||
targets.each { |b| b.pbFaint if b && b.fainted? }
|
||||
user.pbFaint if user.fainted?
|
||||
end
|
||||
end
|
||||
# Move-specific effects after all hits
|
||||
targets.each { |b| move.pbEffectAfterAllHits(user,b) }
|
||||
# Faint if 0 HP
|
||||
targets.each { |b| b.pbFaint if b && b.fainted? }
|
||||
user.pbFaint if user.fainted?
|
||||
# External/general effects after all hits. Eject Button, Shell Bell, etc.
|
||||
pbEffectsAfterMove(user,targets,move,realNumHits)
|
||||
end
|
||||
# End effect of Mold Breaker
|
||||
@battle.moldBreaker = false
|
||||
# Gain Exp
|
||||
@battle.pbGainExp
|
||||
# Battle Arena only - update skills
|
||||
@battle.eachBattler { |b| @battle.successStates[b.index].updateSkill }
|
||||
# Shadow Pokémon triggering Hyper Mode
|
||||
pbHyperMode if @battle.choices[@index][0]!=:None # Not if self is replaced
|
||||
# End of move usage
|
||||
pbEndTurn(choice)
|
||||
# Instruct
|
||||
@battle.eachBattler do |b|
|
||||
next if !b.effects[PBEffects::Instruct]
|
||||
b.effects[PBEffects::Instruct] = false
|
||||
idxMove = -1
|
||||
b.eachMoveWithIndex { |m,i| idxMove = i if m.id==b.lastMoveUsed }
|
||||
next if idxMove<0
|
||||
oldLastRoundMoved = b.lastRoundMoved
|
||||
@battle.pbDisplay(_INTL("{1} used the move instructed by {2}!",b.pbThis,user.pbThis(true)))
|
||||
PBDebug.logonerr{
|
||||
b.effects[PBEffects::Instructed] = true
|
||||
b.pbUseMoveSimple(b.lastMoveUsed,b.lastRegularMoveTarget,idxMove,false)
|
||||
b.effects[PBEffects::Instructed] = false
|
||||
}
|
||||
b.lastRoundMoved = oldLastRoundMoved
|
||||
@battle.pbJudge
|
||||
return if @battle.decision>0
|
||||
end
|
||||
# Dancer
|
||||
if !@effects[PBEffects::Dancer] && !user.lastMoveFailed && realNumHits>0 &&
|
||||
!move.snatched && magicCoater<0 && @battle.pbCheckGlobalAbility(:DANCER)
|
||||
dancers = []
|
||||
@battle.pbPriority(true).each do |b|
|
||||
dancers.push(b) if b.index!=user.index && b.hasActiveAbility?(:DANCER)
|
||||
end
|
||||
while dancers.length>0
|
||||
nextUser = dancers.pop
|
||||
oldLastRoundMoved = nextUser.lastRoundMoved
|
||||
# NOTE: Petal Dance being used because of Dancer shouldn't lock the
|
||||
# Dancer into using that move, and shouldn't contribute to its
|
||||
# turn counter if it's already locked into Petal Dance.
|
||||
oldOutrage = nextUser.effects[PBEffects::Outrage]
|
||||
nextUser.effects[PBEffects::Outrage] += 1 if nextUser.effects[PBEffects::Outrage]>0
|
||||
oldCurrentMove = nextUser.currentMove
|
||||
preTarget = choice[3]
|
||||
preTarget = user.index if nextUser.opposes?(user) || !nextUser.opposes?(preTarget)
|
||||
@battle.pbShowAbilitySplash(nextUser,true)
|
||||
@battle.pbHideAbilitySplash(nextUser)
|
||||
if !PokeBattle_SceneConstants::USE_ABILITY_SPLASH
|
||||
@battle.pbDisplay(_INTL("{1} kept the dance going with {2}!",
|
||||
nextUser.pbThis,nextUser.abilityName))
|
||||
end
|
||||
PBDebug.logonerr{
|
||||
nextUser.effects[PBEffects::Dancer] = true
|
||||
nextUser.pbUseMoveSimple(move.id,preTarget)
|
||||
nextUser.effects[PBEffects::Dancer] = false
|
||||
}
|
||||
nextUser.lastRoundMoved = oldLastRoundMoved
|
||||
nextUser.effects[PBEffects::Outrage] = oldOutrage
|
||||
nextUser.currentMove = oldCurrentMove
|
||||
@battle.pbJudge
|
||||
return if @battle.decision>0
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Attack a single target
|
||||
#=============================================================================
|
||||
def pbProcessMoveHit(move,user,targets,hitNum,skipAccuracyCheck)
|
||||
return false if user.fainted?
|
||||
# For two-turn attacks being used in a single turn
|
||||
move.pbInitialEffect(user,targets,hitNum)
|
||||
numTargets = 0 # Number of targets that are affected by this hit
|
||||
targets.each { |b| b.damageState.resetPerHit }
|
||||
# Count a hit for Parental Bond (if it applies)
|
||||
user.effects[PBEffects::ParentalBond] -= 1 if user.effects[PBEffects::ParentalBond]>0
|
||||
# Accuracy check (accuracy/evasion calc)
|
||||
if hitNum==0 || move.successCheckPerHit?
|
||||
targets.each do |b|
|
||||
next if b.damageState.unaffected
|
||||
if pbSuccessCheckPerHit(move,user,b,skipAccuracyCheck)
|
||||
numTargets += 1
|
||||
else
|
||||
b.damageState.missed = true
|
||||
b.damageState.unaffected = true
|
||||
end
|
||||
end
|
||||
# If failed against all targets
|
||||
if targets.length>0 && numTargets==0 && !move.worksWithNoTargets?
|
||||
targets.each do |b|
|
||||
next if !b.damageState.missed || b.damageState.magicCoat
|
||||
pbMissMessage(move,user,b)
|
||||
end
|
||||
move.pbCrashDamage(user)
|
||||
user.pbItemHPHealCheck
|
||||
pbCancelMoves
|
||||
return false
|
||||
end
|
||||
end
|
||||
# If we get here, this hit will happen and do something
|
||||
#---------------------------------------------------------------------------
|
||||
# Calculate damage to deal
|
||||
if move.pbDamagingMove?
|
||||
targets.each do |b|
|
||||
next if b.damageState.unaffected
|
||||
# Check whether Substitute/Disguise will absorb the damage
|
||||
move.pbCheckDamageAbsorption(user,b)
|
||||
# Calculate the damage against b
|
||||
# pbCalcDamage shows the "eat berry" animation for SE-weakening
|
||||
# berries, although the message about it comes after the additional
|
||||
# effect below
|
||||
move.pbCalcDamage(user,b,targets.length) # Stored in damageState.calcDamage
|
||||
# Lessen damage dealt because of False Swipe/Endure/etc.
|
||||
move.pbReduceDamage(user,b) # Stored in damageState.hpLost
|
||||
end
|
||||
end
|
||||
# Show move animation (for this hit)
|
||||
move.pbShowAnimation(move.id,user,targets,hitNum)
|
||||
# Type-boosting Gem consume animation/message
|
||||
if user.effects[PBEffects::GemConsumed]>0 && hitNum==0
|
||||
# NOTE: The consume animation and message for Gems are shown now, but the
|
||||
# actual removal of the item happens in def pbEffectsAfterMove.
|
||||
@battle.pbCommonAnimation("UseItem",user)
|
||||
@battle.pbDisplay(_INTL("The {1} strengthened {2}'s power!",
|
||||
PBItems.getName(user.effects[PBEffects::GemConsumed]),move.name))
|
||||
end
|
||||
# Messages about missed target(s) (relevant for multi-target moves only)
|
||||
targets.each do |b|
|
||||
next if !b.damageState.missed
|
||||
pbMissMessage(move,user,b)
|
||||
end
|
||||
# Deal the damage (to all allies first simultaneously, then all foes
|
||||
# simultaneously)
|
||||
if move.pbDamagingMove?
|
||||
# This just changes the HP amounts and does nothing else
|
||||
targets.each do |b|
|
||||
next if b.damageState.unaffected
|
||||
move.pbInflictHPDamage(b)
|
||||
end
|
||||
# Animate the hit flashing and HP bar changes
|
||||
move.pbAnimateHitAndHPLost(user,targets)
|
||||
end
|
||||
# Self-Destruct/Explosion's damaging and fainting of user
|
||||
move.pbSelfKO(user) if hitNum==0
|
||||
user.pbFaint if user.fainted?
|
||||
if move.pbDamagingMove?
|
||||
targets.each do |b|
|
||||
next if b.damageState.unaffected
|
||||
# NOTE: This method is also used for the OKHO special message.
|
||||
move.pbHitEffectivenessMessages(user,b,targets.length)
|
||||
# Record data about the hit for various effects' purposes
|
||||
move.pbRecordDamageLost(user,b)
|
||||
end
|
||||
# Close Combat/Superpower's stat-lowering, Flame Burst's splash damage,
|
||||
# and Incinerate's berry destruction
|
||||
targets.each do |b|
|
||||
next if b.damageState.unaffected
|
||||
move.pbEffectWhenDealingDamage(user,b)
|
||||
end
|
||||
# Ability/item effects such as Static/Rocky Helmet, and Grudge, etc.
|
||||
targets.each do |b|
|
||||
next if b.damageState.unaffected
|
||||
pbEffectsOnMakingHit(move,user,b)
|
||||
end
|
||||
# Disguise/Endure/Sturdy/Focus Sash/Focus Band messages
|
||||
targets.each do |b|
|
||||
next if b.damageState.unaffected
|
||||
move.pbEndureKOMessage(b)
|
||||
end
|
||||
# HP-healing held items (checks all battlers rather than just targets
|
||||
# because Flame Burst's splash damage affects non-targets)
|
||||
@battle.pbPriority(true).each { |b| b.pbItemHPHealCheck }
|
||||
# Animate battlers fainting (checks all battlers rather than just targets
|
||||
# because Flame Burst's splash damage affects non-targets)
|
||||
@battle.pbPriority(true).each { |b| b.pbFaint if b && b.fainted? }
|
||||
end
|
||||
@battle.pbJudgeCheckpoint(user,move)
|
||||
# Main effect (recoil/drain, etc.)
|
||||
targets.each do |b|
|
||||
next if b.damageState.unaffected
|
||||
move.pbEffectAgainstTarget(user,b)
|
||||
end
|
||||
move.pbEffectGeneral(user)
|
||||
targets.each { |b| b.pbFaint if b && b.fainted? }
|
||||
user.pbFaint if user.fainted?
|
||||
# Additional effect
|
||||
if !user.hasActiveAbility?(:SHEERFORCE)
|
||||
targets.each do |b|
|
||||
next if b.damageState.calcDamage==0
|
||||
chance = move.pbAdditionalEffectChance(user,b)
|
||||
next if chance<=0
|
||||
if @battle.pbRandom(100)<chance
|
||||
move.pbAdditionalEffect(user,b)
|
||||
end
|
||||
end
|
||||
end
|
||||
# Make the target flinch (because of an item/ability)
|
||||
targets.each do |b|
|
||||
next if b.fainted?
|
||||
next if b.damageState.calcDamage==0 || b.damageState.substitute
|
||||
chance = move.pbFlinchChance(user,b)
|
||||
next if chance<=0
|
||||
if @battle.pbRandom(100)<chance
|
||||
PBDebug.log("[Item/ability triggered] #{user.pbThis}'s King's Rock/Razor Fang or Stench")
|
||||
b.pbFlinch(user)
|
||||
end
|
||||
end
|
||||
# Message for and consuming of type-weakening berries
|
||||
# NOTE: The "consume held item" animation for type-weakening berries occurs
|
||||
# during pbCalcDamage above (before the move's animation), but the
|
||||
# message about it only shows here.
|
||||
targets.each do |b|
|
||||
next if b.damageState.unaffected
|
||||
next if !b.damageState.berryWeakened
|
||||
@battle.pbDisplay(_INTL("The {1} weakened the damage to {2}!",b.itemName,b.pbThis(true)))
|
||||
b.pbConsumeItem
|
||||
end
|
||||
targets.each { |b| b.pbFaint if b && b.fainted? }
|
||||
user.pbFaint if user.fainted?
|
||||
return true
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,193 @@
|
||||
class PokeBattle_Battler
|
||||
#=============================================================================
|
||||
# Get move's user
|
||||
#=============================================================================
|
||||
def pbFindUser(choice,move)
|
||||
return self
|
||||
end
|
||||
|
||||
def pbChangeUser(choice,move,user)
|
||||
# Snatch
|
||||
move.snatched = false
|
||||
if move.canSnatch?
|
||||
newUser = nil; strength = 100
|
||||
@battle.eachBattler do |b|
|
||||
next if b.effects[PBEffects::Snatch]==0 ||
|
||||
b.effects[PBEffects::Snatch]>=strength
|
||||
next if b.effects[PBEffects::SkyDrop]>=0
|
||||
newUser = b
|
||||
strength = b.effects[PBEffects::Snatch]
|
||||
end
|
||||
if newUser
|
||||
user = newUser
|
||||
user.effects[PBEffects::Snatch] = 0
|
||||
move.snatched = true
|
||||
@battle.moldBreaker = user.hasMoldBreaker?
|
||||
choice[3] = -1 # Clear pre-chosen target
|
||||
end
|
||||
end
|
||||
return user
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Get move's default target(s)
|
||||
#=============================================================================
|
||||
def pbFindTargets(choice,move,user)
|
||||
preTarget = choice[3] # A target that was already chosen
|
||||
targets = []
|
||||
# Get list of targets
|
||||
case move.pbTarget(user) # Curse can change its target type
|
||||
when PBTargets::NearAlly
|
||||
targetBattler = (preTarget>=0) ? @battle.battlers[preTarget] : nil
|
||||
if !pbAddTarget(targets,user,targetBattler,move)
|
||||
pbAddTargetRandomAlly(targets,user,move)
|
||||
end
|
||||
when PBTargets::UserOrNearAlly
|
||||
targetBattler = (preTarget>=0) ? @battle.battlers[preTarget] : nil
|
||||
if !pbAddTarget(targets,user,targetBattler,move,true,true)
|
||||
pbAddTarget(targets,user,user,move,true,true)
|
||||
end
|
||||
when PBTargets::NearFoe, PBTargets::NearOther
|
||||
targetBattler = (preTarget>=0) ? @battle.battlers[preTarget] : nil
|
||||
if !pbAddTarget(targets,user,targetBattler,move)
|
||||
if preTarget>=0 && !user.opposes?(preTarget)
|
||||
pbAddTargetRandomAlly(targets,user,move)
|
||||
else
|
||||
pbAddTargetRandomFoe(targets,user,move)
|
||||
end
|
||||
end
|
||||
when PBTargets::AllNearFoes
|
||||
@battle.eachOtherSideBattler(user.index) { |b| pbAddTarget(targets,user,b,move) }
|
||||
when PBTargets::RandomNearFoe
|
||||
pbAddTargetRandomFoe(targets,user,move)
|
||||
when PBTargets::AllNearOthers
|
||||
@battle.eachBattler { |b| pbAddTarget(targets,user,b,move) }
|
||||
when PBTargets::Other
|
||||
targetBattler = (preTarget>=0) ? @battle.battlers[preTarget] : nil
|
||||
if !pbAddTarget(targets,user,targetBattler,move,false)
|
||||
if preTarget>=0 && !user.opposes?(preTarget)
|
||||
pbAddTargetRandomAlly(targets,user,move,false)
|
||||
else
|
||||
pbAddTargetRandomFoe(targets,user,move,false)
|
||||
end
|
||||
end
|
||||
when PBTargets::UserAndAllies
|
||||
pbAddTarget(targets,user,user,move,true,true)
|
||||
@battle.eachSameSideBattler(user.index) { |b| pbAddTarget(targets,user,b,move,false,true) }
|
||||
when PBTargets::AllFoes
|
||||
@battle.eachOtherSideBattler(user.index) { |b| pbAddTarget(targets,user,b,move,false) }
|
||||
when PBTargets::AllBattlers
|
||||
@battle.eachBattler { |b| pbAddTarget(targets,user,b,move,false,true) }
|
||||
else
|
||||
# Used by Counter/Mirror Coat/Metal Burst/Bide
|
||||
move.pbAddTarget(targets,user) # Move-specific pbAddTarget, not the def below
|
||||
end
|
||||
return targets
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Redirect attack to another target
|
||||
#=============================================================================
|
||||
def pbChangeTargets(move,user,targets)
|
||||
targetType = move.pbTarget(user)
|
||||
return targets if @battle.switching # For Pursuit interrupting a switch
|
||||
return targets if move.cannotRedirect?
|
||||
return targets if !PBTargets.canChooseOneFoeTarget?(targetType) || targets.length!=1
|
||||
priority = @battle.pbPriority(true)
|
||||
nearOnly = !PBTargets.canChooseDistantTarget?(move.target)
|
||||
# Spotlight (takes priority over Follow Me/Rage Powder/Lightning Rod/Storm Drain)
|
||||
newTarget = nil; strength = 100 # Lower strength takes priority
|
||||
priority.each do |b|
|
||||
next if b.fainted? || b.effects[PBEffects::SkyDrop]>=0
|
||||
next if b.effects[PBEffects::Spotlight]==0 ||
|
||||
b.effects[PBEffects::Spotlight]>=strength
|
||||
next if !b.opposes?(user)
|
||||
next if nearOnly && !b.near?(user)
|
||||
newTarget = b
|
||||
strength = b.effects[PBEffects::Spotlight]
|
||||
end
|
||||
if newTarget
|
||||
PBDebug.log("[Move target changed] #{newTarget.pbThis}'s Spotlight made it the target")
|
||||
targets = []
|
||||
pbAddTarget(targets,user,newTarget,move,nearOnly)
|
||||
return targets
|
||||
end
|
||||
# Follow Me/Rage Powder (takes priority over Lightning Rod/Storm Drain)
|
||||
newTarget = nil; strength = 100 # Lower strength takes priority
|
||||
priority.each do |b|
|
||||
next if b.fainted? || b.effects[PBEffects::SkyDrop]>=0
|
||||
next if b.effects[PBEffects::RagePowder] && !user.affectedByPowder?
|
||||
next if b.effects[PBEffects::FollowMe]==0 ||
|
||||
b.effects[PBEffects::FollowMe]>=strength
|
||||
next if !b.opposes?(user)
|
||||
next if nearOnly && !b.near?(user)
|
||||
newTarget = b
|
||||
strength = b.effects[PBEffects::FollowMe]
|
||||
end
|
||||
if newTarget
|
||||
PBDebug.log("[Move target changed] #{newTarget.pbThis}'s Follow Me/Rage Powder made it the target")
|
||||
targets = []
|
||||
pbAddTarget(targets,user,newTarget,move,nearOnly)
|
||||
return targets
|
||||
end
|
||||
# Lightning Rod
|
||||
targets = pbChangeTargetByAbility(:LIGHTNINGROD,:ELECTRIC,move,user,targets,priority,nearOnly)
|
||||
# Storm Drain
|
||||
targets = pbChangeTargetByAbility(:STORMDRAIN,:WATER,move,user,targets,priority,nearOnly)
|
||||
return targets
|
||||
end
|
||||
|
||||
def pbChangeTargetByAbility(drawingAbility,drawnType,move,user,targets,priority,nearOnly)
|
||||
return targets if !isConst?(move.calcType,PBTypes,drawnType)
|
||||
return targets if targets[0].hasActiveAbility?(drawingAbility)
|
||||
priority.each do |b|
|
||||
next if b.index==user.index || b.index==targets[0].index
|
||||
next if !b.hasActiveAbility?(drawingAbility)
|
||||
next if nearOnly && !b.near?(user)
|
||||
@battle.pbShowAbilitySplash(b)
|
||||
targets.clear
|
||||
pbAddTarget(targets,user,b,move,nearOnly)
|
||||
if PokeBattle_SceneConstants::USE_ABILITY_SPLASH
|
||||
@battle.pbDisplay(_INTL("{1} took the attack!",b.pbThis))
|
||||
else
|
||||
@battle.pbDisplay(_INTL("{1} took the attack with its {2}!",b.pbThis,b.abilityName))
|
||||
end
|
||||
@battle.pbHideAbilitySplash(b)
|
||||
break
|
||||
end
|
||||
return targets
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Register target
|
||||
#=============================================================================
|
||||
def pbAddTarget(targets,user,target,move,nearOnly=true,allowUser=false)
|
||||
return false if !target || (target.fainted? && !move.cannotRedirect?)
|
||||
return false if !(allowUser && user==target) && nearOnly && !user.near?(target)
|
||||
targets.each { |b| return true if b.index==target.index } # Already added
|
||||
targets.push(target)
|
||||
return true
|
||||
end
|
||||
|
||||
def pbAddTargetRandomAlly(targets,user,move,nearOnly=true)
|
||||
choices = []
|
||||
user.eachAlly do |b|
|
||||
next if nearOnly && !user.near?(b)
|
||||
pbAddTarget(choices,user,b,nearOnly)
|
||||
end
|
||||
if choices.length>0
|
||||
pbAddTarget(targets,user,choices[@battle.pbRandom(choices.length)],nearOnly)
|
||||
end
|
||||
end
|
||||
|
||||
def pbAddTargetRandomFoe(targets,user,move,nearOnly=true)
|
||||
choices = []
|
||||
user.eachOpposing do |b|
|
||||
next if nearOnly && !user.near?(b)
|
||||
pbAddTarget(choices,user,b,nearOnly)
|
||||
end
|
||||
if choices.length>0
|
||||
pbAddTarget(targets,user,choices[@battle.pbRandom(choices.length)],nearOnly)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,538 @@
|
||||
class PokeBattle_Battler
|
||||
#=============================================================================
|
||||
# Decide whether the trainer is allowed to tell the Pokémon to use the given
|
||||
# move. Called when choosing a command for the round.
|
||||
# Also called when processing the Pokémon's action, because these effects also
|
||||
# prevent Pokémon action. Relevant because these effects can become active
|
||||
# earlier in the same round (after choosing the command but before using the
|
||||
# move) or an unusable move may be called by another move such as Metronome.
|
||||
#=============================================================================
|
||||
def pbCanChooseMove?(move,commandPhase,showMessages=true,specialUsage=false)
|
||||
# Disable
|
||||
if @effects[PBEffects::DisableMove]==move.id && !specialUsage
|
||||
if showMessages
|
||||
msg = _INTL("{1}'s {2} is disabled!",pbThis,move.name)
|
||||
(commandPhase) ? @battle.pbDisplayPaused(msg) : @battle.pbDisplay(msg)
|
||||
end
|
||||
return false
|
||||
end
|
||||
# Heal Block
|
||||
if @effects[PBEffects::HealBlock]>0 && move.healingMove?
|
||||
if showMessages
|
||||
msg = _INTL("{1} can't use {2} because of Heal Block!",pbThis,move.name)
|
||||
(commandPhase) ? @battle.pbDisplayPaused(msg) : @battle.pbDisplay(msg)
|
||||
end
|
||||
return false
|
||||
end
|
||||
# Gravity
|
||||
if @battle.field.effects[PBEffects::Gravity]>0 && move.unusableInGravity?
|
||||
if showMessages
|
||||
msg = _INTL("{1} can't use {2} because of gravity!",pbThis,move.name)
|
||||
(commandPhase) ? @battle.pbDisplayPaused(msg) : @battle.pbDisplay(msg)
|
||||
end
|
||||
return false
|
||||
end
|
||||
# Throat Chop
|
||||
if @effects[PBEffects::ThroatChop]>0 && move.soundMove?
|
||||
if showMessages
|
||||
msg = _INTL("{1} can't use {2} because of Throat Chop!",pbThis,move.name)
|
||||
(commandPhase) ? @battle.pbDisplayPaused(msg) : @battle.pbDisplay(msg)
|
||||
end
|
||||
return false
|
||||
end
|
||||
# Choice Band
|
||||
if @effects[PBEffects::ChoiceBand]>=0
|
||||
if hasActiveItem?([:CHOICEBAND,:CHOICESPECS,:CHOICESCARF]) &&
|
||||
pbHasMove?(@effects[PBEffects::ChoiceBand])
|
||||
if move.id!=@effects[PBEffects::ChoiceBand]
|
||||
if showMessages
|
||||
msg = _INTL("{1} allows the use of only {2}!",itemName,
|
||||
PBMoves.getName(@effects[PBEffects::ChoiceBand]))
|
||||
(commandPhase) ? @battle.pbDisplayPaused(msg) : @battle.pbDisplay(msg)
|
||||
end
|
||||
return false
|
||||
end
|
||||
else
|
||||
@effects[PBEffects::ChoiceBand] = -1
|
||||
end
|
||||
end
|
||||
# Taunt
|
||||
if @effects[PBEffects::Taunt]>0 && move.statusMove?
|
||||
if showMessages
|
||||
msg = _INTL("{1} can't use {2} after the taunt!",pbThis,move.name)
|
||||
(commandPhase) ? @battle.pbDisplayPaused(msg) : @battle.pbDisplay(msg)
|
||||
end
|
||||
return false
|
||||
end
|
||||
# Torment
|
||||
if @effects[PBEffects::Torment] && !@effects[PBEffects::Instructed] &&
|
||||
move.id==@lastMoveUsed && move.id!=@battle.struggle.id
|
||||
if showMessages
|
||||
msg = _INTL("{1} can't use the same move twice in a row due to the torment!",pbThis)
|
||||
(commandPhase) ? @battle.pbDisplayPaused(msg) : @battle.pbDisplay(msg)
|
||||
end
|
||||
return false
|
||||
end
|
||||
# Imprison
|
||||
@battle.eachOtherSideBattler(@index) do |b|
|
||||
next if !b.effects[PBEffects::Imprison] || !b.pbHasMove?(move.id)
|
||||
if showMessages
|
||||
msg = _INTL("{1} can't use its sealed {2}!",pbThis,move.name)
|
||||
(commandPhase) ? @battle.pbDisplayPaused(msg) : @battle.pbDisplay(msg)
|
||||
end
|
||||
return false
|
||||
end
|
||||
# Assault Vest (prevents choosing status moves but doesn't prevent
|
||||
# executing them)
|
||||
if hasActiveItem?(:ASSAULTVEST) && move.statusMove? && commandPhase
|
||||
if showMessages
|
||||
msg = _INTL("The effects of the {1} prevent status moves from being used!",
|
||||
itemName)
|
||||
(commandPhase) ? @battle.pbDisplayPaused(msg) : @battle.pbDisplay(msg)
|
||||
end
|
||||
return false
|
||||
end
|
||||
# Belch
|
||||
return false if !move.pbCanChooseMove?(self,commandPhase,showMessages)
|
||||
return true
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Obedience check
|
||||
#=============================================================================
|
||||
# Return true if Pokémon continues attacking (although it may have chosen to
|
||||
# use a different move in disobedience), or false if attack stops.
|
||||
def pbObedienceCheck?(choice)
|
||||
return true if usingMultiTurnAttack?
|
||||
return true if choice[0]!=:UseMove
|
||||
return true if !@battle.internalBattle
|
||||
return true if !@battle.pbOwnedByPlayer?(@index)
|
||||
disobedient = false
|
||||
# Pokémon may be disobedient; calculate if it is
|
||||
badgeLevel = 10*(@battle.pbPlayer.numbadges+1)
|
||||
badgeLevel = PBExperience.maxLevel if @battle.pbPlayer.numbadges>=8
|
||||
if @pokemon.foreign?(@battle.pbPlayer) && @level>badgeLevel
|
||||
a = ((@level+badgeLevel)*@battle.pbRandom(256)/256).floor
|
||||
disobedient |= (a>=badgeLevel)
|
||||
end
|
||||
disobedient |= !pbHyperModeObedience(choice[2])
|
||||
return true if !disobedient
|
||||
# Pokémon is disobedient; make it do something else
|
||||
return pbDisobey(choice,badgeLevel)
|
||||
end
|
||||
|
||||
def pbDisobey(choice,badgeLevel)
|
||||
move = choice[2]
|
||||
PBDebug.log("[Disobedience] #{pbThis} disobeyed")
|
||||
@effects[PBEffects::Rage] = false
|
||||
# Do nothing if using Snore/Sleep Talk
|
||||
if @status==PBStatuses::SLEEP && move.usableWhenAsleep?
|
||||
@battle.pbDisplay(_INTL("{1} ignored orders and kept sleeping!",pbThis))
|
||||
return false
|
||||
end
|
||||
b = ((@level+badgeLevel)*@battle.pbRandom(256)/256).floor
|
||||
# Use another move
|
||||
if b<badgeLevel
|
||||
@battle.pbDisplay(_INTL("{1} ignored orders!",pbThis))
|
||||
return false if !@battle.pbCanShowFightMenu?(@index)
|
||||
otherMoves = []
|
||||
eachMoveWithIndex do |m,i|
|
||||
next if i==choice[1]
|
||||
otherMoves[otherMoves.length] = i if @battle.pbCanChooseMove?(@index,i,false)
|
||||
end
|
||||
return false if otherMoves.length==0 # No other move to use; do nothing
|
||||
newChoice = otherMoves[@battle.pbRandom(otherMoves.length)]
|
||||
choice[1] = newChoice
|
||||
choice[2] = @moves[newChoice]
|
||||
choice[3] = -1
|
||||
return true
|
||||
end
|
||||
c = @level-badgeLevel
|
||||
r = @battle.pbRandom(256)
|
||||
# Fall asleep
|
||||
if r<c && pbCanSleep?(self,false)
|
||||
pbSleepSelf(_INTL("{1} began to nap!",pbThis))
|
||||
return false
|
||||
end
|
||||
# Hurt self in confusion
|
||||
r -= c
|
||||
if r<c && @status!=PBStatuses::SLEEP
|
||||
pbConfusionDamage(_INTL("{1} won't obey! It hurt itself in its confusion!",pbThis))
|
||||
return false
|
||||
end
|
||||
# Show refusal message and do nothing
|
||||
case @battle.pbRandom(4)
|
||||
when 0; @battle.pbDisplay(_INTL("{1} won't obey!",pbThis))
|
||||
when 1; @battle.pbDisplay(_INTL("{1} turned away!",pbThis))
|
||||
when 2; @battle.pbDisplay(_INTL("{1} is loafing around!",pbThis))
|
||||
when 3; @battle.pbDisplay(_INTL("{1} pretended not to notice!",pbThis))
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Check whether the user (self) is able to take action at all.
|
||||
# If this returns true, and if PP isn't a problem, the move will be considered
|
||||
# to have been used (even if it then fails for whatever reason).
|
||||
#=============================================================================
|
||||
def pbTryUseMove(choice,move,specialUsage,skipAccuracyCheck)
|
||||
# Check whether it's possible for self to use the given move
|
||||
# NOTE: Encore has already changed the move being used, no need to have a
|
||||
# check for it here.
|
||||
if !pbCanChooseMove?(move,false,true,specialUsage)
|
||||
@lastMoveFailed = true
|
||||
return false
|
||||
end
|
||||
# Check whether it's possible for self to do anything at all
|
||||
if @effects[PBEffects::SkyDrop]>=0 # Intentionally no message here
|
||||
PBDebug.log("[Move failed] #{pbThis} can't use #{move.name} because of being Sky Dropped")
|
||||
return false
|
||||
end
|
||||
if @effects[PBEffects::HyperBeam]>0 # Intentionally before Truant
|
||||
@battle.pbDisplay(_INTL("{1} must recharge!",pbThis))
|
||||
return false
|
||||
end
|
||||
if choice[1]==-2 # Battle Palace
|
||||
@battle.pbDisplay(_INTL("{1} appears incapable of using its power!",pbThis))
|
||||
return false
|
||||
end
|
||||
# Skip checking all applied effects that could make self fail doing something
|
||||
return true if skipAccuracyCheck
|
||||
# Check status problems and continue their effects/cure them
|
||||
case @status
|
||||
when PBStatuses::SLEEP
|
||||
self.statusCount -= 1
|
||||
if @statusCount<=0
|
||||
pbCureStatus
|
||||
else
|
||||
pbContinueStatus
|
||||
if !move.usableWhenAsleep? # Snore/Sleep Talk
|
||||
@lastMoveFailed = true
|
||||
return false
|
||||
end
|
||||
end
|
||||
when PBStatuses::FROZEN
|
||||
if !move.thawsUser?
|
||||
if @battle.pbRandom(100)<20
|
||||
pbCureStatus
|
||||
else
|
||||
pbContinueStatus
|
||||
@lastMoveFailed = true
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
# Obedience check
|
||||
return false if !pbObedienceCheck?(choice)
|
||||
# Truant
|
||||
if hasActiveAbility?(:TRUANT)
|
||||
@effects[PBEffects::Truant] = !@effects[PBEffects::Truant]
|
||||
if !@effects[PBEffects::Truant] # True means loafing, but was just inverted
|
||||
@battle.pbShowAbilitySplash(self)
|
||||
@battle.pbDisplay(_INTL("{1} is loafing around!",pbThis))
|
||||
@lastMoveFailed = true
|
||||
@battle.pbHideAbilitySplash(self)
|
||||
return false
|
||||
end
|
||||
end
|
||||
# Flinching
|
||||
if @effects[PBEffects::Flinch]
|
||||
@battle.pbDisplay(_INTL("{1} flinched and couldn't move!",pbThis))
|
||||
if abilityActive?
|
||||
BattleHandlers.triggerAbilityOnFlinch(@ability,self,@battle)
|
||||
end
|
||||
@lastMoveFailed = true
|
||||
return false
|
||||
end
|
||||
# Confusion
|
||||
if @effects[PBEffects::Confusion]>0
|
||||
@effects[PBEffects::Confusion] -= 1
|
||||
if @effects[PBEffects::Confusion]<=0
|
||||
pbCureConfusion
|
||||
@battle.pbDisplay(_INTL("{1} snapped out of its confusion.",pbThis))
|
||||
else
|
||||
@battle.pbCommonAnimation("Confusion",self)
|
||||
@battle.pbDisplay(_INTL("{1} is confused!",pbThis))
|
||||
threshold = (NEWEST_BATTLE_MECHANICS) ? 33 : 50 # % chance
|
||||
if @battle.pbRandom(100)<threshold
|
||||
pbConfusionDamage(_INTL("It hurt itself in its confusion!"))
|
||||
@lastMoveFailed = true
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
# Paralysis
|
||||
if @status==PBStatuses::PARALYSIS
|
||||
if @battle.pbRandom(100)<25
|
||||
pbContinueStatus
|
||||
@lastMoveFailed = true
|
||||
return false
|
||||
end
|
||||
end
|
||||
# Infatuation
|
||||
if @effects[PBEffects::Attract]>=0
|
||||
@battle.pbCommonAnimation("Attract",self)
|
||||
@battle.pbDisplay(_INTL("{1} is in love with {2}!",pbThis,
|
||||
@battle.battlers[@effects[PBEffects::Attract]].pbThis(true)))
|
||||
if @battle.pbRandom(100)<50
|
||||
@battle.pbDisplay(_INTL("{1} is immobilized by love!",pbThis))
|
||||
@lastMoveFailed = true
|
||||
return false
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Initial success check against the target. Done once before the first hit.
|
||||
# Includes move-specific failure conditions, protections and type immunities.
|
||||
#=============================================================================
|
||||
def pbSuccessCheckAgainstTarget(move,user,target)
|
||||
typeMod = move.pbCalcTypeMod(move.calcType,user,target)
|
||||
target.damageState.typeMod = typeMod
|
||||
# Two-turn attacks can't fail here in the charging turn
|
||||
return true if user.effects[PBEffects::TwoTurnAttack]>0
|
||||
# Move-specific failures
|
||||
return false if move.pbFailsAgainstTarget?(user,target)
|
||||
# Immunity to priority moves because of Psychic Terrain
|
||||
if @battle.field.terrain==PBBattleTerrains::Psychic && target.affectedByTerrain? &&
|
||||
target.opposes?(user) &&
|
||||
@battle.choices[user.index][4]>0 # Move priority saved from pbCalculatePriority
|
||||
@battle.pbDisplay(_INTL("{1} surrounds itself with psychic terrain!",target.pbThis))
|
||||
return false
|
||||
end
|
||||
# Crafty Shield
|
||||
if target.pbOwnSide.effects[PBEffects::CraftyShield] && user.index!=target.index &&
|
||||
move.statusMove? && move.pbTarget(user)!=PBTargets::AllBattlers
|
||||
@battle.pbCommonAnimation("CraftyShield",target)
|
||||
@battle.pbDisplay(_INTL("Crafty Shield protected {1}!",target.pbThis(true)))
|
||||
target.damageState.protected = true
|
||||
@battle.successStates[user.index].protected = true
|
||||
return false
|
||||
end
|
||||
# Wide Guard
|
||||
if target.pbOwnSide.effects[PBEffects::WideGuard] && user.index!=target.index &&
|
||||
PBTargets.multipleTargets?(move.pbTarget(user)) &&
|
||||
(NEWEST_BATTLE_MECHANICS || move.damagingMove?)
|
||||
@battle.pbCommonAnimation("WideGuard",target)
|
||||
@battle.pbDisplay(_INTL("Wide Guard protected {1}!",target.pbThis(true)))
|
||||
target.damageState.protected = true
|
||||
@battle.successStates[user.index].protected = true
|
||||
return false
|
||||
end
|
||||
if move.canProtectAgainst?
|
||||
# Quick Guard
|
||||
if target.pbOwnSide.effects[PBEffects::QuickGuard] &&
|
||||
@battle.choices[user.index][4]>0 # Move priority saved from pbCalculatePriority
|
||||
@battle.pbCommonAnimation("QuickGuard",target)
|
||||
@battle.pbDisplay(_INTL("Quick Guard protected {1}!",target.pbThis(true)))
|
||||
target.damageState.protected = true
|
||||
@battle.successStates[user.index].protected = true
|
||||
return false
|
||||
end
|
||||
# Protect
|
||||
if target.effects[PBEffects::Protect]
|
||||
@battle.pbCommonAnimation("Protect",target)
|
||||
@battle.pbDisplay(_INTL("{1} protected itself!",target.pbThis))
|
||||
target.damageState.protected = true
|
||||
@battle.successStates[user.index].protected = true
|
||||
return false
|
||||
end
|
||||
# King's Shield
|
||||
if target.effects[PBEffects::KingsShield] && move.damagingMove?
|
||||
@battle.pbCommonAnimation("KingsShield",target)
|
||||
@battle.pbDisplay(_INTL("{1} protected itself!",target.pbThis))
|
||||
target.damageState.protected = true
|
||||
@battle.successStates[user.index].protected = true
|
||||
if move.pbContactMove?(user) && user.affectedByContactEffect?
|
||||
if user.pbCanLowerStatStage?(PBStats::ATTACK)
|
||||
user.pbLowerStatStage(PBStats::ATTACK,2,nil)
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
# Spiky Shield
|
||||
if target.effects[PBEffects::SpikyShield]
|
||||
@battle.pbCommonAnimation("SpikyShield",target)
|
||||
@battle.pbDisplay(_INTL("{1} protected itself!",target.pbThis))
|
||||
target.damageState.protected = true
|
||||
@battle.successStates[user.index].protected = true
|
||||
if move.pbContactMove?(user) && user.affectedByContactEffect?
|
||||
@battle.scene.pbDamageAnimation(user)
|
||||
user.pbReduceHP(user.totalhp/8,false)
|
||||
@battle.pbDisplay(_INTL("{1} was hurt!",user.pbThis))
|
||||
user.pbItemHPHealCheck
|
||||
end
|
||||
return false
|
||||
end
|
||||
# Baneful Bunker
|
||||
if target.effects[PBEffects::BanefulBunker]
|
||||
@battle.pbCommonAnimation("BanefulBunker",target)
|
||||
@battle.pbDisplay(_INTL("{1} protected itself!",target.pbThis))
|
||||
target.damageState.protected = true
|
||||
@battle.successStates[user.index].protected = true
|
||||
if move.pbContactMove?(user) && user.affectedByContactEffect?
|
||||
user.pbPoison(target) if user.pbCanPoison?(target,false)
|
||||
end
|
||||
return false
|
||||
end
|
||||
# Mat Block
|
||||
if target.pbOwnSide.effects[PBEffects::MatBlock] && move.damagingMove?
|
||||
# NOTE: Confirmed no common animation for this effect.
|
||||
@battle.pbDisplay(_INTL("{1} was blocked by the kicked-up mat!",move.name))
|
||||
target.damageState.protected = true
|
||||
@battle.successStates[user.index].protected = true
|
||||
return false
|
||||
end
|
||||
end
|
||||
# Magic Coat/Magic Bounce
|
||||
if move.canMagicCoat? && !target.semiInvulnerable? && target.opposes?(user)
|
||||
if target.effects[PBEffects::MagicCoat]
|
||||
target.damageState.magicCoat = true
|
||||
target.effects[PBEffects::MagicCoat] = false
|
||||
return false
|
||||
end
|
||||
if target.hasActiveAbility?(:MAGICBOUNCE) && !@battle.moldBreaker &&
|
||||
!target.effects[PBEffects::MagicBounce]
|
||||
target.damageState.magicBounce = true
|
||||
target.effects[PBEffects::MagicBounce] = true
|
||||
return false
|
||||
end
|
||||
end
|
||||
# Immunity because of ability (intentionally before type immunity check)
|
||||
return false if move.pbImmunityByAbility(user,target)
|
||||
# Type immunity
|
||||
if move.pbDamagingMove? && PBTypes.ineffective?(typeMod)
|
||||
PBDebug.log("[Target immune] #{target.pbThis}'s type immunity")
|
||||
@battle.pbDisplay(_INTL("It doesn't affect {1}...",target.pbThis(true)))
|
||||
return false
|
||||
end
|
||||
# Dark-type immunity to moves made faster by Prankster
|
||||
if NEWEST_BATTLE_MECHANICS && user.effects[PBEffects::Prankster] &&
|
||||
target.pbHasType?(:DARK) && target.opposes?(user)
|
||||
PBDebug.log("[Target immune] #{target.pbThis} is Dark-type and immune to Prankster-boosted moves")
|
||||
@battle.pbDisplay(_INTL("It doesn't affect {1}...",target.pbThis(true)))
|
||||
return false
|
||||
end
|
||||
# Airborne-based immunity to Ground moves
|
||||
if move.damagingMove? && isConst?(move.calcType,PBTypes,:GROUND) &&
|
||||
target.airborne? && !move.hitsFlyingTargets?
|
||||
if target.hasActiveAbility?(:LEVITATE) && !@battle.moldBreaker
|
||||
@battle.pbShowAbilitySplash(target)
|
||||
if PokeBattle_SceneConstants::USE_ABILITY_SPLASH
|
||||
@battle.pbDisplay(_INTL("{1} avoided the attack!",target.pbThis))
|
||||
else
|
||||
@battle.pbDisplay(_INTL("{1} avoided the attack with {2}!",target.pbThis,target.abilityName))
|
||||
end
|
||||
@battle.pbHideAbilitySplash(target)
|
||||
return false
|
||||
end
|
||||
if target.hasActiveItem?(:AIRBALLOON)
|
||||
@battle.pbDisplay(_INTL("{1}'s {2} makes Ground moves miss!",target.pbThis,target.itemName))
|
||||
return false
|
||||
end
|
||||
if target.effects[PBEffects::MagnetRise]>0
|
||||
@battle.pbDisplay(_INTL("{1} makes Ground moves miss with Magnet Rise!",target.pbThis))
|
||||
return false
|
||||
end
|
||||
if target.effects[PBEffects::Telekinesis]>0
|
||||
@battle.pbDisplay(_INTL("{1} makes Ground moves miss with Telekinesis!",target.pbThis))
|
||||
return false
|
||||
end
|
||||
end
|
||||
# Immunity to powder-based moves
|
||||
if NEWEST_BATTLE_MECHANICS && move.powderMove?
|
||||
if target.pbHasType?(:GRASS)
|
||||
PBDebug.log("[Target immune] #{target.pbThis} is Grass-type and immune to powder-based moves")
|
||||
@battle.pbDisplay(_INTL("It doesn't affect {1}...",target.pbThis(true)))
|
||||
return false
|
||||
end
|
||||
if target.hasActiveAbility?(:OVERCOAT) && !@battle.moldBreaker
|
||||
@battle.pbShowAbilitySplash(target)
|
||||
if PokeBattle_SceneConstants::USE_ABILITY_SPLASH
|
||||
@battle.pbDisplay(_INTL("It doesn't affect {1}...",target.pbThis(true)))
|
||||
else
|
||||
@battle.pbDisplay(_INTL("It doesn't affect {1} because of its {2}.",target.pbThis(true),target.abilityName))
|
||||
end
|
||||
@battle.pbHideAbilitySplash(target)
|
||||
return false
|
||||
end
|
||||
if target.hasActiveItem?(:SAFETYGOGGLES)
|
||||
PBDebug.log("[Item triggered] #{target.pbThis} has Safety Goggles and is immune to powder-based moves")
|
||||
@battle.pbDisplay(_INTL("It doesn't affect {1}...",target.pbThis(true)))
|
||||
return false
|
||||
end
|
||||
end
|
||||
# Substitute
|
||||
if target.effects[PBEffects::Substitute]>0 && move.statusMove? &&
|
||||
!move.ignoresSubstitute?(user) && user.index!=target.index
|
||||
PBDebug.log("[Target immune] #{target.pbThis} is protected by its Substitute")
|
||||
@battle.pbDisplay(_INTL("{1} avoided the attack!",target.pbThis(true)))
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Per-hit success check against the target.
|
||||
# Includes semi-invulnerable move use and accuracy calculation.
|
||||
#=============================================================================
|
||||
def pbSuccessCheckPerHit(move,user,target,skipAccuracyCheck)
|
||||
# Two-turn attacks can't fail here in the charging turn
|
||||
return true if user.effects[PBEffects::TwoTurnAttack]>0
|
||||
# Lock-On
|
||||
return true if user.effects[PBEffects::LockOn]>0 &&
|
||||
user.effects[PBEffects::LockOnPos]==target.index
|
||||
# Toxic
|
||||
return true if move.pbOverrideSuccessCheckPerHit(user,target)
|
||||
miss = false; hitsInvul = false
|
||||
# No Guard
|
||||
hitsInvul = true if user.hasActiveAbility?(:NOGUARD) ||
|
||||
target.hasActiveAbility?(:NOGUARD)
|
||||
# Future Sight
|
||||
hitsInvul = true if @battle.futureSight
|
||||
# Helping Hand
|
||||
hitsInvul = true if move.function=="09C"
|
||||
if !hitsInvul
|
||||
# Semi-invulnerable moves
|
||||
if target.effects[PBEffects::TwoTurnAttack]>0
|
||||
if target.inTwoTurnAttack?("0C9","0CC","0CE") # Fly, Bounce, Sky Drop
|
||||
miss = true if !move.hitsFlyingTargets?
|
||||
elsif target.inTwoTurnAttack?("0CA") # Dig
|
||||
miss = true if !move.hitsDiggingTargets?
|
||||
elsif target.inTwoTurnAttack?("0CB") # Dive
|
||||
miss = true if !move.hitsDivingTargets?
|
||||
elsif target.inTwoTurnAttack?("0CD","14D") # Shadow Force, Phantom Force
|
||||
miss = true
|
||||
end
|
||||
end
|
||||
if target.effects[PBEffects::SkyDrop]>=0 &&
|
||||
target.effects[PBEffects::SkyDrop]!=user.index
|
||||
miss = true if !move.hitsFlyingTargets?
|
||||
end
|
||||
end
|
||||
if !miss
|
||||
# Called by another move
|
||||
return true if skipAccuracyCheck
|
||||
# Accuracy check
|
||||
return true if move.pbAccuracyCheck(user,target) # Includes Counter/Mirror Coat
|
||||
end
|
||||
# Missed
|
||||
PBDebug.log("[Move failed] Failed pbAccuracyCheck or target is semi-invulnerable")
|
||||
return false
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Message shown when a move fails the per-hit success check above.
|
||||
#=============================================================================
|
||||
def pbMissMessage(move,user,target)
|
||||
tar = move.pbTarget(user)
|
||||
if PBTargets.multipleTargets?(tar)
|
||||
@battle.pbDisplay(_INTL("{1} avoided the attack!",target.pbThis))
|
||||
elsif target.effects[PBEffects::TwoTurnAttack]>0
|
||||
@battle.pbDisplay(_INTL("{1} avoided the attack!",target.pbThis))
|
||||
elsif !move.pbMissMessage(user,target)
|
||||
@battle.pbDisplay(_INTL("{1}'s attack missed!",user.pbThis))
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,188 @@
|
||||
class PokeBattle_Battler
|
||||
#=============================================================================
|
||||
# Effect per hit
|
||||
#=============================================================================
|
||||
def pbEffectsOnMakingHit(move,user,target)
|
||||
if target.damageState.calcDamage>0 && !target.damageState.substitute
|
||||
# Target's ability
|
||||
if target.abilityActive?(true)
|
||||
oldHP = user.hp
|
||||
BattleHandlers.triggerTargetAbilityOnHit(target.ability,user,target,move,@battle)
|
||||
user.pbItemHPHealCheck if user.hp<oldHP
|
||||
end
|
||||
# User's ability
|
||||
if user.abilityActive?(true)
|
||||
BattleHandlers.triggerUserAbilityOnHit(user.ability,user,target,move,@battle)
|
||||
user.pbItemHPHealCheck
|
||||
end
|
||||
# Target's item
|
||||
if target.itemActive?(true)
|
||||
oldHP = user.hp
|
||||
BattleHandlers.triggerTargetItemOnHit(target.item,user,target,move,@battle)
|
||||
user.pbItemHPHealCheck if user.hp<oldHP
|
||||
end
|
||||
end
|
||||
if target.opposes?(user)
|
||||
# Rage
|
||||
if target.effects[PBEffects::Rage] && !target.fainted?
|
||||
if target.pbCanRaiseStatStage?(PBStats::ATTACK,target)
|
||||
@battle.pbDisplay(_INTL("{1}'s rage is building!",target.pbThis))
|
||||
target.pbRaiseStatStage(PBStats::ATTACK,1,target)
|
||||
end
|
||||
end
|
||||
# Beak Blast
|
||||
if target.effects[PBEffects::BeakBlast]
|
||||
PBDebug.log("[Lingering effect] #{target.pbThis}'s Beak Blast")
|
||||
if move.pbContactMove?(user) && user.affectedByContactEffect?
|
||||
target.pbBurn(user) if target.pbCanBurn?(user,false,self)
|
||||
end
|
||||
end
|
||||
# Shell Trap (make the trapper move next if the trap was triggered)
|
||||
if target.effects[PBEffects::ShellTrap] &&
|
||||
@battle.choices[target.index][0]==:UseMove && !target.movedThisRound?
|
||||
if target.damageState.hpLost>0 && !target.damageState.substitute && move.physicalMove?
|
||||
target.tookPhysicalHit = true
|
||||
target.effects[PBEffects::MoveNext] = true
|
||||
target.effects[PBEffects::Quash] = 0
|
||||
end
|
||||
end
|
||||
# Grudge
|
||||
if target.effects[PBEffects::Grudge] && target.fainted?
|
||||
move.pp = 0
|
||||
@battle.pbDisplay(_INTL("{1}'s {2} lost all of its PP due to the grudge!",
|
||||
user.pbThis,move.name))
|
||||
end
|
||||
# Destiny Bond (recording that it should apply)
|
||||
if target.effects[PBEffects::DestinyBond] && target.fainted?
|
||||
if user.effects[PBEffects::DestinyBondTarget]<0
|
||||
user.effects[PBEffects::DestinyBondTarget] = target.index
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Effects after all hits (i.e. at end of move usage)
|
||||
#=============================================================================
|
||||
def pbEffectsAfterMove(user,targets,move,numHits)
|
||||
# Defrost
|
||||
if move.damagingMove?
|
||||
targets.each do |b|
|
||||
next if b.damageState.unaffected || b.damageState.substitute
|
||||
next if b.status!=PBStatuses::FROZEN
|
||||
# NOTE: Non-Fire-type moves that thaw the user will also thaw the
|
||||
# target (in Gen 6+).
|
||||
if isConst?(move.calcType,PBTypes,:FIRE) ||
|
||||
(NEWEST_BATTLE_MECHANICS && move.thawsUser?)
|
||||
b.pbCureStatus
|
||||
end
|
||||
end
|
||||
end
|
||||
# Destiny Bond
|
||||
# NOTE: Although Destiny Bond is similar to Grudge, they don't apply at
|
||||
# the same time (although Destiny Bond does check whether it's going
|
||||
# to trigger at the same time as Grudge).
|
||||
if user.effects[PBEffects::DestinyBondTarget]>=0 && !user.fainted?
|
||||
dbName = @battle.battlers[user.effects[PBEffects::DestinyBondTarget]].pbThis
|
||||
@battle.pbDisplay(_INTL("{1} took its attacker down with it!",dbName))
|
||||
user.pbReduceHP(user.hp,false)
|
||||
user.pbItemHPHealCheck
|
||||
user.pbFaint
|
||||
@battle.pbJudgeCheckpoint(user)
|
||||
end
|
||||
# User's ability
|
||||
if user.abilityActive?
|
||||
BattleHandlers.triggerUserAbilityEndOfMove(user.ability,user,targets,move,@battle)
|
||||
end
|
||||
# Greninja - Battle Bond
|
||||
if !user.fainted? && !user.effects[PBEffects::Transform] &&
|
||||
isConst?(user.species,PBSpecies,:GRENINJA) &&
|
||||
isConst?(user.ability,PBAbilities,:BATTLEBOND)
|
||||
if !@battle.pbAllFainted?(user.idxOpposingSide) &&
|
||||
!@battle.battleBond[user.index&1][user.pokemonIndex]
|
||||
numFainted = 0
|
||||
targets.each { |b| numFainted += 1 if b.damageState.fainted }
|
||||
if numFainted>0 && user.form!=1
|
||||
@battle.battleBond[user.index&1][user.pokemonIndex] = true
|
||||
@battle.pbDisplay(_INTL("{1} became fully charged due to its bond with its Trainer!",user.pbThis))
|
||||
@battle.pbShowAbilitySplash(user,true)
|
||||
@battle.pbHideAbilitySplash(user)
|
||||
user.pbChangeForm(1,_INTL("{1} became Ash-Greninja!",user.pbThis))
|
||||
end
|
||||
end
|
||||
end
|
||||
# Consume user's Gem
|
||||
if user.effects[PBEffects::GemConsumed]>0
|
||||
# NOTE: The consume animation and message for Gems are shown immediately
|
||||
# after the move's animation, but the item is only consumed now.
|
||||
user.pbConsumeItem
|
||||
end
|
||||
# Pokémon switching caused by Roar, Whirlwind, Circle Throw, Dragon Tail
|
||||
switchedBattlers = []
|
||||
move.pbSwitchOutTargetsEffect(user,targets,numHits,switchedBattlers)
|
||||
# Target's item, user's item, target's ability (all negated by Sheer Force)
|
||||
if move.addlEffect==0 || !user.hasActiveAbility?(:SHEERFORCE)
|
||||
pbEffectsAfterMove2(user,targets,move,numHits,switchedBattlers)
|
||||
end
|
||||
# Some move effects that need to happen here, i.e. U-turn/Volt Switch
|
||||
# switching, Baton Pass switching, Parting Shot switching, Relic Song's form
|
||||
# changing, Fling/Natural Gift consuming item.
|
||||
if !switchedBattlers.include?(user.index)
|
||||
move.pbEndOfMoveUsageEffect(user,targets,numHits,switchedBattlers)
|
||||
end
|
||||
if numHits>0
|
||||
@battle.eachBattler { |b| b.pbItemEndOfMoveCheck }
|
||||
end
|
||||
end
|
||||
|
||||
# Everything in this method is negated by Sheer Force.
|
||||
def pbEffectsAfterMove2(user,targets,move,numHits,switchedBattlers)
|
||||
hpNow = user.hp # Intentionally determined now, before Shell Bell
|
||||
# Target's held item (Eject Button, Red Card)
|
||||
switchByItem = []
|
||||
@battle.pbPriority(true).each do |b|
|
||||
next if !targets.any? { |targetB| targetB.index==b.index }
|
||||
next if b.damageState.unaffected || b.damageState.calcDamage==0 ||
|
||||
switchedBattlers.include?(b.index)
|
||||
next if !b.itemActive?
|
||||
BattleHandlers.triggerTargetItemAfterMoveUse(b.item,b,user,move,switchByItem,@battle)
|
||||
end
|
||||
@battle.moldBreaker = false if switchByItem.include?(user.index)
|
||||
@battle.pbPriority(true).each do |b|
|
||||
b.pbEffectsOnSwitchIn(true) if switchByItem.include?(b.index)
|
||||
end
|
||||
switchByItem.each { |idxB| switchedBattlers.push(idxB) }
|
||||
# User's held item (Life Orb, Shell Bell)
|
||||
if !switchedBattlers.include?(user.index) && user.itemActive?
|
||||
BattleHandlers.triggerUserItemAfterMoveUse(user.item,user,targets,move,numHits,@battle)
|
||||
end
|
||||
# Target's ability (Berserk, Color Change, Emergency Exit, Pickpocket, Wimp Out)
|
||||
switchWimpOut = []
|
||||
@battle.pbPriority(true).each do |b|
|
||||
next if !targets.any? { |targetB| targetB.index==b.index }
|
||||
next if b.damageState.unaffected || switchedBattlers.include?(b.index)
|
||||
next if !b.abilityActive?
|
||||
BattleHandlers.triggerTargetAbilityAfterMoveUse(b.ability,b,user,move,switchedBattlers,@battle)
|
||||
if !switchedBattlers.include?(b.index) && move.damagingMove?
|
||||
if b.pbAbilitiesOnDamageTaken(b.damageState.initialHP) # Emergency Exit, Wimp Out
|
||||
switchWimpOut.push(b.index)
|
||||
end
|
||||
end
|
||||
end
|
||||
@battle.moldBreaker = false if switchWimpOut.include?(user.index)
|
||||
@battle.pbPriority(true).each do |b|
|
||||
next if b.index==user.index
|
||||
b.pbEffectsOnSwitchIn(true) if switchWimpOut.include?(b.index)
|
||||
end
|
||||
switchWimpOut.each { |idxB| switchedBattlers.push(idxB) }
|
||||
# User's ability (Emergency Exit, Wimp Out)
|
||||
if !switchedBattlers.include?(user.index) && move.damagingMove?
|
||||
hpNow = user.hp if user.hp<hpNow # In case HP was lost because of Life Orb
|
||||
if user.pbAbilitiesOnDamageTaken(user.initialHP,hpNow)
|
||||
@battle.moldBreaker = false
|
||||
user.pbEffectsOnSwitchIn(true)
|
||||
switchedBattlers.push(user.index)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user