#===============================================================================
# This round, user becomes the target of attacks that have single targets.
# (Follow Me, Rage Powder)
#===============================================================================
class Battle::Move::RedirectAllMovesToUser < Battle::Move
  def pbEffectGeneral(user)
    user.effects[PBEffects::FollowMe] = 1
    user.allAllies.each do |b|
      next if b.effects[PBEffects::FollowMe] < user.effects[PBEffects::FollowMe]
      user.effects[PBEffects::FollowMe] = b.effects[PBEffects::FollowMe] + 1
    end
    user.effects[PBEffects::RagePowder] = true if powderMove?
    @battle.pbDisplay(_INTL("{1} became the center of attention!", user.pbThis))
  end
end

#===============================================================================
# This round, target becomes the target of attacks that have single targets.
# (Spotlight)
#===============================================================================
class Battle::Move::RedirectAllMovesToTarget < Battle::Move
  def canMagicCoat?; return true; end

  def pbEffectAgainstTarget(user, target)
    target.effects[PBEffects::Spotlight] = 1
    target.allAllies.each do |b|
      next if b.effects[PBEffects::Spotlight] < target.effects[PBEffects::Spotlight]
      target.effects[PBEffects::Spotlight] = b.effects[PBEffects::Spotlight] + 1
    end
    @battle.pbDisplay(_INTL("{1} became the center of attention!", target.pbThis))
  end
end

#===============================================================================
# Unaffected by moves and abilities that would redirect this move. (Snipe Shot)
#===============================================================================
class Battle::Move::CannotBeRedirected < Battle::Move
  def cannotRedirect?; return true; end
end

#===============================================================================
# Randomly damages or heals the target. (Present)
# NOTE: Apparently a Normal Gem should be consumed even if this move will heal,
#       but I think that's silly so I've omitted that effect.
#===============================================================================
class Battle::Move::RandomlyDamageOrHealTarget < Battle::Move
  def pbOnStartUse(user, targets)
    @presentDmg = 0   # 0 = heal, >0 = damage
    r = @battle.pbRandom(100)
    if r < 40
      @presentDmg = 40
    elsif r < 70
      @presentDmg = 80
    elsif r < 80
      @presentDmg = 120
    end
  end

  def pbFailsAgainstTarget?(user, target, show_message)
    return false if @presentDmg > 0
    if !target.canHeal?
      @battle.pbDisplay(_INTL("But it failed!")) if show_message
      return true
    end
    return false
  end

  def pbDamagingMove?
    return false if @presentDmg == 0
    return super
  end

  def pbBaseDamage(baseDmg, user, target)
    return @presentDmg
  end

  def pbEffectAgainstTarget(user, target)
    return if @presentDmg > 0
    target.pbRecoverHP(target.totalhp / 4)
    @battle.pbDisplay(_INTL("{1}'s HP was restored.", target.pbThis))
  end

  def pbShowAnimation(id, user, targets, hitNum = 0, showAnimation = true)
    hitNum = 1 if @presentDmg == 0   # Healing anim
    super
  end
end

#===============================================================================
# Damages target if target is a foe, or heals target by 1/2 of its max HP if
# target is an ally. (Pollen Puff)
#===============================================================================
class Battle::Move::HealAllyOrDamageFoe < Battle::Move
  def pbTarget(user)
    return GameData::Target.get(:NearFoe) if user.effects[PBEffects::HealBlock] > 0
    return super
  end

  def pbOnStartUse(user, targets)
    @healing = false
    @healing = !user.opposes?(targets[0]) if targets.length > 0
  end

  def pbFailsAgainstTarget?(user, target, show_message)
    return false if !@healing
    if target.effects[PBEffects::Substitute] > 0 && !ignoresSubstitute?(user)
      @battle.pbDisplay(_INTL("But it failed!")) if show_message
      return true
    end
    if !target.canHeal?
      @battle.pbDisplay(_INTL("But it failed!")) if show_message
      return true
    end
    return false
  end

  def pbDamagingMove?
    return false if @healing
    return super
  end

  def pbEffectAgainstTarget(user, target)
    return if !@healing
    target.pbRecoverHP(target.totalhp / 2)
    @battle.pbDisplay(_INTL("{1}'s HP was restored.", target.pbThis))
  end

  def pbShowAnimation(id, user, targets, hitNum = 0, showAnimation = true)
    hitNum = 1 if @healing   # Healing anim
    super
  end
end

#===============================================================================
# User is Ghost: User loses 1/2 of max HP, and curses the target.
# Cursed Pokémon lose 1/4 of their max HP at the end of each round.
# User is not Ghost: Decreases the user's Speed by 1 stage, and increases the
# user's Attack and Defense by 1 stage each. (Curse)
#===============================================================================
class Battle::Move::CurseTargetOrLowerUserSpd1RaiseUserAtkDef1 < Battle::Move
  attr_reader :statUp, :statDown

  def ignoresSubstitute?(user); return true; end

  def initialize(battle, move)
    super
    @statUp   = [:ATTACK, 1, :DEFENSE, 1]
    @statDown = [:SPEED, 1]
  end

  def pbTarget(user)
    if user.pbHasType?(:GHOST)
      ghost_target = (Settings::MECHANICS_GENERATION >= 8) ? :RandomNearFoe : :NearFoe
      return GameData::Target.get(ghost_target)
    end
    return super
  end

  def pbMoveFailed?(user, targets)
    return false if user.pbHasType?(:GHOST)
    failed = true
    (@statUp.length / 2).times do |i|
      next if !user.pbCanRaiseStatStage?(@statUp[i * 2], user, self)
      failed = false
      break
    end
    (@statDown.length / 2).times do |i|
      next if !user.pbCanLowerStatStage?(@statDown[i * 2], user, self)
      failed = false
      break
    end
    if failed
      @battle.pbDisplay(_INTL("But it failed!"))
      return true
    end
    return false
  end

  def pbFailsAgainstTarget?(user, target, show_message)
    if user.pbHasType?(:GHOST) && target.effects[PBEffects::Curse]
      @battle.pbDisplay(_INTL("But it failed!")) if show_message
      return true
    end
    return false
  end

  def pbEffectGeneral(user)
    return if user.pbHasType?(:GHOST)
    # Non-Ghost effect
    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
    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 pbEffectAgainstTarget(user, target)
    return if !user.pbHasType?(:GHOST)
    # Ghost effect
    @battle.pbDisplay(_INTL("{1} cut its own HP and laid a curse on {2}!", user.pbThis, target.pbThis(true)))
    target.effects[PBEffects::Curse] = true
    user.pbReduceHP(user.totalhp / 2, false, false)
    user.pbItemHPHealCheck
  end

  def pbShowAnimation(id, user, targets, hitNum = 0, showAnimation = true)
    hitNum = 1 if !user.pbHasType?(:GHOST)   # Non-Ghost anim
    super
  end
