#=============================================================================== # #=============================================================================== module Battle::AbilityEffects SpeedCalc = AbilityHandlerHash.new WeightCalc = AbilityHandlerHash.new # Battler's HP/stat changed OnHPDroppedBelowHalf = AbilityHandlerHash.new # Battler's status problem StatusCheckNonIgnorable = AbilityHandlerHash.new # Comatose StatusImmunity = AbilityHandlerHash.new StatusImmunityNonIgnorable = AbilityHandlerHash.new StatusImmunityFromAlly = AbilityHandlerHash.new OnStatusInflicted = AbilityHandlerHash.new # Synchronize StatusCure = AbilityHandlerHash.new # Battler's stat stages StatLossImmunity = AbilityHandlerHash.new StatLossImmunityNonIgnorable = AbilityHandlerHash.new # Full Metal Body StatLossImmunityFromAlly = AbilityHandlerHash.new # Flower Veil OnStatGain = AbilityHandlerHash.new # None! OnStatLoss = AbilityHandlerHash.new # Priority and turn order PriorityChange = AbilityHandlerHash.new PriorityBracketChange = AbilityHandlerHash.new # Stall PriorityBracketUse = AbilityHandlerHash.new # None! # Move usage failures OnFlinch = AbilityHandlerHash.new # Steadfast MoveBlocking = AbilityHandlerHash.new MoveImmunity = AbilityHandlerHash.new # Move usage ModifyMoveBaseType = AbilityHandlerHash.new # Accuracy calculation AccuracyCalcFromUser = AbilityHandlerHash.new AccuracyCalcFromAlly = AbilityHandlerHash.new # Victory Star AccuracyCalcFromTarget = AbilityHandlerHash.new # Damage calculation DamageCalcFromUser = AbilityHandlerHash.new DamageCalcFromAlly = AbilityHandlerHash.new DamageCalcFromTarget = AbilityHandlerHash.new DamageCalcFromTargetNonIgnorable = AbilityHandlerHash.new DamageCalcFromTargetAlly = AbilityHandlerHash.new CriticalCalcFromUser = AbilityHandlerHash.new CriticalCalcFromTarget = AbilityHandlerHash.new # Upon a move hitting a target OnBeingHit = AbilityHandlerHash.new OnDealingHit = AbilityHandlerHash.new # Poison Touch # Abilities that trigger at the end of using a move OnEndOfUsingMove = AbilityHandlerHash.new AfterMoveUseFromTarget = AbilityHandlerHash.new # End Of Round EndOfRoundWeather = AbilityHandlerHash.new EndOfRoundHealing = AbilityHandlerHash.new EndOfRoundEffect = AbilityHandlerHash.new EndOfRoundGainItem = AbilityHandlerHash.new # Switching and fainting CertainSwitching = AbilityHandlerHash.new # None! TrappingByTarget = AbilityHandlerHash.new OnSwitchIn = AbilityHandlerHash.new OnSwitchOut = AbilityHandlerHash.new ChangeOnBattlerFainting = AbilityHandlerHash.new OnBattlerFainting = AbilityHandlerHash.new # Soul-Heart OnTerrainChange = AbilityHandlerHash.new # Mimicry OnIntimidated = AbilityHandlerHash.new # Rattled (Gen 8) # Running from battle CertainEscapeFromBattle = AbilityHandlerHash.new # Run Away #============================================================================= def self.trigger(hash, *args, ret: false) new_ret = hash.trigger(*args) return (!new_ret.nil?) ? new_ret : ret end #============================================================================= def self.triggerSpeedCalc(ability, battler, mult) return trigger(SpeedCalc, ability, battler, mult, ret: mult) end def self.triggerWeightCalc(ability, battler, weight) return trigger(WeightCalc, ability, battler, weight, ret: weight) end #============================================================================= def self.triggerOnHPDroppedBelowHalf(ability, user, move_user, battle) return trigger(OnHPDroppedBelowHalf, ability, user, move_user, battle) end #============================================================================= def self.triggerStatusCheckNonIgnorable(ability, battler, status) return trigger(StatusCheckNonIgnorable, ability, battler, status) end def self.triggerStatusImmunity(ability, battler, status) return trigger(StatusImmunity, ability, battler, status) end def self.triggerStatusImmunityNonIgnorable(ability, battler, status) return trigger(StatusImmunityNonIgnorable, ability, battler, status) end def self.triggerStatusImmunityFromAlly(ability, battler, status) return trigger(StatusImmunityFromAlly, ability, battler, status) end def self.triggerOnStatusInflicted(ability, battler, user, status) OnStatusInflicted.trigger(ability, battler, user, status) end def self.triggerStatusCure(ability, battler) return trigger(StatusCure, ability, battler) end #============================================================================= def self.triggerStatLossImmunity(ability, battler, stat, battle, show_messages) return trigger(StatLossImmunity, ability, battler, stat, battle, show_messages) end def self.triggerStatLossImmunityNonIgnorable(ability, battler, stat, battle, show_messages) return trigger(StatLossImmunityNonIgnorable, ability, battler, stat, battle, show_messages) end def self.triggerStatLossImmunityFromAlly(ability, bearer, battler, stat, battle, show_messages) return trigger(StatLossImmunityFromAlly, ability, bearer, battler, stat, battle, show_messages) end def self.triggerOnStatGain(ability, battler, stat, user) OnStatGain.trigger(ability, battler, stat, user) end def self.triggerOnStatLoss(ability, battler, stat, user) OnStatLoss.trigger(ability, battler, stat, user) end #============================================================================= def self.triggerPriorityChange(ability, battler, move, priority) return trigger(PriorityChange, ability, battler, move, priority, ret: priority) end def self.triggerPriorityBracketChange(ability, battler, battle) return trigger(PriorityBracketChange, ability, battler, battle, ret: 0) end def self.triggerPriorityBracketUse(ability, battler, battle) PriorityBracketUse.trigger(ability, battler, battle) end #============================================================================= def self.triggerOnFlinch(ability, battler, battle) OnFlinch.trigger(ability, battler, battle) end def self.triggerMoveBlocking(ability, bearer, user, targets, move, battle) return trigger(MoveBlocking, ability, bearer, user, targets, move, battle) end def self.triggerMoveImmunity(ability, user, target, move, type, battle, show_message) return trigger(MoveImmunity, ability, user, target, move, type, battle, show_message) end #============================================================================= def self.triggerModifyMoveBaseType(ability, user, move, type) return trigger(ModifyMoveBaseType, ability, user, move, type, ret: type) end #============================================================================= def self.triggerAccuracyCalcFromUser(ability, mods, user, target, move, type) AccuracyCalcFromUser.trigger(ability, mods, user, target, move, type) end def self.triggerAccuracyCalcFromAlly(ability, mods, user, target, move, type) AccuracyCalcFromAlly.trigger(ability, mods, user, target, move, type) end def self.triggerAccuracyCalcFromTarget(ability, mods, user, target, move, type) AccuracyCalcFromTarget.trigger(ability, mods, user, target, move, type) end #============================================================================= def self.triggerDamageCalcFromUser(ability, user, target, move, mults, base_damage, type) DamageCalcFromUser.trigger(ability, user, target, move, mults, base_damage, type) end def self.triggerDamageCalcFromAlly(ability, user, target, move, mults, base_damage, type) DamageCalcFromAlly.trigger(ability, user, target, move, mults, base_damage, type) end def self.triggerDamageCalcFromTarget(ability, user, target, move, mults, base_damage, type) DamageCalcFromTarget.trigger(ability, user, target, move, mults, base_damage, type) end def self.triggerDamageCalcFromTargetNonIgnorable(ability, user, target, move, mults, base_damage, type) DamageCalcFromTargetNonIgnorable.trigger(ability, user, target, move, mults, base_damage, type) end def self.triggerDamageCalcFromTargetAlly(ability, user, target, move, mults, base_damage, type) DamageCalcFromTargetAlly.trigger(ability, user, target, move, mults, base_damage, type) end def self.triggerCriticalCalcFromUser(ability, user, target, crit_stage) return trigger(CriticalCalcFromUser, ability, user, target, crit_stage, ret: crit_stage) end def self.triggerCriticalCalcFromTarget(ability, user, target, crit_stage) return trigger(CriticalCalcFromTarget, ability, user, target, crit_stage, ret: crit_stage) end #============================================================================= def self.triggerOnBeingHit(ability, user, target, move, battle) OnBeingHit.trigger(ability, user, target, move, battle) end def self.triggerOnDealingHit(ability, user, target, move, battle) OnDealingHit.trigger(ability, user, target, move, battle) end #============================================================================= def self.triggerOnEndOfUsingMove(ability, user, targets, move, battle) OnEndOfUsingMove.trigger(ability, user, targets, move, battle) end def self.triggerAfterMoveUseFromTarget(ability, target, user, move, switched_battlers, battle) AfterMoveUseFromTarget.trigger(ability, target, user, move, switched_battlers, battle) end #============================================================================= def self.triggerEndOfRoundWeather(ability, weather, battler, battle) EndOfRoundWeather.trigger(ability, weather, battler, battle) end def self.triggerEndOfRoundHealing(ability, battler, battle) EndOfRoundHealing.trigger(ability, battler, battle) end def self.triggerEndOfRoundEffect(ability, battler, battle) EndOfRoundEffect.trigger(ability, battler, battle) end def self.triggerEndOfRoundGainItem(ability, battler, battle) EndOfRoundGainItem.trigger(ability, battler, battle) end #============================================================================= def self.triggerCertainSwitching(ability, switcher, battle) return trigger(CertainSwitching, ability, switcher, battle) end def self.triggerTrappingByTarget(ability, switcher, bearer, battle) return trigger(TrappingByTarget, ability, switcher, bearer, battle) end def self.triggerOnSwitchIn(ability, battler, battle, switch_in = false) OnSwitchIn.trigger(ability, battler, battle, switch_in) end def self.triggerOnSwitchOut(ability, battler, end_of_battle) OnSwitchOut.trigger(ability, battler, end_of_battle) end def self.triggerChangeOnBattlerFainting(ability, battler, fainted, battle) ChangeOnBattlerFainting.trigger(ability, battler, fainted, battle) end def self.triggerOnBattlerFainting(ability, battler, fainted, battle) OnBattlerFainting.trigger(ability, battler, fainted, battle) end def self.triggerOnTerrainChange(ability, battler, battle, ability_changed) OnTerrainChange.trigger(ability, battler, battle, ability_changed) end def self.triggerOnIntimidated(ability, battler, battle) OnIntimidated.trigger(ability, battler, battle) end #============================================================================= def self.triggerCertainEscapeFromBattle(ability, battler) return trigger(CertainEscapeFromBattle, ability, battler) end end #=============================================================================== # SpeedCalc handlers #=============================================================================== Battle::AbilityEffects::SpeedCalc.add(:CHLOROPHYLL, proc { |ability, battler, mult| next mult * 2 if [:Sun, :HarshSun].include?(battler.effectiveWeather) } ) Battle::AbilityEffects::SpeedCalc.add(:QUICKFEET, proc { |ability, battler, mult| next mult * 1.5 if battler.pbHasAnyStatus? } ) Battle::AbilityEffects::SpeedCalc.add(:SANDRUSH, proc { |ability, battler, mult| next mult * 2 if [:Sandstorm].include?(battler.effectiveWeather) } ) Battle::AbilityEffects::SpeedCalc.add(:SLOWSTART, proc { |ability, battler, mult| next mult / 2 if battler.effects[PBEffects::SlowStart] > 0 } ) Battle::AbilityEffects::SpeedCalc.add(:SLUSHRUSH, proc { |ability, battler, mult| next mult * 2 if [:Hail].include?(battler.effectiveWeather) } ) Battle::AbilityEffects::SpeedCalc.add(:SURGESURFER, proc { |ability, battler, mult| next mult * 2 if battler.battle.field.terrain == :Electric } ) Battle::AbilityEffects::SpeedCalc.add(:SWIFTSWIM, proc { |ability, battler, mult| next mult * 2 if [:Rain, :HeavyRain].include?(battler.effectiveWeather) } ) Battle::AbilityEffects::SpeedCalc.add(:UNBURDEN, proc { |ability, battler, mult| next mult * 2 if battler.effects[PBEffects::Unburden] && !battler.item } ) #=============================================================================== # WeightCalcy handlers #=============================================================================== Battle::AbilityEffects::WeightCalc.add(:HEAVYMETAL, proc { |ability, battler, w| next w * 2 } ) Battle::AbilityEffects::WeightCalc.add(:LIGHTMETAL, proc { |ability, battler, w| next [w / 2, 1].max } ) #=============================================================================== # OnHPDroppedBelowHalf handlers #=============================================================================== Battle::AbilityEffects::OnHPDroppedBelowHalf.add(:EMERGENCYEXIT, proc { |ability, battler, move_user, battle| next false if battler.effects[PBEffects::SkyDrop] >= 0 || battler.inTwoTurnAttack?("TwoTurnAttackInvulnerableInSkyTargetCannotAct") # Sky Drop # In wild battles if battle.wildBattle? next false if battler.opposes? && battle.pbSideBattlerCount(battler.index) > 1 next false if !battle.pbCanRun?(battler.index) battle.pbShowAbilitySplash(battler, true) battle.pbHideAbilitySplash(battler) pbSEPlay("Battle flee") battle.pbDisplay(_INTL("{1} fled from battle!", battler.pbThis)) battle.decision = 3 # Escaped next true end # In trainer battles next false if battle.pbAllFainted?(battler.idxOpposingSide) next false if !battle.pbCanSwitch?(battler.index) # Battler can't switch out next false if !battle.pbCanChooseNonActive?(battler.index) # No Pokémon can switch in battle.pbShowAbilitySplash(battler, true) battle.pbHideAbilitySplash(battler) if !Battle::Scene::USE_ABILITY_SPLASH battle.pbDisplay(_INTL("{1}'s {2} activated!", battler.pbThis, battler.abilityName)) end battle.pbDisplay(_INTL("{1} went back to {2}!", battler.pbThis, battle.pbGetOwnerName(battler.index))) if battle.endOfRound # Just switch out battle.scene.pbRecall(battler.index) if !battler.fainted? battler.pbAbilitiesOnSwitchOut # Inc. primordial weather check next true end newPkmn = battle.pbGetReplacementPokemonIndex(battler.index) # Owner chooses next false if newPkmn < 0 # Shouldn't ever do this battle.pbRecallAndReplace(battler.index, newPkmn) battle.pbClearChoice(battler.index) # Replacement Pokémon does nothing this round battle.moldBreaker = false if move_user && battler.index == move_user.index battle.pbOnBattlerEnteringBattle(battler.index) next true } ) Battle::AbilityEffects::OnHPDroppedBelowHalf.copy(:EMERGENCYEXIT, :WIMPOUT) #=============================================================================== # StatusCheckNonIgnorable handlers #=============================================================================== Battle::AbilityEffects::StatusCheckNonIgnorable.add(:COMATOSE, proc { |ability, battler, status| next false if !battler.isSpecies?(:KOMALA) next true if status.nil? || status == :SLEEP } ) #=============================================================================== # StatusImmunity handlers #=============================================================================== Battle::AbilityEffects::StatusImmunity.add(:FLOWERVEIL, proc { |ability, battler, status| next true if battler.pbHasType?(:GRASS) } ) Battle::AbilityEffects::StatusImmunity.add(:IMMUNITY, proc { |ability, battler, status| next true if status == :POISON } ) Battle::AbilityEffects::StatusImmunity.copy(:IMMUNITY, :PASTELVEIL) Battle::AbilityEffects::StatusImmunity.add(:INSOMNIA, proc { |ability, battler, status| next true if status == :SLEEP } ) Battle::AbilityEffects::StatusImmunity.copy(:INSOMNIA, :SWEETVEIL, :VITALSPIRIT) Battle::AbilityEffects::StatusImmunity.add(:LEAFGUARD, proc { |ability, battler, status| next true if [:Sun, :HarshSun].include?(battler.effectiveWeather) } ) Battle::AbilityEffects::StatusImmunity.add(:LIMBER, proc { |ability, battler, status| next true if status == :PARALYSIS } ) Battle::AbilityEffects::StatusImmunity.add(:MAGMAARMOR, proc { |ability, battler, status| next true if status == :FROZEN } ) Battle::AbilityEffects::StatusImmunity.add(:WATERVEIL, proc { |ability, battler, status| next true if status == :BURN } ) Battle::AbilityEffects::StatusImmunity.copy(:WATERVEIL, :WATERBUBBLE) #=============================================================================== # StatusImmunityNonIgnorable handlers #=============================================================================== Battle::AbilityEffects::StatusImmunityNonIgnorable.add(:COMATOSE, proc { |ability, battler, status| next true if battler.isSpecies?(:KOMALA) } ) Battle::AbilityEffects::StatusImmunityNonIgnorable.add(:SHIELDSDOWN, proc { |ability, battler, status| next true if battler.isSpecies?(:MINIOR) && battler.form < 7 } ) #=============================================================================== # StatusImmunityFromAlly handlers #=============================================================================== Battle::AbilityEffects::StatusImmunityFromAlly.add(:FLOWERVEIL, proc { |ability, battler, status| next true if battler.pbHasType?(:GRASS) } ) Battle::AbilityEffects::StatusImmunityFromAlly.add(:PASTELVEIL, proc { |ability, battler, status| next true if status == :POISON } ) Battle::AbilityEffects::StatusImmunityFromAlly.add(:SWEETVEIL, proc { |ability, battler, status| next true if status == :SLEEP } ) #=============================================================================== # OnStatusInflicted handlers #=============================================================================== Battle::AbilityEffects::OnStatusInflicted.add(:SYNCHRONIZE, proc { |ability, battler, user, status| next if !user || user.index == battler.index case status when :POISON if user.pbCanPoisonSynchronize?(battler) battler.battle.pbShowAbilitySplash(battler) msg = nil if !Battle::Scene::USE_ABILITY_SPLASH msg = _INTL("{1}'s {2} poisoned {3}!", battler.pbThis, battler.abilityName, user.pbThis(true)) end user.pbPoison(nil, msg, (battler.statusCount > 0)) battler.battle.pbHideAbilitySplash(battler) end when :BURN if user.pbCanBurnSynchronize?(battler) battler.battle.pbShowAbilitySplash(battler) msg = nil if !Battle::Scene::USE_ABILITY_SPLASH msg = _INTL("{1}'s {2} burned {3}!", battler.pbThis, battler.abilityName, user.pbThis(true)) end user.pbBurn(nil, msg) battler.battle.pbHideAbilitySplash(battler) end when :PARALYSIS if user.pbCanParalyzeSynchronize?(battler) battler.battle.pbShowAbilitySplash(battler) msg = nil if !Battle::Scene::USE_ABILITY_SPLASH msg = _INTL("{1}'s {2} paralyzed {3}! It may be unable to move!", battler.pbThis, battler.abilityName, user.pbThis(true)) end user.pbParalyze(nil, msg) battler.battle.pbHideAbilitySplash(battler) end end } ) #=============================================================================== # StatusCure handlers #=============================================================================== Battle::AbilityEffects::StatusCure.add(:IMMUNITY, proc { |ability, battler| next if battler.status != :POISON battler.battle.pbShowAbilitySplash(battler) battler.pbCureStatus(Battle::Scene::USE_ABILITY_SPLASH) if !Battle::Scene::USE_ABILITY_SPLASH battler.battle.pbDisplay(_INTL("{1}'s {2} cured its poisoning!", battler.pbThis, battler.abilityName)) end battler.battle.pbHideAbilitySplash(battler) } ) Battle::AbilityEffects::StatusCure.copy(:IMMUNITY, :PASTELVEIL) Battle::AbilityEffects::StatusCure.add(:INSOMNIA, proc { |ability, battler| next if battler.status != :SLEEP battler.battle.pbShowAbilitySplash(battler) battler.pbCureStatus(Battle::Scene::USE_ABILITY_SPLASH) if !Battle::Scene::USE_ABILITY_SPLASH battler.battle.pbDisplay(_INTL("{1}'s {2} woke it up!", battler.pbThis, battler.abilityName)) end battler.battle.pbHideAbilitySplash(battler) } ) Battle::AbilityEffects::StatusCure.copy(:INSOMNIA, :VITALSPIRIT) Battle::AbilityEffects::StatusCure.add(:LIMBER, proc { |ability, battler| next if battler.status != :PARALYSIS battler.battle.pbShowAbilitySplash(battler) battler.pbCureStatus(Battle::Scene::USE_ABILITY_SPLASH) if !Battle::Scene::USE_ABILITY_SPLASH battler.battle.pbDisplay(_INTL("{1}'s {2} cured its paralysis!", battler.pbThis, battler.abilityName)) end battler.battle.pbHideAbilitySplash(battler) } ) Battle::AbilityEffects::StatusCure.add(:MAGMAARMOR, proc { |ability, battler| next if battler.status != :FROZEN battler.battle.pbShowAbilitySplash(battler) battler.pbCureStatus(Battle::Scene::USE_ABILITY_SPLASH) if !Battle::Scene::USE_ABILITY_SPLASH battler.battle.pbDisplay(_INTL("{1}'s {2} defrosted it!", battler.pbThis, battler.abilityName)) end battler.battle.pbHideAbilitySplash(battler) } ) Battle::AbilityEffects::StatusCure.add(:OBLIVIOUS, proc { |ability, battler| next if battler.effects[PBEffects::Attract] < 0 && (battler.effects[PBEffects::Taunt] == 0 || Settings::MECHANICS_GENERATION <= 5) battler.battle.pbShowAbilitySplash(battler) if battler.effects[PBEffects::Attract] >= 0 battler.pbCureAttract if Battle::Scene::USE_ABILITY_SPLASH battler.battle.pbDisplay(_INTL("{1} got over its infatuation.", battler.pbThis)) else battler.battle.pbDisplay(_INTL("{1}'s {2} cured its infatuation status!", battler.pbThis, battler.abilityName)) end end if battler.effects[PBEffects::Taunt] > 0 && Settings::MECHANICS_GENERATION >= 6 battler.effects[PBEffects::Taunt] = 0 if Battle::Scene::USE_ABILITY_SPLASH battler.battle.pbDisplay(_INTL("{1}'s Taunt wore off!", battler.pbThis)) else battler.battle.pbDisplay(_INTL("{1}'s {2} made its taunt wear off!", battler.pbThis, battler.abilityName)) end end battler.battle.pbHideAbilitySplash(battler) } ) Battle::AbilityEffects::StatusCure.add(:OWNTEMPO, proc { |ability, battler| next if battler.effects[PBEffects::Confusion] == 0 battler.battle.pbShowAbilitySplash(battler) battler.pbCureConfusion if Battle::Scene::USE_ABILITY_SPLASH battler.battle.pbDisplay(_INTL("{1} snapped out of its confusion.", battler.pbThis)) else battler.battle.pbDisplay(_INTL("{1}'s {2} snapped it out of its confusion!", battler.pbThis, battler.abilityName)) end battler.battle.pbHideAbilitySplash(battler) } ) Battle::AbilityEffects::StatusCure.add(:WATERVEIL, proc { |ability, battler| next if battler.status != :BURN battler.battle.pbShowAbilitySplash(battler) battler.pbCureStatus(Battle::Scene::USE_ABILITY_SPLASH) if !Battle::Scene::USE_ABILITY_SPLASH battler.battle.pbDisplay(_INTL("{1}'s {2} healed its burn!", battler.pbThis, battler.abilityName)) end battler.battle.pbHideAbilitySplash(battler) } ) Battle::AbilityEffects::StatusCure.copy(:WATERVEIL, :WATERBUBBLE) #=============================================================================== # StatLossImmunity handlers #=============================================================================== Battle::AbilityEffects::StatLossImmunity.add(:BIGPECKS, proc { |ability, battler, stat, battle, showMessages| next false if stat != :DEFENSE if showMessages battle.pbShowAbilitySplash(battler) if Battle::Scene::USE_ABILITY_SPLASH battle.pbDisplay(_INTL("{1}'s {2} cannot be lowered!", battler.pbThis, GameData::Stat.get(stat).name)) else battle.pbDisplay(_INTL("{1}'s {2} prevents {3} loss!", battler.pbThis, battler.abilityName, GameData::Stat.get(stat).name)) end battle.pbHideAbilitySplash(battler) end next true } ) Battle::AbilityEffects::StatLossImmunity.add(:CLEARBODY, proc { |ability, battler, stat, battle, showMessages| if showMessages battle.pbShowAbilitySplash(battler) if Battle::Scene::USE_ABILITY_SPLASH battle.pbDisplay(_INTL("{1}'s stats cannot be lowered!", battler.pbThis)) else battle.pbDisplay(_INTL("{1}'s {2} prevents stat loss!", battler.pbThis, battler.abilityName)) end battle.pbHideAbilitySplash(battler) end next true } ) Battle::AbilityEffects::StatLossImmunity.copy(:CLEARBODY, :WHITESMOKE) Battle::AbilityEffects::StatLossImmunity.add(:FLOWERVEIL, proc { |ability, battler, stat, battle, showMessages| next false if !battler.pbHasType?(:GRASS) if showMessages battle.pbShowAbilitySplash(battler) if Battle::Scene::USE_ABILITY_SPLASH battle.pbDisplay(_INTL("{1}'s stats cannot be lowered!", battler.pbThis)) else battle.pbDisplay(_INTL("{1}'s {2} prevents stat loss!", battler.pbThis, battler.abilityName)) end battle.pbHideAbilitySplash(battler) end next true } ) Battle::AbilityEffects::StatLossImmunity.add(:HYPERCUTTER, proc { |ability, battler, stat, battle, showMessages| next false if stat != :ATTACK if showMessages battle.pbShowAbilitySplash(battler) if Battle::Scene::USE_ABILITY_SPLASH battle.pbDisplay(_INTL("{1}'s {2} cannot be lowered!", battler.pbThis, GameData::Stat.get(stat).name)) else battle.pbDisplay(_INTL("{1}'s {2} prevents {3} loss!", battler.pbThis, battler.abilityName, GameData::Stat.get(stat).name)) end battle.pbHideAbilitySplash(battler) end next true } ) Battle::AbilityEffects::StatLossImmunity.add(:KEENEYE, proc { |ability, battler, stat, battle, showMessages| next false if stat != :ACCURACY if showMessages battle.pbShowAbilitySplash(battler) if Battle::Scene::USE_ABILITY_SPLASH battle.pbDisplay(_INTL("{1}'s {2} cannot be lowered!", battler.pbThis, GameData::Stat.get(stat).name)) else battle.pbDisplay(_INTL("{1}'s {2} prevents {3} loss!", battler.pbThis, battler.abilityName, GameData::Stat.get(stat).name)) end battle.pbHideAbilitySplash(battler) end next true } ) #=============================================================================== # StatLossImmunityNonIgnorable handlers #=============================================================================== Battle::AbilityEffects::StatLossImmunityNonIgnorable.add(:FULLMETALBODY, proc { |ability, battler, stat, battle, showMessages| if showMessages battle.pbShowAbilitySplash(battler) if Battle::Scene::USE_ABILITY_SPLASH battle.pbDisplay(_INTL("{1}'s stats cannot be lowered!", battler.pbThis)) else battle.pbDisplay(_INTL("{1}'s {2} prevents stat loss!", battler.pbThis, battler.abilityName)) end battle.pbHideAbilitySplash(battler) end next true } ) #=============================================================================== # StatLossImmunityFromAlly handlers #=============================================================================== Battle::AbilityEffects::StatLossImmunityFromAlly.add(:FLOWERVEIL, proc { |ability, bearer, battler, stat, battle, showMessages| next false if !battler.pbHasType?(:GRASS) if showMessages battle.pbShowAbilitySplash(bearer) if Battle::Scene::USE_ABILITY_SPLASH battle.pbDisplay(_INTL("{1}'s stats cannot be lowered!", battler.pbThis)) else battle.pbDisplay(_INTL("{1}'s {2} prevents {3}'s stat loss!", bearer.pbThis, bearer.abilityName, battler.pbThis(true))) end battle.pbHideAbilitySplash(bearer) end next true } ) #=============================================================================== # OnStatGain handlers #=============================================================================== # There aren't any! #=============================================================================== # OnStatLoss handlers #=============================================================================== Battle::AbilityEffects::OnStatLoss.add(:COMPETITIVE, proc { |ability, battler, stat, user| next if user && !user.opposes?(battler) battler.pbRaiseStatStageByAbility(:SPECIAL_ATTACK, 2, battler) } ) Battle::AbilityEffects::OnStatLoss.add(:DEFIANT, proc { |ability, battler, stat, user| next if user && !user.opposes?(battler) battler.pbRaiseStatStageByAbility(:ATTACK, 2, battler) } ) #=============================================================================== # PriorityChange handlers #=============================================================================== Battle::AbilityEffects::PriorityChange.add(:GALEWINGS, proc { |ability, battler, move, pri| next pri + 1 if (Settings::MECHANICS_GENERATION <= 6 || battler.hp == battler.totalhp) && move.type == :FLYING } ) Battle::AbilityEffects::PriorityChange.add(:PRANKSTER, proc { |ability, battler, move, pri| if move.statusMove? battler.effects[PBEffects::Prankster] = true next pri + 1 end } ) Battle::AbilityEffects::PriorityChange.add(:TRIAGE, proc { |ability, battler, move, pri| next pri + 3 if move.healingMove? } ) #=============================================================================== # PriorityBracketChange handlers #=============================================================================== Battle::AbilityEffects::PriorityBracketChange.add(:QUICKDRAW, proc { |ability, battler, battle| next 1 if battle.pbRandom(100) < 30 } ) Battle::AbilityEffects::PriorityBracketChange.add(:STALL, proc { |ability, battler, battle| next -1 } ) #=============================================================================== # PriorityBracketUse handlers #=============================================================================== Battle::AbilityEffects::PriorityBracketUse.add(:QUICKDRAW, proc { |ability, battler, battle| battle.pbShowAbilitySplash(battler) battle.pbDisplay(_INTL("{1} made {2} move faster!", battler.abilityName, battler.pbThis(true))) battle.pbHideAbilitySplash(battler) } ) #=============================================================================== # OnFlinch handlers #=============================================================================== Battle::AbilityEffects::OnFlinch.add(:STEADFAST, proc { |ability, battler, battle| battler.pbRaiseStatStageByAbility(:SPEED, 1, battler) } ) #=============================================================================== # MoveBlocking handlers #=============================================================================== Battle::AbilityEffects::MoveBlocking.add(:DAZZLING, proc { |ability, bearer, user, targets, move, battle| next false if battle.choices[user.index][4] <= 0 next false if !bearer.opposes?(user) ret = false targets.each do |b| next if !b.opposes?(user) ret = true end next ret } ) Battle::AbilityEffects::MoveBlocking.copy(:DAZZLING, :QUEENLYMAJESTY) #=============================================================================== # MoveImmunity handlers #=============================================================================== Battle::AbilityEffects::MoveImmunity.add(:BULLETPROOF, proc { |ability, user, target, move, type, battle, show_message| next false if !move.bombMove? if show_message battle.pbShowAbilitySplash(target) if Battle::Scene::USE_ABILITY_SPLASH battle.pbDisplay(_INTL("It doesn't affect {1}...", target.pbThis(true))) else battle.pbDisplay(_INTL("{1}'s {2} made {3} ineffective!", target.pbThis, target.abilityName, move.name)) end battle.pbHideAbilitySplash(target) end next true } ) Battle::AbilityEffects::MoveImmunity.add(:FLASHFIRE, proc { |ability, user, target, move, type, battle, show_message| next false if user.index == target.index next false if type != :FIRE if show_message battle.pbShowAbilitySplash(target) if !target.effects[PBEffects::FlashFire] target.effects[PBEffects::FlashFire] = true if Battle::Scene::USE_ABILITY_SPLASH battle.pbDisplay(_INTL("The power of {1}'s Fire-type moves rose!", target.pbThis(true))) else battle.pbDisplay(_INTL("The power of {1}'s Fire-type moves rose because of its {2}!", target.pbThis(true), target.abilityName)) end elsif Battle::Scene::USE_ABILITY_SPLASH battle.pbDisplay(_INTL("It doesn't affect {1}...", target.pbThis(true))) else battle.pbDisplay(_INTL("{1}'s {2} made {3} ineffective!", target.pbThis, target.abilityName, move.name)) end battle.pbHideAbilitySplash(target) end next true } ) Battle::AbilityEffects::MoveImmunity.add(:LIGHTNINGROD, proc { |ability, user, target, move, type, battle, show_message| next target.pbMoveImmunityStatRaisingAbility(user, move, type, :ELECTRIC, :SPECIAL_ATTACK, 1, show_message) } ) Battle::AbilityEffects::MoveImmunity.add(:MOTORDRIVE, proc { |ability, user, target, move, type, battle, show_message| next target.pbMoveImmunityStatRaisingAbility(user, move, type, :ELECTRIC, :SPEED, 1, show_message) } ) Battle::AbilityEffects::MoveImmunity.add(:SAPSIPPER, proc { |ability, user, target, move, type, battle, show_message| next target.pbMoveImmunityStatRaisingAbility(user, move, type, :GRASS, :ATTACK, 1, show_message) } ) Battle::AbilityEffects::MoveImmunity.add(:SOUNDPROOF, proc { |ability, user, target, move, type, battle, show_message| next false if !move.soundMove? next false if Settings::MECHANICS_GENERATION >= 8 && user.index == target.index if show_message battle.pbShowAbilitySplash(target) if Battle::Scene::USE_ABILITY_SPLASH battle.pbDisplay(_INTL("It doesn't affect {1}...", target.pbThis(true))) else battle.pbDisplay(_INTL("{1}'s {2} blocks {3}!", target.pbThis, target.abilityName, move.name)) end battle.pbHideAbilitySplash(target) end next true } ) Battle::AbilityEffects::MoveImmunity.add(:STORMDRAIN, proc { |ability, user, target, move, type, battle, show_message| next target.pbMoveImmunityStatRaisingAbility(user, move, type, :WATER, :SPECIAL_ATTACK, 1, show_message) } ) Battle::AbilityEffects::MoveImmunity.add(:TELEPATHY, proc { |ability, user, target, move, type, battle, show_message| next false if move.statusMove? next false if user.index == target.index || target.opposes?(user) if show_message battle.pbShowAbilitySplash(target) if Battle::Scene::USE_ABILITY_SPLASH battle.pbDisplay(_INTL("{1} avoids attacks by its ally Pokémon!", target.pbThis(true))) else battle.pbDisplay(_INTL("{1} avoids attacks by its ally Pokémon with {2}!", target.pbThis, target.abilityName)) end battle.pbHideAbilitySplash(target) end next true } ) Battle::AbilityEffects::MoveImmunity.add(:VOLTABSORB, proc { |ability, user, target, move, type, battle, show_message| next target.pbMoveImmunityHealingAbility(user, move, type, :ELECTRIC, show_message) } ) Battle::AbilityEffects::MoveImmunity.add(:WATERABSORB, proc { |ability, user, target, move, type, battle, show_message| next target.pbMoveImmunityHealingAbility(user, move, type, :WATER, show_message) } ) Battle::AbilityEffects::MoveImmunity.copy(:WATERABSORB, :DRYSKIN) Battle::AbilityEffects::MoveImmunity.add(:WONDERGUARD, proc { |ability, user, target, move, type, battle, show_message| next false if move.statusMove? next false if !type || Effectiveness.super_effective?(target.damageState.typeMod) if show_message battle.pbShowAbilitySplash(target) if Battle::Scene::USE_ABILITY_SPLASH battle.pbDisplay(_INTL("It doesn't affect {1}...", target.pbThis(true))) else battle.pbDisplay(_INTL("{1} avoided damage with {2}!", target.pbThis, target.abilityName)) end battle.pbHideAbilitySplash(target) end next true } ) #=============================================================================== # ModifyMoveBaseType handlers #=============================================================================== Battle::AbilityEffects::ModifyMoveBaseType.add(:AERILATE, proc { |ability, user, move, type| next if type != :NORMAL || !GameData::Type.exists?(:FLYING) move.powerBoost = true next :FLYING } ) Battle::AbilityEffects::ModifyMoveBaseType.add(:GALVANIZE, proc { |ability, user, move, type| next if type != :NORMAL || !GameData::Type.exists?(:ELECTRIC) move.powerBoost = true next :ELECTRIC } ) Battle::AbilityEffects::ModifyMoveBaseType.add(:LIQUIDVOICE, proc { |ability, user, move, type| next :WATER if GameData::Type.exists?(:WATER) && move.soundMove? } ) Battle::AbilityEffects::ModifyMoveBaseType.add(:NORMALIZE, proc { |ability, user, move, type| next if !GameData::Type.exists?(:NORMAL) move.powerBoost = true if Settings::MECHANICS_GENERATION >= 7 next :NORMAL } ) Battle::AbilityEffects::ModifyMoveBaseType.add(:PIXILATE, proc { |ability, user, move, type| next if type != :NORMAL || !GameData::Type.exists?(:FAIRY) move.powerBoost = true next :FAIRY } ) Battle::AbilityEffects::ModifyMoveBaseType.add(:REFRIGERATE, proc { |ability, user, move, type| next if type != :NORMAL || !GameData::Type.exists?(:ICE) move.powerBoost = true next :ICE } ) #=============================================================================== # AccuracyCalcFromUser handlers #=============================================================================== Battle::AbilityEffects::AccuracyCalcFromUser.add(:COMPOUNDEYES, proc { |ability, mods, user, target, move, type| mods[:accuracy_multiplier] *= 1.3 } ) Battle::AbilityEffects::AccuracyCalcFromUser.add(:HUSTLE, proc { |ability, mods, user, target, move, type| mods[:accuracy_multiplier] *= 0.8 if move.physicalMove? } ) Battle::AbilityEffects::AccuracyCalcFromUser.add(:KEENEYE, proc { |ability, mods, user, target, move, type| mods[:evasion_stage] = 0 if mods[:evasion_stage] > 0 && Settings::MECHANICS_GENERATION >= 6 } ) Battle::AbilityEffects::AccuracyCalcFromUser.add(:NOGUARD, proc { |ability, mods, user, target, move, type| mods[:base_accuracy] = 0 } ) Battle::AbilityEffects::AccuracyCalcFromUser.add(:UNAWARE, proc { |ability, mods, user, target, move, type| mods[:evasion_stage] = 0 if move.damagingMove? } ) Battle::AbilityEffects::AccuracyCalcFromUser.add(:VICTORYSTAR, proc { |ability, mods, user, target, move, type| mods[:accuracy_multiplier] *= 1.1 } ) #=============================================================================== # AccuracyCalcFromAlly handlers #=============================================================================== Battle::AbilityEffects::AccuracyCalcFromAlly.add(:VICTORYSTAR, proc { |ability, mods, user, target, move, type| mods[:accuracy_multiplier] *= 1.1 } ) #=============================================================================== # AccuracyCalcFromTarget handlers #=============================================================================== Battle::AbilityEffects::AccuracyCalcFromTarget.add(:LIGHTNINGROD, proc { |ability, mods, user, target, move, type| mods[:base_accuracy] = 0 if type == :ELECTRIC } ) Battle::AbilityEffects::AccuracyCalcFromTarget.add(:NOGUARD, proc { |ability, mods, user, target, move, type| mods[:base_accuracy] = 0 } ) Battle::AbilityEffects::AccuracyCalcFromTarget.add(:SANDVEIL, proc { |ability, mods, user, target, move, type| mods[:evasion_multiplier] *= 1.25 if target.effectiveWeather == :Sandstorm } ) Battle::AbilityEffects::AccuracyCalcFromTarget.add(:SNOWCLOAK, proc { |ability, mods, user, target, move, type| mods[:evasion_multiplier] *= 1.25 if target.effectiveWeather == :Hail } ) Battle::AbilityEffects::AccuracyCalcFromTarget.add(:STORMDRAIN, proc { |ability, mods, user, target, move, type| mods[:base_accuracy] = 0 if type == :WATER } ) Battle::AbilityEffects::AccuracyCalcFromTarget.add(:TANGLEDFEET, proc { |ability, mods, user, target, move, type| mods[:accuracy_multiplier] /= 2 if target.effects[PBEffects::Confusion] > 0 } ) Battle::AbilityEffects::AccuracyCalcFromTarget.add(:UNAWARE, proc { |ability, mods, user, target, move, type| mods[:accuracy_stage] = 0 if move.damagingMove? } ) Battle::AbilityEffects::AccuracyCalcFromTarget.add(:WONDERSKIN, proc { |ability, mods, user, target, move, type| if move.statusMove? && user.opposes?(target) && mods[:base_accuracy] > 50 mods[:base_accuracy] = 50 end } ) #=============================================================================== # DamageCalcFromUser handlers #=============================================================================== Battle::AbilityEffects::DamageCalcFromUser.add(:AERILATE, proc { |ability, user, target, move, mults, baseDmg, type| mults[:base_damage_multiplier] *= 1.2 if move.powerBoost } ) Battle::AbilityEffects::DamageCalcFromUser.copy(:AERILATE, :PIXILATE, :REFRIGERATE, :GALVANIZE, :NORMALIZE) Battle::AbilityEffects::DamageCalcFromUser.add(:ANALYTIC, proc { |ability, user, target, move, mults, baseDmg, type| # NOTE: In the official games, if another battler faints earlier in the # round but it would have moved after the user, then Analytic does not # power up the move. However, this makes the determination so much # more complicated (involving pbPriority and counting or not counting # speed/priority modifiers depending on which Generation's mechanics # are being used), so I'm choosing to ignore it. The effect is thus: # "power up the move if all other battlers on the field right now have # already moved". if move.pbMoveFailedLastInRound?(user, false) mults[:base_damage_multiplier] *= 1.3 end } ) Battle::AbilityEffects::DamageCalcFromUser.add(:BLAZE, proc { |ability, user, target, move, mults, baseDmg, type| if user.hp <= user.totalhp / 3 && type == :FIRE mults[:attack_multiplier] *= 1.5 end } ) Battle::AbilityEffects::DamageCalcFromUser.add(:DEFEATIST, proc { |ability, user, target, move, mults, baseDmg, type| mults[:attack_multiplier] /= 2 if user.hp <= user.totalhp / 2 } ) Battle::AbilityEffects::DamageCalcFromUser.add(:DRAGONSMAW, proc { |ability, user, target, move, mults, baseDmg, type| mults[:attack_multiplier] *= 1.5 if type == :DRAGON } ) Battle::AbilityEffects::DamageCalcFromUser.add(:FLAREBOOST, proc { |ability, user, target, move, mults, baseDmg, type| if user.burned? && move.specialMove? mults[:base_damage_multiplier] *= 1.5 end } ) Battle::AbilityEffects::DamageCalcFromUser.add(:FLASHFIRE, proc { |ability, user, target, move, mults, baseDmg, type| if user.effects[PBEffects::FlashFire] && type == :FIRE mults[:attack_multiplier] *= 1.5 end } ) Battle::AbilityEffects::DamageCalcFromUser.add(:FLOWERGIFT, proc { |ability, user, target, move, mults, baseDmg, type| if move.physicalMove? && [:Sun, :HarshSun].include?(user.effectiveWeather) mults[:attack_multiplier] *= 1.5 end } ) Battle::AbilityEffects::DamageCalcFromUser.add(:GORILLATACTICS, proc { |ability, user, target, move, mults, baseDmg, type| mults[:attack_multiplier] *= 1.5 if move.physicalMove? } ) Battle::AbilityEffects::DamageCalcFromUser.add(:GUTS, proc { |ability, user, target, move, mults, baseDmg, type| if user.pbHasAnyStatus? && move.physicalMove? mults[:attack_multiplier] *= 1.5 end } ) Battle::AbilityEffects::DamageCalcFromUser.add(:HUGEPOWER, proc { |ability, user, target, move, mults, baseDmg, type| mults[:attack_multiplier] *= 2 if move.physicalMove? } ) Battle::AbilityEffects::DamageCalcFromUser.copy(:HUGEPOWER, :PUREPOWER) Battle::AbilityEffects::DamageCalcFromUser.add(:HUSTLE, proc { |ability, user, target, move, mults, baseDmg, type| mults[:attack_multiplier] *= 1.5 if move.physicalMove? } ) Battle::AbilityEffects::DamageCalcFromUser.add(:IRONFIST, proc { |ability, user, target, move, mults, baseDmg, type| mults[:base_damage_multiplier] *= 1.2 if move.punchingMove? } ) Battle::AbilityEffects::DamageCalcFromUser.add(:MEGALAUNCHER, proc { |ability, user, target, move, mults, baseDmg, type| mults[:base_damage_multiplier] *= 1.5 if move.pulseMove? } ) Battle::AbilityEffects::DamageCalcFromUser.add(:MINUS, proc { |ability, user, target, move, mults, baseDmg, type| next if !move.specialMove? if user.allAllies.any? { |b| b.hasActiveAbility?([:MINUS, :PLUS]) } mults[:attack_multiplier] *= 1.5 end } ) Battle::AbilityEffects::DamageCalcFromUser.copy(:MINUS, :PLUS) Battle::AbilityEffects::DamageCalcFromUser.add(:NEUROFORCE, proc { |ability, user, target, move, mults, baseDmg, type| if Effectiveness.super_effective?(target.damageState.typeMod) mults[:final_damage_multiplier] *= 1.25 end } ) Battle::AbilityEffects::DamageCalcFromUser.add(:OVERGROW, proc { |ability, user, target, move, mults, baseDmg, type| if user.hp <= user.totalhp / 3 && type == :GRASS mults[:attack_multiplier] *= 1.5 end } ) Battle::AbilityEffects::DamageCalcFromUser.add(:PUNKROCK, proc { |ability, user, target, move, mults, baseDmg, type| mults[:attack_multiplier] *= 1.3 if move.soundMove? } ) Battle::AbilityEffects::DamageCalcFromUser.add(:RECKLESS, proc { |ability, user, target, move, mults, baseDmg, type| mults[:base_damage_multiplier] *= 1.2 if move.recoilMove? } ) Battle::AbilityEffects::DamageCalcFromUser.add(:RIVALRY, proc { |ability, user, target, move, mults, baseDmg, type| if user.gender != 2 && target.gender != 2 if user.gender == target.gender mults[:base_damage_multiplier] *= 1.25 else mults[:base_damage_multiplier] *= 0.75 end end } ) Battle::AbilityEffects::DamageCalcFromUser.add(:SANDFORCE, proc { |ability, user, target, move, mults, baseDmg, type| if user.effectiveWeather == :Sandstorm && [:ROCK, :GROUND, :STEEL].include?(type) mults[:base_damage_multiplier] *= 1.3 end } ) Battle::AbilityEffects::DamageCalcFromUser.add(:SHEERFORCE, proc { |ability, user, target, move, mults, baseDmg, type| mults[:base_damage_multiplier] *= 1.3 if move.addlEffect > 0 } ) Battle::AbilityEffects::DamageCalcFromUser.add(:SLOWSTART, proc { |ability, user, target, move, mults, baseDmg, type| mults[:attack_multiplier] /= 2 if user.effects[PBEffects::SlowStart] > 0 && move.physicalMove? } ) Battle::AbilityEffects::DamageCalcFromUser.add(:SOLARPOWER, proc { |ability, user, target, move, mults, baseDmg, type| if move.specialMove? && [:Sun, :HarshSun].include?(user.effectiveWeather) mults[:attack_multiplier] *= 1.5 end } ) Battle::AbilityEffects::DamageCalcFromUser.add(:SNIPER, proc { |ability, user, target, move, mults, baseDmg, type| if target.damageState.critical mults[:final_damage_multiplier] *= 1.5 end } ) Battle::AbilityEffects::DamageCalcFromUser.add(:STAKEOUT, proc { |ability, user, target, move, mults, baseDmg, type| mults[:attack_multiplier] *= 2 if target.battle.choices[target.index][0] == :SwitchOut } ) Battle::AbilityEffects::DamageCalcFromUser.add(:STEELWORKER, proc { |ability, user, target, move, mults, baseDmg, type| mults[:attack_multiplier] *= 1.5 if type == :STEEL } ) Battle::AbilityEffects::DamageCalcFromUser.add(:STEELYSPIRIT, proc { |ability, user, target, move, mults, baseDmg, type| mults[:final_damage_multiplier] *= 1.5 if type == :STEEL } ) Battle::AbilityEffects::DamageCalcFromUser.add(:STRONGJAW, proc { |ability, user, target, move, mults, baseDmg, type| mults[:base_damage_multiplier] *= 1.5 if move.bitingMove? } ) Battle::AbilityEffects::DamageCalcFromUser.add(:SWARM, proc { |ability, user, target, move, mults, baseDmg, type| if user.hp <= user.totalhp / 3 && type == :BUG mults[:attack_multiplier] *= 1.5 end } ) Battle::AbilityEffects::DamageCalcFromUser.add(:TECHNICIAN, proc { |ability, user, target, move, mults, baseDmg, type| if user.index != target.index && move && move.id != :STRUGGLE && baseDmg * mults[:base_damage_multiplier] <= 60 mults[:base_damage_multiplier] *= 1.5 end } ) Battle::AbilityEffects::DamageCalcFromUser.add(:TINTEDLENS, proc { |ability, user, target, move, mults, baseDmg, type| mults[:final_damage_multiplier] *= 2 if Effectiveness.resistant?(target.damageState.typeMod) } ) Battle::AbilityEffects::DamageCalcFromUser.add(:TORRENT, proc { |ability, user, target, move, mults, baseDmg, type| if user.hp <= user.totalhp / 3 && type == :WATER mults[:attack_multiplier] *= 1.5 end } ) Battle::AbilityEffects::DamageCalcFromUser.add(:TOUGHCLAWS, proc { |ability, user, target, move, mults, baseDmg, type| mults[:base_damage_multiplier] *= 4 / 3.0 if move.contactMove? } ) Battle::AbilityEffects::DamageCalcFromUser.add(:TOXICBOOST, proc { |ability, user, target, move, mults, baseDmg, type| if user.poisoned? && move.physicalMove? mults[:base_damage_multiplier] *= 1.5 end } ) Battle::AbilityEffects::DamageCalcFromUser.add(:TRANSISTOR, proc { |ability, user, target, move, mults, baseDmg, type| mults[:attack_multiplier] *= 1.5 if type == :ELECTRIC } ) Battle::AbilityEffects::DamageCalcFromUser.add(:WATERBUBBLE, proc { |ability, user, target, move, mults, baseDmg, type| mults[:attack_multiplier] *= 2 if type == :WATER } ) #=============================================================================== # DamageCalcFromAlly handlers #=============================================================================== Battle::AbilityEffects::DamageCalcFromAlly.add(:BATTERY, proc { |ability, user, target, move, mults, baseDmg, type| next if !move.specialMove? mults[:final_damage_multiplier] *= 1.3 } ) Battle::AbilityEffects::DamageCalcFromAlly.add(:FLOWERGIFT, proc { |ability, user, target, move, mults, baseDmg, type| if move.physicalMove? && [:Sun, :HarshSun].include?(user.effectiveWeather) mults[:attack_multiplier] *= 1.5 end } ) Battle::AbilityEffects::DamageCalcFromAlly.add(:POWERSPOT, proc { |ability, user, target, move, mults, baseDmg, type| mults[:final_damage_multiplier] *= 1.3 } ) Battle::AbilityEffects::DamageCalcFromAlly.add(:STEELYSPIRIT, proc { |ability, user, target, move, mults, baseDmg, type| mults[:final_damage_multiplier] *= 1.5 if type == :STEEL } ) #=============================================================================== # DamageCalcFromTarget handlers #=============================================================================== Battle::AbilityEffects::DamageCalcFromTarget.add(:DRYSKIN, proc { |ability, user, target, move, mults, baseDmg, type| mults[:base_damage_multiplier] *= 1.25 if type == :FIRE } ) Battle::AbilityEffects::DamageCalcFromTarget.add(:FILTER, proc { |ability, user, target, move, mults, baseDmg, type| if Effectiveness.super_effective?(target.damageState.typeMod) mults[:final_damage_multiplier] *= 0.75 end } ) Battle::AbilityEffects::DamageCalcFromTarget.copy(:FILTER, :SOLIDROCK) Battle::AbilityEffects::DamageCalcFromTarget.add(:FLOWERGIFT, proc { |ability, user, target, move, mults, baseDmg, type| if move.specialMove? && [:Sun, :HarshSun].include?(target.effectiveWeather) mults[:defense_multiplier] *= 1.5 end } ) Battle::AbilityEffects::DamageCalcFromTarget.add(:FLUFFY, proc { |ability, user, target, move, mults, baseDmg, type| mults[:final_damage_multiplier] *= 2 if move.calcType == :FIRE mults[:final_damage_multiplier] /= 2 if move.pbContactMove?(user) } ) Battle::AbilityEffects::DamageCalcFromTarget.add(:FURCOAT, proc { |ability, user, target, move, mults, baseDmg, type| mults[:defense_multiplier] *= 2 if move.physicalMove? || move.function == "UseTargetDefenseInsteadOfTargetSpDef" # Psyshock } ) Battle::AbilityEffects::DamageCalcFromTarget.add(:GRASSPELT, proc { |ability, user, target, move, mults, baseDmg, type| if user.battle.field.terrain == :Grassy mults[:defense_multiplier] *= 1.5 end } ) Battle::AbilityEffects::DamageCalcFromTarget.add(:HEATPROOF, proc { |ability, user, target, move, mults, baseDmg, type| mults[:base_damage_multiplier] /= 2 if type == :FIRE } ) Battle::AbilityEffects::DamageCalcFromTarget.add(:ICESCALES, proc { |ability, user, target, move, mults, baseDmg, type| mults[:final_damage_multiplier] /= 2 if move.specialMove? } ) Battle::AbilityEffects::DamageCalcFromTarget.add(:MARVELSCALE, proc { |ability, user, target, move, mults, baseDmg, type| if target.pbHasAnyStatus? && move.physicalMove? mults[:defense_multiplier] *= 1.5 end } ) Battle::AbilityEffects::DamageCalcFromTarget.add(:MULTISCALE, proc { |ability, user, target, move, mults, baseDmg, type| mults[:final_damage_multiplier] /= 2 if target.hp == target.totalhp } ) Battle::AbilityEffects::DamageCalcFromTarget.add(:PUNKROCK, proc { |ability, user, target, move, mults, baseDmg, type| mults[:final_damage_multiplier] /= 2 if move.soundMove? } ) Battle::AbilityEffects::DamageCalcFromTarget.add(:THICKFAT, proc { |ability, user, target, move, mults, baseDmg, type| mults[:base_damage_multiplier] /= 2 if [:FIRE, :ICE].include?(type) } ) Battle::AbilityEffects::DamageCalcFromTarget.add(:WATERBUBBLE, proc { |ability, user, target, move, mults, baseDmg, type| mults[:final_damage_multiplier] /= 2 if type == :FIRE } ) #=============================================================================== # DamageCalcFromTargetNonIgnorable handlers #=============================================================================== Battle::AbilityEffects::DamageCalcFromTargetNonIgnorable.add(:PRISMARMOR, proc { |ability, user, target, move, mults, baseDmg, type| if Effectiveness.super_effective?(target.damageState.typeMod) mults[:final_damage_multiplier] *= 0.75 end } ) Battle::AbilityEffects::DamageCalcFromTargetNonIgnorable.add(:SHADOWSHIELD, proc { |ability, user, target, move, mults, baseDmg, type| if target.hp == target.totalhp mults[:final_damage_multiplier] /= 2 end } ) #=============================================================================== # DamageCalcFromTargetAlly handlers #=============================================================================== Battle::AbilityEffects::DamageCalcFromTargetAlly.add(:FLOWERGIFT, proc { |ability, user, target, move, mults, baseDmg, type| if move.specialMove? && [:Sun, :HarshSun].include?(target.effectiveWeather) mults[:defense_multiplier] *= 1.5 end } ) Battle::AbilityEffects::DamageCalcFromTargetAlly.add(:FRIENDGUARD, proc { |ability, user, target, move, mults, baseDmg, type| mults[:final_damage_multiplier] *= 0.75 } ) #=============================================================================== # CriticalCalcFromUser handlers #=============================================================================== Battle::AbilityEffects::CriticalCalcFromUser.add(:MERCILESS, proc { |ability, user, target, c| next 99 if target.poisoned? } ) Battle::AbilityEffects::CriticalCalcFromUser.add(:SUPERLUCK, proc { |ability, user, target, c| next c + 1 } ) #=============================================================================== # CriticalCalcFromTarget handlers #=============================================================================== Battle::AbilityEffects::CriticalCalcFromTarget.add(:BATTLEARMOR, proc { |ability, user, target, c| next -1 } ) Battle::AbilityEffects::CriticalCalcFromTarget.copy(:BATTLEARMOR, :SHELLARMOR) #=============================================================================== # OnBeingHit handlers #=============================================================================== Battle::AbilityEffects::OnBeingHit.add(:AFTERMATH, proc { |ability, user, target, move, battle| next if !target.fainted? next if !move.pbContactMove?(user) battle.pbShowAbilitySplash(target) if !battle.moldBreaker dampBattler = battle.pbCheckGlobalAbility(:DAMP) if dampBattler battle.pbShowAbilitySplash(dampBattler) if Battle::Scene::USE_ABILITY_SPLASH battle.pbDisplay(_INTL("{1} cannot use {2}!", target.pbThis, target.abilityName)) else battle.pbDisplay(_INTL("{1} cannot use {2} because of {3}'s {4}!", target.pbThis, target.abilityName, dampBattler.pbThis(true), dampBattler.abilityName)) end battle.pbHideAbilitySplash(dampBattler) battle.pbHideAbilitySplash(target) next end end if user.takesIndirectDamage?(Battle::Scene::USE_ABILITY_SPLASH) && user.affectedByContactEffect?(Battle::Scene::USE_ABILITY_SPLASH) battle.scene.pbDamageAnimation(user) user.pbReduceHP(user.totalhp / 4, false) battle.pbDisplay(_INTL("{1} was caught in the aftermath!", user.pbThis)) end battle.pbHideAbilitySplash(target) } ) Battle::AbilityEffects::OnBeingHit.add(:ANGERPOINT, proc { |ability, user, target, move, battle| next if !target.damageState.critical next if !target.pbCanRaiseStatStage?(:ATTACK, target) battle.pbShowAbilitySplash(target) target.stages[:ATTACK] = 6 target.statsRaisedThisRound = true battle.pbCommonAnimation("StatUp", target) if Battle::Scene::USE_ABILITY_SPLASH battle.pbDisplay(_INTL("{1} maxed its {2}!", target.pbThis, GameData::Stat.get(:ATTACK).name)) else battle.pbDisplay(_INTL("{1}'s {2} maxed its {3}!", target.pbThis, target.abilityName, GameData::Stat.get(:ATTACK).name)) end battle.pbHideAbilitySplash(target) } ) Battle::AbilityEffects::OnBeingHit.add(:COTTONDOWN, proc { |ability, user, target, move, battle| next if battle.allBattlers.none? { |b| b.pbCanLowerStatStage?(:DEFENSE, target) } battle.pbShowAbilitySplash(target) battle.allBattlers.each do |b| b.pbLowerStatStageByAbility(:SPEED, 1, target, false) end battle.pbHideAbilitySplash(target) } ) Battle::AbilityEffects::OnBeingHit.add(:CURSEDBODY, proc { |ability, user, target, move, battle| next if user.fainted? next if user.effects[PBEffects::Disable] > 0 regularMove = nil user.eachMove do |m| next if m.id != user.lastRegularMoveUsed regularMove = m break end next if !regularMove || (regularMove.pp == 0 && regularMove.total_pp > 0) next if battle.pbRandom(100) >= 30 battle.pbShowAbilitySplash(target) if !move.pbMoveFailedAromaVeil?(target, user, Battle::Scene::USE_ABILITY_SPLASH) user.effects[PBEffects::Disable] = 3 user.effects[PBEffects::DisableMove] = regularMove.id if Battle::Scene::USE_ABILITY_SPLASH battle.pbDisplay(_INTL("{1}'s {2} was disabled!", user.pbThis, regularMove.name)) else battle.pbDisplay(_INTL("{1}'s {2} was disabled by {3}'s {4}!", user.pbThis, regularMove.name, target.pbThis(true), target.abilityName)) end battle.pbHideAbilitySplash(target) user.pbItemStatusCureCheck end battle.pbHideAbilitySplash(target) } ) Battle::AbilityEffects::OnBeingHit.add(:CUTECHARM, proc { |ability, user, target, move, battle| next if target.fainted? next if !move.pbContactMove?(user) next if battle.pbRandom(100) >= 30 battle.pbShowAbilitySplash(target) if user.pbCanAttract?(target, Battle::Scene::USE_ABILITY_SPLASH) && user.affectedByContactEffect?(Battle::Scene::USE_ABILITY_SPLASH) msg = nil if !Battle::Scene::USE_ABILITY_SPLASH msg = _INTL("{1}'s {2} made {3} fall in love!", target.pbThis, target.abilityName, user.pbThis(true)) end user.pbAttract(target, msg) end battle.pbHideAbilitySplash(target) } ) Battle::AbilityEffects::OnBeingHit.add(:EFFECTSPORE, proc { |ability, user, target, move, battle| # NOTE: This ability has a 30% chance of triggering, not a 30% chance of # inflicting a status condition. It can try (and fail) to inflict a # status condition that the user is immune to. next if !move.pbContactMove?(user) next if battle.pbRandom(100) >= 30 r = battle.pbRandom(3) next if r == 0 && user.asleep? next if r == 1 && user.poisoned? next if r == 2 && user.paralyzed? battle.pbShowAbilitySplash(target) if user.affectedByPowder?(Battle::Scene::USE_ABILITY_SPLASH) && user.affectedByContactEffect?(Battle::Scene::USE_ABILITY_SPLASH) case r when 0 if user.pbCanSleep?(target, Battle::Scene::USE_ABILITY_SPLASH) msg = nil if !Battle::Scene::USE_ABILITY_SPLASH msg = _INTL("{1}'s {2} made {3} fall asleep!", target.pbThis, target.abilityName, user.pbThis(true)) end user.pbSleep(msg) end when 1 if user.pbCanPoison?(target, Battle::Scene::USE_ABILITY_SPLASH) msg = nil if !Battle::Scene::USE_ABILITY_SPLASH msg = _INTL("{1}'s {2} poisoned {3}!", target.pbThis, target.abilityName, user.pbThis(true)) end user.pbPoison(target, msg) end when 2 if user.pbCanParalyze?(target, Battle::Scene::USE_ABILITY_SPLASH) msg = nil if !Battle::Scene::USE_ABILITY_SPLASH msg = _INTL("{1}'s {2} paralyzed {3}! It may be unable to move!", target.pbThis, target.abilityName, user.pbThis(true)) end user.pbParalyze(target, msg) end end end battle.pbHideAbilitySplash(target) } ) Battle::AbilityEffects::OnBeingHit.add(:FLAMEBODY, proc { |ability, user, target, move, battle| next if !move.pbContactMove?(user) next if user.burned? || battle.pbRandom(100) >= 30 battle.pbShowAbilitySplash(target) if user.pbCanBurn?(target, Battle::Scene::USE_ABILITY_SPLASH) && user.affectedByContactEffect?(Battle::Scene::USE_ABILITY_SPLASH) msg = nil if !Battle::Scene::USE_ABILITY_SPLASH msg = _INTL("{1}'s {2} burned {3}!", target.pbThis, target.abilityName, user.pbThis(true)) end user.pbBurn(target, msg) end battle.pbHideAbilitySplash(target) } ) Battle::AbilityEffects::OnBeingHit.add(:GOOEY, proc { |ability, user, target, move, battle| next if !move.pbContactMove?(user) user.pbLowerStatStageByAbility(:SPEED, 1, target, true, true) } ) Battle::AbilityEffects::OnBeingHit.copy(:GOOEY, :TANGLINGHAIR) Battle::AbilityEffects::OnBeingHit.add(:ILLUSION, proc { |ability, user, target, move, battle| # NOTE: This intentionally doesn't show the ability splash. next if !target.effects[PBEffects::Illusion] target.effects[PBEffects::Illusion] = nil battle.scene.pbChangePokemon(target, target.pokemon) battle.pbDisplay(_INTL("{1}'s illusion wore off!", target.pbThis)) battle.pbSetSeen(target) } ) Battle::AbilityEffects::OnBeingHit.add(:INNARDSOUT, proc { |ability, user, target, move, battle| next if !target.fainted? || user.dummy battle.pbShowAbilitySplash(target) if user.takesIndirectDamage?(Battle::Scene::USE_ABILITY_SPLASH) battle.scene.pbDamageAnimation(user) user.pbReduceHP(target.damageState.hpLost, false) if Battle::Scene::USE_ABILITY_SPLASH battle.pbDisplay(_INTL("{1} is hurt!", user.pbThis)) else battle.pbDisplay(_INTL("{1} is hurt by {2}'s {3}!", user.pbThis, target.pbThis(true), target.abilityName)) end end battle.pbHideAbilitySplash(target) } ) Battle::AbilityEffects::OnBeingHit.add(:IRONBARBS, proc { |ability, user, target, move, battle| next if !move.pbContactMove?(user) battle.pbShowAbilitySplash(target) if user.takesIndirectDamage?(Battle::Scene::USE_ABILITY_SPLASH) && user.affectedByContactEffect?(Battle::Scene::USE_ABILITY_SPLASH) battle.scene.pbDamageAnimation(user) user.pbReduceHP(user.totalhp / 8, false) if Battle::Scene::USE_ABILITY_SPLASH battle.pbDisplay(_INTL("{1} is hurt!", user.pbThis)) else battle.pbDisplay(_INTL("{1} is hurt by {2}'s {3}!", user.pbThis, target.pbThis(true), target.abilityName)) end end battle.pbHideAbilitySplash(target) } ) Battle::AbilityEffects::OnBeingHit.copy(:IRONBARBS, :ROUGHSKIN) Battle::AbilityEffects::OnBeingHit.add(:JUSTIFIED, proc { |ability, user, target, move, battle| next if move.calcType != :DARK target.pbRaiseStatStageByAbility(:ATTACK, 1, target) } ) Battle::AbilityEffects::OnBeingHit.add(:MUMMY, proc { |ability, user, target, move, battle| next if !move.pbContactMove?(user) next if user.fainted? next if user.unstoppableAbility? || user.ability == ability oldAbil = nil battle.pbShowAbilitySplash(target) if user.opposes?(target) if user.affectedByContactEffect?(Battle::Scene::USE_ABILITY_SPLASH) oldAbil = user.ability battle.pbShowAbilitySplash(user, true, false) if user.opposes?(target) user.ability = ability battle.pbReplaceAbilitySplash(user) if user.opposes?(target) if Battle::Scene::USE_ABILITY_SPLASH battle.pbDisplay(_INTL("{1}'s Ability became {2}!", user.pbThis, user.abilityName)) else battle.pbDisplay(_INTL("{1}'s Ability became {2} because of {3}!", user.pbThis, user.abilityName, target.pbThis(true))) end battle.pbHideAbilitySplash(user) if user.opposes?(target) end battle.pbHideAbilitySplash(target) if user.opposes?(target) user.pbOnLosingAbility(oldAbil) user.pbTriggerAbilityOnGainingIt } ) Battle::AbilityEffects::OnBeingHit.add(:PERISHBODY, proc { |ability, user, target, move, battle| next if !move.pbContactMove?(user) next if user.fainted? next if user.effects[PBEffects::PerishSong] > 0 || target.effects[PBEffects::PerishSong] > 0 battle.pbShowAbilitySplash(target) if user.affectedByContactEffect?(Battle::Scene::USE_ABILITY_SPLASH) user.effects[PBEffects::PerishSong] = 4 user.effects[PBEffects::PerishSongUser] = target.index target.effects[PBEffects::PerishSong] = 4 target.effects[PBEffects::PerishSongUser] = target.index if Battle::Scene::USE_ABILITY_SPLASH battle.pbDisplay(_INTL("Both Pokémon will faint in three turns!")) else battle.pbDisplay(_INTL("Both Pokémon will faint in three turns because of {1}'s {2}!", target.pbThis(true), target.abilityName)) end end battle.pbHideAbilitySplash(target) } ) Battle::AbilityEffects::OnBeingHit.add(:POISONPOINT, proc { |ability, user, target, move, battle| next if !move.pbContactMove?(user) next if user.poisoned? || battle.pbRandom(100) >= 30 battle.pbShowAbilitySplash(target) if user.pbCanPoison?(target, Battle::Scene::USE_ABILITY_SPLASH) && user.affectedByContactEffect?(Battle::Scene::USE_ABILITY_SPLASH) msg = nil if !Battle::Scene::USE_ABILITY_SPLASH msg = _INTL("{1}'s {2} poisoned {3}!", target.pbThis, target.abilityName, user.pbThis(true)) end user.pbPoison(target, msg) end battle.pbHideAbilitySplash(target) } ) Battle::AbilityEffects::OnBeingHit.add(:RATTLED, proc { |ability, user, target, move, battle| next if ![:BUG, :DARK, :GHOST].include?(move.calcType) target.pbRaiseStatStageByAbility(:SPEED, 1, target) } ) Battle::AbilityEffects::OnBeingHit.add(:SANDSPIT, proc { |ability, user, target, move, battle| battle.pbStartWeatherAbility(:Sandstorm, target) } ) Battle::AbilityEffects::OnBeingHit.add(:STAMINA, proc { |ability, user, target, move, battle| target.pbRaiseStatStageByAbility(:DEFENSE, 1, target) } ) Battle::AbilityEffects::OnBeingHit.add(:STATIC, proc { |ability, user, target, move, battle| next if !move.pbContactMove?(user) next if user.paralyzed? || battle.pbRandom(100) >= 30 battle.pbShowAbilitySplash(target) if user.pbCanParalyze?(target, Battle::Scene::USE_ABILITY_SPLASH) && user.affectedByContactEffect?(Battle::Scene::USE_ABILITY_SPLASH) msg = nil if !Battle::Scene::USE_ABILITY_SPLASH msg = _INTL("{1}'s {2} paralyzed {3}! It may be unable to move!", target.pbThis, target.abilityName, user.pbThis(true)) end user.pbParalyze(target, msg) end battle.pbHideAbilitySplash(target) } ) Battle::AbilityEffects::OnBeingHit.add(:WANDERINGSPIRIT, proc { |ability, user, target, move, battle| next if !move.pbContactMove?(user) next if user.ungainableAbility? || [:RECEIVER, :WONDERGUARD].include?(user.ability_id) oldUserAbil = nil oldTargetAbil = nil battle.pbShowAbilitySplash(target) if user.opposes?(target) if user.affectedByContactEffect?(Battle::Scene::USE_ABILITY_SPLASH) battle.pbShowAbilitySplash(user, true, false) if user.opposes?(target) oldUserAbil = user.ability oldTargetAbil = target.ability user.ability = oldTargetAbil target.ability = oldUserAbil if user.opposes?(target) battle.pbReplaceAbilitySplash(user) battle.pbReplaceAbilitySplash(target) end if Battle::Scene::USE_ABILITY_SPLASH battle.pbDisplay(_INTL("{1} swapped Abilities with {2}!", target.pbThis, user.pbThis(true))) else battle.pbDisplay(_INTL("{1} swapped its {2} Ability with {3}'s {4} Ability!", target.pbThis, user.abilityName, user.pbThis(true), target.abilityName)) end if user.opposes?(target) battle.pbHideAbilitySplash(user) battle.pbHideAbilitySplash(target) end end battle.pbHideAbilitySplash(target) if user.opposes?(target) user.pbOnLosingAbility(oldUserAbil) target.pbOnLosingAbility(oldTargetAbil) user.pbTriggerAbilityOnGainingIt target.pbTriggerAbilityOnGainingIt } ) Battle::AbilityEffects::OnBeingHit.add(:WATERCOMPACTION, proc { |ability, user, target, move, battle| next if move.calcType != :WATER target.pbRaiseStatStageByAbility(:DEFENSE, 2, target) } ) Battle::AbilityEffects::OnBeingHit.add(:WEAKARMOR, proc { |ability, user, target, move, battle| next if !move.physicalMove? next if !target.pbCanLowerStatStage?(:DEFENSE, target) && !target.pbCanRaiseStatStage?(:SPEED, target) battle.pbShowAbilitySplash(target) target.pbLowerStatStageByAbility(:DEFENSE, 1, target, false) target.pbRaiseStatStageByAbility(:SPEED, (Settings::MECHANICS_GENERATION >= 7) ? 2 : 1, target, false) battle.pbHideAbilitySplash(target) } ) #=============================================================================== # OnDealingHit handlers #=============================================================================== Battle::AbilityEffects::OnDealingHit.add(:POISONTOUCH, proc { |ability, user, target, move, battle| next if !move.contactMove? next if battle.pbRandom(100) >= 30 battle.pbShowAbilitySplash(user) if target.hasActiveAbility?(:SHIELDDUST) && !battle.moldBreaker battle.pbShowAbilitySplash(target) if !Battle::Scene::USE_ABILITY_SPLASH battle.pbDisplay(_INTL("{1} is unaffected!", target.pbThis)) end battle.pbHideAbilitySplash(target) elsif target.pbCanPoison?(user, Battle::Scene::USE_ABILITY_SPLASH) msg = nil if !Battle::Scene::USE_ABILITY_SPLASH msg = _INTL("{1}'s {2} poisoned {3}!", user.pbThis, user.abilityName, target.pbThis(true)) end target.pbPoison(user, msg) end battle.pbHideAbilitySplash(user) } ) #=============================================================================== # OnEndOfUsingMove handlers #=============================================================================== Battle::AbilityEffects::OnEndOfUsingMove.add(:BEASTBOOST, proc { |ability, user, targets, move, battle| next if battle.pbAllFainted?(user.idxOpposingSide) numFainted = 0 targets.each { |b| numFainted += 1 if b.damageState.fainted } next if numFainted == 0 userStats = user.plainStats highestStatValue = 0 userStats.each_value { |value| highestStatValue = value if highestStatValue < value } GameData::Stat.each_main_battle do |s| next if userStats[s.id] < highestStatValue if user.pbCanRaiseStatStage?(s.id, user) user.pbRaiseStatStageByAbility(s.id, numFainted, user) end break end } ) Battle::AbilityEffects::OnEndOfUsingMove.add(:CHILLINGNEIGH, proc { |ability, user, targets, move, battle| next if battle.pbAllFainted?(user.idxOpposingSide) numFainted = 0 targets.each { |b| numFainted += 1 if b.damageState.fainted } next if numFainted == 0 || !user.pbCanRaiseStatStage?(:ATTACK, user) user.ability_id = :CHILLINGNEIGH # So the As One abilities can just copy this user.pbRaiseStatStageByAbility(:ATTACK, 1, user) user.ability_id = ability } ) Battle::AbilityEffects::OnEndOfUsingMove.copy(:CHILLINGNEIGH, :ASONECHILLINGNEIGH) Battle::AbilityEffects::OnEndOfUsingMove.add(:GRIMNEIGH, proc { |ability, user, targets, move, battle| next if battle.pbAllFainted?(user.idxOpposingSide) numFainted = 0 targets.each { |b| numFainted += 1 if b.damageState.fainted } next if numFainted == 0 || !user.pbCanRaiseStatStage?(:SPECIAL_ATTACK, user) user.ability_id = :GRIMNEIGH # So the As One abilities can just copy this user.pbRaiseStatStageByAbility(:SPECIAL_ATTACK, 1, user) user.ability_id = ability } ) Battle::AbilityEffects::OnEndOfUsingMove.copy(:GRIMNEIGH, :ASONEGRIMNEIGH) Battle::AbilityEffects::OnEndOfUsingMove.add(:MAGICIAN, proc { |ability, user, targets, move, battle| next if battle.futureSight next if !move.pbDamagingMove? next if user.item next if user.wild? targets.each do |b| next if b.damageState.unaffected || b.damageState.substitute next if !b.item next if b.unlosableItem?(b.item) || user.unlosableItem?(b.item) battle.pbShowAbilitySplash(user) if b.hasActiveAbility?(:STICKYHOLD) battle.pbShowAbilitySplash(b) if user.opposes?(b) if Battle::Scene::USE_ABILITY_SPLASH battle.pbDisplay(_INTL("{1}'s item cannot be stolen!", b.pbThis)) end battle.pbHideAbilitySplash(b) if user.opposes?(b) next end user.item = b.item b.item = nil b.effects[PBEffects::Unburden] = true if b.hasActiveAbility?(:UNBURDEN) if battle.wildBattle? && !user.initialItem && user.item == b.initialItem user.setInitialItem(user.item) b.setInitialItem(nil) end if Battle::Scene::USE_ABILITY_SPLASH battle.pbDisplay(_INTL("{1} stole {2}'s {3}!", user.pbThis, b.pbThis(true), user.itemName)) else battle.pbDisplay(_INTL("{1} stole {2}'s {3} with {4}!", user.pbThis, b.pbThis(true), user.itemName, user.abilityName)) end battle.pbHideAbilitySplash(user) user.pbHeldItemTriggerCheck break end } ) Battle::AbilityEffects::OnEndOfUsingMove.add(:MOXIE, proc { |ability, user, targets, move, battle| next if battle.pbAllFainted?(user.idxOpposingSide) numFainted = 0 targets.each { |b| numFainted += 1 if b.damageState.fainted } next if numFainted == 0 || !user.pbCanRaiseStatStage?(:ATTACK, user) user.pbRaiseStatStageByAbility(:ATTACK, numFainted, user) } ) #=============================================================================== # AfterMoveUseFromTarget handlers #=============================================================================== Battle::AbilityEffects::AfterMoveUseFromTarget.add(:BERSERK, proc { |ability, target, user, move, switched_battlers, battle| next if !move.damagingMove? next if !target.droppedBelowHalfHP next if !target.pbCanRaiseStatStage?(:SPECIAL_ATTACK, target) target.pbRaiseStatStageByAbility(:SPECIAL_ATTACK, 1, target) } ) Battle::AbilityEffects::AfterMoveUseFromTarget.add(:COLORCHANGE, proc { |ability, target, user, move, switched_battlers, battle| next if target.damageState.calcDamage == 0 || target.damageState.substitute next if !move.calcType || GameData::Type.get(move.calcType).pseudo_type next if target.pbHasType?(move.calcType) && !target.pbHasOtherType?(move.calcType) typeName = GameData::Type.get(move.calcType).name battle.pbShowAbilitySplash(target) target.pbChangeTypes(move.calcType) battle.pbDisplay(_INTL("{1}'s type changed to {2} because of its {3}!", target.pbThis, typeName, target.abilityName)) battle.pbHideAbilitySplash(target) } ) Battle::AbilityEffects::AfterMoveUseFromTarget.add(:PICKPOCKET, proc { |ability, target, user, move, switched_battlers, battle| # NOTE: According to Bulbapedia, this can still trigger to steal the user's # item even if it was switched out by a Red Card. That doesn't make # sense, so this code doesn't do it. next if target.wild? next if switched_battlers.include?(user.index) # User was switched out next if !move.contactMove? next if user.effects[PBEffects::Substitute] > 0 || target.damageState.substitute next if target.item || !user.item next if user.unlosableItem?(user.item) || target.unlosableItem?(user.item) battle.pbShowAbilitySplash(target) if user.hasActiveAbility?(:STICKYHOLD) battle.pbShowAbilitySplash(user) if target.opposes?(user) if Battle::Scene::USE_ABILITY_SPLASH battle.pbDisplay(_INTL("{1}'s item cannot be stolen!", user.pbThis)) end battle.pbHideAbilitySplash(user) if target.opposes?(user) battle.pbHideAbilitySplash(target) next end target.item = user.item user.item = nil user.effects[PBEffects::Unburden] = true if user.hasActiveAbility?(:UNBURDEN) if battle.wildBattle? && !target.initialItem && target.item == user.initialItem target.setInitialItem(target.item) user.setInitialItem(nil) end battle.pbDisplay(_INTL("{1} pickpocketed {2}'s {3}!", target.pbThis, user.pbThis(true), target.itemName)) battle.pbHideAbilitySplash(target) target.pbHeldItemTriggerCheck } ) #=============================================================================== # EndOfRoundWeather handlers #=============================================================================== Battle::AbilityEffects::EndOfRoundWeather.add(:DRYSKIN, proc { |ability, weather, battler, battle| case weather when :Sun, :HarshSun battle.pbShowAbilitySplash(battler) battle.scene.pbDamageAnimation(battler) battler.pbReduceHP(battler.totalhp / 8, false) battle.pbDisplay(_INTL("{1} was hurt by the sunlight!", battler.pbThis)) battle.pbHideAbilitySplash(battler) battler.pbItemHPHealCheck when :Rain, :HeavyRain next if !battler.canHeal? battle.pbShowAbilitySplash(battler) battler.pbRecoverHP(battler.totalhp / 8) if Battle::Scene::USE_ABILITY_SPLASH battle.pbDisplay(_INTL("{1}'s HP was restored.", battler.pbThis)) else battle.pbDisplay(_INTL("{1}'s {2} restored its HP.", battler.pbThis, battler.abilityName)) end battle.pbHideAbilitySplash(battler) end } ) Battle::AbilityEffects::EndOfRoundWeather.add(:ICEBODY, proc { |ability, weather, battler, battle| next unless weather == :Hail next if !battler.canHeal? battle.pbShowAbilitySplash(battler) battler.pbRecoverHP(battler.totalhp / 16) if Battle::Scene::USE_ABILITY_SPLASH battle.pbDisplay(_INTL("{1}'s HP was restored.", battler.pbThis)) else battle.pbDisplay(_INTL("{1}'s {2} restored its HP.", battler.pbThis, battler.abilityName)) end battle.pbHideAbilitySplash(battler) } ) Battle::AbilityEffects::EndOfRoundWeather.add(:ICEFACE, proc { |ability, weather, battler, battle| next if weather != :Hail next if !battler.canRestoreIceFace || battler.form != 1 battle.pbShowAbilitySplash(battler) if !Battle::Scene::USE_ABILITY_SPLASH battle.pbDisplay(_INTL("{1}'s {2} activated!", battler.pbThis, battler.abilityName)) end battler.pbChangeForm(0, _INTL("{1} transformed!", battler.pbThis)) battle.pbHideAbilitySplash(battler) } ) Battle::AbilityEffects::EndOfRoundWeather.add(:RAINDISH, proc { |ability, weather, battler, battle| next unless [:Rain, :HeavyRain].include?(weather) next if !battler.canHeal? battle.pbShowAbilitySplash(battler) battler.pbRecoverHP(battler.totalhp / 16) if Battle::Scene::USE_ABILITY_SPLASH battle.pbDisplay(_INTL("{1}'s HP was restored.", battler.pbThis)) else battle.pbDisplay(_INTL("{1}'s {2} restored its HP.", battler.pbThis, battler.abilityName)) end battle.pbHideAbilitySplash(battler) } ) Battle::AbilityEffects::EndOfRoundWeather.add(:SOLARPOWER, proc { |ability, weather, battler, battle| next unless [:Sun, :HarshSun].include?(weather) battle.pbShowAbilitySplash(battler) battle.scene.pbDamageAnimation(battler) battler.pbReduceHP(battler.totalhp / 8, false) battle.pbDisplay(_INTL("{1} was hurt by the sunlight!", battler.pbThis)) battle.pbHideAbilitySplash(battler) battler.pbItemHPHealCheck } ) #=============================================================================== # EndOfRoundHealing handlers #=============================================================================== Battle::AbilityEffects::EndOfRoundHealing.add(:HEALER, proc { |ability, battler, battle| next unless battle.pbRandom(100) < 30 battler.allAllies.each do |b| next if b.status == :NONE battle.pbShowAbilitySplash(battler) oldStatus = b.status b.pbCureStatus(Battle::Scene::USE_ABILITY_SPLASH) if !Battle::Scene::USE_ABILITY_SPLASH case oldStatus when :SLEEP battle.pbDisplay(_INTL("{1}'s {2} woke its partner up!", battler.pbThis, battler.abilityName)) when :POISON battle.pbDisplay(_INTL("{1}'s {2} cured its partner's poison!", battler.pbThis, battler.abilityName)) when :BURN battle.pbDisplay(_INTL("{1}'s {2} healed its partner's burn!", battler.pbThis, battler.abilityName)) when :PARALYSIS battle.pbDisplay(_INTL("{1}'s {2} cured its partner's paralysis!", battler.pbThis, battler.abilityName)) when :FROZEN battle.pbDisplay(_INTL("{1}'s {2} defrosted its partner!", battler.pbThis, battler.abilityName)) end end battle.pbHideAbilitySplash(battler) end } ) Battle::AbilityEffects::EndOfRoundHealing.add(:HYDRATION, proc { |ability, battler, battle| next if battler.status == :NONE next if ![:Rain, :HeavyRain].include?(battler.effectiveWeather) battle.pbShowAbilitySplash(battler) oldStatus = battler.status battler.pbCureStatus(Battle::Scene::USE_ABILITY_SPLASH) if !Battle::Scene::USE_ABILITY_SPLASH case oldStatus when :SLEEP battle.pbDisplay(_INTL("{1}'s {2} woke it up!", battler.pbThis, battler.abilityName)) when :POISON battle.pbDisplay(_INTL("{1}'s {2} cured its poison!", battler.pbThis, battler.abilityName)) when :BURN battle.pbDisplay(_INTL("{1}'s {2} healed its burn!", battler.pbThis, battler.abilityName)) when :PARALYSIS battle.pbDisplay(_INTL("{1}'s {2} cured its paralysis!", battler.pbThis, battler.abilityName)) when :FROZEN battle.pbDisplay(_INTL("{1}'s {2} defrosted it!", battler.pbThis, battler.abilityName)) end end battle.pbHideAbilitySplash(battler) } ) Battle::AbilityEffects::EndOfRoundHealing.add(:SHEDSKIN, proc { |ability, battler, battle| next if battler.status == :NONE next unless battle.pbRandom(100) < 30 battle.pbShowAbilitySplash(battler) oldStatus = battler.status battler.pbCureStatus(Battle::Scene::USE_ABILITY_SPLASH) if !Battle::Scene::USE_ABILITY_SPLASH case oldStatus when :SLEEP battle.pbDisplay(_INTL("{1}'s {2} woke it up!", battler.pbThis, battler.abilityName)) when :POISON battle.pbDisplay(_INTL("{1}'s {2} cured its poison!", battler.pbThis, battler.abilityName)) when :BURN battle.pbDisplay(_INTL("{1}'s {2} healed its burn!", battler.pbThis, battler.abilityName)) when :PARALYSIS battle.pbDisplay(_INTL("{1}'s {2} cured its paralysis!", battler.pbThis, battler.abilityName)) when :FROZEN battle.pbDisplay(_INTL("{1}'s {2} defrosted it!", battler.pbThis, battler.abilityName)) end end battle.pbHideAbilitySplash(battler) } ) #=============================================================================== # EndOfRoundEffect handlers #=============================================================================== Battle::AbilityEffects::EndOfRoundEffect.add(:BADDREAMS, proc { |ability, battler, battle| battle.allOtherSideBattlers(battler.index).each do |b| next if !b.near?(battler) || !b.asleep? battle.pbShowAbilitySplash(battler) next if !b.takesIndirectDamage?(Battle::Scene::USE_ABILITY_SPLASH) b.pbTakeEffectDamage(b.totalhp / 8) { |hp_lost| if Battle::Scene::USE_ABILITY_SPLASH battle.pbDisplay(_INTL("{1} is tormented!", b.pbThis)) else battle.pbDisplay(_INTL("{1} is tormented by {2}'s {3}!", b.pbThis, battler.pbThis(true), battler.abilityName)) end battle.pbHideAbilitySplash(battler) } end } ) Battle::AbilityEffects::EndOfRoundEffect.add(:MOODY, proc { |ability, battler, battle| randomUp = [] randomDown = [] if Settings::MECHANICS_GENERATION >= 8 GameData::Stat.each_main_battle do |s| randomUp.push(s.id) if battler.pbCanRaiseStatStage?(s.id, battler) randomDown.push(s.id) if battler.pbCanLowerStatStage?(s.id, battler) end else GameData::Stat.each_battle do |s| randomUp.push(s.id) if battler.pbCanRaiseStatStage?(s.id, battler) randomDown.push(s.id) if battler.pbCanLowerStatStage?(s.id, battler) end end next if randomUp.length == 0 && randomDown.length == 0 battle.pbShowAbilitySplash(battler) if randomUp.length > 0 r = battle.pbRandom(randomUp.length) battler.pbRaiseStatStageByAbility(randomUp[r], 2, battler, false) randomDown.delete(randomUp[r]) end if randomDown.length > 0 r = battle.pbRandom(randomDown.length) battler.pbLowerStatStageByAbility(randomDown[r], 1, battler, false) end battle.pbHideAbilitySplash(battler) battler.pbItemStatRestoreCheck if randomDown.length > 0 battler.pbItemOnStatDropped } ) Battle::AbilityEffects::EndOfRoundEffect.add(:SPEEDBOOST, proc { |ability, battler, battle| # A Pokémon's turnCount is 0 if it became active after the beginning of a # round if battler.turnCount > 0 && battle.choices[battler.index][0] != :Run && battler.pbCanRaiseStatStage?(:SPEED, battler) battler.pbRaiseStatStageByAbility(:SPEED, 1, battler) end } ) #=============================================================================== # EndOfRoundGainItem handlers #=============================================================================== Battle::AbilityEffects::EndOfRoundGainItem.add(:BALLFETCH, proc { |ability, battler, battle| next if battler.item next if battle.first_poke_ball.nil? battle.pbShowAbilitySplash(battler) battler.item = battle.first_poke_ball battler.setInitialItem(battler.item) if !battler.initialItem battle.first_poke_ball = nil battle.pbDisplay(_INTL("{1} retrieved the thrown {2}!", battler.pbThis, battler.itemName)) battle.pbHideAbilitySplash(battler) battler.pbHeldItemTriggerCheck } ) Battle::AbilityEffects::EndOfRoundGainItem.add(:HARVEST, proc { |ability, battler, battle| next if battler.item next if !battler.recycleItem || !GameData::Item.get(battler.recycleItem).is_berry? if ![:Sun, :HarshSun].include?(battler.effectiveWeather) next unless battle.pbRandom(100) < 50 end battle.pbShowAbilitySplash(battler) battler.item = battler.recycleItem battler.setRecycleItem(nil) battler.setInitialItem(battler.item) if !battler.initialItem battle.pbDisplay(_INTL("{1} harvested one {2}!", battler.pbThis, battler.itemName)) battle.pbHideAbilitySplash(battler) battler.pbHeldItemTriggerCheck } ) Battle::AbilityEffects::EndOfRoundGainItem.add(:PICKUP, proc { |ability, battler, battle| next if battler.item foundItem = nil fromBattler = nil use = 0 battle.allBattlers.each do |b| next if b.index == battler.index next if b.effects[PBEffects::PickupUse] <= use foundItem = b.effects[PBEffects::PickupItem] fromBattler = b use = b.effects[PBEffects::PickupUse] end next if !foundItem battle.pbShowAbilitySplash(battler) battler.item = foundItem fromBattler.effects[PBEffects::PickupItem] = nil fromBattler.effects[PBEffects::PickupUse] = 0 fromBattler.setRecycleItem(nil) if fromBattler.recycleItem == foundItem if battle.wildBattle? && !battler.initialItem && fromBattler.initialItem == foundItem battler.setInitialItem(foundItem) fromBattler.setInitialItem(nil) end battle.pbDisplay(_INTL("{1} found one {2}!", battler.pbThis, battler.itemName)) battle.pbHideAbilitySplash(battler) battler.pbHeldItemTriggerCheck } ) #=============================================================================== # CertainSwitching handlers #=============================================================================== # There aren't any! #=============================================================================== # TrappingByTarget handlers #=============================================================================== Battle::AbilityEffects::TrappingByTarget.add(:ARENATRAP, proc { |ability, switcher, bearer, battle| next true if !switcher.airborne? } ) Battle::AbilityEffects::TrappingByTarget.add(:MAGNETPULL, proc { |ability, switcher, bearer, battle| next true if switcher.pbHasType?(:STEEL) } ) Battle::AbilityEffects::TrappingByTarget.add(:SHADOWTAG, proc { |ability, switcher, bearer, battle| next true if !switcher.hasActiveAbility?(:SHADOWTAG) } ) #=============================================================================== # OnSwitchIn handlers #=============================================================================== Battle::AbilityEffects::OnSwitchIn.add(:AIRLOCK, proc { |ability, battler, battle, switch_in| battle.pbShowAbilitySplash(battler) if !Battle::Scene::USE_ABILITY_SPLASH battle.pbDisplay(_INTL("{1} has {2}!", battler.pbThis, battler.abilityName)) end battle.pbDisplay(_INTL("The effects of the weather disappeared.")) battle.pbHideAbilitySplash(battler) } ) Battle::AbilityEffects::OnSwitchIn.copy(:AIRLOCK, :CLOUDNINE) Battle::AbilityEffects::OnSwitchIn.add(:ANTICIPATION, proc { |ability, battler, battle, switch_in| next if !battler.pbOwnedByPlayer? battlerTypes = battler.pbTypes(true) types = battlerTypes found = false battle.allOtherSideBattlers(battler.index).each do |b| b.eachMove do |m| next if m.statusMove? if types.length > 0 moveType = m.type if Settings::MECHANICS_GENERATION >= 6 && m.function == "TypeDependsOnUserIVs" # Hidden Power moveType = pbHiddenPower(b.pokemon)[0] end eff = Effectiveness.calculate(moveType, types[0], types[1], types[2]) next if Effectiveness.ineffective?(eff) next if !Effectiveness.super_effective?(eff) && !["OHKO", "OHKOIce", "OHKOHitsUndergroundTarget"].include?(m.function) elsif !["OHKO", "OHKOIce", "OHKOHitsUndergroundTarget"].include?(m.function) next end found = true break end break if found end if found battle.pbShowAbilitySplash(battler) battle.pbDisplay(_INTL("{1} shuddered with anticipation!", battler.pbThis)) battle.pbHideAbilitySplash(battler) end } ) Battle::AbilityEffects::OnSwitchIn.add(:ASONECHILLINGNEIGH, proc { |ability, battler, battle, switch_in| battle.pbShowAbilitySplash(battler) battle.pbDisplay(_INTL("{1} has two Abilities!", battler.pbThis)) battle.pbHideAbilitySplash(battler) battler.ability_id = :UNNERVE battle.pbShowAbilitySplash(battler) battle.pbDisplay(_INTL("{1} is too nervous to eat Berries!", battler.pbOpposingTeam)) battle.pbHideAbilitySplash(battler) battler.ability_id = ability } ) Battle::AbilityEffects::OnSwitchIn.copy(:ASONECHILLINGNEIGH, :ASONEGRIMNEIGH) Battle::AbilityEffects::OnSwitchIn.add(:AURABREAK, proc { |ability, battler, battle, switch_in| battle.pbShowAbilitySplash(battler) battle.pbDisplay(_INTL("{1} reversed all other Pokémon's auras!", battler.pbThis)) battle.pbHideAbilitySplash(battler) } ) Battle::AbilityEffects::OnSwitchIn.add(:COMATOSE, proc { |ability, battler, battle, switch_in| battle.pbShowAbilitySplash(battler) battle.pbDisplay(_INTL("{1} is drowsing!", battler.pbThis)) battle.pbHideAbilitySplash(battler) } ) Battle::AbilityEffects::OnSwitchIn.add(:CURIOUSMEDICINE, proc { |ability, battler, battle, switch_in| next if battler.allAllies.none? { |b| b.hasAlteredStatStages? } battle.pbShowAbilitySplash(battler) battler.allAllies.each do |b| next if !b.hasAlteredStatStages? b.pbResetStatStages if Battle::Scene::USE_ABILITY_SPLASH battle.pbDisplay(_INTL("{1}'s stat changes were removed!", b.pbThis)) else battle.pbDisplay(_INTL("{1}'s stat changes were removed by {2}'s {3}!", b.pbThis, battler.pbThis(true), battler.abilityName)) end end battle.pbHideAbilitySplash(battler) } ) Battle::AbilityEffects::OnSwitchIn.add(:DARKAURA, proc { |ability, battler, battle, switch_in| battle.pbShowAbilitySplash(battler) battle.pbDisplay(_INTL("{1} is radiating a dark aura!", battler.pbThis)) battle.pbHideAbilitySplash(battler) } ) Battle::AbilityEffects::OnSwitchIn.add(:DAUNTLESSSHIELD, proc { |ability, battler, battle, switch_in| battler.pbRaiseStatStageByAbility(:DEFENSE, 1, battler) } ) Battle::AbilityEffects::OnSwitchIn.add(:DELTASTREAM, proc { |ability, battler, battle, switch_in| battle.pbStartWeatherAbility(:StrongWinds, battler, true) } ) Battle::AbilityEffects::OnSwitchIn.add(:DESOLATELAND, proc { |ability, battler, battle, switch_in| battle.pbStartWeatherAbility(:HarshSun, battler, true) } ) Battle::AbilityEffects::OnSwitchIn.add(:DOWNLOAD, proc { |ability, battler, battle, switch_in| oDef = oSpDef = 0 battle.allOtherSideBattlers(battler.index).each do |b| oDef += b.defense oSpDef += b.spdef end stat = (oDef < oSpDef) ? :ATTACK : :SPECIAL_ATTACK battler.pbRaiseStatStageByAbility(stat, 1, battler) } ) Battle::AbilityEffects::OnSwitchIn.add(:DRIZZLE, proc { |ability, battler, battle, switch_in| battle.pbStartWeatherAbility(:Rain, battler) } ) Battle::AbilityEffects::OnSwitchIn.add(:DROUGHT, proc { |ability, battler, battle, switch_in| battle.pbStartWeatherAbility(:Sun, battler) } ) Battle::AbilityEffects::OnSwitchIn.add(:ELECTRICSURGE, proc { |ability, battler, battle, switch_in| next if battle.field.terrain == :Electric battle.pbShowAbilitySplash(battler) battle.pbStartTerrain(battler, :Electric) # NOTE: The ability splash is hidden again in def pbStartTerrain. } ) Battle::AbilityEffects::OnSwitchIn.add(:FAIRYAURA, proc { |ability, battler, battle, switch_in| battle.pbShowAbilitySplash(battler) battle.pbDisplay(_INTL("{1} is radiating a fairy aura!", battler.pbThis)) battle.pbHideAbilitySplash(battler) } ) Battle::AbilityEffects::OnSwitchIn.add(:FOREWARN, proc { |ability, battler, battle, switch_in| next if !battler.pbOwnedByPlayer? highestPower = 0 forewarnMoves = [] battle.allOtherSideBattlers(battler.index).each do |b| b.eachMove do |m| power = m.baseDamage power = 160 if ["OHKO", "OHKOIce", "OHKOHitsUndergroundTarget"].include?(m.function) power = 150 if ["PowerHigherWithUserHP"].include?(m.function) # Eruption # Counter, Mirror Coat, Metal Burst power = 120 if ["CounterPhysicalDamage", "CounterSpecialDamage", "CounterDamagePlusHalf"].include?(m.function) # Sonic Boom, Dragon Rage, Night Shade, Endeavor, Psywave, # Return, Frustration, Crush Grip, Gyro Ball, Hidden Power, # Natural Gift, Trump Card, Flail, Grass Knot power = 80 if ["FixedDamage20", "FixedDamage40", "FixedDamageUserLevel", "LowerTargetHPToUserHP", "FixedDamageUserLevelRandom", "PowerHigherWithUserHappiness", "PowerLowerWithUserHappiness", "PowerHigherWithUserHP", "PowerHigherWithTargetFasterThanUser", "TypeAndPowerDependOnUserBerry", "PowerHigherWithLessPP", "PowerLowerWithUserHP", "PowerHigherWithTargetWeight"].include?(m.function) power = 80 if Settings::MECHANICS_GENERATION <= 5 && m.function == "TypeDependsOnUserIVs" next if power < highestPower forewarnMoves = [] if power > highestPower forewarnMoves.push(m.name) highestPower = power end end if forewarnMoves.length > 0 battle.pbShowAbilitySplash(battler) forewarnMoveName = forewarnMoves[battle.pbRandom(forewarnMoves.length)] if Battle::Scene::USE_ABILITY_SPLASH battle.pbDisplay(_INTL("{1} was alerted to {2}!", battler.pbThis, forewarnMoveName)) else battle.pbDisplay(_INTL("{1}'s Forewarn alerted it to {2}!", battler.pbThis, forewarnMoveName)) end battle.pbHideAbilitySplash(battler) end } ) Battle::AbilityEffects::OnSwitchIn.add(:FRISK, proc { |ability, battler, battle, switch_in| next if !battler.pbOwnedByPlayer? foes = battle.allOtherSideBattlers(battler.index).select { |b| b.item } if foes.length > 0 battle.pbShowAbilitySplash(battler) if Settings::MECHANICS_GENERATION >= 6 foes.each do |b| battle.pbDisplay(_INTL("{1} frisked {2} and found its {3}!", battler.pbThis, b.pbThis(true), b.itemName)) end else foe = foes[battle.pbRandom(foes.length)] battle.pbDisplay(_INTL("{1} frisked the foe and found one {2}!", battler.pbThis, foe.itemName)) end battle.pbHideAbilitySplash(battler) end } ) Battle::AbilityEffects::OnSwitchIn.add(:GRASSYSURGE, proc { |ability, battler, battle, switch_in| next if battle.field.terrain == :Grassy battle.pbShowAbilitySplash(battler) battle.pbStartTerrain(battler, :Grassy) # NOTE: The ability splash is hidden again in def pbStartTerrain. } ) Battle::AbilityEffects::OnSwitchIn.add(:ICEFACE, proc { |ability, battler, battle, switch_in| next if !battler.isSpecies?(:EISCUE) || battler.form != 1 next if battler.effectiveWeather != :Hail battle.pbShowAbilitySplash(battler) if !Battle::Scene::USE_ABILITY_SPLASH battle.pbDisplay(_INTL("{1}'s {2} activated!", battler.pbThis, battler.abilityName)) end battler.pbChangeForm(0, _INTL("{1} transformed!", battler.pbThis)) battle.pbHideAbilitySplash(battler) } ) Battle::AbilityEffects::OnSwitchIn.add(:IMPOSTER, proc { |ability, battler, battle, switch_in| next if !switch_in || battler.effects[PBEffects::Transform] choice = battler.pbDirectOpposing next if choice.fainted? next if choice.effects[PBEffects::Transform] || choice.effects[PBEffects::Illusion] || choice.effects[PBEffects::Substitute] > 0 || choice.effects[PBEffects::SkyDrop] >= 0 || choice.semiInvulnerable? battle.pbShowAbilitySplash(battler, true) battle.pbHideAbilitySplash(battler) battle.pbAnimation(:TRANSFORM, battler, choice) battle.scene.pbChangePokemon(battler, choice.pokemon) battler.pbTransform(choice) } ) Battle::AbilityEffects::OnSwitchIn.add(:INTIMIDATE, proc { |ability, battler, battle, switch_in| battle.pbShowAbilitySplash(battler) battle.allOtherSideBattlers(battler.index).each do |b| next if !b.near?(battler) check_item = true if b.hasActiveAbility?(:CONTRARY) check_item = false if b.statStageAtMax?(:ATTACK) elsif b.statStageAtMin?(:ATTACK) check_item = false end check_ability = b.pbLowerAttackStatStageIntimidate(battler) b.pbAbilitiesOnIntimidated if check_ability b.pbItemOnIntimidatedCheck if check_item end battle.pbHideAbilitySplash(battler) } ) Battle::AbilityEffects::OnSwitchIn.add(:INTREPIDSWORD, proc { |ability, battler, battle, switch_in| battler.pbRaiseStatStageByAbility(:ATTACK, 1, battler) } ) Battle::AbilityEffects::OnSwitchIn.add(:MIMICRY, proc { |ability, battler, battle, switch_in| next if battle.field.terrain == :None Battle::AbilityEffects.triggerOnTerrainChange(ability, battler, battle, false) } ) Battle::AbilityEffects::OnSwitchIn.add(:MISTYSURGE, proc { |ability, battler, battle, switch_in| next if battle.field.terrain == :Misty battle.pbShowAbilitySplash(battler) battle.pbStartTerrain(battler, :Misty) # NOTE: The ability splash is hidden again in def pbStartTerrain. } ) Battle::AbilityEffects::OnSwitchIn.add(:MOLDBREAKER, proc { |ability, battler, battle, switch_in| battle.pbShowAbilitySplash(battler) battle.pbDisplay(_INTL("{1} breaks the mold!", battler.pbThis)) battle.pbHideAbilitySplash(battler) } ) Battle::AbilityEffects::OnSwitchIn.add(:NEUTRALIZINGGAS, proc { |ability, battler, battle, switch_in| battle.pbShowAbilitySplash(battler, true) battle.pbHideAbilitySplash(battler) battle.pbDisplay(_INTL("Neutralizing gas filled the area!")) battle.allBattlers.each do |b| # Slow Start - end all turn counts b.effects[PBEffects::SlowStart] = 0 # Truant - let b move on its first turn after Neutralizing Gas disappears b.effects[PBEffects::Truant] = false # Gorilla Tactics - end choice lock if !b.hasActiveItem?([:CHOICEBAND, :CHOICESPECS, :CHOICESCARF]) b.effects[PBEffects::ChoiceBand] = nil end # Illusion - end illusions if b.effects[PBEffects::Illusion] b.effects[PBEffects::Illusion] = nil if !b.effects[PBEffects::Transform] battle.scene.pbChangePokemon(b, b.pokemon) battle.pbDisplay(_INTL("{1}'s {2} wore off!", b.pbThis, b.abilityName)) battle.pbSetSeen(b) end end end # Trigger items upon Unnerve being negated battler.ability_id = nil # Allows checking if Unnerve was active before had_unnerve = battle.pbCheckGlobalAbility(:UNNERVE) battler.ability_id = :NEUTRALIZINGGAS if had_unnerve && !battle.pbCheckGlobalAbility(:UNNERVE) battle.allBattlers.each { |b| b.pbItemsOnUnnerveEnding } end } ) Battle::AbilityEffects::OnSwitchIn.add(:PASTELVEIL, proc { |ability, battler, battle, switch_in| next if battler.allAllies.none? { |b| b.status == :POISON } battle.pbShowAbilitySplash(battler) battler.allAllies.each do |b| next if b.status != :POISON b.pbCureStatus(Battle::Scene::USE_ABILITY_SPLASH) if !Battle::Scene::USE_ABILITY_SPLASH battle.pbDisplay(_INTL("{1}'s {2} cured {3}'s poisoning!", battler.pbThis, battler.abilityName, b.pbThis(true))) end end battle.pbHideAbilitySplash(battler) } ) Battle::AbilityEffects::OnSwitchIn.add(:PRESSURE, proc { |ability, battler, battle, switch_in| battle.pbShowAbilitySplash(battler) battle.pbDisplay(_INTL("{1} is exerting its pressure!", battler.pbThis)) battle.pbHideAbilitySplash(battler) } ) Battle::AbilityEffects::OnSwitchIn.add(:PRIMORDIALSEA, proc { |ability, battler, battle, switch_in| battle.pbStartWeatherAbility(:HeavyRain, battler, true) } ) Battle::AbilityEffects::OnSwitchIn.add(:PSYCHICSURGE, proc { |ability, battler, battle, switch_in| next if battle.field.terrain == :Psychic battle.pbShowAbilitySplash(battler) battle.pbStartTerrain(battler, :Psychic) # NOTE: The ability splash is hidden again in def pbStartTerrain. } ) Battle::AbilityEffects::OnSwitchIn.add(:SANDSTREAM, proc { |ability, battler, battle, switch_in| battle.pbStartWeatherAbility(:Sandstorm, battler) } ) Battle::AbilityEffects::OnSwitchIn.add(:SCREENCLEANER, proc { |ability, battler, battle, switch_in| next if battler.pbOwnSide.effects[PBEffects::AuroraVeil] == 0 && battler.pbOwnSide.effects[PBEffects::LightScreen] == 0 && battler.pbOwnSide.effects[PBEffects::Reflect] == 0 && battler.pbOpposingSide.effects[PBEffects::AuroraVeil] == 0 && battler.pbOpposingSide.effects[PBEffects::LightScreen] == 0 && battler.pbOpposingSide.effects[PBEffects::Reflect] == 0 battle.pbShowAbilitySplash(battler) if battler.pbOpposingSide.effects[PBEffects::AuroraVeil] > 0 battler.pbOpposingSide.effects[PBEffects::AuroraVeil] = 0 battle.pbDisplay(_INTL("{1}'s Aurora Veil wore off!", battler.pbOpposingTeam)) end if battler.pbOpposingSide.effects[PBEffects::LightScreen] > 0 battler.pbOpposingSide.effects[PBEffects::LightScreen] = 0 battle.pbDisplay(_INTL("{1}'s Light Screen wore off!", battler.pbOpposingTeam)) end if battler.pbOpposingSide.effects[PBEffects::Reflect] > 0 battler.pbOpposingSide.effects[PBEffects::Reflect] = 0 battle.pbDisplay(_INTL("{1}'s Reflect wore off!", battler.pbOpposingTeam)) end if battler.pbOwnSide.effects[PBEffects::AuroraVeil] > 0 battler.pbOwnSide.effects[PBEffects::AuroraVeil] = 0 battle.pbDisplay(_INTL("{1}'s Aurora Veil wore off!", battler.pbTeam)) end if battler.pbOwnSide.effects[PBEffects::LightScreen] > 0 battler.pbOwnSide.effects[PBEffects::LightScreen] = 0 battle.pbDisplay(_INTL("{1}'s Light Screen wore off!", battler.pbTeam)) end if battler.pbOwnSide.effects[PBEffects::Reflect] > 0 battler.pbOwnSide.effects[PBEffects::Reflect] = 0 battle.pbDisplay(_INTL("{1}'s Reflect wore off!", battler.pbTeam)) end battle.pbHideAbilitySplash(battler) } ) Battle::AbilityEffects::OnSwitchIn.add(:SLOWSTART, proc { |ability, battler, battle, switch_in| battle.pbShowAbilitySplash(battler) battler.effects[PBEffects::SlowStart] = 5 if Battle::Scene::USE_ABILITY_SPLASH battle.pbDisplay(_INTL("{1} can't get it going!", battler.pbThis)) else battle.pbDisplay(_INTL("{1} can't get it going because of its {2}!", battler.pbThis, battler.abilityName)) end battle.pbHideAbilitySplash(battler) } ) Battle::AbilityEffects::OnSwitchIn.add(:SNOWWARNING, proc { |ability, battler, battle, switch_in| battle.pbStartWeatherAbility(:Hail, battler) } ) Battle::AbilityEffects::OnSwitchIn.add(:TERAVOLT, proc { |ability, battler, battle, switch_in| battle.pbShowAbilitySplash(battler) battle.pbDisplay(_INTL("{1} is radiating a bursting aura!", battler.pbThis)) battle.pbHideAbilitySplash(battler) } ) Battle::AbilityEffects::OnSwitchIn.add(:TURBOBLAZE, proc { |ability, battler, battle, switch_in| battle.pbShowAbilitySplash(battler) battle.pbDisplay(_INTL("{1} is radiating a blazing aura!", battler.pbThis)) battle.pbHideAbilitySplash(battler) } ) Battle::AbilityEffects::OnSwitchIn.add(:UNNERVE, proc { |ability, battler, battle, switch_in| battle.pbShowAbilitySplash(battler) battle.pbDisplay(_INTL("{1} is too nervous to eat Berries!", battler.pbOpposingTeam)) battle.pbHideAbilitySplash(battler) } ) #=============================================================================== # OnSwitchOut handlers #=============================================================================== Battle::AbilityEffects::OnSwitchOut.add(:IMMUNITY, proc { |ability, battler, endOfBattle| next if battler.status != :POISON PBDebug.log("[Ability triggered] #{battler.pbThis}'s #{battler.abilityName}") battler.status = :NONE } ) Battle::AbilityEffects::OnSwitchOut.add(:INSOMNIA, proc { |ability, battler, endOfBattle| next if battler.status != :SLEEP PBDebug.log("[Ability triggered] #{battler.pbThis}'s #{battler.abilityName}") battler.status = :NONE } ) Battle::AbilityEffects::OnSwitchOut.copy(:INSOMNIA, :VITALSPIRIT) Battle::AbilityEffects::OnSwitchOut.add(:LIMBER, proc { |ability, battler, endOfBattle| next if battler.status != :PARALYSIS PBDebug.log("[Ability triggered] #{battler.pbThis}'s #{battler.abilityName}") battler.status = :NONE } ) Battle::AbilityEffects::OnSwitchOut.add(:MAGMAARMOR, proc { |ability, battler, endOfBattle| next if battler.status != :FROZEN PBDebug.log("[Ability triggered] #{battler.pbThis}'s #{battler.abilityName}") battler.status = :NONE } ) Battle::AbilityEffects::OnSwitchOut.add(:NATURALCURE, proc { |ability, battler, endOfBattle| PBDebug.log("[Ability triggered] #{battler.pbThis}'s #{battler.abilityName}") battler.status = :NONE } ) Battle::AbilityEffects::OnSwitchOut.add(:REGENERATOR, proc { |ability, battler, endOfBattle| next if endOfBattle PBDebug.log("[Ability triggered] #{battler.pbThis}'s #{battler.abilityName}") battler.pbRecoverHP(battler.totalhp / 3, false, false) } ) Battle::AbilityEffects::OnSwitchOut.add(:WATERVEIL, proc { |ability, battler, endOfBattle| next if battler.status != :BURN PBDebug.log("[Ability triggered] #{battler.pbThis}'s #{battler.abilityName}") battler.status = :NONE } ) Battle::AbilityEffects::OnSwitchOut.copy(:WATERVEIL, :WATERBUBBLE) #=============================================================================== # ChangeOnBattlerFainting handlers #=============================================================================== Battle::AbilityEffects::ChangeOnBattlerFainting.add(:POWEROFALCHEMY, proc { |ability, battler, fainted, battle| next if battler.opposes?(fainted) next if fainted.ungainableAbility? || [:POWEROFALCHEMY, :RECEIVER, :TRACE, :WONDERGUARD].include?(fainted.ability_id) battle.pbShowAbilitySplash(battler, true) battler.ability = fainted.ability battle.pbReplaceAbilitySplash(battler) battle.pbDisplay(_INTL("{1}'s {2} was taken over!", fainted.pbThis, fainted.abilityName)) battle.pbHideAbilitySplash(battler) } ) Battle::AbilityEffects::ChangeOnBattlerFainting.copy(:POWEROFALCHEMY, :RECEIVER) #=============================================================================== # OnBattlerFainting handlers #=============================================================================== Battle::AbilityEffects::OnBattlerFainting.add(:SOULHEART, proc { |ability, battler, fainted, battle| battler.pbRaiseStatStageByAbility(:SPECIAL_ATTACK, 1, battler) } ) #=============================================================================== # OnTerrainChange handlers #=============================================================================== Battle::AbilityEffects::OnTerrainChange.add(:MIMICRY, proc { |ability, battler, battle, ability_changed| if battle.field.terrain == :None # Revert to original typing battle.pbShowAbilitySplash(battler) battler.pbResetTypes battle.pbDisplay(_INTL("{1} changed back to its regular type!", battler.pbThis)) battle.pbHideAbilitySplash(battler) else # Change to new typing terrain_hash = { :Electric => :ELECTRIC, :Grassy => :GRASS, :Misty => :FAIRY, :Psychic => :PSYCHIC } new_type = terrain_hash[battle.field.terrain] new_type_name = nil if new_type type_data = GameData::Type.try_get(new_type) new_type = nil if !type_data new_type_name = type_data.name if type_data end if new_type battle.pbShowAbilitySplash(battler) battler.pbChangeTypes(new_type) battle.pbDisplay(_INTL("{1}'s type changed to {2}!", battler.pbThis, new_type_name)) battle.pbHideAbilitySplash(battler) end end } ) #=============================================================================== # OnIntimidated handlers #=============================================================================== Battle::AbilityEffects::OnIntimidated.add(:RATTLED, proc { |ability, battler, battle| next if Settings::MECHANICS_GENERATION < 8 battler.pbRaiseStatStageByAbility(:SPEED, 1, battler) } ) #=============================================================================== # CertainEscapeFromBattle handlers #=============================================================================== Battle::AbilityEffects::CertainEscapeFromBattle.add(:RUNAWAY, proc { |ability, battler| next true } )