@ItemData = ItemData = require './data_items.json'
{Attachment, Status, VolatileAttachment} = require('../attachment')
{Weather} = require '../../../shared/weather'
{Protocol} = require '../../../shared/protocol'
util = require '../util'

@Item = Item = {}

makeItem = (name, func) ->
  if name not of ItemData
    throw new Error("Cannot extend Item '#{name}' because it does not exist.")
  condensed = name.replace(/\s+/g, '')
  class Item[condensed] extends VolatileAttachment
    @displayName: name
    displayName: name
    item: true
    (this[property] = value  for property, value of ItemData[name])
    func?.call(this)

makePinchBerry = (name, hookName, func) ->
  if !func?
    func = hookName
    hookName = "update"

  makeItem name, ->
    this.eat = (battle, eater) ->
      func.call(this, battle, eater)

    this::[hookName] = ->
      fraction     = (if @pokemon.hasAbility("Gluttony") then 1 else 2)
      activationHP = @pokemon.stat('hp') >> fraction
      if @pokemon.currentHP <= activationHP
        @constructor.eat(@battle, @pokemon)
        @pokemon.useItem()

# TODO: If the stat is maxed, does anything special happen?
#       Is the berry still consumed?
makeStatBoostBerry = (name, boosts) ->
  makePinchBerry name, (battle, eater) ->
    boostedStats = eater.boost(boosts)

makeFlavorHealingBerry = (name, stat) ->
  makeItem name, ->
    this.eat = (battle, owner) ->
      if owner.heal(Math.floor(owner.stat('hp') / 8))
        battle.cannedText('BERRY_RESTORE', owner, this)
      if owner.natureBoost(stat) < 1.0
        owner.attach(Attachment.Confusion)

    this::update = ->
      if @pokemon.currentHP <= Math.floor(@pokemon.stat('hp') / 2) && @pokemon.canHeal()
        @constructor.eat(@battle, @pokemon)
        @pokemon.useItem()

makeHealingBerry = (name, func) ->
  makeItem name, ->
    this.eat = (battle, owner) ->
      if owner.heal(func(owner))
        battle.cannedText('BERRY_RESTORE', owner, this)

    this::update = ->
      if @pokemon.currentHP <= Math.floor(@pokemon.stat('hp') / 2) && @pokemon.canHeal()
        @constructor.eat(@battle, @pokemon)
        @pokemon.useItem()

makeTypeResistBerry = (name, type) ->
  makeItem name, ->
    this.eat = ->
    this::modifyBasePowerTarget = (move, user) ->
      return 0x1000  if move.getType(@battle, user, @pokemon) != type
      return 0x1000  if util.typeEffectiveness(type, @pokemon.types) <= 1 && type != 'Normal'
      @battle.cannedText('ITEM_WEAKEN', @constructor, @pokemon)
      @pokemon.useItem()
      return 0x800

makeFeedbackDamageBerry = (name, klass) ->
  makeItem name, ->
    this.eat = ->
    this::afterBeingHit = (move, user, target) ->
      return  if !move[klass]()
      return  if target.isFainted()
      if user.damage(Math.floor(user.stat('hp') / 8))
        @battle.cannedText('POKEMON_HURT_BY_ITEM', user, target, @constructor)
      target.useItem()

makeStatusCureBerry = (name, statuses...) ->
  makeItem name, ->
    this.eat = (battle, owner) ->
      for attachment in statuses
        if owner.cureAttachment(attachment, message: name)
          return true
      return false

    this::update = ->
      if @constructor.eat(@battle, @pokemon) then @pokemon.useItem()

makeOrbItem = (name, species) ->
  makeItem name, ->
    this::modifyBasePower = (move, target) ->
      if @pokemon.species == species && move.type in @pokemon.types
        0x1333
      else
        0x1000

makeStatusOrbItem = (name, status) ->
  makeItem name, ->
    this::endTurn = ->
      @pokemon.attach(status)

makeTypeBoostItem = (name, type) ->
  makeItem name, ->
    this::modifyBasePower = (move, target) ->
      if move.type == type
        0x1333
      else
        0x1000

# Same as makeTypeBoostItem, but sets item.plate = type.
makePlateItem = (name, type) ->
  makeTypeBoostItem(name, type)
  makeItem(name, -> @plate = type)