end

#===============================================================================
# Effect depends on the environment. (Secret Power)
#===============================================================================
class Battle::Move::EffectDependsOnEnvironment < Battle::Move
  attr_reader :secretPower

  def flinchingMove?; return [6, 10, 12].include?(@secretPower); end

  def pbOnStartUse(user, targets)
    # NOTE: This is Gen 7's list plus some of Gen 6 plus a bit of my own.
    @secretPower = 0   # Body Slam, paralysis
    case @battle.field.terrain
    when :Electric
      @secretPower = 1   # Thunder Shock, paralysis
    when :Grassy
      @secretPower = 2   # Vine Whip, sleep
    when :Misty
      @secretPower = 3   # Fairy Wind, lower Sp. Atk by 1
    when :Psychic
      @secretPower = 4   # Confusion, lower Speed by 1
    else
      case @battle.environment
      when :Grass, :TallGrass, :Forest, :ForestGrass
        @secretPower = 2    # (Same as Grassy Terrain)
      when :MovingWater, :StillWater, :Underwater
        @secretPower = 5    # Water Pulse, lower Attack by 1
      when :Puddle
        @secretPower = 6    # Mud Shot, lower Speed by 1
      when :Cave
        @secretPower = 7    # Rock Throw, flinch
      when :Rock, :Sand
        @secretPower = 8    # Mud-Slap, lower Acc by 1
      when :Snow, :Ice
        @secretPower = 9    # Ice Shard, freeze
      when :Volcano
        @secretPower = 10   # Incinerate, burn
      when :Graveyard
        @secretPower = 11   # Shadow Sneak, flinch
      when :Sky
        @secretPower = 12   # Gust, lower Speed by 1
      when :Space
        @secretPower = 13   # Swift, flinch
      when :UltraSpace
        @secretPower = 14   # Psywave, lower Defense by 1
      end
    end
  end

  # NOTE: This intentionally doesn't use def pbAdditionalEffect, because that
  #       method is called per hit and this move's additional effect only occurs
  #       once per use, after all the hits have happened (two hits are possible
  #       via Parental Bond).
  def pbEffectAfterAllHits(user, target)
    return if target.fainted?
    return if target.damageState.unaffected || target.damageState.substitute
    return if user.hasActiveAbility?(:SHEERFORCE)
    chance = pbAdditionalEffectChance(user, target)
    return if @battle.pbRandom(100) >= chance
    case @secretPower
    when 2
      target.pbSleep if target.pbCanSleep?(user, false, self)
    when 10
      target.pbBurn(user) if target.pbCanBurn?(user, false, self)
    when 0, 1
      target.pbParalyze(user) if target.pbCanParalyze?(user, false, self)
    when 9
      target.pbFreeze if target.pbCanFreeze?(user, false, self)
    when 5
      if target.pbCanLowerStatStage?(:ATTACK, user, self)
        target.pbLowerStatStage(:ATTACK, 1, user)
      end
    when 14
      if target.pbCanLowerStatStage?(:DEFENSE, user, self)
        target.pbLowerStatStage(:DEFENSE, 1, user)
      end
    when 3
      if target.pbCanLowerStatStage?(:SPECIAL_ATTACK, user, self)
        target.pbLowerStatStage(:SPECIAL_ATTACK, 1, user)
      end
    when 4, 6, 12
      if target.pbCanLowerStatStage?(:SPEED, user, self)
        target.pbLowerStatStage(:SPEED, 1, user)
      end
    when 8
      if target.pbCanLowerStatStage?(:ACCURACY, user, self)
        target.pbLowerStatStage(:ACCURACY, 1, user)
      end
    when 7, 11, 13
      target.pbFlinch(user)
    end
  end

  def pbShowAnimation(id, user, targets, hitNum = 0, showAnimation = true)
    id = :BODYSLAM   # Environment-specific anim
    case @secretPower
    when 1  then id = :THUNDERSHOCK if GameData::Move.exists?(:THUNDERSHOCK)
    when 2  then id = :VINEWHIP if GameData::Move.exists?(:VINEWHIP)
    when 3  then id = :FAIRYWIND if GameData::Move.exists?(:FAIRYWIND)
    when 4  then id = :CONFUSIO if GameData::Move.exists?(:CONFUSION)
    when 5  then id = :WATERPULSE if GameData::Move.exists?(:WATERPULSE)
    when 6  then id = :MUDSHOT if GameData::Move.exists?(:MUDSHOT)
    when 7  then id = :ROCKTHROW if GameData::Move.exists?(:ROCKTHROW)
    when 8  then id = :MUDSLAP if GameData::Move.exists?(:MUDSLAP)
    when 9  then id = :ICESHARD if GameData::Move.exists?(:ICESHARD)
    when 10 then id = :INCINERATE if GameData::Move.exists?(:INCINERATE)
    when 11 then id = :SHADOWSNEAK if GameData::Move.exists?(:SHADOWSNEAK)
    when 12 then id = :GUST if GameData::Move.exists?(:GUST)
    when 13 then id = :SWIFT if GameData::Move.exists?(:SWIFT)
    when 14 then id = :PSYWAVE if GameData::Move.exists?(:PSYWAVE)
    end
    super
  end
end

#===============================================================================
# If Psychic Terrain applies and the user is grounded, power is multiplied by
# 1.5 (in addition to Psychic Terrain's multiplier) and it targets all opposing
# Pokémon. (Expanding Force)
#===============================================================================
class Battle::Move::HitsAllFoesAndPowersUpInPsychicTerrain < Battle::Move
  def pbTarget(user)
    if @battle.field.terrain == :Psychic && user.affectedByTerrain?
      return GameData::Target.get(:AllNearFoes)
    end
    return super
  end

  def pbBaseDamage(baseDmg, user, target)
    if @battle.field.terrain == :Psychic && user.affectedByTerrain?
      baseDmg = baseDmg * 3 / 2
    end
    return baseDmg
  end
end

#===============================================================================
# Powders the foe. This round, if it uses a Fire move, it loses 1/4 of its max
# HP instead. (Powder)
#===============================================================================
class Battle::Move::TargetNextFireMoveDamagesTarget < Battle::Move
  def ignoresSubstitute?(user); return true; end
  def canMagicCoat?;            return true; end

  def pbFailsAgainstTarget?(user, target, show_message)
    if target.effects[PBEffects::Powder]
      @battle.pbDisplay(_INTL("But it failed!")) if show_message
      return true
    end
    return false
  end

  def pbEffectAgainstTarget(user, target)
    target.effects[PBEffects::Powder] = true
    @battle.pbDisplay(_INTL("{1} is covered in powder!", user.pbThis))
  end
end

