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