# Gem items are one-time use.
GEM_BOOST_AMOUNT = GEM_BOOST_AMOUNT ? 0x1800
makeGemItem = (name, type) ->
  makeItem name, ->
    this::modifyBasePower = (move, target) ->
      if move.type == type
        GEM_BOOST_AMOUNT
      else
        0x1000

    this::afterSuccessfulHit = (move, user, target) ->
      if move.type == type
        @battle.cannedText('GEM_BOOST', @constructor, move)
        user.useItem()

makeChoiceItem = (name, func) ->
  makeItem name, ->
    this::initialize = ->
      @move = null

    this::beforeMove = (move, user, targets) ->
      @move = move
      true

    this::beginTurn = ->
      @pokemon.lockMove(@move)  if @move?

    func.call(this)

makeWeatherItem = (name, weather) ->
  makeItem name, ->
    @lengthensWeather = weather

makeSpeciesBoostingItem = (name, speciesArray, statsHash) ->
  makeItem name, ->
    for stat, boost of statsHash
      capitalizedStat = stat[0].toUpperCase() + stat.substr(1)
      # TODO: Use modifiers
      this::["edit#{capitalizedStat}"] = (stat) ->
        isTransformed = @pokemon.has(Attachment.Transform)
        if @pokemon.species in speciesArray && !isTransformed
          Math.floor(stat * boost)
        else
          stat

makeSpeciesCriticalItem = (name, species) ->
  makeItem name, ->
    this::criticalModifier = (sum) ->
      sum + (if @pokemon.species == species then 2 else 0)

makeDelayItem = (name) ->
  makeItem name, ->
    this::afterTurnOrder = ->
      @battle.delay(@pokemon)

makeEvasionItem = (name, ratio=0.9) ->
  makeItem name, ->
    this::editEvasion = (accuracy) ->
      Math.floor(accuracy * ratio)

makeFlinchItem = (name) ->
  makeItem name, ->
    this::afterSuccessfulHit = (move, user, target) ->
      multiplier = (if user.hasAbility("Serene Grace") then 2 else 1)
      if move.flinchChance == 0 && !move.isNonDamaging() &&
          @battle.rng.next("flinch item chance") < .1 * multiplier
        target.attach(Attachment.Flinch)

makeCriticalBoostItem = (name) ->
  makeItem name, ->
    this::criticalModifier = (sum) -> sum + 1

makeBoostOnTypeItem = (name, type, boosts) ->
  stats = Object.keys(boosts)
  length = stats.length
  stats = stats.map (stat) ->
    stat[0].toUpperCase() + stat[1...length].replace(/[A-Z]/g, " $1")
  stats[length - 1] = "and #{stats[length - 1]}"  if length >= 2
  stats = stats.join(", ")  if length >= 3
  stats = stats.join(" ")   if length == 2
  makeItem name, ->
    this::afterBeingHit = (move, user, target) ->
      if move.type == type
        @battle.cannedText('BERRY_RAISE_STAT', @constructor, user, stats)
        target.boost(boosts)
        target.useItem()

makeBoostOnTypeItem 'Absorb Bulb', 'Water', specialAttack: 1

makeOrbItem 'Adamant Orb', 'Dialga'
makeFlavorHealingBerry 'Aguav Berry', "specialDefense"

makeItem 'Air Balloon', ->
  this::initialize = ->
    @pokemon.tell(Protocol.POKEMON_ATTACH, @displayName)

  this::afterBeingHit = (move, user, target) ->
    return  if move.isNonDamaging()
    @pokemon.tell(Protocol.POKEMON_UNATTACH, @displayName)
    target.removeItem()

  this::isImmune = (type) ->
    return true  if type == 'Ground'

makeStatBoostBerry 'Apicot Berry', specialDefense: 1
makeStatusCureBerry 'Aspear Berry', Status.Freeze
makeTypeResistBerry 'Babiri Berry', 'Steel'
makeHealingBerry 'Berry Juice', -> 20
makeTypeBoostItem 'Black Belt', 'Fighting'
makeTypeBoostItem 'BlackGlasses', 'Dark'

makeItem 'Black Sludge', ->
  this::endTurn = ->
    maxHP = @pokemon.stat('hp')
    if @pokemon.hasType('Poison')
      return  if maxHP == @pokemon.currentHP
      amount = Math.floor(maxHP / 16)
      amount = 1  if amount == 0
      if @pokemon.heal(amount)
        @battle.cannedText('ITEM_RESTORE', @pokemon, @constructor)
    else
      amount = Math.floor(maxHP / 8)
      amount = 1  if amount == 0
      if @pokemon.damage(amount)
        @battle.cannedText('ITEM_SELF_HURT', @pokemon, @constructor)