#===============================================================================
# Power is doubled if Fusion Flare has already been used this round. (Fusion Bolt)
#===============================================================================
class Battle::Move::DoublePowerAfterFusionFlare < Battle::Move
  def pbChangeUsageCounters(user, specialUsage)
    @doublePower = @battle.field.effects[PBEffects::FusionFlare]
    super
  end

  def pbBaseDamageMultiplier(damageMult, user, target)
    damageMult *= 2 if @doublePower
    return damageMult
  end

  def pbEffectGeneral(user)
    @battle.field.effects[PBEffects::FusionBolt] = true
  end

  def pbShowAnimation(id, user, targets, hitNum = 0, showAnimation = true)
    hitNum = 1 if (targets.length > 0 && targets[0].damageState.critical) ||
                  @doublePower   # Charged anim
    super
  end
end

#===============================================================================
# Power is doubled if Fusion Bolt has already been used this round. (Fusion Flare)
#===============================================================================
class Battle::Move::DoublePowerAfterFusionBolt < Battle::Move
  def pbChangeUsageCounters(user, specialUsage)
    @doublePower = @battle.field.effects[PBEffects::FusionBolt]
    super
  end

  def pbBaseDamageMultiplier(damageMult, user, target)
    damageMult *= 2 if @doublePower
    return damageMult
  end

  def pbEffectGeneral(user)
    @battle.field.effects[PBEffects::FusionFlare] = true
  end

  def pbShowAnimation(id, user, targets, hitNum = 0, showAnimation = true)
    hitNum = 1 if (targets.length > 0 && targets[0].damageState.critical) ||
                  @doublePower   # Charged anim
    super
  end
end

#===============================================================================
# Powers up the ally's attack this round by 1.5. (Helping Hand)
#===============================================================================
class Battle::Move::PowerUpAllyMove < Battle::Move
  def ignoresSubstitute?(user); return true; end

  def pbFailsAgainstTarget?(user, target, show_message)
    if target.fainted? || target.effects[PBEffects::HelpingHand]
      @battle.pbDisplay(_INTL("But it failed!")) if show_message
      return true
    end
    return true if pbMoveFailedTargetAlreadyMoved?(target, show_message)
    return false
  end

  def pbEffectAgainstTarget(user, target)
    target.effects[PBEffects::HelpingHand] = true
    @battle.pbDisplay(_INTL("{1} is ready to help {2}!", user.pbThis, target.pbThis(true)))
  end
end

#===============================================================================
# Counters a physical move used against the user this round, with 2x the power.
# (Counter)
#===============================================================================
class Battle::Move::CounterPhysicalDamage < Battle::Move::FixedDamageMove
  def pbAddTarget(targets, user)
    t = user.effects[PBEffects::CounterTarget]
    return if t < 0 || !user.opposes?(t)
    user.pbAddTarget(targets, user, @battle.battlers[t], self, false)
  end

  def pbMoveFailed?(user, targets)
    if targets.length == 0
      @battle.pbDisplay(_INTL("But there was no target..."))
      return true
    end
    return false
  end

  def pbFixedDamage(user, target)
    dmg = user.effects[PBEffects::Counter] * 2
    dmg = 1 if dmg == 0
    return dmg
  end
end

#===============================================================================
# Counters a specical move used against the user this round, with 2x the power.
# (Mirror Coat)
#===============================================================================
class Battle::Move::CounterSpecialDamage < Battle::Move::FixedDamageMove
  def pbAddTarget(targets, user)
    t = user.effects[PBEffects::MirrorCoatTarget]
    return if t < 0 || !user.opposes?(t)
    user.pbAddTarget(targets, user, @battle.battlers[t], self, false)
  end

  def pbMoveFailed?(user, targets)
    if targets.length == 0
      @battle.pbDisplay(_INTL("But there was no target..."))
      return true
    end
    return false
  end

  def pbFixedDamage(user, target)
    dmg = user.effects[PBEffects::MirrorCoat] * 2
    dmg = 1 if dmg == 0
    return dmg
  end
end

#===============================================================================
# Counters the last damaging move used against the user this round, with 1.5x
# the power. (Metal Burst)
#===============================================================================
class Battle::Move::CounterDamagePlusHalf < Battle::Move::FixedDamageMove
  def pbAddTarget(targets, user)
    return if user.lastFoeAttacker.length == 0
    lastAttacker = user.lastFoeAttacker.last
    return if lastAttacker < 0 || !user.opposes?(lastAttacker)
    user.pbAddTarget(targets, user, @battle.battlers[lastAttacker], self, false)
  end

  def pbMoveFailed?(user, targets)
    if targets.length == 0
      @battle.pbDisplay(_INTL("But there was no target..."))
      return true
    end
    return false
  end

  def pbFixedDamage(user, target)
    dmg = (user.lastHPLostFromFoe * 1.5).floor
    dmg = 1 if dmg == 0
    return dmg
  end
end

#===============================================================================
# Increases the user's Defense and Special Defense by 1 stage each. Ups the
# user's stockpile by 1 (max. 3). (Stockpile)
#===============================================================================
class Battle::Move::UserAddStockpileRaiseDefSpDef1 < Battle::Move
  def canSnatch?; return true; end

  def pbMoveFailed?(user, targets)
    if user.effects[PBEffects::Stockpile] >= 3
      @battle.pbDisplay(_INTL("{1} can't stockpile any more!", user.pbThis))
      return true
    end
    return false
  end

  def pbEffectGeneral(user)
    user.effects[PBEffects::Stockpile] += 1
    @battle.pbDisplay(_INTL("{1} stockpiled {2}!",
                            user.pbThis, user.effects[PBEffects::Stockpile]))
    showAnim = true
    if user.pbCanRaiseStatStage?(:DEFENSE, user, self)
      if user.pbRaiseStatStage(:DEFENSE, 1, user, showAnim)
        user.effects[PBEffects::StockpileDef] += 1
        showAnim = false
      end
    end
    if user.pbCanRaiseStatStage?(:SPECIAL_DEFENSE, user, self)
      if user.pbRaiseStatStage(:SPECIAL_DEFENSE, 1, user, showAnim)
        user.effects[PBEffects::StockpileSpDef] += 1
      end
    end
  end
end

