-- Generated by Rico8
-- Pico-8 API functions are available natively

-- struct Player
Player = {}

-- impl Player
function Player:new()
  local obj
  obj = {x = 64, y = 64, dx = 0, dy = 0, flip = false}
  setmetatable(obj, {__index = Player})
  return obj
end

-- impl Updatable for Player
function Player:update()
  if btn(0, 0)   then
    self.dx = -2
    self.flip = true
  else
    if btn(1, 0)     then
      self.dx = 2
      self.flip = false
    else
      self.dx = (self.dx * 0.8)
    end
  end
  if btn(2, 0)   then
    self.dy = -2
  else
    if btn(3, 0)     then
      self.dy = 2
    else
      self.dy = (self.dy * 0.8)
    end
  end
  self.x = (self.x + self.dx)
  self.y = (self.y + self.dy)
  if (self.x < 4)   then
    self.x = 4
  end
  if (self.x > 120)   then
    self.x = 120
  end
  if (self.y < 4)   then
    self.y = 4
  end
  if (self.y > 120)   then
    self.y = 120
  end
end

-- impl Drawable for Player
function Player:draw()
  local color = self:get_color()
  rectfill((flr(self.x) - 3), (flr(self.y) - 3), (flr(self.x) + 3), (flr(self.y) + 3), color)
end
function Player:get_color()
  return 12
end

-- trait Drawable
Drawable = {}

-- impl Drawable for Player
function Player:draw()
  local color = self:get_color()
  rectfill((flr(self.x) - 3), (flr(self.y) - 3), (flr(self.x) + 3), (flr(self.y) + 3), color)
end
function Player:get_color()
  return 12
end

-- trait Updatable
Updatable = {}

-- impl Updatable for Player
function Player:update()
  if btn(0, 0)   then
    self.dx = -2
    self.flip = true
  else
    if btn(1, 0)     then
      self.dx = 2
      self.flip = false
    else
      self.dx = (self.dx * 0.8)
    end
  end
  if btn(2, 0)   then
    self.dy = -2
  else
    if btn(3, 0)     then
      self.dy = 2
    else
      self.dy = (self.dy * 0.8)
    end
  end
  self.x = (self.x + self.dx)
  self.y = (self.y + self.dy)
  if (self.x < 4)   then
    self.x = 4
  end
  if (self.x > 120)   then
    self.x = 120
  end
  if (self.y < 4)   then
    self.y = 4
  end
  if (self.y > 120)   then
    self.y = 120
  end
end

-- struct Coin
Coin = {}

-- impl Coin
function Coin:new(x, y)
  local obj
  obj = {x = x, y = y, collected = false, anim_timer = rnd(30)}
  setmetatable(obj, {__index = Coin})
  return obj
end
function Coin:update(player)
  if self.collected   then
    return false
  end
  self.anim_timer = (self.anim_timer + 1)
  local dx = (self.x - flr(player.x))
  local dy = (self.y - flr(player.y))
  if ((abs(dx) < 6) and (abs(dy) < 6))   then
    self.collected = true
    sfx(1, -1, 0, 0)
    return true
  end
  return false
end

-- impl Drawable for Coin
function Coin:draw()
  if not self.collected   then
    local color = self:get_color()
    circfill(self.x, self.y, 3, color)
    circ(self.x, self.y, 3, 9)
  end
end
function Coin:get_color()
  return 10
end

-- struct Powerup
Powerup = {}

-- impl Powerup
function Powerup:new(x, y)
  local obj
  obj = {x = x, y = y, collected = false, active = false, timer = 0}
  setmetatable(obj, {__index = Powerup})
  return obj
end
function Powerup:check_collection(player)
  if self.collected   then
    return
  end
  local dx = (self.x - flr(player.x))
  local dy = (self.y - flr(player.y))
  if ((abs(dx) < 8) and (abs(dy) < 8))   then
    self.collected = true
    self.active = true
    self.timer = 300
    sfx(2, -1, 0, 0)
  end
end

-- impl Updatable for Powerup
function Powerup:update()
  if (self.active and (self.timer > 0))   then
    self.timer = (self.timer - 1)
    if (self.timer == 0)     then
      self.active = false
    end
  end
end