makeEvasionItem 'BrightPowder', 0.9
makeGemItem 'Bug Gem', 'Bug'
makeBoostOnTypeItem 'Cell Battery', 'Electric', attack: 1
makeTypeBoostItem 'Charcoal', 'Fire'
makeTypeResistBerry 'Charti Berry', 'Rock'
makeStatusCureBerry 'Cheri Berry', Status.Paralyze
makeStatusCureBerry 'Chesto Berry', Status.Sleep
makeTypeResistBerry 'Chilan Berry', 'Normal'
makeChoiceItem 'Choice Band', ->
  this::modifyAttack = (move) ->
    if move.isPhysical() then 0x1800 else 0x1000

makeChoiceItem 'Choice Specs', ->
  this::modifyAttack = (move) ->
    if move.isSpecial() then 0x1800 else 0x1000

makeChoiceItem 'Choice Scarf', ->
  this::editSpeed = (stat) ->
    Math.floor(stat * 1.5)

makeTypeResistBerry 'Chople Berry', 'Fighting'
makeTypeResistBerry 'Coba Berry', 'Flying'
makeTypeResistBerry 'Colbur Berry', 'Dark'

makePinchBerry 'Custap Berry', 'afterTurnOrder', (battle, eater) ->
  battle.cannedText('MOVE_FIRST', eater, this)
  battle.bump(eater)

makeWeatherItem 'Damp Rock', Weather.RAIN
makeWeatherItem 'Dark Rock', Weather.MOON
makeGemItem 'Dark Gem', 'Dark'
makeTypeBoostItem 'Dragon Fang', 'Dragon'
makeGemItem 'Dragon Gem', 'Dragon'
makePlateItem 'Draco Plate', 'Dragon'
makePlateItem 'Dread Plate', 'Dark'
makePlateItem 'Earth Plate', 'Ground'

makeItem 'Eject Button', ->
  this::afterAllHitsTarget = (move, user) ->
    return  if move.isNonDamaging()
    return  if !@battle.forceSwitch(@pokemon)
    @battle.cannedText('EJECT_BUTTON', @pokemon)
    @pokemon.useItem()

makeGemItem 'Electric Gem', 'Electric'

makeItem 'Enigma Berry', ->
  this.eat = ->
  this::afterBeingHit = (move, user, target) ->
    return  if util.typeEffectiveness(move.type, target.types) <= 1
    if target.heal(Math.floor(target.stat('hp') / 4))
      @battle.cannedText('BERRY_RESTORE', target, @constructor)
      target.useItem()

makeItem 'Eviolite', ->
  this::editDefense = this::editSpecialDefense = (defense) ->
    return Math.floor(1.5 * defense)  if @pokemon.nfe
    return defense

makeItem 'Expert Belt', ->
  this::modifyAttack = (move, target) ->
    effectiveness = move.typeEffectiveness(@battle, @pokemon, target)
    return 0x1333  if effectiveness > 1
    return 0x1000

makeGemItem 'Fighting Gem', 'Fighting'
makeFlavorHealingBerry 'Figy Berry', "attack"
makeGemItem 'Fire Gem', 'Fire'
makePlateItem 'Fist Plate', 'Fighting'
makeStatusOrbItem 'Flame Orb', Status.Burn
makePlateItem 'Flame Plate', 'Fire'
makeItem 'Float Stone', ->
  this::calculateWeight = (weight) ->
    Math.floor(weight / 2)
makeGemItem 'Flying Gem', 'Flying'

makeItem 'Focus Band', ->
  this::transformHealthChange = (amount, options) ->
    if amount >= @pokemon.currentHP && @battle.rng.randInt(0, 9, "focus band") == 0 &&
        options.source == 'move'
      @battle.cannedText('HANG_ON', @pokemon, @constructor)
      @pokemon.useItem()
      return @pokemon.currentHP - 1
    return amount

makeItem 'Focus Sash', ->
  this::transformHealthChange = (amount, options) ->
    maxHP = @pokemon.stat('hp')
    if @pokemon.currentHP == maxHP && amount >= maxHP && options.source == 'move'
      @battle.cannedText('HANG_ON', @pokemon, @constructor)
      @pokemon.useItem()
      return maxHP - 1
    return amount