#===============================================================================
# Power is 100 multiplied by the user's stockpile (X). Resets the stockpile to
# 0. Decreases the user's Defense and Special Defense by X stages each. (Spit Up)
#===============================================================================
class Battle::Move::PowerDependsOnUserStockpile < Battle::Move
  def pbMoveFailed?(user, targets)
    if user.effects[PBEffects::Stockpile] == 0
      @battle.pbDisplay(_INTL("But it failed to spit up a thing!"))
      return true
    end
    return false
  end

  def pbBaseDamage(baseDmg, user, target)
    return 100 * user.effects[PBEffects::Stockpile]
  end

  def pbEffectAfterAllHits(user, target)
    return if user.fainted? || user.effects[PBEffects::Stockpile] == 0
    return if target.damageState.unaffected
    @battle.pbDisplay(_INTL("{1}'s stockpiled effect wore off!", user.pbThis))
    return if @battle.pbAllFainted?(target.idxOwnSide)
    showAnim = true
    if user.effects[PBEffects::StockpileDef] > 0 &&
       user.pbCanLowerStatStage?(:DEFENSE, user, self)
      showAnim = false if user.pbLowerStatStage(:DEFENSE, user.effects[PBEffects::StockpileDef], user, showAnim)
    end
    if user.effects[PBEffects::StockpileSpDef] > 0 &&
       user.pbCanLowerStatStage?(:SPECIAL_DEFENSE, user, self)
      user.pbLowerStatStage(:SPECIAL_DEFENSE, user.effects[PBEffects::StockpileSpDef], user, showAnim)
    end
    user.effects[PBEffects::Stockpile]      = 0
    user.effects[PBEffects::StockpileDef]   = 0
    user.effects[PBEffects::StockpileSpDef] = 0
  end
end

#===============================================================================
# Heals user depending on the user's stockpile (X). Resets the stockpile to 0.
# Decreases the user's Defense and Special Defense by X stages each. (Swallow)
#===============================================================================
class Battle::Move::HealUserDependingOnUserStockpile < Battle::Move
  def healingMove?; return true; end
  def canSnatch?;   return true; end

  def pbMoveFailed?(user, targets)
    if user.effects[PBEffects::Stockpile] == 0
      @battle.pbDisplay(_INTL("But it failed to swallow a thing!"))
      return true
    end
    if !user.canHeal? &&
       user.effects[PBEffects::StockpileDef] == 0 &&
       user.effects[PBEffects::StockpileSpDef] == 0
      @battle.pbDisplay(_INTL("But it failed!"))
      return true
    end
    return false
  end

  def pbEffectGeneral(user)
    hpGain = 0
    case [user.effects[PBEffects::Stockpile], 1].max
    when 1 then hpGain = user.totalhp / 4
    when 2 then hpGain = user.totalhp / 2
    when 3 then hpGain = user.totalhp
    end
    if user.pbRecoverHP(hpGain) > 0
      @battle.pbDisplay(_INTL("{1}'s HP was restored.", user.pbThis))
    end
    @battle.pbDisplay(_INTL("{1}'s stockpiled effect wore off!", user.pbThis))
    showAnim = true
    if user.effects[PBEffects::StockpileDef] > 0 &&
       user.pbCanLowerStatStage?(:DEFENSE, user, self)
      if user.pbLowerStatStage(:DEFENSE, user.effects[PBEffects::StockpileDef], user, showAnim)
        showAnim = false
      end
    end
    if user.effects[PBEffects::StockpileSpDef] > 0 &&
       user.pbCanLowerStatStage?(:SPECIAL_DEFENSE, user, self)
      user.pbLowerStatStage(:SPECIAL_DEFENSE, user.effects[PBEffects::StockpileSpDef], user, showAnim)
    end
    user.effects[PBEffects::Stockpile]      = 0
    user.effects[PBEffects::StockpileDef]   = 0
    user.effects[PBEffects::StockpileSpDef] = 0
  end
end

#===============================================================================
# Combos with another Pledge move used by the ally. (Grass Pledge)
# If the move is a combo, power is doubled and causes either a sea of fire or a
# swamp on the opposing side.
#===============================================================================
class Battle::Move::GrassPledge < Battle::Move::PledgeMove
  def initialize(battle, move)
    super
    # [Function code to combo with, effect, override type, override animation]
    @combos = [["FirePledge",  :SeaOfFire, :FIRE, :FIREPLEDGE],
               ["WaterPledge", :Swamp,     nil,   nil]]
  end
end

#===============================================================================
# Combos with another Pledge move used by the ally. (Fire Pledge)
# If the move is a combo, power is doubled and causes either a rainbow on the
# user's side or a sea of fire on the opposing side.
#===============================================================================
class Battle::Move::FirePledge < Battle::Move::PledgeMove
  def initialize(battle, move)
    super
    # [Function code to combo with, effect, override type, override animation]
    @combos = [["WaterPledge", :Rainbow,   :WATER, :WATERPLEDGE],
               ["GrassPledge", :SeaOfFire, nil,    nil]]
  end
end

#===============================================================================
# Combos with another Pledge move used by the ally. (Water Pledge)
# If the move is a combo, power is doubled and causes either a swamp on the
# opposing side or a rainbow on the user's side.
#===============================================================================
class Battle::Move::WaterPledge < Battle::Move::PledgeMove
  def initialize(battle, move)
    super
    # [Function code to combo with, effect, override type, override animation]
    @combos = [["GrassPledge", :Swamp,   :GRASS, :GRASSPLEDGE],
               ["FirePledge",  :Rainbow, nil,    nil]]
  end
end

