0  0 H@Î@Hï™HÿÎa²ðm;É]o66o;]ÉyÎöôôô¶ÆÖy•ª8@a4à                                 fweVWgvvÕÕW\ÌÝÝÜÝÝÝÝÝÍÜÝÝÍÜÍÜÝÝÝÜÝÝÜÝÍÝÝÝÌÝÌÝÝÝÝÝÝÝÝÝÍÜÜÝÍÜÝÜÝÝÝD3D3 3 @  4C44   4         D34C@   @ C4C4                3D3D 3 0  0C4C@   C   C   0   0D34C@   D C4                                                                                                                                                                                                                                                                                                                       °  KD  K4  K4  D4  0                                                                                                                                                                                                                                                                                                                                                                                                     ªª¤ªºªª«ª«ºª¤:£ªª:£JJªªªªª¤ª¤ªª¤ªªªª*""ª"""¢"DD¢BI”¢JDDªzw§ªºª«ª@      "" """"D$BDD@DD pww ° °      "" """"DDBDD@DD °w  °       "" """"DDBDD@DD pw     "" """"D$BDD@DD pww                    "" """"D$@DD °w·      "" BDDBDDBDDpww pww ° °  "  ""  D$  D$  D$  w  w        " """ "D$ BD$ @D pw °°                                                                                                                                                                                                                                                   		                     °   +³  0                         °;´ @                          K² °                                                                                                                                                                                                                                                                                                                                                                                                                                                  °  KD  K4  K4  D4  0          °  °  °  °  @  0                                                                                                                                                                                                                                                                                                                                                                                                                                                                                """"0@ @ @0""""""""0   @  0  @  0 @  """"                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                �À?                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     fweV                                                   @                                                                Wgvv                                                                                                                    ÕÕW\                                                                                                                    ÌÝÝÜ                                                                                                                    ÝÝÝÝ                                                                                                                    ÝÍÜÝ                                                                                                                    ÝÍÜÍ                                                                                                                    ÜÝÝÝ                                                                                                                    ÜÝÝÜ                                                                                                                    ÝÍÝÝ                                                    °;´                                                            ÝÌÝÌ                                                     @                                                             ÝÝÝÝ                                                                                                                    ÝÝÝÝ                                                                                                                    ÝÍÜÜ                                                                                                                    ÝÍÜÝ                                                                                                                    ÜÝÝÝ                                                                fweV    fweV    fweV                                ÜÝÝÜ                                                                Wgvv    Wgvv    Wgvv                                ÝÍÝÝ                                                                ÕÕW\    ÕÕW\    ÕÕW\                                ÝÌÝÌ                                                                ÌÝÝÜ    ÌÝÝÜ    ÌÝÝÜ                                ÝÝÝÝ                                                                ÝÝÝÝ    ÝÝÝÝ    ÝÝÝÝ                                ÝÝÝÝ                                                                ÝÍÜÝ    ÝÍÜÝ    ÝÍÜÝ                                ÝÍÜÜ                                                              ÝÍÜÍ    ÝÍÜÍ    ÝÍÜÍ                                ÝÍÜÝ                                                                ÜÝÝÝ    ÜÝÝÝ    ÜÝÝÝ                                ÜÝÝÝ                    fweV    fweV    fweV    fweV                                            fweVD3D3D34CD34CD34C3D3DÍÝÝÍ                    Wgvv    Wgvv    Wgvv    Wgvv                                            Wgvv 3 @  @  @   3 0ÝÝÜÝ                    ÕÕW\    ÕÕW\    ÕÕW\    ÕÕW\                                            ÕÕW\@   @  @  @   0ÌÝÌÝ                    ÌÝÝÜ    ÌÝÝÜ    ÌÝÝÜ    ÌÝÝÜ                                            ÌÝÝÜ4C4C4C4C4C4C4C4C4C@ÝÝÝÝ                    ÝÝÝÝ    ÝÝÝÝ    ÝÝÝÝ    ÝÝÝÝ                                            ÝÝÝÝ4                  CÝÝÝÝ                    ÝÍÜÝ    ÝÍÜÝ    ÝÍÜÝ    ÝÍÜÝ                                            ÝÍÜÝ4                  CÍÍÜÝ                    ÝÍÜÍ    ÝÍÜÍ    ÝÍÜÍ    ÝÍÜÍ                                            ÝÍÜÍ                  0ÝÍÜÝ                    ÜÝÝÝ    ÜÝÝÝ    ÜÝÝÝ    ÜÝÝÝ                                            ÜÝÝÝ                  0ÝÝÝÍ                                                                                            ÍÝÝÍ                    ÜÝÝÍ                                                                                            ÝÝÜÝ         °         ÝÝÝÝ                                                                                            ÌÝÌÝ         KD         ÝÝÍÝ                                                                                            ÝÝÝÝ         K4         ÍÜÍÜ                                                                                            ÝÝÝÝ         K4         ÍÜÝÝ                                                                                            ÍÍÜÝ         D4         ÝÝÝÝ                                                                                            ÝÍÜÝ         0         ÝÜÍÍ                                                                                            ÝÝÝÍ                    ÝÝÍÝ                                                                                            ÜÝÝÍ                    ÜÝÝÜ                                                                                            ÝÝÝÝ                    ÝÍÝÝ                                                                                            ÝÝÍÝ                    ÝÌÝÌ                                                                                            ÍÜÍÜ                    ÝÝÝÝ                                                                                            ÍÜÝÝ                    ÝÝÝÝ                                                                                            ÝÝÝÝ                    ÝÍÜÜ                                                                                            ÝÜÍÍ                    ÝÍÜÝ                                                                                            ÝÝÍÝ                    ÜÝÝÝfweV                                                                                        ÜÝÝÜ                    ÜÝÝÍWgvv                                                                                        ÝÍÝÝ                    ÝÝÝÝÕÕW\                                                                                        ÝÌÝÌ                    ÝÜÝÝÌÝÝÜ                                                                                        ÝÝÝÝ                    ÍÜÍÜÝÝÝÝ                                                                                        ÝÝÝÝ                    ÝÝÍÜÝÍÜÝ                                                                                        ÝÍÜÜ                    ÝÝÝÝÝÍÜÍ                                                                                        ÝÍÜÝ                    ÜÜÍÝÜÝÝÝ                                                                                        ÜÝÝÝ                    ÝÜÝÝÜÝÝÍ                                                                                        ÍÝÝÍ                    ÜÝÝÍÝÝÝÝ                                                                                        ÝÝÜÝ                    ÝÝÝÝÝÜÝÝ                                                                                        ÌÝÌÝ                    ÝÜÝÝÍÜÍÜ                                                                                        ÝÝÝÝ                    ÍÜÍÜÝÝÍÜ                                                                                        ÝÝÝÝ                    ÝÝÍÜÝÝÝÝ                                                                                        ÍÍÜÝ                    ÝÝÝÝÜÜÍÝ                                                                                        ÝÍÜÝ                    ÜÜÍÝÝÜÝÝ                                                                                        ÝÝÝÍ                    ÝÜÝÝÜÝÝÜ                                                                                        ÜÝÝÍ                    ÜÝÝÜÝÍÝÝ                                                                                        ÝÝÝÝ                    ÝÍÝÝÝÌÝÌ                            °K³                                                        ÝÝÍÝ                    ÝÌÝÌÝÝÝÝ                                                                                       ÍÜÍÜ                    ÝÝÝÝÝÝÝÝ                                                                                        ÍÜÝÝ                    ÝÝÝÝÝÍÜÜ                                                                                        ÝÝÝÝ                    ÝÍÜÜÝÍÜÝ                                                                                        ÝÜÍÍ                    ÝÍÜÝÜÝÝÝ                                                                                        ÝÝÍÝ                    ÜÝÝÝÜÝÝÍD3D3D34C                                                                               ÜÝÝÍ                    ÜÝÝÍÝÝÝÝ 3 @                                                                                  ÝÝÝÝ                    ÝÝÝÝÝÝÍÝ@   @                                                                                 ÝÝÍÝ                    ÝÜÝÝÍÜÍÜ4C4C4C4                                                                                ÍÜÍÜ                    ÍÜÍÜÍÜÝÝ4                           °                                                           ÍÜÝÝ                    ÝÝÍÜÝÝÝÝ4                                                                                       ÝÝÝÝ                    ÝÝÝÝÝÜÍÍ                                                                                       ÝÜÍÍ                    ÜÜÍÝÝÝÍÝ                                                                                       ÝÝÍÝ                    ÝÜÝÝÜÝÝÜ                    fweV                                                                ÍÝÝÍ                    ÜÝÝÍÝÍÝÝ                    Wgvv                                                               ÝÝÜÝ                    ÝÝÝÝÝÌÝÌ                    ÕÕW\                                                                ÌÝÌÝ                    ÝÜÝÝÝÝÝÝ                    ÌÝÝÜ                    »C»                                         ÝÝÝÝ                    ÍÜÍÜÝÝÝÝ                    ÝÝÝÝ                     $                                          ÝÝÝÝ                    ÝÝÍÜÝÍÜÜ                    ÝÍÜÝ                                                                ÍÍÜÝ                    ÝÝÝÝÝÍÜÝ                    ÝÍÜÍ                           0                                    ÝÍÜÝ                    ÜÜÍÝÜÝÝÝ                    ÜÝÝÝ                    0@                                          ÝÝÝÍ                    ÝÜÝÝfweV                    ÍÝÝÍ                                                                ÍÝÝÍ                    ÍÝÝÍWgvv                    ÝÝÜÝ                                                                ÝÝÜÝ                    ÝÝÜÝÕÕW\                    ÌÝÌÝ                                                                ÌÝÌÝ                    ÌÝÌÝÌÝÝÜ                    ÝÝÝÝ                                                                ÝÝÝÝ                    ÝÝÝÝÝÝÝÝ                    ÝÝÝÝ                                                                ÝÝÝÝ                    ÝÝÝÝÝÍÜÝ                    ÍÍÜÝ                                                                ÍÍÜÝ                    ÍÍÜÝÝÍÜÍ                    ÝÍÜÝ                                                                ÝÍÜÝ                    ÝÍÜÝÜÝÝÝ                    ÝÝÝÍ                                                                ÝÝÝÍ                    ÝÝÝÍÜÝÝÜ                    ÜÝÝÜ            fweV                                                        D34CD34CD34C3D3DÜÝÝÜÝÍÝÝ                    ÝÍÝÝ            Wgvv                                                        @  @  @   3 0ÝÍÝÝÝÌÝÌ                    ÝÌÝÌ            ÕÕW\                                                         @  @  @   0ÝÌÝÌÝÝÝÝ                    ÝÝÝÝ            ÌÝÝÜ                                                        C4C4C4C4C4C4C4C@ÝÝÝÝÝÝÝÝ                    ÝÝÝÝ            ÝÝÝÝ                                                                       CÝÝÝÝÝÍÜÜ                    ÝÍÜÜ            ÝÍÜÝ                                                                       CÝÍÜÜÝÍÜÝ                    ÝÍÜÝ            ÝÍÜÍ                                                                       0ÝÍÜÝÜÝÝÝ                    ÜÝÝÝ            ÜÝÝÝ                                                                       0ÜÝÝÝÜÝÝÍD3D3            3D3DfweV            ÜÝÝÜ                                                                        ÍÝÝÍÝÝÝÝ 3              3 0Wgvv            ÝÍÝÝ                                                                        ÝÝÜÝÝÜÝÝ@                0ÕÕW\            ÝÌÝÌ                                                                        ÌÝÌÝÍÜÍÜ4C4            C4C@ÌÝÝÜ            ÝÝÝÝ                                                                        ÝÝÝÝÝÝÍÜ4                  CÝÝÝÝ            ÝÝÝÝ                                                                        ÝÝÝÝÝÝÝÝ4                  CÝÍÜÝ            ÝÍÜÜ                                                                        ÍÍÜÝÜÜÍÝ                  0ÝÍÜÍ            ÝÍÜÝ                                                                        ÝÍÜÝÝÜÝÝ                  0ÜÝÝÝ            ÜÝÝÝ                                                                        ÝÝÝÍfweV                    ÍÝÝÍ            ÜÝÝÍ        D34CfweV                                                        ÜÝÝÜWgvv                    ÝÝÜÝ            ÝÝÝÝ        @  Wgvv                                    ""                 ÝÍÝÝÕÕW\                    ÌÝÌÝ            ÝÝÍÝ         @ ÕÕW\                                    """                 ÝÌÝÌÌÝÝÜ                    ÝÝÝÝ            ÍÜÍÜ        C4C4ÌÝÝÜ                                    BD"                 ÝÝÝÝÝÝÝÝ                    ÝÝÝÝ            ÍÜÝÝ            ÝÝÝÝ                                    ””$                 ÝÝÝÝÝÍÜÝ                    ÍÍÜÝ            ÝÝÝÝ            ÝÍÜÝ                                    DD                 ÝÍÜÜÝÍÜÍ                    ÝÍÜÝ            ÝÜÍÍ            ÝÍÜÍ                                    ww                 ÝÍÜÝÜÝÝÝ                    ÝÝÝÍ            ÝÝÍÝ            ÜÝÝÝ                                                      ÜÝÝÝÜÝÝÜfweVfweVfweVfweVfweVÍÝÝÍfweVfweVfweVÍÝÝÍfweVfweVfweVÜÝÝÍfweVfweVfweVfweVfweVfweVfweVfweVfweVfweVfweVfweVfweVfweVÜÝÝÜÝÍÝÝWgvvWgvvWgvvWgvvWgvvÝÝÜÝWgvvWgvvWgvvÝÝÜÝWgvvWgvvWgvvÝÝÝÝWgvvWgvvWgvvWgvvWgvvWgvvWgvvWgvvWgvvWgvvWgvvWgvvWgvvWgvvÝÍÝÝÝÌÝÌÕÕW\ÕÕW\ÕÕW\ÕÕW\ÕÕW\ÌÝÌÝÕÕW\ÕÕW\ÕÕW\ÌÝÌÝÕÕW\ÕÕW\ÕÕW\ÝÝÍÝÕÕW\ÕÕW\ÕÕW\ÕÕW\ÕÕW\ÕÕW\ÕÕW\ÕÕW\ÕÕW\ÕÕW\ÕÕW\ÕÕW\ÕÕW\ÕÕW\ÝÌÝÌÝÝÝÝÌÝÝÜÌÝÝÜÌÝÝÜÌÝÝÜÌÝÝÜÝÝÝÝÌÝÝÜÌÝÝÜÌÝÝÜÝÝÝÝÌÝÝÜÌÝÝÜÌÝÝÜÍÜÍÜÌÝÝÜÌÝÝÜÌÝÝÜÌÝÝÜÌÝÝÜÌÝÝÜÌÝÝÜÌÝÝÜÌÝÝÜÌÝÝÜÌÝÝÜÌÝÝÜÌÝÝÜÌÝÝÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÍÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÍÜÜÝÍÜÝÝÍÜÝÝÍÜÝÝÍÜÝÝÍÜÝÍÍÜÝÝÍÜÝÝÍÜÝÝÍÜÝÍÍÜÝÝÍÜÝÝÍÜÝÝÍÜÝÝÝÝÝÝÍÜÝÝÍÜÝÝÍÜÝÝÍÜÝÝÍÜÝÝÍÜÝÝÍÜÝÝÍÜÝÝÍÜÝÝÍÜÝÝÍÜÝÝÍÜÝÝÍÜÝÝÍÜÝÝÍÜÜÝÍÜÝÝÍÜÍÝÍÜÍÝÍÜÍÝÍÜÍÝÍÜÍÝÍÜÝÝÍÜÍÝÍÜÍÝÍÜÍÝÍÜÝÝÍÜÍÝÍÜÍÝÍÜÍÝÜÍÍÝÍÜÍÝÍÜÍÝÍÜÍÝÍÜÍÝÍÜÍÝÍÜÍÝÍÜÍÝÍÜÍÝÍÜÍÝÍÜÍÝÍÜÍÝÍÜÍÝÍÜÍÝÍÜÍÝÍÜÝÜÝÝÝÜÝÝÝÜÝÝÝÜÝÝÝÜÝÝÝÜÝÝÝÝÝÝÍÜÝÝÝÜÝÝÝÜÝÝÝÝÝÝÍÜÝÝÝÜÝÝÝÜÝÝÝÝÝÍÝÜÝÝÝÜÝÝÝÜÝÝÝÜÝÝÝÜÝÝÝÜÝÝÝÜÝÝÝÜÝÝÝÜÝÝÝÜÝÝÝÜÝÝÝÜÝÝÝÜÝÝÝÜÝÝÝÜÝÝÝÚ2 -- title:  Fun Jumpy Game
-- author: JKBYKM
-- desc:   A wip platformer
-- script: lua