makeDelayItem 'Full Incense'
makeStatBoostBerry 'Ganlon Berry', defense: 1
makeGemItem 'Ghost Gem', 'Ghost'
makeGemItem 'Grass Gem', 'Grass'
makeOrbItem 'Griseous Orb', 'Giratina'
makeGemItem 'Ground Gem', 'Ground'
makeTypeResistBerry 'Haban Berry', 'Dragon'
makeTypeBoostItem 'Hard Stone', 'Rock'
makeWeatherItem 'Heat Rock', Weather.SUN
makeFlavorHealingBerry 'Iapapa Berry', "defense"
makeGemItem 'Ice Gem', 'Ice'
makePlateItem 'Icicle Plate', 'Ice'
makeWeatherItem 'Icy Rock', Weather.HAIL
makePlateItem 'Insect Plate', 'Bug'
makePlateItem 'Iron Plate', 'Steel'
makeFeedbackDamageBerry 'Jaboca Berry', 'isPhysical'
makeTypeResistBerry 'Kasib Berry', 'Ghost'
makeTypeResistBerry 'Kebia Berry', 'Poison'
makeFlinchItem "King's Rock"
makeDelayItem 'Lagging Tail'

# TODO: What happens if the Pokemon already has Focus Energy?
#       Does the berry still get eaten? Same goes for the other stat berries.
makePinchBerry 'Lansat Berry', (battle, eater) ->
  eater.attach(Attachment.FocusEnergy)

makeEvasionItem 'Lax Incense', 0.9

makeItem 'Leftovers', ->
  this::endTurn = ->
    maxHP = @pokemon.stat('hp')
    return  if maxHP == @pokemon.currentHP
    amount = Math.floor(maxHP / 16)
    amount = 1  if amount == 0
    if @pokemon.heal(amount)
      @battle.cannedText('ITEM_RESTORE', @pokemon, @constructor)

makeStatBoostBerry 'Liechi Berry', attack: 1

makeItem 'Life Orb', ->
  this::modifyAttack = ->
    0x14CC

  this::afterAllHits = (move) ->
    return  if move.isNonDamaging()
    if @pokemon.damage(Math.floor(@pokemon.stat('hp') / 10))
      @battle.cannedText('ITEM_SELF_HURT', @pokemon, @constructor)

makeItem 'Light Clay' # Hardcoded in Attachment.Screen

makeStatusCureBerry 'Lum Berry', Status.Paralyze, Status.Sleep, Status.Poison,
  Status.Toxic, Status.Burn, Status.Freeze, Attachment.Confusion
makeOrbItem 'Lustrous Orb', 'Palkia'
makeItem 'Macho Brace', ->
  this::editSpeed = (stat) ->
    Math.floor(stat / 2)
makeTypeBoostItem 'Magnet', 'Electric'
makeFlavorHealingBerry 'Mago Berry', "speed"
makePlateItem 'Meadow Plate', 'Grass'

makeItem 'Mental Herb', ->
  this.activate = (battle, pokemon) ->
    for effectName in [ 'Attract', 'Taunt', 'Encore', 'Torment', 'Disable' ]
      attachment = Attachment[effectName]
      if pokemon.has(attachment)
        battle.cannedText('MENTAL_HERB', pokemon)
        pokemon.unattach(attachment)
        return true
    return false

  this::update = ->
    if @constructor.activate(@battle, @pokemon)
      @pokemon.useItem()

makeTypeBoostItem 'Metal Coat', 'Steel'

makeItem 'Metronome', ->
  this::modifyBasePower = (move, target) ->
    attachment = @pokemon.get(Attachment.Metronome)
    layers = attachment?.layers || 0
    0x1000 + layers * 0x333

  this::afterSuccessfulHit = (move, user, target) ->
    user.attach(Attachment.Metronome, {move})

makePinchBerry 'Micle Berry', (battle, eater) ->
  eater.attach(Attachment.MicleBerry)

makePlateItem 'Mind Plate', 'Psychic'
makeTypeBoostItem 'Miracle Seed', 'Grass'

makeItem 'Muscle Band', ->
  this::modifyBasePower = (move, target) ->
    if move.isPhysical()
      0x1199
    else
      0x1000