#===============================================================================
# Uses the last move that was used. (Copycat)
#===============================================================================
class Battle::Move::UseLastMoveUsed < Battle::Move
  attr_reader :moveBlacklist

  def callsAnotherMove?; return true; end

  def initialize(battle, move)
    super
    @moveBlacklist = [
      # Struggle, Belch
      "Struggle",                                          # Struggle
      "FailsIfUserNotConsumedBerry",                       # Belch              # Not listed on Bulbapedia
      # Moves that affect the moveset
      "ReplaceMoveThisBattleWithTargetLastMoveUsed",       # Mimic
      "ReplaceMoveWithTargetLastMoveUsed",                 # Sketch
      "TransformUserIntoTarget",                           # Transform
      # Counter moves
      "CounterPhysicalDamage",                             # Counter
      "CounterSpecialDamage",                              # Mirror Coat
      "CounterDamagePlusHalf",                             # Metal Burst        # Not listed on Bulbapedia
      # Helping Hand, Feint (always blacklisted together, don't know why)
      "PowerUpAllyMove",                                   # Helping Hand
      "RemoveProtections",                                 # Feint
      # Protection moves
      "ProtectUser",                                       # Detect, Protect
      "ProtectUserSideFromPriorityMoves",                  # Quick Guard        # Not listed on Bulbapedia
      "ProtectUserSideFromMultiTargetDamagingMoves",       # Wide Guard         # Not listed on Bulbapedia
      "UserEnduresFaintingThisTurn",                       # Endure
      "ProtectUserSideFromDamagingMovesIfUserFirstTurn",   # Mat Block
      "ProtectUserSideFromStatusMoves",                    # Crafty Shield      # Not listed on Bulbapedia
      "ProtectUserFromDamagingMovesKingsShield",           # King's Shield
      "ProtectUserFromDamagingMovesObstruct",              # Obstruct           # Not listed on Bulbapedia
      "ProtectUserFromTargetingMovesSpikyShield",          # Spiky Shield
      "ProtectUserBanefulBunker",                          # Baneful Bunker
      # Moves that call other moves
      "UseLastMoveUsedByTarget",                           # Mirror Move
      "UseLastMoveUsed",                                   # Copycat (this move)
      "UseMoveTargetIsAboutToUse",                         # Me First
      "UseMoveDependingOnEnvironment",                     # Nature Power       # Not listed on Bulbapedia
      "UseRandomUserMoveIfAsleep",                         # Sleep Talk
      "UseRandomMoveFromUserParty",                        # Assist
      "UseRandomMove",                                     # Metronome
      # Move-redirecting and stealing moves
      "BounceBackProblemCausingStatusMoves",               # Magic Coat         # Not listed on Bulbapedia
      "StealAndUseBeneficialStatusMove",                   # Snatch
      "RedirectAllMovesToUser",                            # Follow Me, Rage Powder
      "RedirectAllMovesToTarget",                          # Spotlight
      # Set up effects that trigger upon KO
      "ReduceAttackerMovePPTo0IfUserFaints",               # Grudge             # Not listed on Bulbapedia
      "AttackerFaintsIfUserFaints",                        # Destiny Bond
      # Held item-moving moves
      "UserTakesTargetItem",                               # Covet, Thief
      "UserTargetSwapItems",                               # Switcheroo, Trick
      "TargetTakesUserItem",                               # Bestow
      # Moves that start focussing at the start of the round
      "FailsIfUserDamagedThisTurn",                        # Focus Punch
      "UsedAfterUserTakesPhysicalDamage",                  # Shell Trap
      "BurnAttackerBeforeUserActs",                        # Beak Blast
      # Event moves that do nothing
      "DoesNothingFailsIfNoAlly",                          # Hold Hands
      "DoesNothingCongratulations"                         # Celebrate
    ]
    if Settings::MECHANICS_GENERATION >= 6
      @moveBlacklist += [
        # Target-switching moves
        "SwitchOutTargetStatusMove",                       # Roar, Whirlwind
        "SwitchOutTargetDamagingMove"                      # Circle Throw, Dragon Tail
      ]
    end
  end

  def pbChangeUsageCounters(user, specialUsage)
    super
    @copied_move = @battle.lastMoveUsed
  end

  def pbMoveFailed?(user, targets)
    if !@copied_move ||
       !GameData::Move.exists?(@copied_move) ||
       @moveBlacklist.include?(GameData::Move.get(@copied_move).function_code)
      @battle.pbDisplay(_INTL("But it failed!"))
      return true
    end
    return false
  end

  def pbEffectGeneral(user)
    user.pbUseMoveSimple(@copied_move)
  end
end

#===============================================================================
# Uses the last move that the target used. (Mirror Move)
#===============================================================================
class Battle::Move::UseLastMoveUsedByTarget < Battle::Move
  def ignoresSubstitute?(user); return true; end
  def callsAnotherMove?; return true; end

  def pbFailsAgainstTarget?(user, target, show_message)
    if !target.lastRegularMoveUsed ||
       !GameData::Move.exists?(target.lastRegularMoveUsed) ||
       !GameData::Move.get(target.lastRegularMoveUsed).has_flag?("CanMirrorMove")
      @battle.pbDisplay(_INTL("The mirror move failed!")) if show_message
      return true
    end
    return false
  end

  def pbEffectAgainstTarget(user, target)
    user.pbUseMoveSimple(target.lastRegularMoveUsed, target.index)
  end

  def pbShowAnimation(id, user, targets, hitNum = 0, showAnimation = true)
    # No animation
  end
end

#===============================================================================
# Uses the move the target was about to use this round, with 1.5x power.
# (Me First)
#===============================================================================
class Battle::Move::UseMoveTargetIsAboutToUse < Battle::Move
  attr_reader :moveBlacklist

  def ignoresSubstitute?(user); return true; end
  def callsAnotherMove?; return true; end

  def initialize(battle, move)
    super
    @moveBlacklist = [
      "UserTakesTargetItem",                # Covet, Thief
      # Struggle, Belch
      "Struggle",                           # Struggle
      "FailsIfUserNotConsumedBerry",        # Belch
      # Counter moves
      "CounterPhysicalDamage",              # Counter
      "CounterSpecialDamage",               # Mirror Coat
      "CounterDamagePlusHalf",              # Metal Burst
      # Moves that start focussing at the start of the round
      "FailsIfUserDamagedThisTurn",         # Focus Punch
      "UsedAfterUserTakesPhysicalDamage",   # Shell Trap
      "BurnAttackerBeforeUserActs"          # Beak Blast
    ]
  end

  def pbFailsAgainstTarget?(user, target, show_message)
    return true if pbMoveFailedTargetAlreadyMoved?(target, show_message)
    oppMove = @battle.choices[target.index][2]
    if !oppMove || oppMove.statusMove? || @moveBlacklist.include?(oppMove.function_code)
      @battle.pbDisplay(_INTL("But it failed!")) if show_message
      return true
    end
    return false
  end

  def pbEffectAgainstTarget(user, target)
    user.effects[PBEffects::MeFirst] = true
    user.pbUseMoveSimple(@battle.choices[target.index][2].id)
    user.effects[PBEffects::MeFirst] = false
  end
end

#===============================================================================
# Uses a different move depending on the environment. (Nature Power)
# NOTE: This code does not support the Gen 5 and older definition of the move
#       where it targets the user. It makes more sense for it to target another
#       Pokémon.
#===============================================================================
class Battle::Move::UseMoveDependingOnEnvironment < Battle::Move
  attr_reader :npMove

  def callsAnotherMove?; return true; end

  def pbOnStartUse(user, targets)
    # NOTE: It's possible in theory to not have the move Nature Power wants to
    #       turn into, but what self-respecting game wouldn't at least have Tri
    #       Attack in it?
    @npMove = :TRIATTACK
    case @battle.field.terrain
    when :Electric
      @npMove = :THUNDERBOLT if GameData::Move.exists?(:THUNDERBOLT)
    when :Grassy
      @npMove = :ENERGYBALL if GameData::Move.exists?(:ENERGYBALL)
    when :Misty
      @npMove = :MOONBLAST if GameData::Move.exists?(:MOONBLAST)
    when :Psychic
      @npMove = :PSYCHIC if GameData::Move.exists?(:PSYCHIC)
    else
      try_move = nil
      case @battle.environment
      when :Grass, :TallGrass, :Forest, :ForestGrass
        try_move = (Settings::MECHANICS_GENERATION >= 6) ? :ENERGYBALL : :SEEDBOMB
      when :MovingWater, :StillWater, :Underwater
        try_move = :HYDROPUMP
      when :Puddle
        try_move = :MUDBOMB
      when :Cave
        try_move = (Settings::MECHANICS_GENERATION >= 6) ? :POWERGEM : :ROCKSLIDE
      when :Rock, :Sand
        try_move = (Settings::MECHANICS_GENERATION >= 6) ? :EARTHPOWER : :EARTHQUAKE
      when :Snow
        try_move = :BLIZZARD
        try_move = :FROSTBREATH if Settings::MECHANICS_GENERATION == 6
        try_move = :ICEBEAM if Settings::MECHANICS_GENERATION >= 7
      when :Ice
        try_move = :ICEBEAM
      when :Volcano
        try_move = :LAVAPLUME
      when :Graveyard
        try_move = :SHADOWBALL
      when :Sky
        try_move = :AIRSLASH
      when :Space
        try_move = :DRACOMETEOR
      when :UltraSpace
        try_move = :PSYSHOCK
      end
      @npMove = try_move if GameData::Move.exists?(try_move)
    end
  end

  def pbEffectAgainstTarget(user, target)
    @battle.pbDisplay(_INTL("{1} turned into {2}!", @name, GameData::Move.get(@npMove).name))
    user.pbUseMoveSimple(@npMove, target.index)
  end
