#=============================================================================== # #=============================================================================== class Battle::Move #----------------------------------------------------------------------------- # Effect methods per move usage. #----------------------------------------------------------------------------- def pbCanChooseMove?(user, commandPhase, showMessages); return true; end # For Belch def pbDisplayChargeMessage(user); end # For Focus Punch/shell Trap/Beak Blast def pbOnStartUse(user, targets); end def pbAddTarget(targets, user); end # For Counter, etc. and Bide def pbModifyTargets(targets, user); end # For Dragon Darts # Reset move usage counters (child classes can increment them). def pbChangeUsageCounters(user, specialUsage) user.effects[PBEffects::FuryCutter] = 0 user.effects[PBEffects::ParentalBond] = 0 user.effects[PBEffects::ProtectRate] = 1 @battle.field.effects[PBEffects::FusionBolt] = false @battle.field.effects[PBEffects::FusionFlare] = false end def pbDisplayUseMessage(user) @battle.pbDisplayBrief(_INTL("{1} used {2}!", user.pbThis, @name)) end def pbShowFailMessages?(targets); return true; end def pbMissMessage(user, target); return false; end #----------------------------------------------------------------------------- # #----------------------------------------------------------------------------- # Whether the move is currently in the "charging" turn of a two-turn move. # Is false if Power Herb or another effect lets a two-turn move charge and # attack in the same turn. # user.effects[PBEffects::TwoTurnAttack] is set to the move's ID during the # charging turn, and is nil during the attack turn. def pbIsChargingTurn?(user); return false; end def pbDamagingMove?; return damagingMove?; end def pbContactMove?(user) return false if user.hasActiveAbility?(:LONGREACH) return false if punchingMove? && user.hasActiveItem?(:PUNCHINGGLOVE) return contactMove? end # The maximum number of hits in a round this move will actually perform. This # can be 1 for Beat Up, and can be 2 for any moves affected by Parental Bond. def pbNumHits(user, targets) if user.hasActiveAbility?(:PARENTALBOND) && pbDamagingMove? && !chargingTurnMove? && targets.length == 1 # Record that Parental Bond applies, to weaken the second attack user.effects[PBEffects::ParentalBond] = 3 return 2 end return 1 end # For two-turn moves when they charge and attack in the same turn. def pbQuickChargingMove(user, targets); end #----------------------------------------------------------------------------- # Effect methods per hit. #----------------------------------------------------------------------------- def pbOverrideSuccessCheckPerHit(user, target); return false; end def pbCrashDamage(user); end def pbInitialEffect(user, targets, hitNum); end def pbDesignateTargetsForHit(targets, hitNum); return targets; end # For Dragon Darts def pbRepeatHit?; return false; end # For Dragon Darts def pbShowAnimation(id, user, targets, hitNum = 0, showAnimation = true) return if !showAnimation if user.effects[PBEffects::ParentalBond] == 1 @battle.pbCommonAnimation("ParentalBond", user, targets) else @battle.pbAnimation(id, user, targets, hitNum) end end def pbSelfKO(user); end def pbEffectWhenDealingDamage(user, target); end def pbEffectAgainstTarget(user, target); end def pbEffectGeneral(user); end def pbAdditionalEffect(user, target); end def pbEffectAfterAllHits(user, target); end # Move effects that occur after all hits def pbSwitchOutTargetEffect(user, targets, numHits, switched_battlers); end def pbEndOfMoveUsageEffect(user, targets, numHits, switchedBattlers); end #----------------------------------------------------------------------------- # Check if target is immune to the move because of its ability. #----------------------------------------------------------------------------- def pbImmunityByAbility(user, target, show_message) ret = false if target.abilityActive? && !target.beingMoldBroken? ret = Battle::AbilityEffects.triggerMoveImmunity(target.ability, user, target, self, @calcType, @battle, show_message) end return ret end #----------------------------------------------------------------------------- # Move failure checks. #----------------------------------------------------------------------------- # Check whether the move fails completely due to move-specific requirements. def pbMoveFailed?(user, targets); return false; end # Checks whether the move will be ineffective against the target. def pbFailsAgainstTarget?(user, target, show_message); return false; end def pbMoveFailedLastInRound?(user, showMessage = true) unmoved = @battle.allBattlers.any? do |b| next b.index != user.index && [:UseMove, :Shift].include?(@battle.choices[b.index][0]) && !b.movedThisRound? end if !unmoved @battle.pbDisplay(_INTL("But it failed!")) if showMessage return true end return false end def pbMoveFailedTargetAlreadyMoved?(target, showMessage = true) if (@battle.choices[target.index][0] != :UseMove && @battle.choices[target.index][0] != :Shift) || target.movedThisRound? @battle.pbDisplay(_INTL("But it failed!")) if showMessage return true end return false end def pbMoveFailedAromaVeil?(user, target, showMessage = true) if target.hasActiveAbility?(:AROMAVEIL) && !target.beingMoldBroken? if showMessage @battle.pbShowAbilitySplash(target) if Battle::Scene::USE_ABILITY_SPLASH @battle.pbDisplay(_INTL("{1} is unaffected!", target.pbThis)) else @battle.pbDisplay(_INTL("{1} is unaffected because of its {2}!", target.pbThis, target.abilityName)) end @battle.pbHideAbilitySplash(target) end return true end target.allAllies.each do |b| next if !b.hasActiveAbility?(:AROMAVEIL) || b.beingMoldBroken? if showMessage @battle.pbShowAbilitySplash(b) if Battle::Scene::USE_ABILITY_SPLASH @battle.pbDisplay(_INTL("{1} is unaffected!", target.pbThis)) else @battle.pbDisplay(_INTL("{1} is unaffected because of {2}'s {3}!", target.pbThis, b.pbThis(true), b.abilityName)) end @battle.pbHideAbilitySplash(b) end return true end return false end #----------------------------------------------------------------------------- # Weaken the damage dealt (doesn't actually change a battler's HP). #----------------------------------------------------------------------------- def pbCheckDamageAbsorption(user, target) # Substitute will take the damage if target.effects[PBEffects::Substitute] > 0 && !ignoresSubstitute?(user) && (!user || user.index != target.index) target.damageState.substitute = true return end # Ice Face will take the damage if !target.beingMoldBroken? && target.isSpecies?(:EISCUE) && target.form == 0 && target.ability == :ICEFACE && physicalMove? target.damageState.iceFace = true return end # Disguise will take the damage if !target.beingMoldBroken? && target.isSpecies?(:MIMIKYU) && target.form == 0 && target.ability == :DISGUISE target.damageState.disguise = true return end end def pbReduceDamage(user, target) damage = target.damageState.calcDamage # Substitute takes the damage if target.damageState.substitute damage = target.effects[PBEffects::Substitute] if damage > target.effects[PBEffects::Substitute] target.damageState.hpLost = damage target.damageState.totalHPLost += damage return end # Disguise/Ice Face takes the damage return if target.damageState.disguise || target.damageState.iceFace # Target takes the damage if damage >= target.hp damage = target.hp # Survive a lethal hit with 1 HP effects if nonLethal?(user, target) damage -= 1 elsif target.effects[PBEffects::Endure] target.damageState.endured = true damage -= 1 elsif target.hasActiveAbility?(:STURDY) && !target.beingMoldBroken? && target.hp == target.totalhp target.damageState.sturdy = true damage -= 1 elsif target.hasActiveItem?(:FOCUSSASH) && target.hp == target.totalhp target.damageState.focusSash = true damage -= 1 elsif target.hasActiveItem?(:FOCUSBAND) && @battle.pbRandom(100) < 10 target.damageState.focusBand = true damage -= 1 elsif Settings::AFFECTION_EFFECTS && @battle.internalBattle && target.pbOwnedByPlayer? && !target.mega? chance = [0, 0, 0, 10, 15, 25][target.affection_level] if chance > 0 && @battle.pbRandom(100) < chance target.damageState.affection_endured = true damage -= 1 end end end damage = 0 if damage < 0 target.damageState.hpLost = damage target.damageState.totalHPLost += damage end #----------------------------------------------------------------------------- # Change the target's HP by the amount calculated above. #----------------------------------------------------------------------------- def pbInflictHPDamage(target) if target.damageState.substitute target.effects[PBEffects::Substitute] -= target.damageState.hpLost elsif target.damageState.hpLost > 0 target.pbReduceHP(target.damageState.hpLost, false, true, false) end end #----------------------------------------------------------------------------- # Animate the damage dealt, including lowering the HP. #----------------------------------------------------------------------------- # Animate being damaged and losing HP (by a move) def pbAnimateHitAndHPLost(user, targets) # Animate allies first, then foes animArray = [] 2.times do |side| # side here means "allies first, then foes" targets.each do |b| next if b.damageState.unaffected || b.damageState.hpLost == 0 next if (side == 0 && b.opposes?(user)) || (side == 1 && !b.opposes?(user)) oldHP = b.hp if b.damageState.substitute old_sub_hp = b.effects[PBEffects::Substitute] + b.damageState.hpLost PBDebug.log("[Substitute HP change] #{b.pbThis}'s substitute lost #{b.damageState.hpLost} HP (#{old_sub_hp} -> #{b.effects[PBEffects::Substitute]})") else oldHP += b.damageState.hpLost end effectiveness = 0 if !self.is_a?(Battle::Move::FixedDamageMove) if Effectiveness.resistant?(b.damageState.typeMod) effectiveness = 1 elsif Effectiveness.super_effective?(b.damageState.typeMod) effectiveness = 2 end end animArray.push([b, oldHP, effectiveness]) end if animArray.length > 0 @battle.scene.pbHitAndHPLossAnimation(animArray) animArray.clear end end end #----------------------------------------------------------------------------- # Messages upon being hit. #----------------------------------------------------------------------------- def pbEffectivenessMessage(user, target, numTargets = 1) return if self.is_a?(Battle::Move::FixedDamageMove) return if target.damageState.disguise || target.damageState.iceFace if Effectiveness.super_effective?(target.damageState.typeMod) if numTargets > 1 @battle.pbDisplay(_INTL("It's super effective on {1}!", target.pbThis(true))) else @battle.pbDisplay(_INTL("It's super effective!")) end elsif Effectiveness.not_very_effective?(target.damageState.typeMod) if numTargets > 1 @battle.pbDisplay(_INTL("It's not very effective on {1}...", target.pbThis(true))) else @battle.pbDisplay(_INTL("It's not very effective...")) end end end def pbHitEffectivenessMessages(user, target, numTargets = 1) return if target.damageState.disguise || target.damageState.iceFace if target.damageState.substitute @battle.pbDisplay(_INTL("The substitute took damage for {1}!", target.pbThis(true))) end if target.damageState.critical if user.pokemon.isSpecies?(:FARFETCHD) && user.pokemon.form == 1 user.pokemon.evolution_counter += 1 end if target.damageState.affection_critical if numTargets > 1 @battle.pbDisplay(_INTL("{1} landed a critical hit on {2}, wishing to be praised!", user.pbThis, target.pbThis(true))) else @battle.pbDisplay(_INTL("{1} landed a critical hit, wishing to be praised!", user.pbThis)) end elsif numTargets > 1 @battle.pbDisplay(_INTL("A critical hit on {1}!", target.pbThis(true))) else @battle.pbDisplay(_INTL("A critical hit!")) end end # Effectiveness message, for moves with 1 hit if !multiHitMove? && user.effects[PBEffects::ParentalBond] == 0 pbEffectivenessMessage(user, target, numTargets) end if target.damageState.substitute && target.effects[PBEffects::Substitute] == 0 target.effects[PBEffects::Substitute] = 0 @battle.pbDisplay(_INTL("{1}'s substitute faded!", target.pbThis)) end end def pbEndureKOMessage(target) if target.damageState.disguise @battle.pbShowAbilitySplash(target) if Battle::Scene::USE_ABILITY_SPLASH @battle.pbDisplay(_INTL("Its disguise served it as a decoy!")) else @battle.pbDisplay(_INTL("{1}'s disguise served it as a decoy!", target.pbThis)) end @battle.pbHideAbilitySplash(target) target.pbChangeForm(1, _INTL("{1}'s disguise was busted!", target.pbThis)) target.pbReduceHP(target.totalhp / 8, false) if Settings::MECHANICS_GENERATION >= 8 elsif target.damageState.iceFace @battle.pbShowAbilitySplash(target) if !Battle::Scene::USE_ABILITY_SPLASH @battle.pbDisplay(_INTL("{1}'s {2} activated!", target.pbThis, target.abilityName)) end target.pbChangeForm(1, _INTL("{1} transformed!", target.pbThis)) @battle.pbHideAbilitySplash(target) elsif target.damageState.endured @battle.pbDisplay(_INTL("{1} endured the hit!", target.pbThis)) elsif target.damageState.sturdy @battle.pbShowAbilitySplash(target) if Battle::Scene::USE_ABILITY_SPLASH @battle.pbDisplay(_INTL("{1} endured the hit!", target.pbThis)) else @battle.pbDisplay(_INTL("{1} hung on with Sturdy!", target.pbThis)) end @battle.pbHideAbilitySplash(target) elsif target.damageState.focusSash @battle.pbCommonAnimation("UseItem", target) @battle.pbDisplay(_INTL("{1} hung on using its Focus Sash!", target.pbThis)) target.pbConsumeItem elsif target.damageState.focusBand @battle.pbCommonAnimation("UseItem", target) @battle.pbDisplay(_INTL("{1} hung on using its Focus Band!", target.pbThis)) elsif target.damageState.affection_endured @battle.pbDisplay(_INTL("{1} toughed it out so you wouldn't feel sad!", target.pbThis)) end end # Used by Counter/Mirror Coat/Metal Burst/Revenge/Focus Punch/Bide/Assurance. def pbRecordDamageLost(user, target) damage = target.damageState.hpLost # NOTE: In Gen 3 where a move's category depends on its type, Hidden Power # is for some reason countered by Counter rather than Mirror Coat, # regardless of its calculated type. Hence the following two lines of # code. moveType = nil moveType = :NORMAL if @function_code == "TypeDependsOnUserIVs" # Hidden Power if !target.damageState.substitute if physicalMove?(moveType) target.effects[PBEffects::Counter] = damage target.effects[PBEffects::CounterTarget] = user.index elsif specialMove?(moveType) target.effects[PBEffects::MirrorCoat] = damage target.effects[PBEffects::MirrorCoatTarget] = user.index end if target.opposes?(user) target.lastHPLostFromFoe = damage # For Metal Burst target.lastFoeAttacker.push(user.pokemonIndex) # For Metal Burst end end if target.effects[PBEffects::Bide] > 0 target.effects[PBEffects::BideDamage] += damage target.effects[PBEffects::BideTarget] = user.index end target.damageState.fainted = true if target.fainted? target.lastHPLost = damage target.tookMoveDamageThisRound = true if damage > 0 && !target.damageState.substitute # For Focus Punch target.tookDamageThisRound = true if damage > 0 # For Assurance target.lastAttacker.push(user.index) # For Revenge if target.pokemon.isSpecies?(:YAMASK) && target.pokemon.form == 1 target.pokemon.evolution_counter += damage end end end