makeTypeBoostItem 'Mystic Water', 'Water'
makeTypeBoostItem 'NeverMeltIce', 'Ice'
makeGemItem 'Normal Gem', 'Normal'
makeTypeResistBerry 'Occa Berry', 'Fire'
makeTypeBoostItem 'Odd Incense', 'Psychic'
makeHealingBerry 'Oran Berry', -> 10
makeTypeResistBerry 'Passho Berry', 'Water'
makeTypeResistBerry 'Payapa Berry', 'Psychic'
makeStatusCureBerry 'Pecha Berry', Status.Toxic, Status.Poison
makeStatusCureBerry 'Persim Berry', Attachment.Confusion
makeStatBoostBerry 'Petaya Berry', specialAttack: 1
makeTypeBoostItem 'Poison Barb', 'Poison'
makeGemItem 'Poison Gem', 'Poison'
makeGemItem 'Psychic Gem', 'Psychic'

makeItem 'Quick Claw', ->
  this::afterTurnOrder = ->
    if @battle.rng.next("quick claw") < .2
      @battle.cannedText('MOVE_FIRST', @pokemon, @constructor)
      @battle.bump(@pokemon)

makeStatusCureBerry 'Rawst Berry', Status.Burn
makeFlinchItem "Razor Fang"

makeItem 'Red Card', ->
  this::afterAllHitsTarget = (move, user) ->
    return  if move.isNonDamaging()
    benched  = user.team.getAliveBenchedPokemon()
    return  if benched.length == 0
    @battle.cannedText('RED_CARD', @pokemon, user)
    @pokemon.useItem()
    return  if user.shouldPhase(@battle, @pokemon) == false
    pokemon = @battle.rng.choice(benched)
    index = user.team.indexOf(pokemon)
    user.team.switch(user, index)

makeTypeResistBerry 'Rindo Berry', 'Grass'
makeGemItem 'Rock Gem', 'Rock'

makeItem 'Rocky Helmet', ->
  this::isAliveCheck = -> true

  this::afterBeingHit = (move, user, target) ->
    if move.hasFlag("contact")
      amount = Math.floor(user.stat('hp') / 6)
      if user.damage(amount)
        @battle.cannedText('POKEMON_HURT_BY_ITEM', user, target, @constructor)

makeTypeBoostItem 'Rock Incense', 'Rock'
makeTypeBoostItem 'Rose Incense', 'Grass'
makeFeedbackDamageBerry 'Rowap Berry', 'isSpecial'
makeStatBoostBerry 'Salac Berry', speed: 1
makeTypeBoostItem 'Sea Incense', 'Water'
makeTypeBoostItem 'Sharp Beak', 'Flying'

makeItem 'Shell Bell', ->
  this::afterSuccessfulHit = (move, user, target, damage) ->
    return  if damage == 0
    if user.heal(Math.floor(damage / 8))
      @battle.cannedText('ITEM_RESTORE', user, @constructor)

makeTypeResistBerry 'Shuca Berry', 'Ground'
makeTypeBoostItem 'Silk Scarf', 'Normal'
makeTypeBoostItem 'SilverPowder', 'Bug'
makeHealingBerry 'Sitrus Berry', (owner) -> Math.floor(owner.stat('hp') / 4)
makePlateItem 'Sky Plate', 'Flying'
makeWeatherItem 'Smooth Rock', Weather.SAND
makeTypeBoostItem 'Soft Sand', 'Ground'
makeSpeciesBoostingItem 'Soul Dew', ["Latias", "Latios"],
  specialAttack: 1.5, specialDefense: 1.5
makeTypeBoostItem 'Spell Tag', 'Ghost'
makePlateItem 'Splash Plate', 'Water'
makePlateItem 'Spooky Plate', 'Ghost'

# TODO: If there is no stat left to boost, is it still consumed?
makePinchBerry 'Starf Berry', (battle, eater) ->
  stats = ["attack", "defense", "specialAttack", "specialDefense", "speed"]
  stats = stats.filter((stat) -> eater.stages[stat] != 6)
  return  if stats.length == 0
  index = battle.rng.randInt(0, stats.length - 1, "starf berry stat")
  boosts = {}
  boosts[stats[index]] = 2
  boostedStats = eater.boost(boosts)