end

#===============================================================================
# Uses a random move that exists. (Metronome)
#===============================================================================
class Battle::Move::UseRandomMove < Battle::Move
  attr_reader :moveBlacklist

  def callsAnotherMove?; return true; end

  def initialize(battle, move)
    super
    @moveBlacklist = [
      "FlinchTargetFailsIfUserNotAsleep",                  # Snore
      "TargetActsNext",                                    # After You
      "TargetActsLast",                                    # Quash
      "TargetUsesItsLastUsedMoveAgain",                    # Instruct
      # Struggle, Belch
      "Struggle",                                          # Struggle
      "FailsIfUserNotConsumedBerry",                       # Belch
      # Moves that affect the moveset
      "ReplaceMoveThisBattleWithTargetLastMoveUsed",       # Mimic
      "ReplaceMoveWithTargetLastMoveUsed",                 # Sketch
      "TransformUserIntoTarget",                           # Transform
      # Counter moves
      "CounterPhysicalDamage",                             # Counter
      "CounterSpecialDamage",                              # Mirror Coat
      "CounterDamagePlusHalf",                             # Metal Burst        # Not listed on Bulbapedia
      # Helping Hand, Feint (always blacklisted together, don't know why)
      "PowerUpAllyMove",                                   # Helping Hand
      "RemoveProtections",                                 # Feint
      # Protection moves
      "ProtectUser",                                       # Detect, Protect
      "ProtectUserSideFromPriorityMoves",                  # Quick Guard
      "ProtectUserSideFromMultiTargetDamagingMoves",       # Wide Guard
      "UserEnduresFaintingThisTurn",                       # Endure
      "ProtectUserSideFromDamagingMovesIfUserFirstTurn",   # Mat Block
      "ProtectUserSideFromStatusMoves",                    # Crafty Shield
      "ProtectUserFromDamagingMovesKingsShield",           # King's Shield
      "ProtectUserFromDamagingMovesObstruct",              # Obstruct
      "ProtectUserFromTargetingMovesSpikyShield",          # Spiky Shield
      "ProtectUserBanefulBunker",                          # Baneful Bunker
      # Moves that call other moves
      "UseLastMoveUsedByTarget",                           # Mirror Move
      "UseLastMoveUsed",                                   # Copycat
      "UseMoveTargetIsAboutToUse",                         # Me First
      "UseMoveDependingOnEnvironment",                     # Nature Power
      "UseRandomUserMoveIfAsleep",                         # Sleep Talk
      "UseRandomMoveFromUserParty",                        # Assist
      "UseRandomMove",                                     # Metronome
      # Move-redirecting and stealing moves
      "BounceBackProblemCausingStatusMoves",               # Magic Coat         # Not listed on Bulbapedia
      "StealAndUseBeneficialStatusMove",                   # Snatch
      "RedirectAllMovesToUser",                            # Follow Me, Rage Powder
      "RedirectAllMovesToTarget",                          # Spotlight
      # Set up effects that trigger upon KO
      "ReduceAttackerMovePPTo0IfUserFaints",               # Grudge             # Not listed on Bulbapedia
      "AttackerFaintsIfUserFaints",                        # Destiny Bond
      # Held item-moving moves
      "UserTakesTargetItem",                               # Covet, Thief
      "UserTargetSwapItems",                               # Switcheroo, Trick
      "TargetTakesUserItem",                               # Bestow
      # Moves that start focussing at the start of the round
      "FailsIfUserDamagedThisTurn",                        # Focus Punch
      "UsedAfterUserTakesPhysicalDamage",                  # Shell Trap
      "BurnAttackerBeforeUserActs",                        # Beak Blast
      # Event moves that do nothing
      "DoesNothingFailsIfNoAlly",                          # Hold Hands
      "DoesNothingCongratulations"                         # Celebrate
    ]
  end

  def pbMoveFailed?(user, targets)
    @metronomeMove = nil
    move_keys = GameData::Move.keys
    # NOTE: You could be really unlucky and roll blacklisted moves 1000 times in
    #       a row. This is too unlikely to care about, though.
    1000.times do
      move_id = move_keys[@battle.pbRandom(move_keys.length)]
      move_data = GameData::Move.get(move_id)
      next if @moveBlacklist.include?(move_data.function_code)
      next if move_data.has_flag?("CannotMetronome")
      next if move_data.type == :SHADOW
      @metronomeMove = move_data.id
      break
    end
    if !@metronomeMove
      @battle.pbDisplay(_INTL("But it failed!"))
      return true
    end
    return false
  end

  def pbEffectGeneral(user)
    user.pbUseMoveSimple(@metronomeMove)
  end
end