-- impl Drawable for Powerup
function Powerup:draw()
  if not self.collected   then
    local color = self:get_color()
    circfill(self.x, self.y, 4, color)
    pset((self.x - 6), self.y, color)
    pset((self.x + 6), self.y, color)
    pset(self.x, (self.y - 6), color)
    pset(self.x, (self.y + 6), color)
  end
end
function Powerup:get_color()
  return 8
end

-- enum GameState
Title = {
  tag = "Title"
}
Playing = {
  tag = "Playing"
}
GameOver = {
  tag = "GameOver"
}
Victory = {
  tag = "Victory"
}

-- struct Game
Game = {}

game = nil

function _init()
  game = {state = Title, player = Player:new(), coins = {}, powerup = Powerup:new(60, 60), score = 0, time = 0}
  setup_level()
  music(0, 0, 0)
end

function setup_level()
  game.coins = {}
  for i=0,10   do
    local x = (10 + ((i * 10) % 100))
    local y = (20 + ((i * 7) % 80))
    add(game.coins, Coin:new(x, y))
  end
  game.powerup = Powerup:new(60, 60)
end

function _update()
  local __match = game.state
  if __match.tag == "Title"   then
        (function()
      if (btnp(4, 0) or btnp(5, 0))       then
        game.state = Playing
        game.score = 0
        game.time = 0
        game.player = Player:new()
        setup_level()
      end
    end)()
  elseif __match.tag == "Playing"   then
        (function()
      game.time = (game.time + 1)
      game.player:update()
      game.powerup:update()
      game.powerup:check_collection(game.player)
      for _,coin in pairs(game.coins)       do
        if coin:update(game.player)         then
          if game.powerup.active           then
            game.score = (game.score + 20)
          else
            game.score = (game.score + 10)
          end
        end
      end
      local all_collected = true
      local has_coins = false
      for _,coin in pairs(game.coins)       do
        has_coins = true
        if not coin.collected         then
          all_collected = false
        end
      end
      if (all_collected and has_coins)       then
        game.state = Victory
        music(-1, 0, 0)
        sfx(4, -1, 0, 0)
      end
    end)()
  elseif __match.tag == "GameOver"   then
        (function()
      if (btnp(4, 0) or btnp(5, 0))       then
        game.state = Title
        music(0, 0, 0)
      end
    end)()
  elseif __match.tag == "Victory"   then
        (function()
      if (btnp(4, 0) or btnp(5, 0))       then
        game.state = Title
        music(0, 0, 0)
      end
    end)()
  end
end

function _draw()
  cls(1)
  local __match = game.state
  if __match.tag == "Title"   then
        (function()
      print("RICO8 EXAMPLE", 24, 40, 7)
      print("COLLECT ALL COINS!", 20, 50, 10)
      print("ARROW KEYS TO MOVE", 20, 64, 6)
      print("PRESS O TO START", 24, 88, 11)
    end)()
  elseif __match.tag == "Playing"   then
        (function()
      cls(1)
      for _,coin in pairs(game.coins)       do
        coin:draw()
      end
      game.powerup:draw()
      game.player:draw()
      rectfill(0, 0, 127, 7, 0)
      print(("SCORE: " .. tostr(game.score, false)), 2, 1, 7)
      print((("TIME: " .. tostr(flr((game.time / 30)), false)) .. "s"), 80, 1, 7)
      if game.powerup.active       then
        print("2X!", 60, 1, 8)
      end
    end)()
  elseif __match.tag == "GameOver"   then
        (function()
      rectfill(20, 48, 107, 80, 0)
      rect(20, 48, 107, 80, 8)
      print("GAME OVER", 44, 56, 8)
      print(("SCORE: " .. tostr(game.score, false)), 36, 66, 7)
      print("PRESS O TO RETRY", 24, 96, 11)
    end)()
  elseif __match.tag == "Victory"   then
        (function()
      rectfill(20, 48, 107, 80, 0)
      rect(20, 48, 107, 80, 11)
      print("VICTORY!", 48, 56, 11)
      print(("SCORE: " .. tostr(game.score, false)), 36, 66, 7)
      print((("TIME: " .. tostr(flr((game.time / 30)), false)) .. "s"), 40, 74, 7)
      print("PRESS O TO MENU", 28, 96, 10)
    end)()
  end
end

