require '../helpers'

{Item} = require('../../server/bw/data/items')
{Ability} = require('../../server/bw/data/abilities')
{Pokemon} = require '../../server/bw/pokemon'
{Attachment, Status} = require '../../server/bw/attachment'
{Move} = require '../../server/bw/move'
{Factory} = require '../factory'
util = require '../../server/bw/util'
should = require 'should'
sinon = require 'sinon'
{_} = require 'underscore'
shared = require '../shared'

describe "BW Items:", ->
  describe "Leftovers", ->
    it "heals 1/16 of a pokemon's HP at the end of a turn", ->
      shared.create.call this,
        team1: [Factory('Magikarp', item: 'Leftovers')]
      @p1.currentHP = 1
      @battle.endTurn()
      amount = Math.floor(@p1.stat('hp') / 16)
      @p1.currentHP.should.equal(1 + amount)

  describe "Black Sludge", ->
    it "heals 1/16 of a poison pokemon's HP at the end of a turn", ->
      shared.create.call this,
        team1: [Factory('Weezing', item: 'Black Sludge')]
      @p1.currentHP = 1
      @battle.endTurn()
      amount = Math.floor(@p1.stat('hp') / 16)
      @p1.currentHP.should.equal(1 + amount)

    it "damages 1/8 of a non-poison pokemon's HP at the end of a turn", ->
      shared.create.call this,
        team1: [Factory('Magikarp', item: 'Black Sludge')]
      @battle.endTurn()
      fullHP = @p1.stat('hp')
      amount = Math.floor(fullHP / 8)
      (fullHP - @p1.currentHP).should.equal(amount)

  describe "Muscle Band", ->
    it "increases base power of physical moves by 0x1199", ->
      shared.create.call(this)
      move = @battle.getMove('Tackle')
      modifier = Item.MuscleBand::modifyBasePower(move, @p1, @p2)
      modifier.should.equal 0x1199

      move = @battle.getMove('Shadow Ball')
      modifier = Item.MuscleBand::modifyBasePower(move, @p1, @p2)
      modifier.should.equal 0x1000

  describe "Wise Glasses", ->
    it "increases base power of special moves by 0x1199", ->
      shared.create.call(this)
      move = @battle.getMove('Tackle')
      modifier = Item.WiseGlasses::modifyBasePower(move, @p1, @p2)
      modifier.should.equal 0x1000

      move = @battle.getMove('Shadow Ball')
      modifier = Item.WiseGlasses::modifyBasePower(move, @p1, @p2)
      modifier.should.equal 0x1199

  describe "An Orb item", ->
    it "increases base power of moves matching the user's type by 0x1333", ->
      shared.create.call this,
        team1: [Factory('Giratina', item: "Griseous Orb")]
      move = @battle.getMove('Outrage')
      modifier = move.modifyBasePower(@battle, @p1, @p2)
      modifier.should.equal 0x1333

      move = @battle.getMove('Shadow Ball')
      modifier = move.modifyBasePower(@battle, @p1, @p2)
      modifier.should.equal 0x1333

      move = @battle.getMove('Tackle')
      modifier = move.modifyBasePower(@battle, @p1, @p2)
      modifier.should.equal 0x1000

  describe "A type-boosting miscellaneous item", ->
    it "increases base power of certain typed moves by 0x1333", ->
      shared.create.call(this)
      move = @battle.getMove('Outrage')
      modifier = Item.OddIncense::modifyBasePower(move, @p1, @p2)
      modifier.should.equal 0x1000

      move = @battle.getMove('Psychic')
      modifier = Item.OddIncense::modifyBasePower(move, @p1, @p2)
      modifier.should.equal 0x1333

  describe "A typed Gem", ->
    it "increases base power of certain typed moves by 0x1800", ->
      shared.create.call(this)
      move = @battle.getMove('Acrobatics')
      modifier = Item.FlyingGem::modifyBasePower(move, @p1, @p2)
      modifier.should.equal 0x1800

      move = @battle.getMove('Psychic')
      modifier = Item.FlyingGem::modifyBasePower(move, @p1, @p2)
      modifier.should.equal 0x1000

    it "is removed after use", ->
      shared.create.call this,
        team1: [Factory('Magikarp', item: 'Flying Gem')]
      @battle.performMove(@p1, @battle.getMove("Acrobatics"))
      @p1.hasItem().should.equal.false

    it "is not removed after use if the move isn't the right type", ->
      shared.create.call this,
        team1: [Factory('Magikarp', item: 'Flying Gem')]
      @battle.performMove(@p1, @battle.getMove("Tackle"))
      @p1.hasItem("Flying Gem").should.equal.true

  describe "A typed plate", ->
    it "has the plate attribute set", ->
      item = Item.DracoPlate
      item.should.have.property('plate')

    it "changes the Arceus type"

  describe "Rocky Helmet", ->
    it "deals 1/6 of the attacker's total HP on a contact move", ->
      shared.create.call this,
        team2: [Factory('Ferrothorn', item: 'Rocky Helmet')]

      hp = @p1.stat('hp')
      currentHP = @p1.currentHP = Math.floor(hp * 2 / 3)
      @battle.performMove(@p1, @battle.getMove("Tackle"))
      @p1.currentHP.should.equal currentHP - Math.floor(hp / 6)

    it "doesn't deal damage back to attacker if not a contact move", ->
      shared.create.call this,
        team2: [Factory('Ferrothorn', item: 'Rocky Helmet')]

      hp = @p1.stat('hp')
      currentHP = @p1.currentHP = Math.floor(hp * 2 / 3)
      @battle.performMove(@p1, @battle.getMove("Earthquake"))
      @p1.currentHP.should.equal currentHP

    it "stacks with each hit of multi-hit moves like Triple Kick", ->
      shared.create.call this,
        team2: [Factory('Ferrothorn', item: 'Rocky Helmet')]

      @battle.performMove(@p1, @battle.getMove("Triple Kick"))
      maxHP = @p1.stat('hp')
      @p1.currentHP.should.equal(maxHP - (Math.floor(maxHP / 6) * 3))

    it "still works even if user faints", ->
      shared.create.call this,
        team2: [Factory('Magikarp', item: 'Rocky Helmet'), Factory("Magikarp")]

      @p2.currentHP = 1
      hp = @p1.stat('hp')
      @battle.performMove(@p1, @battle.getMove("Tackle"))
      @p1.currentHP.should.equal(hp - Math.floor(hp / 6))

  testBoostOnTypeItem = (itemName, type, stat) ->
    describe itemName, ->
      it "boosts the special attack of the target by 1 if hit by a #{type} move", ->
        shared.create.call this,
          team2: [Factory("Ferrothorn", item: itemName)]
        move = _(@battle.MoveList).find (m) ->
            m.type == type && !m.isNonDamaging()
        @battle.performMove(@p1, move)
        @p2.stages[stat].should.equal 1

      it "is one-time use", ->
        shared.create.call this,
          team2: [Factory("Ferrothorn", item: itemName)]
        move = _(@battle.MoveList).find (m) ->
            m.type == type && !m.isNonDamaging()
        @battle.performMove(@p1, move)
        should.not.exist @p2.item

      it "doesn't boost target's special attack if not hit by a #{type} move", ->
        shared.create.call this,
          team2: [Factory("Ferrothorn", item: itemName)]
        move = _(@battle.MoveList).find (m) ->
            m.type != type && !m.isNonDamaging()
        @battle.performMove(@p1, move)
        @p2.stages[stat].should.equal 0

  testBoostOnTypeItem("Absorb Bulb", "Water", "specialAttack")
  testBoostOnTypeItem("Cell Battery", "Electric", "attack")

  describe "Float Stone", ->
    it "halves the user's weight", ->
      shared.create.call this,
        team1: [Factory("Magikarp", item: "Float Stone")]

      weight = @p1.weight
      @p1.calculateWeight().should.equal Math.floor(weight / 2)

  describe "Focus Sash", ->
    it "always lets the user survive at 100% HP", ->
      shared.create.call this,
        team2: [Factory("Magikarp", item: "Focus Sash")]

      ember = @battle.getMove('Ember')
      stub = @sandbox.stub(ember, 'calculateDamage', -> 9999)
      @battle.performMove(@p1, ember)
      @p2.currentHP.should.equal(1)

    it "fails to protect from multihit moves", ->
      shared.create.call this,
        team2: [Factory("Magikarp", item: "Focus Sash")]

      overpoweredMultihitMove = new Move(null, minHits: 5, maxHits: 5, target: "selected-pokemon")
      overpoweredMultihitMove.calculateDamage = -> 99999

      @battle.performMove(@p1, overpoweredMultihitMove)
      @p2.isFainted().should.be.true

    it "triggers on the first hit of a multihit move if each strike OHKOs", ->
      shared.create.call this,
        team2: [Factory("Magikarp", item: "Focus Sash")]

      overpoweredMultihitMove = new Move(null, minHits: 2, maxHits: 2, target: "selected-pokemon")
      overpoweredMultihitMove.calculateDamage = -> 99999
      spy = @sandbox.spy(overpoweredMultihitMove, 'hit')

      @battle.performMove(@p1, overpoweredMultihitMove)
      sinon.assert.calledTwice(spy)

    it "should not activate at <100% HP", ->
      shared.create.call this,
        team2: [Factory("Magikarp", item: "Focus Sash")]

      @p2.currentHP -= 1
      ember = @battle.getMove('Ember')
      stub = @sandbox.stub(ember, 'calculateDamage', -> 9999)
      @battle.performMove(@p1, ember)
      @p2.currentHP.should.equal(0)

    it "disappears after activation", ->
      shared.create.call this,
        team2: [Factory("Magikarp", item: "Focus Sash")]

      ember = @battle.getMove('Ember')
      stub = @sandbox.stub(ember, 'calculateDamage', -> 9999)
      @battle.performMove(@p1, ember)
      @p2.hasItem().should.be.false

  describe "Choice items", ->
    it "locks the user into its first selected move", ->
      shared.create.call this,
        team1: [Factory("Magikarp", item: "Choice Band")]

      @controller.makeMove(@id1, 'Splash')
      @controller.makeMove(@id2, 'Splash')

      requestedMoves = @battle.requestFor(@p1).moves
      requestedMoves.should.eql [ @battle.getMove('Splash').name ]

    it "locks the user if it gains the item after an attack", ->
      shared.create.call this,
        team1: [Factory("Magikarp", item: "Choice Band")]
        team2: [Factory("Magikarp", item: "Leftovers")]

      @battle.performMove(@p1, @battle.getMove('Trick'))
      @battle.performMove(@p2, @battle.getMove('Splash'))
      @battle.beginTurn()
      requestedMoves = @battle.requestFor(@p2).moves
      requestedMoves.should.eql [ @battle.getMove('Splash').name ]

    it "does not automatically lock the user when it switches back in", ->
      shared.create.call this,
        team1: [Factory("Magikarp", item: "Choice Band"), Factory("Magikarp")]

      @controller.makeMove(@id1, 'Splash')
      @controller.makeMove(@id2, 'Splash')

      @controller.makeSwitch(@id1, 1)
      @controller.makeMove(@id2, 'Splash')

      @controller.makeSwitch(@id1, 1)
      @controller.makeMove(@id2, 'Splash')

      request = @battle.requestFor(@p1)
      should.exist(request)
      request.moves.should.eql [ @battle.getMove('Splash').name, @battle.getMove('Tackle').name ]

    it "increases the respective stat by 1.5", ->
      shared.create.call this,
        team1: [Factory("Magikarp", item: "Choice Band")]
      tackle = @battle.getMove("Tackle")
      thunder = @battle.getMove("Thunder")
      tackle.modifyAttack(@battle, @p1, @p2).should.equal(0x1800)
      thunder.modifyAttack(@battle, @p1, @p2).should.equal(0x1000)

    xit "relocks the pokemon after Magic Room"

  describe "Choice Scarf", ->
    it "increases the speed of the Pokemon by x1.5", ->
      shared.create.call(this)

      speed = @p1.stat('speed')
      @p1.setItem(Item.ChoiceScarf)
      @p1.stat('speed').should.equal Math.floor(speed * 1.5)

  describe "Flame Orb", ->
    it "burns the user at the end of the turn", ->
      shared.create.call this,
        team1: [Factory("Magikarp", item: "Flame Orb")]

      @controller.makeMove(@id1, 'Splash')
      @controller.makeMove(@id2, 'Splash')

      @p1.has(Status.Burn).should.be.true

    it "does not burn the user if it is already statused", ->
      shared.create.call this,
        team1: [Factory("Magikarp", item: "Flame Orb")]

      @p1.attach(Status.Sleep)

      @controller.makeMove(@id1, 'Splash')
      @controller.makeMove(@id2, 'Splash')

      @p1.has(Status.Burn).should.be.false

  describe "Toxic Orb", ->
    it "toxics the user at the end of the turn", ->
      shared.create.call this,
        team1: [Factory("Magikarp", item: "Toxic Orb")]

      @controller.makeMove(@id1, 'Splash')
      @controller.makeMove(@id2, 'Splash')

      @p1.has(Status.Toxic).should.be.true

    it "does not toxic the user if it is already statused", ->
      shared.create.call this,
        team1: [Factory("Magikarp", item: "Toxic Orb")]

      @p1.attach(Status.Sleep)

      @controller.makeMove(@id1, 'Splash')
      @controller.makeMove(@id2, 'Splash')

      @p1.has(Status.Toxic).should.be.false

  describe "Air Balloon", ->
    it "makes the user immune to ground moves", ->
      shared.create.call this,
        team1: [Factory("Magikarp", item: "Air Balloon")]

      move = @battle.getMove('Earthquake')
      type = move.getType(@battle, @p1, @p2)
      @p1.isImmune(type).should.be.true

    it "pops if hit by an attacking move", ->
      shared.create.call this,
        team1: [Factory("Magikarp", item: "Air Balloon")]

      @controller.makeMove(@id1, 'Splash')
      @controller.makeMove(@id2, 'Tackle')

      @p1.hasItem().should.be.false

    it "does not pop if hit by a non-attacking move", ->
      shared.create.call this,
        team1: [Factory("Magikarp", item: "Air Balloon")]

      @battle.performMove(@p2, @battle.getMove('Flatter'))
      @p1.hasItem().should.be.true

    it "no longer makes the pokemon immune when popped", ->
      shared.create.call this,
        team1: [Factory("Magikarp", item: "Air Balloon")]

      @controller.makeMove(@id1, 'Splash')
      @controller.makeMove(@id2, 'Tackle')

      move = @battle.getMove('Earthquake')
      type = move.getType(@battle, @p1, @p2)
      @p1.isImmune(type).should.be.false

    it "stops effecting a pokemon if Tricked away", ->
      shared.create.call this,
        team1: [Factory("Magikarp", item: "Air Balloon")]
        team2: [Factory("Magikarp", item: "Leftovers")]

      @battle.performMove(@p2, @battle.getMove('Trick'))
      @p1.has(Item.AirBalloon).should.be.false
      @p2.has(Item.AirBalloon).should.be.true

  describe "White Herb", ->
    it "negates negative status boosts", ->
      shared.create.call this,
        team1: [Factory("Magikarp", item: "White Herb")]

      @battle.performMove(@p1, @battle.getMove('Shell Smash'))
      @p1.update()
      @p1.stages.should.containEql {
        attack: 2, defense: 0, speed: 2, specialAttack: 2, specialDefense: 0
      }

  describe "Life Orb", ->
    it "removes 10% from the pokemon's HP when using an attacking move", ->
      shared.create.call this,
        team1: [Factory("Magikarp", item: "Life Orb")]

      @controller.makeMove(@id1, 'Tackle')
      @controller.makeMove(@id2, 'Splash')

      hp = @p1.stat('hp')
      (hp - @p1.currentHP).should.equal Math.floor(hp / 10)

    it "only recoils once in a multi-hit move", ->
      shared.create.call this,
        team1: [Factory("Magikarp", item: "Life Orb")]

      @battle.performMove(@p1, @battle.getMove("Fury Swipes"))

      maxHP = @p1.stat('hp')
      (maxHP - @p1.currentHP).should.equal Math.floor(maxHP / 10)

    it "doesn't remove 10% HP when using a non-attacking move", ->
      shared.create.call this,
        team1: [Factory("Magikarp", item: "Life Orb")]

      @battle.performMove(@p1, @battle.getMove('Growl'))
      @p1.currentHP.should.equal @p1.stat('hp')

    it "adds a x1.3 modifier to attacks", ->
      shared.create.call this,
        team1: [Factory("Magikarp", item: "Life Orb")]

      tackle = @battle.getMove("Tackle")
      tackle.modifyAttack(@battle, @p1, @p2).should.equal(0x14CC)

  describe "Salac berry", ->
    it "raises the Pokemon's Speed when HP falls at 25% or less", ->
      shared.create.call this,
        team1: [Factory("Magikarp", item: "Salac Berry")]

      @controller.makeMove(@id1, 'Splash')
      @controller.makeMove(@id2, 'Splash')

      @p1.stages.speed.should.equal(0)

      @p1.currentHP = Math.floor(@p1.currentHP / 4)
      @controller.makeMove(@id1, 'Splash')
      @controller.makeMove(@id2, 'Splash')

      @p1.stages.speed.should.equal(1)

    it "is consumed after use", ->
      shared.create.call this,
        team1: [Factory("Magikarp", item: "Salac Berry")]

      @p1.currentHP = Math.floor(@p1.currentHP / 4)
      @controller.makeMove(@id1, 'Splash')
      @controller.makeMove(@id2, 'Splash')

      @p1.hasItem().should.be.false

  describe "Starf berry", ->
    it "sharply raises a random stat when HP falls at 25% or less", ->
      shared.create.call this,
        team1: [Factory("Magikarp", item: "Starf Berry")]

      shared.biasRNG.call(this, "randInt", 'starf berry stat', 1)

      @p1.currentHP = Math.floor(@p1.currentHP / 4)
      @controller.makeMove(@id1, 'Splash')
      @controller.makeMove(@id2, 'Splash')

      @p1.stages.defense.should.equal(2)

    it "is consumed after use", ->
      shared.create.call this,
        team1: [Factory("Magikarp", item: "Salac Berry")]

      @p1.currentHP = Math.floor(@p1.currentHP / 4)
      @controller.makeMove(@id1, 'Splash')
      @controller.makeMove(@id2, 'Splash')

      @p1.hasItem().should.be.false

    it "only raises stats that aren't at +6", ->
      shared.create.call this,
        team1: [Factory("Magikarp", item: "Starf Berry")]

      shared.biasRNG.call(this, "randInt", 'starf berry stat', 1)

      @p1.stages.defense = 6
      @p1.currentHP = Math.floor(@p1.currentHP / 4)
      @controller.makeMove(@id1, 'Splash')
      @controller.makeMove(@id2, 'Splash')

      # Note: This depends on the stats array inside
      # the definition of Starf Berry. Not exactly robust.
      @p1.stages.specialAttack.should.equal(2)
      @p1.hasItem().should.be.false

    it "doesn't raise any stat if all main stats are at +6", ->
      shared.create.call this,
        team1: [Factory("Magikarp", item: "Starf Berry")]

      shared.biasRNG.call(this, "randInt", 'starf berry stat', 1)

      stats = ["attack", "defense", "specialAttack", "specialDefense", "speed"]
      for stat in stats
        @p1.stages[stat] = 6

      @p1.currentHP = Math.floor(@p1.currentHP / 4)
      @controller.makeMove(@id1, 'Splash')
      @controller.makeMove(@id2, 'Splash')

      hash = {}
      for stat in stats
        hash[stat] = 6
      @p1.stages.should.containEql(hash)
      @p1.hasItem().should.be.false

  describe "a flavor healing berry", ->
    it "restores 1/8 of the Pokemon's HP when at 50% HP or under", ->
      shared.create.call this,
        team1: [Factory("Magikarp", item: "Figy Berry")]

      @controller.makeMove(@id1, 'Splash')
      @controller.makeMove(@id2, 'Splash')

      @p1.hasItem().should.be.true

      maxHP = @p1.stat('hp')
      hp = Math.floor(maxHP / 2)
      @p1.currentHP = hp
      @controller.makeMove(@id1, 'Splash')
      @controller.makeMove(@id2, 'Splash')

      @p1.currentHP.should.equal(hp + Math.floor(maxHP / 8))

    it "is consumed after use", ->
      shared.create.call this,
        team1: [Factory("Magikarp", item: "Figy Berry")]

      @p1.currentHP = Math.floor(@p1.stat('hp') / 2)
      @controller.makeMove(@id1, 'Splash')
      @controller.makeMove(@id2, 'Splash')

      @p1.hasItem().should.be.false

    it "confuses the owner if its nature decreases a specific stat", ->
      shared.create.call this,
        team1: [Factory("Magikarp", item: "Figy Berry", nature: "Calm")]

      @p1.currentHP = Math.floor(@p1.stat('hp') / 2)
      @controller.makeMove(@id1, 'Splash')
      @controller.makeMove(@id2, 'Splash')

      @p1.has(Attachment.Confusion).should.be.true

  describe "a healing berry", ->
    it "restores a variable number of HP when owner is at 50% HP or under", ->
      shared.create.call this,
        team1: [Factory("Magikarp", item: "Sitrus Berry")]

      @controller.makeMove(@id1, 'Splash')
      @controller.makeMove(@id2, 'Splash')

      @p1.hasItem().should.be.true

      maxHP = @p1.stat('hp')
      hp = Math.floor(maxHP / 2)
      @p1.currentHP = hp
      @controller.makeMove(@id1, 'Splash')
      @controller.makeMove(@id2, 'Splash')

      @p1.currentHP.should.equal(hp + Math.floor(maxHP / 4))

    it "is consumed after use", ->
      shared.create.call this,
        team1: [Factory("Magikarp", item: "Sitrus Berry")]

      @p1.currentHP = Math.floor(@p1.stat('hp') / 2)
      @controller.makeMove(@id1, 'Splash')
      @controller.makeMove(@id2, 'Splash')

      @p1.hasItem().should.be.false

  describe "a type-resist berry", ->
    it "halves base power of a super-effective move used on the target", ->
      shared.create.call this,
        team2: [Factory("Blaziken", item: "Shuca Berry")]

      move = @battle.getMove('Earthquake')
      move.modifyBasePower(@battle, @p1, @p2).should.equal(0x800)

    it "is consumed after use", ->
      shared.create.call this,
        team2: [Factory("Blaziken", item: "Shuca Berry")]

      @battle.performMove(@p1, @battle.getMove("Earthquake"))
      @p2.hasItem().should.be.false

    it "is not triggered by non-damaging moves", ->
      shared.create.call this,
        team2: [Factory("Celebi", item: "Occa Berry")]

      @battle.performMove(@p1, @battle.getMove("Will-O-Wisp"))
      @p2.hasItem().should.be.true

    it "does not halve if the move is not of the required type", ->
      shared.create.call this,
        team2: [Factory("Blaziken", item: "Shuca Berry")]

      move = @battle.getMove('Surf')
      move.modifyBasePower(@battle, @p1, @p2).should.equal(0x1000)

    it "does not halve if the move is not super-effective", ->
      shared.create.call this,
        team2: [Factory("Magikarp", item: "Shuca Berry")]

      move = @battle.getMove('Earthquake')
      move.modifyBasePower(@battle, @p1, @p2).should.equal(0x1000)

    it "halves nevertheless, if it's the normal-resist berry", ->
      shared.create.call this,
        team2: [Factory("Magikarp", item: "Chilan Berry")]

      move = @battle.getMove('Double-Edge')
      move.modifyBasePower(@battle, @p1, @p2).should.equal(0x800)

    it "halves base power of moves even if they aren't naturally that type", ->
      shared.create.call this,
        team2: [Factory("Blaziken", item: "Shuca Berry")]

      move = @battle.getMove('Tackle')
      @sandbox.stub(move, 'getType', -> 'Ground')
      move.modifyBasePower(@battle, @p1, @p2).should.equal(0x800)

  describe "a feedback damage berry", ->
    it "damages the attacker by 12.5% if move class matches", ->
      shared.create.call this,
        team2: [Factory("Magikarp", item: "Jaboca Berry")]

      @controller.makeMove(@id1, 'Tackle')
      @controller.makeMove(@id2, 'Splash')

      hp = @p1.stat('hp')
      (hp - @p1.currentHP).should.equal Math.floor(hp / 8)

    it "is consumed after use", ->
      shared.create.call this,
        team2: [Factory("Magikarp", item: "Jaboca Berry")]

      @controller.makeMove(@id1, 'Tackle')
      @controller.makeMove(@id2, 'Splash')

      @p2.hasItem().should.be.false

    it "does not damage the attacker by 12.5% if move class doesn't match", ->
      shared.create.call this,
        team2: [Factory("Magikarp", item: "Rowap Berry")]

      @controller.makeMove(@id1, 'Tackle')
      @controller.makeMove(@id2, 'Splash')

      @p1.currentHP.should.equal @p1.stat('hp')

    it "does not damage the attacker if defender faints", ->
      shared.create.call this,
        team2: [Factory("Magikarp", item: "Rowap Berry")]

      @p2.currentHP = 1
      @controller.makeMove(@id1, 'Tackle')
      @controller.makeMove(@id2, 'Splash')

      @p1.currentHP.should.equal @p1.stat('hp')

  describe "status cure berries", ->
    it "restores certain statuses", ->
      shared.create.call this,
        team2: [Factory("Magikarp", item: "Cheri Berry")]

      @p2.attach(Status.Paralyze)
      @p2.update()
      @p2.has(Status.Paralyze).should.be.false

    it "is consumed after use", ->
      shared.create.call this,
        team2: [Factory("Magikarp", item: "Cheri Berry")]

      @p2.attach(Status.Paralyze)
      @p2.update()
      @p2.hasItem().should.be.false

    it "restores confusion", ->
      shared.create.call this,
        team2: [Factory("Magikarp", item: "Lum Berry")]

      shared.biasRNG.call(this, "randInt", 'confusion turns', 4)
      @p2.attach(Attachment.Confusion, {@battle})
      @p2.update()
      @p2.has(Attachment.Confusion).should.be.false

    it "sends a message about status being restored", ->
      shared.create.call this,
        team2: [Factory("Magikarp", item: "Lum Berry")]

      spy = @sandbox.spy(@battle, 'message')
      shared.biasRNG.call(this, "randInt", 'confusion turns', 4)
      @p2.attach(Attachment.Confusion, {@battle})
      @p2.update()
      spy.args.join(',').should.containEql("#{@p1.name}'s Lum Berry snapped it out of its confusion!")

  describe "Enigma Berry", ->
    it "restores 25% of HP after the owner is hit by a super-effective move", ->
      shared.create.call this,
        team1: [Factory("Magikarp", item: "Enigma Berry")]

      hp = @p1.stat('hp')
      damage = Math.floor(hp / 2)
      thunderbolt = @battle.getMove("Thunderbolt")
      @sandbox.stub(thunderbolt, "calculateDamage", -> damage)
      @battle.performMove(@p2, thunderbolt)
      @p1.currentHP.should.equal(hp - damage + Math.floor(hp / 4))

    it "is consumed after use", ->
      shared.create.call this,
        team1: [Factory("Magikarp", item: "Enigma Berry")]

      @battle.performMove(@p2, @battle.getMove("Thunderbolt"))
      @p1.hasItem().should.be.false

    it "doesn't restore 25% of HP if move isn't super-effective", ->
      shared.create.call this,
        team1: [Factory("Magikarp", item: "Enigma Berry")]

      hp = @p1.stat('hp')
      damage = Math.floor(hp / 2)
      tackle = @battle.getMove("Tackle")
      @sandbox.stub(tackle, "calculateDamage", -> damage)
      @battle.performMove(@p2, tackle)
      @p1.currentHP.should.equal(hp - damage)

  testSpeciesBoostingItem = (itemName, speciesArray, statsHash) ->
    describe itemName, ->
      for species in speciesArray
        it "should raise the proper stats given that the wielder is #{species}", ->
          shared.create.call this,
            team1: [Factory(species)]

          stats = (stat  for stat of statsHash)
          pokemonStats = (@p1.stat(stat)  for stat in stats)

          @p1.setItem(Item[itemName.replace(/\s+/g, '')])

          for stat, i in stats
            amount = @p1.stat(stat)
            amount.should.equal Math.floor(pokemonStats[i] * statsHash[stat])

      it "shouldn't raise the proper stats given the wrong species", ->
          shared.create.call this,
            team1: [Factory("Magikarp")]

          stats = (stat  for stat of statsHash)
          pokemonStats = (@p1.stat(stat)  for stat in stats)

          @p1.setItem(Item[itemName.replace(/\s+/g, '')])

          for stat, i in stats
            amount = @p1.stat(stat)
            amount.should.equal(pokemonStats[i])

      it "shouldn't raise the proper stats given the pokemon is Transformed", ->
          shared.create.call this,
            team1: [Factory(species)]
            team2: [Factory("Magikarp")]

          @p1.attach(Attachment.Transform, target: @p2)
          stats = (stat  for stat of statsHash)
          pokemonStats = (@p1.stat(stat)  for stat in stats)

          @p1.setItem(Item[itemName.replace(/\s+/g, '')])

          for stat, i in stats
            amount = @p1.stat(stat)
            amount.should.equal(pokemonStats[i])

  testSpeciesBoostingItem("Soul Dew", ["Latios", "Latias"],
    specialAttack: 1.5, specialDefense: 1.5)
  testSpeciesBoostingItem("DeepSeaTooth", ["Clamperl"], specialAttack: 2)
  testSpeciesBoostingItem("DeepSeaScale", ["Clamperl"], specialDefense: 2)
  testSpeciesBoostingItem("Light Ball", ["Pikachu"], attack: 2, specialAttack: 2)
  testSpeciesBoostingItem("Thick Club", ["Cubone", "Marowak"], attack: 2)
  testSpeciesBoostingItem("Metal Powder", ["Ditto"],
    defense: 2, specialDefense: 2)
  testSpeciesBoostingItem("Quick Powder", ["Ditto"], speed: 2)

  describe "Iron Ball", ->
    it "halves the owner's speed", ->
      shared.create.call(this)

      speed = @p1.stat('speed')
      @p1.setItem(Item.IronBall)
      @p1.stat('speed').should.equal Math.floor(speed / 2)

    it "removes the immunity to ground-type moves", ->
      shared.create.call(this, team1: [Factory("Gyarados", item: "Iron Ball")])

      @p1.isImmune("Ground").should.be.false

  describe "Leppa Berry", ->
    it "restores 10 PP when the user reaches 0 PP", ->
      shared.create.call this,
        team1: [Factory("Magikarp", item: "Leppa Berry")]

      pokemon = @p1
      move = pokemon.moves[0]
      pokemon.setPP(move, 1)

      @controller.makeMove(@id1, move.name)
      @controller.makeMove(@id2, 'Splash')

      pokemon.pp(move).should.equal 10

    it "restores 10 PP to the first move with 0 PP", ->
      shared.create.call this,
        team1: [Factory("Magikarp", item: "Leppa Berry")]

      pokemon = @p1
      for move in pokemon.moves
        pokemon.setPP(move, 0)
      secondMove  = pokemon.moves[1]
      pokemon.setPP(secondMove, 1)

      @controller.makeMove(@id1, secondMove.name)
      @controller.makeMove(@id2, 'Splash')

      pokemon.pp(pokemon.moves[0]).should.equal 10
      pokemon.pp(secondMove).should.equal 0

  it "is consumed after use", ->
      shared.create.call this,
        team1: [Factory("Magikarp", item: "Leppa Berry")]

      pokemon = @p1
      move = pokemon.moves[0]
      pokemon.setPP(move, 1)

      @controller.makeMove(@id1, move.name)
      @controller.makeMove(@id2, 'Splash')

      pokemon.hasItem().should.be.false

  describe "Focus Band", ->
    it "has a 10% chance to survive an attack", ->
      shared.create.call this,
        team1: [Factory("Magikarp", item: "Focus Band")]

      pokemon = @p1
      pokemon.currentHP = 1

      shared.biasRNG.call(this, "randInt", 'focus band', 0)

      @controller.makeMove(@id1, "Splash")
      @controller.makeMove(@id2, "Tackle")

      pokemon.currentHP.should.equal 1

    it "lets the pokemon faint otherwise", ->
      shared.create.call this,
        team1: [Factory("Magikarp", item: "Focus Band")]

      pokemon = @p1
      pokemon.currentHP = 1

      shared.biasRNG.call(this, "randInt", 'focus band', 1)

      @controller.makeMove(@id1, "Splash")
      @controller.makeMove(@id2, "Tackle")

      pokemon.isFainted().should.be.true

  describe "Binding Band", ->
    it "makes trapping moves deal 1/8 damage per turn, not 1/16", ->
      shared.create.call this,
        team1: [Factory("Magikarp", evs: {speed: 4}, item: "Binding Band")]

      @battle.performMove(@p1, @battle.getMove("Fire Spin"))
      maxHP = @p2.stat('hp')
      @p2.currentHP = maxHP

      @battle.endTurn()
      expected = maxHP - Math.floor(maxHP / 8)
      @p2.currentHP.should.equal expected

  describe "Red Card", ->
    it "drags a pokemon out if a damaging move is used", ->
      shared.create.call this,
        team1: [Factory("Magikarp", item: "Red Card")]
        team2: [Factory("Magikarp"), Factory("Abra")]

      target = @team2.at(1)
      @battle.performMove(@p2, @battle.getMove("Tackle"))
      @team2.first().should.equal target

    it "cancels any future action of the pokemon", ->
      shared.create.call this,
        team1: [Factory("Magikarp", item: "Red Card")]
        team2: [Factory("Magikarp"), Factory("Abra")]

      target = @team2.at(1)
      @battle.performMove(@p2, @battle.getMove("Volt Switch"))
      @team2.first().should.equal(target)
      should.not.exist @battle.requestFor(@p2)
      should.not.exist @battle.requestFor(@team2.first())

    it "destroys the Red Card after use", ->
      shared.create.call this,
        team1: [Factory("Magikarp", item: "Red Card")]
        team2: [Factory("Magikarp"), Factory("Abra")]

      @battle.performMove(@p2, @battle.getMove("Tackle"))
      @p1.hasItem().should.be.false

    it "does not activate if KOed by the move", ->
      shared.create.call this,
        team1: [Factory("Magikarp", item: "Red Card"), Factory("Magikarp")]
        team2: [Factory("Magikarp"), Factory("Abra")]

      @p1.currentHP = 1
      @battle.performMove(@p2, @battle.getMove("Tackle"))
      @team2.first().should.equal(@p2)

    it "does not activate if there is only one Pokemon left", ->
      shared.create.call this,
        team1: [Factory("Magikarp", item: "Red Card")]
        team2: [Factory("Magikarp")]

      @battle.performMove(@p2, @battle.getMove("Tackle"))
      @p1.hasItem().should.be.true

    it "does not activate if a non-damaging move is used", ->
      shared.create.call this,
        team1: [Factory("Magikarp", item: "Red Card")]
        team2: [Factory("Magikarp"), Factory("Abra")]

      target = @p2
      @battle.performMove(@p2, @battle.getMove("Will-O-Wisp"))
      @p1.hasItem().should.be.true
      @p2.should.equal target

    it "activates and is used up even if the forced switch is prevented", ->
      shared.create.call this,
        team1: [Factory("Magikarp", item: "Red Card")]
        team2: [Factory("Magikarp", ability: "Suction Cups"), Factory("Abra")]

      target = @p2
      @battle.performMove(@p2, @battle.getMove("Tackle"))
      @p1.hasItem().should.be.false
      @p2.should.equal target

  describe "Shell Bell", ->
    it "restores 1/8 of damage dealt to target", ->
      shared.create.call(this, team1: [Factory("Magikarp", item: "Shell Bell")])

      @p1.currentHP = startHP = 1

      @battle.performMove(@p1, @battle.getMove("Outrage"))
      damage = @p2.stat('hp') - @p2.currentHP
      @p1.currentHP.should.equal(startHP + Math.floor(damage / 8))

  describe "Sticky Barb", ->
    it "damages 1/8 of holder's HP each turn", ->
      shared.create.call this,
        team1: [Factory("Magikarp", item: "Sticky Barb")]

      @battle.endTurn()
      hp = @p1.stat('hp')
      (hp - @p1.currentHP).should.equal Math.floor(hp / 8)

    it "attaches to the attacking pokemon on a contact move", ->
      shared.create.call this,
        team1: [Factory("Magikarp", item: "Sticky Barb")]

      @battle.performMove(@p2, @battle.getMove("Tackle"))
      @p1.hasItem().should.be.false
      @p2.hasItem("Sticky Barb").should.be.true

    it "does not attach to the attacking pokemon on non-contact moves", ->
      shared.create.call this,
        team1: [Factory("Magikarp", item: "Sticky Barb")]

      @battle.performMove(@p2, @battle.getMove("Aura Sphere"))
      @p1.hasItem("Sticky Barb").should.be.true
      @p2.hasItem().should.be.false

    it "does not attach if the attacker has an item", ->
      shared.create.call this,
        team1: [Factory("Magikarp", item: "Sticky Barb")]
        team2: [Factory("Magikarp", item: "Leftovers")]

      @battle.performMove(@p2, @battle.getMove("Tackle"))

      @p1.hasItem("Sticky Barb").should.be.true
      @p2.hasItem("Leftovers").should.be.true

  describe "Destiny Knot", ->
    it "infatuates the enemy as well if the holder becomes attracted", ->
      shared.create.call this,
        team1: [Factory("Magikarp", gender: "F", item: "Destiny Knot")]
        team2: [Factory("Magikarp", gender: "M")]

      @battle.performMove(@p2, @battle.getMove("Attract"))
      @p1.has(Attachment.Attract).should.be.true
      @p2.has(Attachment.Attract).should.be.true

    it "is one-time use", ->
      shared.create.call this,
        team1: [Factory("Magikarp", gender: "F", item: "Destiny Knot")]
        team2: [Factory("Magikarp", gender: "M")]

      @battle.performMove(@p2, @battle.getMove("Attract"))
      @p1.hasItem().should.be.false

    it "what happens if both pokemon have Destiny Knot?"
    it "what happens if the target is already attracted?"

  describe "Custap Berry", ->
    it "bumps the holder to the front of its priority bracket", ->
      shared.create.call this,
        team1: [Factory("Magikarp", item: "Custap Berry")]
        team2: [Factory("Magikarp", evs: {speed: 4})]

      @p1.currentHP = 1
      @p2.currentHP = 1

      @battle.recordMove(@id1, @battle.getMove('Tackle'))
      @battle.recordMove(@id2, @battle.getMove('Tackle'))
      @battle.determineTurnOrder()
      pokemon = @battle.pokemonActions.map((o) -> o.pokemon)
      pokemon.should.eql [ @p1, @p2 ]

    it "is one-time use", ->
      shared.create.call this,
        team1: [Factory("Magikarp", item: "Custap Berry")]
        team2: [Factory("Magikarp", evs: {speed: 4})]

      @p1.currentHP = 1

      @controller.makeMove(@id1, "Splash")
      @controller.makeMove(@id2, "Splash")

      @p1.hasItem().should.be.false

    it "does not activate at 26% HP", ->
      shared.create.call this,
        team1: [Factory("Magikarp", item: "Custap Berry")]
        team2: [Factory("Magikarp", evs: {speed: 4})]

      @p1.currentHP = Math.floor(@p1.currentHP / 4) + 1

      @battle.recordMove(@id1, @battle.getMove('Tackle'))
      @battle.recordMove(@id2, @battle.getMove('Tackle'))
      @battle.determineTurnOrder()
      pokemon = @battle.pokemonActions.map((o) -> o.pokemon)
      pokemon.should.eql [ @p2, @p1 ]
      @p1.hasItem().should.be.true

    it "activates at 50% HP if the Pokemon has Gluttony"
    it "is not activated by Pursuit on a switching Pokemon"

  describe 'Lansat Berry', ->
    it "gives the owner a Focus Energy attachment", ->
      shared.create.call this,
        team1: [Factory("Magikarp", item: "Lansat Berry")]

      @p1.currentHP = Math.floor(@p1.currentHP / 4)
      @p1.update()
      @p1.has(Attachment.FocusEnergy).should.be.true

  describe "Micle Berry", ->
    it "gives the owner a 1.2x accuracy boost on their next move", ->
      shared.create.call this,
        team1: [Factory("Magikarp", item: "Micle Berry")]

      @p1.currentHP = Math.floor(@p1.currentHP / 4)

      @controller.makeMove(@id1, "Tackle")
      @controller.makeMove(@id2, "Splash")

      @p1.has(Attachment.MicleBerry).should.be.true
      @battle.getMove('Tackle').chanceToHit(@battle, @p1, @p2)
        .should.equal Math.floor(@battle.getMove('Tackle').accuracy * 1.2)

    it "goes away after their next move", ->
      shared.create.call this,
        team1: [Factory("Magikarp", item: "Micle Berry")]

      @p1.currentHP = Math.floor(@p1.currentHP / 4)

      @controller.makeMove(@id1, "Tackle")
      @controller.makeMove(@id2, "Splash")

      @controller.makeMove(@id1, "Splash")
      @controller.makeMove(@id2, "Splash")

      @p1.has(Attachment.MicleBerry).should.be.false

  testEvasionItem = (itemName, ratio=0.9) ->
    describe itemName, ->
      it "gives the owner a #{ratio}x accuracy reduction", ->
        shared.create.call this,
          team2: [Factory("Magikarp", item: itemName)]

        @controller.makeMove(@id1, "Tackle")
        @controller.makeMove(@id2, "Splash")

        @battle.getMove('Tackle').chanceToHit(@battle, @p1, @p2)
          .should.equal Math.floor(@battle.getMove('Tackle').accuracy * ratio)

      it "no longer reduces accuracy if item is knocked off", ->
        shared.create.call this,
          team2: [Factory("Magikarp", item: itemName)]

        @p2.removeItem()

        @controller.makeMove(@id1, "Tackle")
        @controller.makeMove(@id2, "Splash")

        @battle.getMove('Tackle').chanceToHit(@battle, @p1, @p2)
          .should.equal Math.floor(@battle.getMove('Tackle').accuracy)

  testEvasionItem "BrightPowder"
  testEvasionItem "Lax Incense"

  testDelayItem = (itemName) ->
    describe itemName, ->
      it "delays the user to be last in its priority bracket", ->
        shared.create.call this,
          team1: [Factory("Magikarp", item: itemName, evs: {speed: 4})]
          team2: [Factory("Magikarp")]

        @battle.recordMove(@id1, @battle.getMove('Tackle'))
        @battle.recordMove(@id2, @battle.getMove('Tackle'))
        @battle.determineTurnOrder()
        pokemon = @battle.pokemonActions.map((o) -> o.pokemon)
        pokemon.should.eql [ @p2, @p1 ]

  testDelayItem 'Full Incense'
  testDelayItem 'Lagging Tail'

  describe "Macho Brace", ->
    it "halves the owner's speed", ->
      shared.create.call(this)

      speed = @p1.stat('speed')
      @p1.setItem(Item.MachoBrace)
      @p1.stat('speed').should.equal Math.floor(speed / 2)

  describe "Eject Button", ->
    it "requests a switch immediately after being damaged", ->
      shared.create.call this,
        team1: [Factory("Magikarp", item: "Eject Button"), Factory("Abra")]
        team2: [Factory("Magikarp")]

      bench = @team1.getAliveBenchedPokemon()
      # This record move is necessary to get rid of the initial request.
      @battle.recordMove(@id1, @battle.getMove('Splash'))
      @battle.recordMove(@id2, @battle.getMove('Tackle'))
      @battle.performMove(@p2, @battle.getMove('Tackle'))

      request = @battle.requestFor(@p1)
      should.exist(request)
      request.should.have.property("switches")
      request.switches.should.eql bench.map((p) => @team1.indexOf(p))

    it "cancels whatever action the ejecter had", ->
      shared.create.call this,
        team1: [Factory("Magikarp", item: "Eject Button"), Factory("Abra")]
        team2: [Factory("Magikarp")]

      bench = @team1.getAliveBenchedPokemon()
      @battle.recordMove(@id1, @battle.getMove('Splash'))
      @battle.recordMove(@id2, @battle.getMove('Tackle'))

      should.exist(@battle.getAction(@p1))
      @battle.performMove(@p2, @battle.getMove('Tackle'))
      should.not.exist(@battle.getAction(@p1))

    it "destroys the Eject Button after use", ->
      shared.create.call this,
        team1: [Factory("Magikarp", item: "Eject Button"), Factory("Abra")]
        team2: [Factory("Magikarp")]

      @controller.makeMove(@id1, "Splash")
      @controller.makeMove(@id2, "Tackle")

      @p1.hasItem().should.be.false

    # TODO: Eject Button will force the owner out, and prevent
    # the attacker from switching.
    it "prevents self-switching moves from switching"

    it "does not activate if there is only one Pokemon left", ->
      shared.create.call this,
        team1: [Factory("Magikarp", item: "Eject Button")]
        team2: [Factory("Magikarp")]

      @controller.makeMove(@id1, "Splash")
      @controller.makeMove(@id2, "Tackle")

      @p1.hasItem().should.be.true

    it "does not activate if a non-damaging move is used", ->
      shared.create.call this,
        team1: [Factory("Magikarp", item: "Eject Button"), Factory("Abra")]
        team2: [Factory("Magikarp")]

      @battle.recordMove(@id1, @battle.getMove('Splash'))
      @battle.recordMove(@id2, @battle.getMove('Will-O-Wisp'))
      @battle.performMove(@p2, @battle.getMove('Will-O-Wisp'))

      @p1.hasItem().should.be.true
      should.not.exist @battle.requestFor(@p1)

  describe "Mental Herb", ->
    for effectName in ['Attract','Taunt','Encore','Torment','Disable']
      it "removes the effect of #{effectName} on Pokemon#update", ->
        shared.create.call this,
          team1: [Factory("Magikarp", gender: "M", item: "Mental Herb")]
          team2: [Factory("Magikarp", gender: "F")]

        @battle.performMove(@p1, @battle.getMove("Splash"))

        pokemon = @p1
        attachment = Attachment[effectName]
        pokemon.has(attachment).should.be.false
        pokemon.attach(attachment, source: @p2)
        pokemon.has(attachment).should.be.true

        pokemon.update(@battle)

        pokemon.has(attachment).should.be.false

    it "disappears after use", ->
      shared.create.call this,
        team1: [Factory("Magikarp", gender: "M", item: "Mental Herb")]
        team2: [Factory("Magikarp", gender: "F")]

      @battle.performMove(@p1, @battle.getMove("Splash"))

      pokemon = @p1
      pokemon.attach(Attachment.Attract, source: @p2)
      pokemon.update(@battle)

      pokemon.hasItem().should.be.false

    it "gets rid of the first highest priority effect", ->
      shared.create.call this,
        team1: [Factory("Magikarp", gender: "M", item: "Mental Herb")]
        team2: [Factory("Magikarp", gender: "F")]

      @battle.performMove(@p1, @battle.getMove("Splash"))

      pokemon = @p1
      pokemon.attach(Attachment.Attract, source: @p2)
      pokemon.attach(Attachment.Torment, source: @p2)
      pokemon.update(@battle)

      pokemon.has(Attachment.Attract).should.be.false
      pokemon.has(Attachment.Torment).should.be.true

  describe "Quick Claw", ->
    it "has a 20% chance to bump the owner's priority", ->
      shared.create.call this,
        team1: [Factory("Magikarp", item: "Quick Claw")]
        team2: [Factory("Magikarp", evs: {speed: 4})]

      shared.biasRNG.call(this, "next", 'quick claw', .1)
      @battle.recordMove(@id1, @battle.getMove('Tackle'))
      @battle.recordMove(@id2, @battle.getMove('Tackle'))
      @battle.determineTurnOrder()
      pokemon = @battle.pokemonActions.map((o) -> o.pokemon)
      pokemon.should.eql [ @p1, @p2 ]

    it "has a 80% chance to do nothing", ->
      shared.create.call this,
        team1: [Factory("Magikarp", item: "Quick Claw")]
        team2: [Factory("Magikarp", evs: {speed: 4})]

      shared.biasRNG.call(this, "next", 'quick claw', .2)
      @battle.recordMove(@id1, @battle.getMove('Tackle'))
      @battle.recordMove(@id2, @battle.getMove('Tackle'))
      @battle.determineTurnOrder()
      pokemon = @battle.pokemonActions.map((o) -> o.pokemon)
      pokemon.should.eql [ @p2, @p1 ]

  testFlinchItem = (itemName) ->
    describe itemName, ->
      it "has a 10% chance to flinch a Pokemon", ->
        shared.create.call this,
          team1: [Factory("Magikarp", item: itemName)]

        shared.biasRNG.call(this, "next", 'flinch item chance', 0)
        @battle.performMove(@p1, @battle.getMove('Tackle'))
        @p2.has(Attachment.Flinch).should.be.true

      it "has a 20% chance to flinch with Serene Grace", ->
        shared.create.call this,
          team1: [Factory("Magikarp", item: itemName)]

        shared.biasRNG.call(this, "next", 'flinch item chance', .1)
        @battle.performMove(@p1, @battle.getMove('Tackle'))
        @p2.has(Attachment.Flinch).should.be.false

        @p1.copyAbility(Ability.SereneGrace)
        @battle.performMove(@p1, @battle.getMove('Tackle'))
        @p2.has(Attachment.Flinch).should.be.true

      it "has a 90% chance to do nothing", ->
        shared.create.call this,
          team1: [Factory("Magikarp", item: itemName)]

        shared.biasRNG.call(this, "next", 'flinch item chance', 0.1)
        @battle.performMove(@p1, @battle.getMove('Tackle'))
        @p2.has(Attachment.Flinch).should.be.false

      it "can't flinch if the move used can already flinch", ->
        shared.create.call this,
          team1: [Factory("Magikarp", item: itemName)]

        shared.biasRNG.call(this, "next", 'flinch item chance', 0)
        shared.biasRNG.call(this, "next", 'secondary effect', 1)
        @battle.performMove(@p1, @battle.getMove('Headbutt'))
        @p2.has(Attachment.Flinch).should.be.false

      it "can't flinch if the move is non-damaging", ->
        shared.create.call this,
          team1: [Factory("Magikarp", item: itemName)]

        shared.biasRNG.call(this, "next", 'flinch item chance', 0)
        @battle.performMove(@p1, @battle.getMove('Glare'))
        @p2.has(Attachment.Flinch).should.be.false

  testFlinchItem "King's Rock"
  testFlinchItem "Razor Fang"

  describe "Zoom Lens", ->
    it "multiplies accuracy by 120% if target is moving after", ->
      shared.create.call this,
        team1: [Factory("Magikarp", item: "Zoom Lens", evs: {speed: 4})]
        team2: [Factory("Magikarp")]

      @battle.recordMove(@id1, @battle.getMove('Tackle'))
      @battle.recordMove(@id2, @battle.getMove('Tackle'))

      @battle.getMove('Tackle').chanceToHit(@battle, @p1, @p2)
        .should.equal Math.floor(@battle.getMove('Tackle').accuracy * 1.2)

    it "doesn't change accuracy if target will not move", ->
      shared.create.call this,
        team1: [Factory("Magikarp", item: "Zoom Lens")]
        team2: [Factory("Magikarp", evs: {speed: 4})]

      @battle.recordMove(@id1, @battle.getMove('Tackle'))

      @battle.getMove('Tackle').chanceToHit(@battle, @p1, @p2)
        .should.equal Math.floor(@battle.getMove('Tackle').accuracy)

  describe "Wide Lens", ->
    it "boosts accuracy by 110%", ->
      shared.create.call this,
        team1: [Factory("Magikarp", item: "Wide Lens")]

      @battle.getMove('Tackle').chanceToHit(@battle, @p1, @p2)
        .should.equal Math.floor(@battle.getMove('Tackle').accuracy * 1.1)

  describe "Metronome", ->
    it "has a base power of x1.0 the first time a Pokemon uses a move", ->
      shared.create.call this,
        team1: [Factory("Magikarp", item: "Metronome")]

      modifier = @battle.getMove("Tackle").modifyBasePower(@battle, @p1, @p2)
      modifier.should.equal 0x1000

    it "has a base power of x1.2 the second time a Pokemon uses a move", ->
      shared.create.call this,
        team1: [Factory("Magikarp", item: "Metronome")]

      @battle.performMove(@p1, @battle.getMove('Tackle'))

      modifier = @battle.getMove("Tackle").modifyBasePower(@battle, @p1, @p2)
      modifier.should.equal 0x1333

    it "has a base power of x2.0 the sixth time a Pokemon uses a move", ->
      shared.create.call this,
        team1: [Factory("Magikarp", item: "Metronome")]

      for i in [1..5]
        @battle.performMove(@p1, @battle.getMove('Tackle'))

      modifier = @battle.getMove("Tackle").modifyBasePower(@battle, @p1, @p2)
      modifier.should.equal 0x1FFF

    it "has a base power of x2.0 further times a Pokemon uses a move", ->
      shared.create.call this,
        team1: [Factory("Magikarp", item: "Metronome")]

      for i in [1..6]
        @battle.performMove(@p1, @battle.getMove('Tackle'))

      modifier = @battle.getMove("Tackle").modifyBasePower(@battle, @p1, @p2)
      modifier.should.equal 0x1FFF

    it "resets base power multiplier to x1.0 on a different move", ->
      shared.create.call this,
        team1: [Factory("Magikarp", item: "Metronome")]
      tackle = @battle.getMove('Tackle')
      splash = @battle.getMove('Splash')

      @battle.performMove(@p1, tackle)
      @battle.performMove(@p1, splash)

      modifier = splash.modifyBasePower(@battle, @p1, @p2)
      modifier.should.equal 0x1000

  describe "Shed Shell", ->
    it "prevents blocking switches", ->
      pokemon = new Pokemon(item: "Shed Shell")
      pokemon.blockSwitch()
      pokemon.isSwitchBlocked().should.be.false

  describe "Big Root", ->
    it "boosts draining move recovery", ->
      shared.create.call this,
        team1: [Factory('Conkeldurr', item: "Big Root")]
        team2: [Factory('Hitmonchan')]
      startHP = 1
      @p1.currentHP = startHP
      hp = @p2.currentHP
      @battle.performMove(@p1, @battle.getMove('Drain Punch'))
      damage = (hp - @p2.currentHP)
      amount = util.roundHalfDown(Math.floor(damage / 2) * 1.3)
      (@p1.currentHP - startHP).should.equal(amount)

    it "boosts Leech Seed recovery, but not damage", ->
      shared.create.call this,
        team1: [Factory('Magikarp', item: "Big Root")]
      @p1.currentHP = startHP = 1
      targetAmount = (@p2.stat('hp') >> 3)
      userAmount = util.roundHalfDown(targetAmount * 1.3)

      @battle.performMove(@p1, @battle.getMove('Leech Seed'))
      @battle.endTurn()
      (@p1.currentHP - startHP).should.equal(userAmount)
      (@p2.stat('hp') - @p2.currentHP).should.equal(targetAmount)

    it "boosts Ingrain recovery", ->
      shared.create.call this,
        team1: [Factory('Magikarp', item: "Big Root")]
      @p1.currentHP = startHP = 1
      amount = util.roundHalfDown((@p1.stat('hp') >> 4) * 1.3)

      @battle.performMove(@p1, @battle.getMove('Ingrain'))
      @battle.endTurn()
      (@p1.currentHP - startHP).should.equal(amount)

    it "boosts Aqua Ring recovery", ->
      shared.create.call this,
        team1: [Factory('Magikarp', item: "Big Root")]
      @p1.currentHP = startHP = 1
      amount = util.roundHalfDown((@p1.stat('hp') >> 4) * 1.3)

      @battle.performMove(@p1, @battle.getMove('Aqua Ring'))
      @battle.endTurn()
      (@p1.currentHP - startHP).should.equal(amount)

  describe "Light Clay", ->
    it "boosts the Reflect/Light Screen turns to 8", ->
      shared.create.call(this, team1: [Factory('Magikarp', item: "Light Clay")])

      @battle.performMove(@p1, @battle.getMove('Reflect'))

      for i in [1..8]
        @team1.has(Attachment.Reflect).should.be.true
        @battle.endTurn()
      @team1.has(Attachment.Reflect).should.be.false

  describe "Eviolite", ->
    it "boosts defense and special defense by 50% if holder can evolve", ->
      shared.create.call(this, team1: [Factory('Magikarp')])
      defense = @p1.stat('defense')
      specialDefense = @p1.stat('specialDefense')
      @p1.setItem(Item.Eviolite)
      @p1.stat('defense').should.equal Math.floor(1.5 * defense)
      @p1.stat('specialDefense').should.equal Math.floor(1.5 * specialDefense)

    it "boosts nothing if holder cannot evolve", ->
      shared.create.call(this, team1: [Factory('Mew')])
      defense = @p1.stat('defense')
      @p1.setItem(Item.Eviolite)
      @p1.stat('defense').should.equal(defense)
      @p1.stat('specialDefense').should.equal(defense)

  describe "Expert Belt", ->
    it "boosts attacks by x1.2 if super-effective, x1.0 otherwise", ->
      shared.create.call this,
        team1: [Factory("Magikarp", item: "Expert Belt")]
        team2: [Factory("Magikarp")]
      tackle = @battle.getMove("Tackle")
      thunder = @battle.getMove("Thunder")
      tackle.modifyAttack(@battle, @p1, @p2).should.equal(0x1000)
      thunder.modifyAttack(@battle, @p1, @p2).should.equal(0x1333)