#===============================================================================
# Uses a random move known by any non-user Pokémon in the user's party. (Assist)
#===============================================================================
class Battle::Move::UseRandomMoveFromUserParty < Battle::Move
  attr_reader :moveBlacklist

  def callsAnotherMove?; return true; end

  def initialize(battle, move)
    super
    @moveBlacklist = [
      # Struggle, Belch
      "Struggle",                                          # Struggle
      "FailsIfUserNotConsumedBerry",                       # Belch
      # Moves that affect the moveset
      "ReplaceMoveThisBattleWithTargetLastMoveUsed",       # Mimic
      "ReplaceMoveWithTargetLastMoveUsed",                 # Sketch
      "TransformUserIntoTarget",                           # Transform
      # Counter moves
      "CounterPhysicalDamage",                             # Counter
      "CounterSpecialDamage",                              # Mirror Coat
      "CounterDamagePlusHalf",                             # Metal Burst        # Not listed on Bulbapedia
      # Helping Hand, Feint (always blacklisted together, don't know why)
      "PowerUpAllyMove",                                   # Helping Hand
      "RemoveProtections",                                 # Feint
      # Protection moves
      "ProtectUser",                                       # Detect, Protect
      "ProtectUserSideFromPriorityMoves",                  # Quick Guard        # Not listed on Bulbapedia
      "ProtectUserSideFromMultiTargetDamagingMoves",       # Wide Guard         # Not listed on Bulbapedia
      "UserEnduresFaintingThisTurn",                       # Endure
      "ProtectUserSideFromDamagingMovesIfUserFirstTurn",   # Mat Block
      "ProtectUserSideFromStatusMoves",                    # Crafty Shield      # Not listed on Bulbapedia
      "ProtectUserFromDamagingMovesKingsShield",           # King's Shield
      "ProtectUserFromDamagingMovesObstruct",              # Obstruct           # Not listed on Bulbapedia
      "ProtectUserFromTargetingMovesSpikyShield",          # Spiky Shield
      "ProtectUserBanefulBunker",                          # Baneful Bunker
      # Moves that call other moves
      "UseLastMoveUsedByTarget",                           # Mirror Move
      "UseLastMoveUsed",                                   # Copycat
      "UseMoveTargetIsAboutToUse",                         # Me First
#      "UseMoveDependingOnEnvironment",                    # Nature Power       # See below
      "UseRandomUserMoveIfAsleep",                         # Sleep Talk
      "UseRandomMoveFromUserParty",                        # Assist
      "UseRandomMove",                                     # Metronome
      # Move-redirecting and stealing moves
      "BounceBackProblemCausingStatusMoves",               # Magic Coat         # Not listed on Bulbapedia
      "StealAndUseBeneficialStatusMove",                   # Snatch
      "RedirectAllMovesToUser",                            # Follow Me, Rage Powder
      "RedirectAllMovesToTarget",                          # Spotlight
      # Set up effects that trigger upon KO
      "ReduceAttackerMovePPTo0IfUserFaints",               # Grudge             # Not listed on Bulbapedia
      "AttackerFaintsIfUserFaints",                        # Destiny Bond
      # Target-switching moves
#      "SwitchOutTargetStatusMove",                        # Roar, Whirlwind    # See below
      "SwitchOutTargetDamagingMove",                       # Circle Throw, Dragon Tail
      # Held item-moving moves
      "UserTakesTargetItem",                               # Covet, Thief
      "UserTargetSwapItems",                               # Switcheroo, Trick
      "TargetTakesUserItem",                               # Bestow
      # Moves that start focussing at the start of the round
      "FailsIfUserDamagedThisTurn",                        # Focus Punch
      "UsedAfterUserTakesPhysicalDamage",                  # Shell Trap
      "BurnAttackerBeforeUserActs",                        # Beak Blast
      # Event moves that do nothing
      "DoesNothingFailsIfNoAlly",                          # Hold Hands
      "DoesNothingCongratulations"                         # Celebrate
    ]
    if Settings::MECHANICS_GENERATION >= 6
      @moveBlacklist += [
        # Moves that call other moves
        "UseMoveDependingOnEnvironment",                   # Nature Power
        # Two-turn attacks
        "TwoTurnAttack",                                   # Razor Wind                # Not listed on Bulbapedia
        "TwoTurnAttackOneTurnInSun",                       # Solar Beam, Solar Blade   # Not listed on Bulbapedia
        "TwoTurnAttackParalyzeTarget",                     # Freeze Shock              # Not listed on Bulbapedia
        "TwoTurnAttackBurnTarget",                         # Ice Burn                  # Not listed on Bulbapedia
        "TwoTurnAttackFlinchTarget",                       # Sky Attack                # Not listed on Bulbapedia
        "TwoTurnAttackChargeRaiseUserDefense1",            # Skull Bash                # Not listed on Bulbapedia
        "TwoTurnAttackInvulnerableInSky",                  # Fly
        "TwoTurnAttackInvulnerableUnderground",            # Dig
        "TwoTurnAttackInvulnerableUnderwater",             # Dive
        "TwoTurnAttackInvulnerableInSkyParalyzeTarget",    # Bounce
        "TwoTurnAttackInvulnerableRemoveProtections",      # Shadow Force/Phantom Force
        "TwoTurnAttackInvulnerableInSkyTargetCannotAct",   # Sky Drop
        "AllBattlersLoseHalfHPUserSkipsNextTurn",          # Shadow Half
        "TwoTurnAttackRaiseUserSpAtkSpDefSpd2",            # Geomancy                  # Not listed on Bulbapedia
        # Target-switching moves
        "SwitchOutTargetStatusMove"                        # Roar, Whirlwind
      ]
    end
  end

  def pbMoveFailed?(user, targets)
    @assistMoves = []
    # NOTE: This includes the Pokémon of ally trainers in multi battles.
    @battle.pbParty(user.index).each_with_index do |pkmn, i|
      next if !pkmn || i == user.pokemonIndex
      next if Settings::MECHANICS_GENERATION >= 6 && pkmn.egg?
      pkmn.moves.each do |move|
        next if @moveBlacklist.include?(move.function_code)
        next if move.type == :SHADOW
        @assistMoves.push(move.id)
      end
    end
    if @assistMoves.length == 0
      @battle.pbDisplay(_INTL("But it failed!"))
      return true
    end
    return false
  end

  def pbEffectGeneral(user)
    move = @assistMoves[@battle.pbRandom(@assistMoves.length)]
    user.pbUseMoveSimple(move)
  end
end

