# DO NOT USE ANY CLASS NAMES IN HERE AS FUNCTION CODES! # These are base classes for other classes to build on; those other classes are # named after function codes, so use those instead. #=============================================================================== # Superclass that handles moves using a non-existent function code. # Damaging moves just do damage with no additional effect. # Status moves always fail. #=============================================================================== class Battle::Move::Unimplemented < Battle::Move def pbMoveFailed?(user, targets) if statusMove? @battle.pbDisplay(_INTL("But it failed!")) return true end return false end end #=============================================================================== # Pseudomove for confusion damage. #=============================================================================== class Battle::Move::Confusion < Battle::Move def initialize(battle, move) @battle = battle @realMove = move @id = :CONFUSEDAMAGE @name = "" @function = "None" @baseDamage = 40 @type = nil @category = 0 @accuracy = 100 @pp = -1 @target = 0 @priority = 0 @flags = [] @addlEffect = 0 @calcType = nil @powerBoost = false @snatched = false end def physicalMove?(thisType = nil); return true; end def specialMove?(thisType = nil); return false; end def pbCritialOverride(user, target); return -1; end end #=============================================================================== # Struggle. #=============================================================================== class Battle::Move::Struggle < Battle::Move def initialize(battle, move) @battle = battle @realMove = nil # Not associated with a move @id = (move) ? move.id : :STRUGGLE @name = (move) ? move.name : _INTL("Struggle") @function = "Struggle" @baseDamage = 50 @type = nil @category = 0 @accuracy = 0 @pp = -1 @target = 0 @priority = 0 @flags = ["Contact", "CanProtect"] @addlEffect = 0 @calcType = nil @powerBoost = false @snatched = false end def physicalMove?(thisType = nil); return true; end def specialMove?(thisType = nil); return false; end def pbEffectAfterAllHits(user, target) return if target.damageState.unaffected user.pbReduceHP((user.totalhp / 4.0).round, false) @battle.pbDisplay(_INTL("{1} is damaged by recoil!", user.pbThis)) user.pbItemHPHealCheck end end #=============================================================================== # Raise one of user's stats. #=============================================================================== class Battle::Move::StatUpMove < Battle::Move def canSnatch?; return true; end def pbMoveFailed?(user, targets) return false if damagingMove? return !user.pbCanRaiseStatStage?(@statUp[0], user, self, true) end def pbEffectGeneral(user) return if damagingMove? user.pbRaiseStatStage(@statUp[0], @statUp[1], user) end def pbAdditionalEffect(user, target) if user.pbCanRaiseStatStage?(@statUp[0], user, self) user.pbRaiseStatStage(@statUp[0], @statUp[1], user) end end end #=============================================================================== # Raise multiple of user's stats. #=============================================================================== class Battle::Move::MultiStatUpMove < Battle::Move def canSnatch?; return true; end def pbMoveFailed?(user, targets) return false if damagingMove? failed = true for i in 0...@statUp.length / 2 next if !user.pbCanRaiseStatStage?(@statUp[i * 2], user, self) failed = false break end if failed @battle.pbDisplay(_INTL("{1}'s stats won't go any higher!", user.pbThis)) return true end return false end def pbEffectGeneral(user) return if damagingMove? showAnim = true for i in 0...@statUp.length / 2 next if !user.pbCanRaiseStatStage?(@statUp[i * 2], user, self) if user.pbRaiseStatStage(@statUp[i * 2], @statUp[i * 2 + 1], user, showAnim) showAnim = false end end end def pbAdditionalEffect(user, target) showAnim = true for i in 0...@statUp.length / 2 next if !user.pbCanRaiseStatStage?(@statUp[i * 2], user, self) if user.pbRaiseStatStage(@statUp[i * 2], @statUp[i * 2 + 1], user, showAnim) showAnim = false end end end end #=============================================================================== # Lower multiple of user's stats. #=============================================================================== class Battle::Move::StatDownMove < Battle::Move def pbEffectWhenDealingDamage(user, target) return if @battle.pbAllFainted?(target.idxOwnSide) showAnim = true for i in 0...@statDown.length / 2 next if !user.pbCanLowerStatStage?(@statDown[i * 2], user, self) if user.pbLowerStatStage(@statDown[i * 2], @statDown[i * 2 + 1], user, showAnim) showAnim = false end end end end #=============================================================================== # Lower one of target's stats. #=============================================================================== class Battle::Move::TargetStatDownMove < Battle::Move def canMagicCoat?; return true; end def pbFailsAgainstTarget?(user, target, show_message) return false if damagingMove? return !target.pbCanLowerStatStage?(@statDown[0], user, self, show_message) end def pbEffectAgainstTarget(user, target) return if damagingMove? target.pbLowerStatStage(@statDown[0], @statDown[1], user) end def pbAdditionalEffect(user, target) return if target.damageState.substitute return if !target.pbCanLowerStatStage?(@statDown[0], user, self) target.pbLowerStatStage(@statDown[0], @statDown[1], user) end end #=============================================================================== # Lower multiple of target's stats. #=============================================================================== class Battle::Move::TargetMultiStatDownMove < Battle::Move def canMagicCoat?; return true; end def pbFailsAgainstTarget?(user, target, show_message) return false if damagingMove? failed = true for i in 0...@statDown.length / 2 next if !target.pbCanLowerStatStage?(@statDown[i * 2], user, self) failed = false break end if failed # NOTE: It's a bit of a faff to make sure the appropriate failure message # is shown here, I know. canLower = false if target.hasActiveAbility?(:CONTRARY) && !@battle.moldBreaker for i in 0...@statDown.length / 2 next if target.statStageAtMax?(@statDown[i * 2]) canLower = true break end @battle.pbDisplay(_INTL("{1}'s stats won't go any higher!", user.pbThis)) if !canLower && show_message else for i in 0...@statDown.length / 2 next if target.statStageAtMin?(@statDown[i * 2]) canLower = true break end @battle.pbDisplay(_INTL("{1}'s stats won't go any lower!", user.pbThis)) if !canLower && show_message end if canLower target.pbCanLowerStatStage?(@statDown[0], user, self, show_message) end return true end return false end def pbCheckForMirrorArmor(user, target) if target.hasActiveAbility?(:MIRRORARMOR) && user.index != target.index failed = true for i in 0...@statDown.length / 2 next if target.statStageAtMin?(@statDown[i * 2]) next if !user.pbCanLowerStatStage?(@statDown[i * 2], target, self, false, false, true) failed = false break end if failed @battle.pbShowAbilitySplash(target) if !Battle::Scene::USE_ABILITY_SPLASH @battle.pbDisplay(_INTL("{1}'s {2} activated!", target.pbThis, target.abilityName)) end user.pbCanLowerStatStage?(@statDown[0], target, self, true, false, true) # Show fail message @battle.pbHideAbilitySplash(target) return false end end return true end def pbLowerTargetMultipleStats(user, target) return if !pbCheckForMirrorArmor(user, target) showAnim = true showMirrorArmorSplash = true for i in 0...@statDown.length / 2 next if !target.pbCanLowerStatStage?(@statDown[i * 2], user, self) if target.pbLowerStatStage(@statDown[i * 2], @statDown[i * 2 + 1], user, showAnim, false, (showMirrorArmorSplash) ? 1 : 3) showAnim = false end showMirrorArmorSplash = false end @battle.pbHideAbilitySplash(target) # To hide target's Mirror Armor splash end def pbEffectAgainstTarget(user, target) pbLowerTargetMultipleStats(user, target) if !damagingMove? end def pbAdditionalEffect(user, target) pbLowerTargetMultipleStats(user, target) if !target.damageState.substitute end end #=============================================================================== # Fixed damage-inflicting move. #=============================================================================== class Battle::Move::FixedDamageMove < Battle::Move def pbFixedDamage(user, target); return 1; end def pbCalcDamage(user, target, numTargets = 1) target.damageState.critical = false target.damageState.calcDamage = pbFixedDamage(user, target) target.damageState.calcDamage = 1 if target.damageState.calcDamage < 1 end end #=============================================================================== # Two turn move. #=============================================================================== class Battle::Move::TwoTurnMove < Battle::Move attr_reader :chargingTurn def chargingTurnMove?; return true; end # user.effects[PBEffects::TwoTurnAttack] is set to the move's ID if this # method returns true, or nil if false. # Non-nil means the charging turn. nil means the attacking turn. def pbIsChargingTurn?(user) @powerHerb = false @chargingTurn = false # Assume damaging turn by default @damagingTurn = true # nil at start of charging turn, move's ID at start of damaging turn if !user.effects[PBEffects::TwoTurnAttack] @powerHerb = user.hasActiveItem?(:POWERHERB) @chargingTurn = true @damagingTurn = @powerHerb end return !@damagingTurn # Deliberately not "return @chargingTurn" end def pbDamagingMove? # Stops damage being dealt in the first (charging) turn return false if !@damagingTurn return super end def pbAccuracyCheck(user, target) return true if !@damagingTurn return super end def pbInitialEffect(user, targets, hitNum) pbChargingTurnMessage(user, targets) if @chargingTurn if @chargingTurn && @damagingTurn # Move only takes one turn to use pbShowAnimation(@id, user, targets, 1) # Charging anim targets.each { |b| pbChargingTurnEffect(user, b) } if @powerHerb # Moves that would make the user semi-invulnerable will hide the user # after the charging animation, so the "UseItem" animation shouldn't show # for it if !["TwoTurnAttackInvulnerableInSky", "TwoTurnAttackInvulnerableUnderground", "TwoTurnAttackInvulnerableUnderwater", "TwoTurnAttackInvulnerableInSkyParalyzeTarget", "TwoTurnAttackInvulnerableRemoveProtections", "TwoTurnAttackInvulnerableInSkyTargetCannotAct"].include?(@function) @battle.pbCommonAnimation("UseItem", user) end @battle.pbDisplay(_INTL("{1} became fully charged due to its Power Herb!", user.pbThis)) user.pbConsumeItem end end pbAttackingTurnMessage(user, targets) if @damagingTurn end def pbChargingTurnMessage(user, targets) @battle.pbDisplay(_INTL("{1} began charging up!", user.pbThis)) end def pbAttackingTurnMessage(user, targets) end def pbChargingTurnEffect(user, target) # Skull Bash/Sky Drop are the only two-turn moves with an effect here, and # the latter just records the target is being Sky Dropped end def pbAttackingTurnEffect(user, target) end def pbEffectAgainstTarget(user, target) if @damagingTurn pbAttackingTurnEffect(user, target) elsif @chargingTurn pbChargingTurnEffect(user, target) end end def pbShowAnimation(id, user, targets, hitNum = 0, showAnimation = true) hitNum = 1 if @chargingTurn && !@damagingTurn # Charging anim super end end #=============================================================================== # Healing move. #=============================================================================== class Battle::Move::HealingMove < Battle::Move def healingMove?; return true; end def pbHealAmount(user); return 1; end def canSnatch?; return true; end def pbMoveFailed?(user, targets) if user.hp == user.totalhp @battle.pbDisplay(_INTL("{1}'s HP is full!", user.pbThis)) return true end return false end def pbEffectGeneral(user) amt = pbHealAmount(user) user.pbRecoverHP(amt) @battle.pbDisplay(_INTL("{1}'s HP was restored.", user.pbThis)) end end #=============================================================================== # Recoil move. #=============================================================================== class Battle::Move::RecoilMove < Battle::Move def recoilMove?; return true; end def pbRecoilDamage(user, target); return 1; end def pbEffectAfterAllHits(user, target) return if target.damageState.unaffected return if !user.takesIndirectDamage? return if user.hasActiveAbility?(:ROCKHEAD) amt = pbRecoilDamage(user, target) amt = 1 if amt < 1 user.pbReduceHP(amt, false) @battle.pbDisplay(_INTL("{1} is damaged by recoil!", user.pbThis)) user.pbItemHPHealCheck end end #=============================================================================== # Protect move. #=============================================================================== class Battle::Move::ProtectMove < Battle::Move def initialize(battle, move) super @sidedEffect = false end def pbChangeUsageCounters(user, specialUsage) oldVal = user.effects[PBEffects::ProtectRate] super user.effects[PBEffects::ProtectRate] = oldVal end def pbMoveFailed?(user, targets) if @sidedEffect if user.pbOwnSide.effects[@effect] user.effects[PBEffects::ProtectRate] = 1 @battle.pbDisplay(_INTL("But it failed!")) return true end elsif user.effects[@effect] user.effects[PBEffects::ProtectRate] = 1 @battle.pbDisplay(_INTL("But it failed!")) return true end if (!@sidedEffect || Settings::MECHANICS_GENERATION <= 5) && user.effects[PBEffects::ProtectRate] > 1 && @battle.pbRandom(user.effects[PBEffects::ProtectRate]) != 0 user.effects[PBEffects::ProtectRate] = 1 @battle.pbDisplay(_INTL("But it failed!")) return true end if pbMoveFailedLastInRound?(user) user.effects[PBEffects::ProtectRate] = 1 return true end return false end def pbEffectGeneral(user) if @sidedEffect user.pbOwnSide.effects[@effect] = true else user.effects[@effect] = true end user.effects[PBEffects::ProtectRate] *= (Settings::MECHANICS_GENERATION >= 6) ? 3 : 2 pbProtectMessage(user) end def pbProtectMessage(user) if @sidedEffect @battle.pbDisplay(_INTL("{1} protected {2}!", @name, user.pbTeam(true))) else @battle.pbDisplay(_INTL("{1} protected itself!", user.pbThis)) end end end #=============================================================================== # Weather-inducing move. #=============================================================================== class Battle::Move::WeatherMove < Battle::Move def initialize(battle, move) super @weatherType = :None end def pbMoveFailed?(user, targets) case @battle.field.weather when :HarshSun @battle.pbDisplay(_INTL("The extremely harsh sunlight was not lessened at all!")) return true when :HeavyRain @battle.pbDisplay(_INTL("There is no relief from this heavy rain!")) return true when :StrongWinds @battle.pbDisplay(_INTL("The mysterious air current blows on regardless!")) return true when @weatherType @battle.pbDisplay(_INTL("But it failed!")) return true end return false end def pbEffectGeneral(user) @battle.pbStartWeather(user, @weatherType, true, false) end end #=============================================================================== # Pledge move. #=============================================================================== class Battle::Move::PledgeMove < Battle::Move def pbOnStartUse(user, targets) @pledgeSetup = false @pledgeCombo = false @pledgeOtherUser = nil @comboEffect = nil @overrideAnim = nil # Check whether this is the use of a combo move @combos.each do |i| next if i[0] != user.effects[PBEffects::FirstPledge] @battle.pbDisplay(_INTL("The two moves have become one! It's a combined move!")) @pledgeCombo = true @comboEffect = i[1] @overrideAnim = i[3] break end return if @pledgeCombo # Check whether this is the setup of a combo move user.allAllies.each do |b| next if @battle.choices[b.index][0] != :UseMove || b.movedThisRound? move = @battle.choices[b.index][2] next if !move @combos.each do |i| next if i[0] != move.function @pledgeSetup = true @pledgeOtherUser = b break end break if @pledgeSetup end end def pbDamagingMove? return false if @pledgeSetup return super end def pbBaseType(user) # This method is called before pbOnStartUse, so it has to calculate the type # separately @combos.each do |i| next if i[0] != user.effects[PBEffects::FirstPledge] next if !GameData::Type.exists?(i[2]) return i[2] end return super end def pbBaseDamage(baseDmg, user, target) baseDmg *= 2 if @pledgeCombo return baseDmg end def pbEffectGeneral(user) user.effects[PBEffects::FirstPledge] = nil return if !@pledgeSetup @battle.pbDisplay(_INTL("{1} is waiting for {2}'s move...", user.pbThis, @pledgeOtherUser.pbThis(true))) @pledgeOtherUser.effects[PBEffects::FirstPledge] = @function @pledgeOtherUser.effects[PBEffects::MoveNext] = true user.lastMoveFailed = true # Treated as a failure for Stomping Tantrum end def pbEffectAfterAllHits(user, target) return if !@pledgeCombo msg = nil animName = nil case @comboEffect when :SeaOfFire # Grass + Fire if user.pbOpposingSide.effects[PBEffects::SeaOfFire] == 0 user.pbOpposingSide.effects[PBEffects::SeaOfFire] = 4 msg = _INTL("A sea of fire enveloped {1}!", user.pbOpposingTeam(true)) animName = (user.opposes?) ? "SeaOfFire" : "SeaOfFireOpp" end when :Rainbow # Fire + Water if user.pbOwnSide.effects[PBEffects::Rainbow] == 0 user.pbOwnSide.effects[PBEffects::Rainbow] = 4 msg = _INTL("A rainbow appeared in the sky on {1}'s side!", user.pbTeam(true)) animName = (user.opposes?) ? "RainbowOpp" : "Rainbow" end when :Swamp # Water + Grass if user.pbOpposingSide.effects[PBEffects::Swamp] == 0 user.pbOpposingSide.effects[PBEffects::Swamp] = 4 msg = _INTL("A swamp enveloped {1}!", user.pbOpposingTeam(true)) animName = (user.opposes?) ? "Swamp" : "SwampOpp" end end @battle.pbDisplay(msg) if msg @battle.pbCommonAnimation(animName) if animName end def pbShowAnimation(id, user, targets, hitNum = 0, showAnimation = true) return if @pledgeSetup # No animation for setting up id = @overrideAnim if @overrideAnim return super end end