makeItem 'Sticky Barb', ->
  this::afterBeingHit = (move, user, target) ->
    return  unless move.hasFlag("contact")
    return  if user.hasItem()
    user.setItem(@constructor)
    target.useItem()

  this::endTurn = ->
    @pokemon.damage(Math.floor(@pokemon.stat('hp') / 8))

makeGemItem 'Steel Gem', 'Steel'
makePlateItem 'Stone Plate', 'Rock'
makeTypeResistBerry 'Tanga Berry', 'Bug'
makeStatusOrbItem 'Toxic Orb', Status.Toxic
makePlateItem 'Toxic Plate', 'Poison'
makeTypeBoostItem 'TwistedSpoon', 'Psychic'
makeTypeResistBerry 'Wacan Berry', 'Electric'
makeGemItem 'Water Gem', 'Water'
makeTypeBoostItem 'Wave Incense', 'Water'

# TODO: What if White Herb is tricked onto a Pokemon? Are all boosts negated?
makeItem 'White Herb', ->
  this.activate = (battle, pokemon) ->
    triggered = false
    boosts = {}
    for stat, boost of pokemon.stages
      if boost < 0
        triggered = true
        boosts[stat] = 0
    if triggered
      pokemon.setBoosts(boosts)
      battle.cannedText('WHITE_HERB', pokemon)
    return triggered

  this::update = ->
    if @constructor.activate(@battle, @pokemon)
      @pokemon.useItem()

makeItem "Wide Lens", ->
  this::editAccuracy = (accuracy) ->
    Math.floor(accuracy * 1.1)

makeFlavorHealingBerry 'Wiki Berry', "specialAttack"

makeItem 'Wise Glasses', ->
  this::modifyBasePower = (move, target) ->
    if move.isSpecial()
      0x1199
    else
      0x1000

makeTypeResistBerry 'Yache Berry', 'Ice'
makePlateItem 'Zap Plate', 'Electric'

makeItem 'Zoom Lens', ->
  this::editAccuracy = (accuracy, move, target) ->
    return Math.floor(accuracy * 1.2)  if @battle.willMove(target)
    return accuracy

makeSpeciesBoostingItem("DeepSeaTooth", ["Clamperl"], specialAttack: 2)
makeSpeciesBoostingItem("DeepSeaScale", ["Clamperl"], specialDefense: 2)
makeSpeciesBoostingItem("Light Ball", ["Pikachu"], attack: 2, specialAttack: 2)
makeSpeciesBoostingItem("Thick Club", ["Cubone", "Marowak"], attack: 2)
makeSpeciesBoostingItem("Metal Powder", ["Ditto"],
  defense: 2, specialDefense: 2)
makeSpeciesBoostingItem("Quick Powder", ["Ditto"], speed: 2)

makeSpeciesCriticalItem "Lucky Punch", "Chansey"
makeSpeciesCriticalItem "Stick", "Farfetch'd"

makeCriticalBoostItem 'Razor Claw'
makeCriticalBoostItem 'Scope Lens'

makeItem 'Iron Ball', ->
  this::editSpeed = (stat) ->
    Math.floor(stat / 2)

  this::isImmune = (type) ->
    return false  if type == 'Ground'

makeItem 'Leppa Berry', ->
  this.eat = (battle, eater) ->
    for move in eater.moves
      if eater.pp(move) == 0
        eater.setPP(move, 10)
        break

  this::update = ->
    if @pokemon.lastMove? && @pokemon.pp(@pokemon.lastMove) == 0
      @constructor.eat(@battle, @pokemon)
      @pokemon.useItem()

# TODO: Implement Nature Power and implement eat there.
for berry in "Belue Berry, Bluk Berry, Cornn Berry, Durin Berry, Grepa Berry,
              Hondew Berry, Kelpsy Berry, Magost Berry, Nanab Berry,
              Nomel Berry, Pamtre Berry, Pinap Berry, Pomeg Berry, Qualot Berry,
              Rabuta Berry, Razz Berry, Spelon Berry, Tamato Berry,
              Watmel Berry, Wepear Berry".split(/,\s+/)
  makeItem berry, ->
    this.eat = ->

# Ensure we aren't purposefully missing berries that need an `eat` function.
for name, item of Item
  if item.type == 'berries' && 'eat' not of item
    console.warn "Note: Item '#{item.displayName}' does not have `eat` implemented."

# Make all leftover items
for itemName of ItemData
  makeItem(itemName)  if itemName.replace(/\s+/, '') not of Item