#===============================================================================
# Uses a random move the user knows. Fails if user is not asleep. (Sleep Talk)
#===============================================================================
class Battle::Move::UseRandomUserMoveIfAsleep < Battle::Move
  attr_reader :moveBlacklist

  def usableWhenAsleep?; return true; end
  def callsAnotherMove?; return true; end

  def initialize(battle, move)
    super
    @moveBlacklist = [
      "MultiTurnAttackPreventSleeping",                  # Uproar
      "MultiTurnAttackBideThenReturnDoubleDamage",       # Bide
      # Struggle, Belch
      "Struggle",                                        # Struggle             # Not listed on Bulbapedia
      "FailsIfUserNotConsumedBerry",                     # Belch
      # Moves that affect the moveset (except Transform)
      "ReplaceMoveThisBattleWithTargetLastMoveUsed",     # Mimic
      "ReplaceMoveWithTargetLastMoveUsed",               # Sketch
      # Moves that call other moves
      "UseLastMoveUsedByTarget",                         # Mirror Move
      "UseLastMoveUsed",                                 # Copycat
      "UseMoveTargetIsAboutToUse",                       # Me First
      "UseMoveDependingOnEnvironment",                   # Nature Power         # Not listed on Bulbapedia
      "UseRandomUserMoveIfAsleep",                       # Sleep Talk
      "UseRandomMoveFromUserParty",                      # Assist
      "UseRandomMove",                                   # Metronome
      # Two-turn attacks
      "TwoTurnAttack",                                   # Razor Wind
      "TwoTurnAttackOneTurnInSun",                       # Solar Beam, Solar Blade
      "TwoTurnAttackParalyzeTarget",                     # Freeze Shock
      "TwoTurnAttackBurnTarget",                         # Ice Burn
      "TwoTurnAttackFlinchTarget",                       # Sky Attack
      "TwoTurnAttackChargeRaiseUserDefense1",            # Skull Bash
      "TwoTurnAttackInvulnerableInSky",                  # Fly
      "TwoTurnAttackInvulnerableUnderground",            # Dig
      "TwoTurnAttackInvulnerableUnderwater",             # Dive
      "TwoTurnAttackInvulnerableInSkyParalyzeTarget",    # Bounce
      "TwoTurnAttackInvulnerableRemoveProtections",      # Shadow Force/Phantom Force
      "TwoTurnAttackInvulnerableInSkyTargetCannotAct",   # Sky Drop
      "AllBattlersLoseHalfHPUserSkipsNextTurn",          # Shadow Half
      "TwoTurnAttackRaiseUserSpAtkSpDefSpd2",            # Geomancy
      # Moves that start focussing at the start of the round
      "FailsIfUserDamagedThisTurn",                      # Focus Punch
      "UsedAfterUserTakesPhysicalDamage",                # Shell Trap
      "BurnAttackerBeforeUserActs"                       # Beak Blast
    ]
  end

  def pbMoveFailed?(user, targets)
    @sleepTalkMoves = []
    user.eachMoveWithIndex do |m, i|
      next if @moveBlacklist.include?(m.function_code)
      next if !@battle.pbCanChooseMove?(user.index, i, false, true)
      @sleepTalkMoves.push(i)
    end
    if !user.asleep? || @sleepTalkMoves.length == 0
      @battle.pbDisplay(_INTL("But it failed!"))
      return true
    end
    return false
  end

  def pbEffectGeneral(user)
    choice = @sleepTalkMoves[@battle.pbRandom(@sleepTalkMoves.length)]
    user.pbUseMoveSimple(user.moves[choice].id, user.pbDirectOpposing.index)
  end
end

#===============================================================================
# This round, reflects all moves that can be Magic Coated which target the user
# or which have no target back at their origin. (Magic Coat)
#===============================================================================
class Battle::Move::BounceBackProblemCausingStatusMoves < Battle::Move
  def pbEffectGeneral(user)
    user.effects[PBEffects::MagicCoat] = true
    @battle.pbDisplay(_INTL("{1} shrouded itself with Magic Coat!", user.pbThis))
  end
end

#===============================================================================
# This round, snatches all used moves that can be Snatched. (Snatch)
#===============================================================================
class Battle::Move::StealAndUseBeneficialStatusMove < Battle::Move
  def pbEffectGeneral(user)
    user.effects[PBEffects::Snatch] = 1
    @battle.allBattlers.each do |b|
      next if b.effects[PBEffects::Snatch] < user.effects[PBEffects::Snatch]
      user.effects[PBEffects::Snatch] = b.effects[PBEffects::Snatch] + 1
    end
    @battle.pbDisplay(_INTL("{1} waits for a target to make a move!", user.pbThis))
  end
end

#===============================================================================
# This move turns into the last move used by the target, until user switches
# out. (Mimic)
#===============================================================================
class Battle::Move::ReplaceMoveThisBattleWithTargetLastMoveUsed < Battle::Move
  attr_reader :moveBlacklist

  def ignoresSubstitute?(user); return true; end

  def initialize(battle, move)
    super
    @moveBlacklist = [
      "UseRandomMove",                                 # Metronome
      # Struggle
      "Struggle",                                      # Struggle
      # Moves that affect the moveset
      "ReplaceMoveThisBattleWithTargetLastMoveUsed",   # Mimic
      "ReplaceMoveWithTargetLastMoveUsed",             # Sketch
      "TransformUserIntoTarget"                        # Transform
    ]
  end

  def pbMoveFailed?(user, targets)
    if user.effects[PBEffects::Transform] || !user.pbHasMove?(@id)
      @battle.pbDisplay(_INTL("But it failed!"))
      return true
    end
    return false
  end

  def pbFailsAgainstTarget?(user, target, show_message)
    lastMoveData = GameData::Move.try_get(target.lastRegularMoveUsed)
    if !lastMoveData ||
       user.pbHasMove?(target.lastRegularMoveUsed) ||
       @moveBlacklist.include?(lastMoveData.function_code) ||
       lastMoveData.type == :SHADOW
      @battle.pbDisplay(_INTL("But it failed!")) if show_message
      return true
    end
    return false
  end

  def pbEffectAgainstTarget(user, target)
    user.eachMoveWithIndex do |m, i|
      next if m.id != @id
      newMove = Pokemon::Move.new(target.lastRegularMoveUsed)
      user.moves[i] = Battle::Move.from_pokemon_move(@battle, newMove)
      @battle.pbDisplay(_INTL("{1} learned {2}!", user.pbThis, newMove.name))
      user.pbCheckFormOnMovesetChange
      break
    end
  end
end

#===============================================================================
# This move permanently turns into the last move used by the target. (Sketch)
#===============================================================================
class Battle::Move::ReplaceMoveWithTargetLastMoveUsed < Battle::Move
  attr_reader :moveBlacklist

  def ignoresSubstitute?(user); return true; end

  def initialize(battle, move)
    super
    @moveBlacklist = [
      "ReplaceMoveWithTargetLastMoveUsed",   # Sketch (this move)
      # Struggle
      "Struggle"                             # Struggle
    ]
  end

  def pbMoveFailed?(user, targets)
    if user.effects[PBEffects::Transform] || !user.pbHasMove?(@id)
      @battle.pbDisplay(_INTL("But it failed!"))
      return true
    end
    return false
  end

  def pbFailsAgainstTarget?(user, target, show_message)
    lastMoveData = GameData::Move.try_get(target.lastRegularMoveUsed)
    if !lastMoveData ||
       user.pbHasMove?(target.lastRegularMoveUsed) ||
       @moveBlacklist.include?(lastMoveData.function_code) ||
       lastMoveData.type == :SHADOW
      @battle.pbDisplay(_INTL("But it failed!")) if show_message
      return true
    end
    return false
  end

  def pbEffectAgainstTarget(user, target)
    user.eachMoveWithIndex do |m, i|
      next if m.id != @id
      newMove = Pokemon::Move.new(target.lastRegularMoveUsed)
      user.pokemon.moves[i] = newMove
      user.moves[i] = Battle::Move.from_pokemon_move(@battle, newMove)
      @battle.pbDisplay(_INTL("{1} learned {2}!", user.pbThis, newMove.name))
      user.pbCheckFormOnMovesetChange
      break
    end
  end
end
