-- Gallery #7 (Total-conversion team): the smallest thing that is
-- recognizably a different game.  Its own boot config, its own title
-- screen, its own three-species dex, its own single badge, and one map.
--
-- LEGAL POSTURE (constraint 1): the Red import still runs and supplies the
-- fallback infrastructure this conversion sits on -- the OVERWORLD tileset,
-- the font, the move table.  The conversion overrides on top.  Every pixel
-- under assets/ is original work generated by tools/make_assets.py; nothing
-- here transforms extracted Red art into "new" content.
local MAP = "SABLE_COVE"
local BADGE = "SABLE_TIDE_BADGE"

-- three original species; ids are namespaced so a mixed load cannot
-- collide with Red's
local DEX = {
  { id = "SABLE_EMBERKIT", name = "EMBERKIT", dex = 1, art = "emberkit",
    types = { "FIRE" }, stats = { hp = 45, attack = 60, defense = 40,
                                  speed = 65, special = 50 } },
  { id = "SABLE_TIDEPUP", name = "TIDEPUP", dex = 2, art = "tidepup",
    types = { "WATER" }, stats = { hp = 50, attack = 48, defense = 60,
                                   speed = 45, special = 55 } },
  { id = "SABLE_MOSSLING", name = "MOSSLING", dex = 3, art = "mossling",
    types = { "GRASS", "POISON" }, stats = { hp = 55, attack = 50,
                                             defense = 55, speed = 40,
                                             special = 60 } },
}

return function(mod)
  local ChipAsm = require("src.audio.ChipAsm")

  -- ------- species, cries and icons

  for _, entry in ipairs(DEX) do
    mod.content.pokemon:register(entry.id, {
      id = entry.id,
      name = entry.name,
      dex = entry.dex,
      types = entry.types,
      baseStats = entry.stats,
      catchRate = 190,
      baseExp = 64,
      growthRate = "MEDIUM_FAST",
      level1Moves = { "TACKLE" },
      learnset = {
        { level = 7, move = "GROWL" },
        { level = 13, move = "QUICK_ATTACK" },
      },
      evolutions = {},
      spriteFront = mod.path .. "/assets/" .. entry.art .. "_front.png",
      spriteBack = mod.path .. "/assets/" .. entry.art .. "_back.png",
      frontSize = 5,
      cry = entry.id,
      icon = { image = mod.path .. "/assets/" .. entry.art .. "_icon.png",
               frames = 2 },
    })

    -- one authored chip effect per species, keyed by species id exactly
    -- like the vanilla cry table
    mod.content.cries:register(entry.id, {
      chip = ChipAsm.sfx{
        channels = { { hw = 1, program = {
          { pitchSweep = { pace = 2 + entry.dex, subtract = entry.dex == 2,
                           shift = 3 } },
          { squareNote = { len = 5, volume = 13, fade = 2,
                           frequency = 0x480 + entry.dex * 0x60 } },
        } } },
      }.chip,
      pitch = 128, length = 128,
    })

    mod.content.icons:register(entry.id, {
      image = mod.path .. "/assets/" .. entry.art .. "_icon.png",
      frames = 2,
    })
  end

  -- ------- the badge, which is an item like every vanilla badge

  mod.content.items:register(BADGE, {
    id = BADGE, name = "TIDEBADGE", price = 0, keyItem = true, tossable = false,
  })

  -- ------- the rules the engine used to hard-code
  -- deep registry: register and patch are the same verb, and only the keys
  -- named here move.  Everything else keeps its imported value.

  mod.content.constants:patch("dexSize", #DEX)
  mod.content.constants:patch("dexDigits", 1)
  mod.content.constants:patch("levelCap", 50)
  -- override, not patch: under deep semantics a list APPENDS, so patching
  -- here would leave Kanto's eight badges in front of this one.  override
  -- is the verb that drops a list, which is exactly what a conversion wants
  mod.content.constants:override("badges", { { id = BADGE, name = "TIDE" } })
  mod.content.constants:override("hmMoves", { "CUT", "SURF" })

  -- ------- the one map

  local blocks = {}
  for i = 1, 10 * 9 do blocks[i] = 1 end
  mod.content.maps:register(MAP, {
    id = MAP,
    label = "SableCove",
    index = 1000,
    tileset = "OVERWORLD",
    width = 10, height = 9,
    blocks = blocks,
    borderBlock = 11,
    warps = {}, objects = {}, signs = {},
  })

  mod.content.encounters:register(MAP, {
    grass = { rate = 25, slots = {
      { level = 3, species = "SABLE_EMBERKIT" },
      { level = 3, species = "SABLE_TIDEPUP" },
      { level = 3, species = "SABLE_MOSSLING" },
      { level = 4, species = "SABLE_TIDEPUP" },
      { level = 4, species = "SABLE_MOSSLING" },
      { level = 5, species = "SABLE_EMBERKIT" },
      { level = 5, species = "SABLE_TIDEPUP" },
      { level = 5, species = "SABLE_MOSSLING" },
      { level = 6, species = "SABLE_EMBERKIT" },
      { level = 6, species = "SABLE_MOSSLING" },
    } },
  })

  -- ------- the new game itself

  mod.content.field:patch("boot", {
    startMap = MAP, startX = 5, startY = 4, startFacing = "down",
    playerName = "SABLE", rivalName = "CORAL",
    startMoney = 1500,
    lastHeal = { map = MAP, x = 5, y = 4 },
    namePresets = { player = { "SABLE", "WREN", "PIKE" },
                    rival = { "CORAL", "REEF", "SHOAL" } },
    -- the conversion owns the boot flow; splash and newGame keep the
    -- engine screens, which is the point of naming them individually
    screens = { title = "SableTitle" },
  })

  -- ------- the title screen

  mod.content.screens:register("SableTitle", {
    new = function(game, opts)
      opts = opts or {}
      local Font = mod.ui.Font
      local state = { game = game, isOpaque = true, blink = 0 }

      function state:update()
        self.blink = (self.blink + 1) % 60
        local input = game.input
        if not input then return end
        if input:wasPressed("a") or input:wasPressed("start") then
          if opts.onNewGame then opts.onNewGame() end
        end
      end

      function state:draw()
        love.graphics.setColor(1, 1, 1, 1)
        love.graphics.rectangle("fill", 0, 0, 160, 144)
        love.graphics.setColor(0, 0, 0, 1)
        Font.draw("SABLE COVE", 40, 40)
        Font.draw("A MINI CONVERSION", 12, 56)
        if self.blink < 40 then Font.draw("PRESS A", 52, 104) end
      end

      return state
    end,
  })

  mod.events:on("game.ready", function(ev)
    -- the payload carries the live Game; a conversion uses it to check
    -- that its own boot config actually took
    local boot = ev.game and ev.game.data and ev.game.data.field
      and ev.game.data.field.boot
    if not (boot and boot.startMap == MAP) then
      mod.log:warn("another mod owns field.boot; raise this mod's priority "
        .. "above %s to win the merge", tostring(boot and boot.startMap))
    end
  end)
end