local random, floor, ceil, max, min, abs = math.random, math.floor, math.ceil, math.max, math.min, math.abs
local sign = function(x) return x == 0 and 0 or (x > 0 and 1 or -1) end
local clamp = function(x, lo, hi) return x < lo and lo or (x > hi and hi or x) end

local function rng(x, y, s)
 s = s or 0x387

 local n = x * 0x1f123bb5
     ~ y * 0x05491333
     ~ s

 n = n ~ (n >> 16)
 n = n * 0x45d9f3b
 n = n ~ (n >> 16)
 n = n * 0x45d9f3b
 n = n ~ (n >> 16)

 return n
end

local function solidTileAt(x, y)
 local tile = mget(x // 8, y // 8)
 return fget(tile, 0)
end

--#region Particles
local Particles = {}
local Particle = {}
Particle.__index = Particle
function Particle:new(x, y, type)
 local p = {}
 p.x = x
 p.y = y
 p.dx = random() * 2 - 1
 p.dy = random() * 2 - 1
 p.type = type

 setmetatable(p, Particle)
 Particles[#Particles + 1] = p
 return p
end

function Particle:die()
 for i, v in ipairs(Particles) do
  if v == self then
   table.remove(Particles, i)
   break
  end
 end
end

function Particle:update()
 if self.type == "pixie dust" then
  if not self.timer then self.timer = 200 end
  self.dx = clamp(self.dx + random() - .5 - self.dx / 100, -15, 15)
  self.dy = clamp(self.dy + random() - .495 - self.dy / 100, -15, 15)
 elseif self.type == "dust" then
  if not self.timer then self.timer = random(20, 30) end
  self.dx = clamp(self.dx + random() - .5 - self.dx / 50, -15, 15)
  self.dy = clamp(self.dy + random() - .495 - self.dy / 50, -10, 5)
 end
 self.x = self.x + self.dx / 30
 self.y = self.y + self.dy / 30
 if self.timer then
  if self.timer == 0 then self:die() end
  self.timer = self.timer - 1
 end
end

function Particle:draw()
 if self.type == "pixie dust" then
  local colors = { 3, 4, 11 }
  pix(self.x, self.y, colors[random(#colors)])
 elseif self.type == 'dust' then
  pix(self.x, self.y, random(11, 13))
 end
end

--#endregion

local Faes = {}
--#region FireFae
local FireFae = {}
FireFae.__index = FireFae

function FireFae:new(x, y)
 local f = {}
 f.homeX = x
 f.homeY = y
 f.x = x
 f.y = y
 f.dx = 0
 f.dy = 0
 f.frame = math.random(100)
 f.id = 272
 setmetatable(f, FireFae)
 Faes[#Faes + 1] = f
 return f
end

function FireFae:update()
 self.frame = self.frame + 1
 if self.frame % 60 == 0 then
  self.dx = ((self.homeX - self.x) + math.random(-1, 1)) / 60
  self.dy = ((self.homeY - self.y) + math.random(-1, 1)) / 60
 end
 if self.frame % 50 == 0 then
  Particle:new(self.x + random(-2, 2), self.y + random(-2, 2), "pixie dust")
 end
 self.x, self.y = self.x + self.dx, self.y + self.dy
end

function FireFae:draw()
 spr(self.id + (self.frame // 5) % 3, self.x - 4, self.y - 4, 0, 1, math.random(0, 1))
end

--#endregion


--#region Player
local SLOWGRAV, GRAV, FASTGRAV = .1, .2, .5
local FLOATTHRESHOLD = 3
local ACCELTIME = 20
local FRICTION = .2
local FALLSPEED, FASTFALLSPEED, MAXSPEED, GROUNDCONTROL, AIRCONTROL = 3.3, 4, 2, 1.5, 1
local JUMPIMPULSE, JUMPBOOST = -2.3, .4
local DASHFRAMES = 45
local RESPAWNTIME = 10
local WALLMOMENTUMLENIENCY, WALLUPFORCE = 3, 0.05
local CYOTEFRAMES, WALLCYOTEFRAMES = 5, 7
local Player = {}
Player.__index = Player
function Player:new(x, y)
 local p = {}

 p.x = x
 p.y = y
 p.vx = 0
 p.vy = 0
 p.sprOffSet = { x = 3, y = 7 }
 p.physBox = {
  left   = -2,
  right  = 2,
  top    = -5,
  bottom = 0
 }
 p.wallMomentumTimer = 0

 p.action = 'idle'
 p.actionFrame = 0

 p.pressed = 0
 p.btnpBuffer = {}
 p.againstWall = 0

 p.cyote = 0
 p.wallCyote = 0

 setmetatable(p, Player)

 return p
end

function Player:spawn(x, y)
 self.action = 'spawn'
 self.actionFrame = 0
 self.animation = 'spawn'
 self.lastAnimation = 'spawn'
 self.animationFrame = 0
 self.x = x
 self.y = y
 self.vx = 0
 self.vy = 0
end

function Player:update()
 self:readInputs()
 self:moveAndCollide()
end

--#region Player:readInputs()
local BTNBUFFERTIME = {
 5, 5, 5, 5, -- up down left right
 7, 5, 5, 5  -- A B X Y
}
function Player:readInputs()
 local pressed = 0

 for i = 0, 7 do
  if btn(i) and (self.held & (1 << i) == 0) then
   self.btnpBuffer[i] = BTNBUFFERTIME[i + 1]
  else
   self.btnpBuffer[i] = max((self.btnpBuffer[i] or 0) - 1, 0)
  end

  if self.btnpBuffer[i] > 0 then
   pressed = pressed | (1 << i)
  end
 end
 self.pressed = pressed
 self.held = btn() & 0xff
end

function Player:btnp(x)
 return (self.pressed & (1 << x)) ~= 0
end

function Player:consumeBtnp(x)
 self.btnpBuffer[x] = 0
 self.pressed = self.pressed & ~(1 << x)
end

--#endregion Player:readInputs()

--#region Player:moveAndCollide()
function Player:moveAndCollide()
 self:applyForces()
 self:applyImpulses()
 local maxMovement = max(abs(self.vx), abs(self.vy))

 local steps = 1 + maxMovement // min(self.physBox.right - self.physBox.left, self.physBox.bottom - self.physBox.top)
 local stepX = self.vx / steps
 local stepY = self.vy / steps

 for _ = 1, steps do
  --#region Y step
  self.onGround = false
  self.cyote = self.cyote - 1
  if self:collidesAt(self.x, self.y + stepY) then
   if self.vy < 0 then
    local ceiling = true
    for dx = 1, 2 do
     for s = -1, 1, 2 do
      if ceiling and not self:collidesAt(self.x + s * dx, self.y + stepY) then
       self.y = self.y + stepY
       self.x = self.x + s * dx
       ceiling = false
       break
      end
     end
    end
    if ceiling then
     self.vy = 0
     self.y = ceil((self.y + stepY + self.physBox.top) / 8) * 8 - self.physBox.top
    end
   else
    self.vy = 0
    --the +/- 1 is for the half open interval behavior
    self.y = floor((self.y + stepY + self.physBox.bottom + 1) / 8) * 8 - self.physBox.bottom - 1
    self.onGround = true
    self.cyote = CYOTEFRAMES
   end
  else
   self.y = self.y + stepY
  end
  --#endregion Y step
  --#region X step
  if self.wallCyote < 0 then
   self.againstWall = 0
  end
  self.wallCyote = self.wallCyote - 1
  if self:collidesAt(self.x + stepX, self.y) then
   self.wallMomentumTimer = self.wallMomentumTimer + 1
   self.againstWall = sign(self.vx)
   self.wallCyote = WALLCYOTEFRAMES
   if self.wallMomentumTimer > WALLMOMENTUMLENIENCY then
    self.vx = 0
   end
   if self.vx > 0 then
    --the +/- 1 is for the half open interval behavior
    self.x = floor((self.x + stepX + self.physBox.right + 1) / 8) * 8 - self.physBox.right - 1
   elseif self.vx < 0 then
    self.x = ceil((self.x + stepX + self.physBox.left) / 8) * 8 - self.physBox.left
   end
   if not self.onGround then
    if self.vy < 0 then
     self.vy = self.vy - abs(self.vx * WALLUPFORCE)
    else
     self.vy = max(self.vy - FRICTION, FRICTION)
    end
   end
  else
   self.x = self.x + stepX
   self.wallMomentumTimer = 0
  end
  --#endregion X step
 end
end

function Player:applyForces()
 -- define vertical movment state
 local floating = btn(4) and (abs(self.vy) < FLOATTHRESHOLD)
 local fastfall = btn(1) and not floating

 -- define gravity for different vertical movement states
 local g
 if floating then
  g = SLOWGRAV
 elseif fastfall then
  g = FASTGRAV
 else
  g = GRAV
 end

 local maxFallSpeed = fastfall and FASTFALLSPEED or FALLSPEED

 self.vy = min(self.vy + g, maxFallSpeed)

 --define horizontal movement state
 local dx = (btn(3) and 1 or 0) - (btn(2) and 1 or 0)

 local horizontalAccel
 if dx ~= 0 then -- if input calculate acceleration
  local targetVel = dx * MAXSPEED
  local acceldirx = sign(targetVel - self.vx)
  local accelmag = abs(targetVel - self.vx) * (self.onGround and GROUNDCONTROL or AIRCONTROL) / ACCELTIME

  horizontalAccel = acceldirx * accelmag
 elseif dx == 0 then
  if abs(self.vx) <= FRICTION / 2 then --snap to 0
   horizontalAccel = -self.vx
  else
   horizontalAccel = -sign(self.vx) * FRICTION -- friction if no input
  end
 end

 --aply horizontal movement
 self.vx = self.vx + horizontalAccel
end

function Player:applyImpulses()
 local dx = (btn(3) and 1 or 0) - (btn(2) and 1 or 0)
 if self:btnp(4) then
  if self:canJump() then
   self.vy = self.vy + JUMPIMPULSE
   self.vx = self.vx + dx * JUMPBOOST
   self:consumeBtnp(4)
  elseif self:canWallJump() then
   self.vy = JUMPIMPULSE * .5
   self.vx = sign(self.againstWall) * JUMPIMPULSE * .866
   self:consumeBtnp(4)
   self.wallCyote = 0
  end
 end
end

function Player:collidesAt(x, y)
 local left, right, top, bottom =
     x + self.physBox.left, x + self.physBox.right,
     y + self.physBox.top, y + self.physBox.bottom
 local tileLeft, tileRight, tileTop, tileBottom = --the +/- 1 is for the half open interval behavior
     floor(left / 8), ceil((right + 1) / 8) - 1,
     floor(top / 8), ceil((bottom + 1) / 8) - 1

 local collidesAt = false

 for tx = tileLeft, tileRight do
  for ty = tileTop, tileBottom do
   local tile = mget(tx, ty)
   if fget(tile, 0) then
    collidesAt = collidesAt or true
   elseif fget(tile, 1) then
    collidesAt = collidesAt or (self.vy > 0) and self.y / 8 < ty
   end
  end
 end

 return collidesAt
end

--#region jumping

function Player:canJump()
 if self.cyote < 0 then
  return false
 end
 self.cyote = 0
 for _ = 1, 7 do
  Particle:new(self.x + random(-3, 3), self.y, 'dust')
 end
 return true
end

function Player:canWallJump()
 if self.wallCyote < 0 then
  return false
 end
 self.wallCyote = 0
 for _ = 1, 7 do
  Particle:new(self.x + self.againstWall * 2 + 1, self.y + random(-3, 3), 'dust')
 end
 return true
end

--#endregion jumping

--#endregion Player:moveAndCollide()


--#region Player:Draw()
local animationSprites = {
 ['idle'] = 256,
 ['running'] = 257,
 ['airborne'] = 259,
 ['dashing'] = 258,
 ['fastfalling'] = 262,
 ['wallslide'] = 263,
 ['spawn'] = 259
}
function Player:draw()
 self:setAnimation()
 local id, eyes          = animationSprites[self.animation], 271
 local sprX, sprY, eyedx = self.x - self.sprOffSet.x, self.y - self.sprOffSet.y, sign(self.vx)
 local eyedy             = 0
 local colorKey, scale   = 0, 1
 local flip, rot, w, h   = 0, 0, 1, 1
 if self.animation == 'idle' then
  local dy = (btn(1) and 1 or 0) - (btn(0) and 1 or 0)
  if dy == 1 then
   id = 260
   eyedy = 2
  elseif dy == -1 then
   id = 261
   eyedy = -2
  end
 elseif self.animation == 'running' then
  id   = id + (self.animationFrame // 7) % 2
  flip = self.vx < 0 and 1 or 0
 elseif self.animation == 'airborne' then
  if self.vy > FLOATTHRESHOLD / 2 then
   id = animationSprites['idle']
  else
   sprY = sprY + 1
   eyedy = -1
  end
 elseif self.animation == 'fastfalling' then
 elseif self.animation == 'wallslide' then
  eyedx = 0
  flip  = self.againstWall == 1 and 1 or 0
 end
 sprX = sprX - flip
 spr(id, sprX, sprY, colorKey, scale, flip, rot, w, h)
 spr(eyes, sprX + eyedx, sprY + eyedy, colorKey, scale, flip, rot, w, h)

 --self:debugDraw(sprX, sprY)
end

function Player:setAnimation()
 if self.animation ~= self.lastAnimation then
  self.animationFrame = 0
 else
  self.animationFrame = self.animationFrame + 1
 end
 self.lastAnimation = self.animation
 if self.animation == 'spawn' then
  if self.animationFrame > RESPAWNTIME then
   self.animation = 'idle'
   return
  end
 end

 if self.action == 'dashing' then
  self.animation = 'dashing'
  return
 end

 if self.againstWall ~= 0 then
  if self.vy >= 0 then
   self.animation = 'wallslide'
   return
  end
 end

 if self.onGround then
  if self.vx == 0 then
   self.animation = 'idle'

   return
  elseif self.vx < 0 then
   self.animation = 'running'

   return
  else
   self.animation = 'running'

   return
  end
 else
  if self.vy > 3.5 then
   self.animation = 'fastfalling'

   return
  else
   self.animation = 'airborne'

   return
  end
 end
end

function Player:debugDraw(sprX, sprY)
 pix(self.x, self.y + 1, self.onGround and 7 or 2)
 if self.animationFrame % 5 == 0 then
  rectb(
   self.x + self.physBox.left,
   self.y + self.physBox.top,
   self.physBox.right - self.physBox.left + 1,
   self.physBox.bottom - self.physBox.top + 1,
   11
  )
 end
 rectb(sprX - 1, sprY - 1, 10, 10, 7)
end

--#endregion Player:Draw()
--#endregion Player

local player = Player:new(0, 0)
local FAESPAWNER = 29
local PLAYERSPAWNER = 30

local function remap(tile, x, y)
 local outtile, flip, rotate = tile, 0, 0
 if fget(tile, 7) then flip, rotate = rng(x, y) % 4, rng(x, y) % 4 end
 if tile == FAESPAWNER then
  FireFae:new(x * 8 + 4, y * 8 + 4)
  mset(x, y, 0)
 end
 if tile == PLAYERSPAWNER then
  player:spawn(x * 8 + 4, y * 8 + 4)
  mset(x, y, 0)
 end
 return outtile, flip, rotate
end

function BOOT()
 map(0, 0, 30, 17, 0, 0, 0, 1, remap)
 for _ = 1, 200 do
  for _, particle in ipairs(Particles) do
   particle:update()
  end

  for _, fae in ipairs(Faes) do
   fae:update()
  end
 end
end

function TIC()
 if not btn(7) or keyp(6) then
  player:update()
  player.x = clamp(player.x, 0, 240)
  player.y = clamp(player.y, 0, 136)

  for _, particle in ipairs(Particles) do
   particle:update()
  end
  for _, fae in ipairs(Faes) do
   fae:update()
  end



  cls()
  map(0, 0, 30, 17, 0, 0, 0, 1, remap)

  for _, particle in ipairs(Particles) do
   particle:draw()
  end

  for _, fae in ipairs(Faes) do
   fae:draw()
  end
  player:draw()
 end
end
