Files

409 lines
8.5 KiB
Lua

love = lutro
require("slam")
require("resources")
require("map")
require("player")
require("enemies")
require("spike")
require("particles")
require("checkpoint")
require("jumppad")
require("orb")
require("coin")
require("menu")
require("levelselection")
require("data")
local host = require('hostinfo')
local love = love
local min = math.min
local max = math.max
local floor = math.floor
local lg = love.graphics
TILEW = 16
WIDTH = 300
HEIGHT = 200
function love.conf(t)
t.width = WIDTH
t.height = HEIGHT
end
STATE_MAINMENU = 0
STATE_INGAME_MENU = 1
STATE_INGAME = 2
STATE_LEVEL_MENU = 3
STATE_LEVEL_COMPLETED = 4
function love.load()
loadSettings()
loadData()
lg.setDefaultFilter("nearest","nearest")
lg.setBackgroundColor(COLORS.darkbrown)
lg.setLineStyle("rough")
loadImages()
loadSounds()
createQuads()
createMenus()
gamestate = STATE_MAINMENU
current_menu = main_menu
player = Player.create()
end
function love.update(dt)
if gamestate == STATE_INGAME then
-- Upper bound on frame delay
if dt > 0.06 then dt = 0.06 end
if love.input.joypad("select") then
dt = dt/100
end
-- Progress timer
map.time = map.time + dt
-- Update entitites
player:update(dt)
if player.x > MAPW+6 then
gamestate = STATE_LEVEL_COMPLETED
end
Spike.globalUpdate(dt)
Jumppad.globalUpdate(dt)
Coin.globalUpdate(dt)
-- Update enemies
for i=#map.enemies,1,-1 do
local enem = map.enemies[i]
if enem.alive == true then
if enem.update then
enem:update(dt)
end
else
table.remove(map.enemies, i)
end
end
-- Update particles
for i=#map.particles,1,-1 do
local part = map.particles[i]
if part.alive == true then
part:update(dt)
else
table.remove(map.particles, i)
end
end
-- Target screen translation
local totx = player.x + 6.5 - WIDTH/2
local toty = player.y + 10 - HEIGHT/2
-- Calculate new screen translation
if SCROLL_SPEED == 9 then
tx = min(max(0, totx), MAPW-WIDTH)
ty = min(max(0, toty), MAPH-HEIGHT)
else
tx = min(max(0, tx+(totx-tx)*SCROLL_SPEED*dt), MAPW-WIDTH)
ty = min(max(0, ty+(toty-ty)*SCROLL_SPEED*dt), MAPH-HEIGHT)
end
end
end
local scale_x, scale_y
function love.draw()
love.graphics.clear()
-- STATE: In game
if gamestate == STATE_INGAME then
lg.push()
drawIngame()
lg.pop()
drawIngameHUD()
elseif gamestate == STATE_INGAME_MENU then
lg.push()
drawIngame()
lg.pop()
current_menu:draw()
elseif gamestate == STATE_MAINMENU then
love.graphics.draw(imgTitle, quads.title, 0,0, 0, WIDTH/900)
current_menu:draw()
elseif gamestate == STATE_LEVEL_MENU then
LevelSelection.draw()
elseif gamestate == STATE_LEVEL_COMPLETED then
lg.push()
drawIngame()
lg.pop()
drawCompletionHUD()
end
end
function drawIngame()
lg.push()
lg.translate(-tx-16, -ty-16)
map:setDrawRange(tx,ty,WIDTH,HEIGHT)
map:draw()
lg.translate(4, 17)
player:draw()
for i,v in ipairs(map.entities) do
v:draw()
end
for i,v in ipairs(map.coins) do
v:draw()
end
for i,v in ipairs(map.enemies) do
if v.draw then
v:draw()
end
end
for i,v in ipairs(map.particles) do
v:draw()
end
end
function drawIngameHUD()
local time = getTimerString(map.time)
-- Draw text
lg.draw(imgHUD, quads.hud_coin, 9, 10)
lg.draw(imgHUD, quads.hud_skull, 48, 10)
lg.setColor(255,255,255,255)
lg.print(map.numcoins.."/5", 21, 13)
lg.print(map.deaths, 67, 13)
lg.printf(time, WIDTH-120, 13, 100, "right")
end
function drawCompletionHUD()
lg.setColor(0,0,0,200)
lg.rectangle("fill", 0,0, WIDTH,HEIGHT)
lg.setColor(255,255,255,255)
lg.draw(imgHUD, quads.text_level, 48,40)
lg.draw(imgHUD, quads.text_cleared, 140,40)
lg.print("COINS:", 66,75)
lg.print(map.numcoins.."/5", 130,75)
lg.print("DEATHS:", 66,95)
lg.print(map.deaths, 130,95)
lg.print("TIME:", 66,115)
lg.print(getTimerString(map.time), 130,115)
-- Draw coins difference
if map.numcoins > level_status[current_map].coins then
lg.setColor(COLORS.green)
lg.print("+"..map.numcoins-level_status[current_map].coins, 160, 75)
end
-- Draw deaths difference
if level_status[current_map].deaths then
if map.deaths > level_status[current_map].deaths then
lg.setColor(COLORS.red)
lg.print("+"..map.deaths-level_status[current_map].deaths, 148, 95)
elseif map.deaths < level_status[current_map].deaths then
lg.setColor(COLORS.green)
lg.print("-"..level_status[current_map].deaths-map.deaths, 148, 95)
end
end
-- Draw time difference
if level_status[current_map].time then
if map.time > level_status[current_map].time then
lg.setColor(COLORS.red)
lg.print("+"..getTimerString(map.time-level_status[current_map].time), 194, 115)
elseif map.time < level_status[current_map].time then
lg.setColor(COLORS.green)
lg.print("-"..getTimerString(level_status[current_map].time-map.time), 194, 115)
end
end
lg.setColor(255,255,255,255)
lg.print("PRESS ANY KEY TO CONTINUE", 55, 165)
end
function getTimerString(time)
local msec = math.floor((time % 1)*100)
local sec = math.floor(time % 60)
local min = math.floor(time/60)
return string.format("%02d'%02d\"%02d",min,sec,msec)
end
function love.gamepadpressed(i, k)
if gamestate == STATE_INGAME then
if k == "a" then
player:keypressed(k)
elseif k == "b" then
gamestate = STATE_INGAME_MENU
current_menu = ingame_menu
ingame_menu.selected = 1
elseif k == "x" then
player:kill()
elseif k == "start" then
reloadMap()
elseif k == "y" then
gamestate = STATE_LEVEL_COMPLETED
end
elseif gamestate == STATE_INGAME_MENU or gamestate == STATE_MAINMENU then
current_menu:keypressed(k)
elseif gamestate == STATE_LEVEL_MENU then
LevelSelection.keypressed(k)
elseif gamestate == STATE_LEVEL_COMPLETED then
levelCompleted()
end
end
function love.gamepadreleased(i, k)
if gamestate == STATE_INGAME then
if k ~= "b" and k ~= "x" then
player:keyreleased(k)
end
end
end
local touches = {}
function love.touchpressed(id, x, y)
table.insert(touches, {id = id, x = x, y = y})
if gamestate == STATE_INGAME then
player:keypressed(' ')
end
end
function love.touchreleased(id, x, y)
local ignore = false
for i = #touches, 1, -1 do
if touches[i].moved then
ignore = true
end
if touches[i].id == id then
table.remove(touches, i)
end
end
if not ignore then
if gamestate == STATE_INGAME then
player:keyreleased(' ')
elseif gamestate == STATE_INGAME_MENU or gamestate == STATE_MAINMENU then
current_menu:keypressed('return')
elseif gamestate == STATE_LEVEL_MENU then
LevelSelection.keypressed('return')
elseif gamestate == STATE_LEVEL_COMPLETED then
levelCompleted()
end
end
end
function love.touchmoved(id, x, y)
for i, v in ipairs(touches) do
if v.id == id and not v.moved then
local xv = x - v.x
local yv = y - v.y
local axv = math.abs(xv)
local ayv = math.abs(yv)
-- Ignore touchmoves below a certain threshold
local threshold = 0.08
if axv < threshold and ayv < threshold then
return
end
v.moved = true
local function send(key)
if gamestate == STATE_INGAME_MENU or gamestate == STATE_MAINMENU then
current_menu:keypressed(key)
elseif gamestate == STATE_LEVEL_MENU then
LevelSelection.keypressed(key)
end
end
if ayv > axv then
if yv > 0 then
send('down')
elseif yv < 0 then
send('up')
end
else
if xv > 0 then
send('right')
elseif xv < 0 then
send('left')
end
end
return
end
end
end
function love.focus(f)
if f == false and gamestate == STATE_INGAME then
gamestate = STATE_INGAME_MENU
current_menu = ingame_menu
ingame_menu.selected = 1
end
end
function setScale(scale)
if scale < 1 or scale == SCALE then return end
SCALE = scale
if host.isTouchDevice() then
scale_x = love.window.getWidth() / WIDTH
scale_y = love.window.getHeight() / HEIGHT
else
scale_x = scale
scale_y = scale
end
SCREEN_WIDTH = WIDTH
SCREEN_HEIGHT = HEIGHT
love.window.setMode(SCREEN_WIDTH, SCREEN_HEIGHT, {
fullscreen=false,
vsync=true,
borderless = host.isTouchDevice()
})
end
function setResolution(w,h)
love.window.setMode(w, h, {
fullscreen=false,
vsync=true,
borderless = host.isTouchDevice()
})
if w == 0 and h == 0 then
SCREEN_WIDTH = lg.getWidth()
SCREEN_HEIGHT = lg.getHeight()
love.window.setMode(SCREEN_WIDTH, SCREEN_HEIGHT, {
fullscreen=false,
vsync=true,
borderless = host.isTouchDevice()
})
else
SCREEN_WIDTH = w
SCREEN_HEIGHT = h
end
SCALE = 1
while (20*16*SCALE) < SCREEN_WIDTH or (16*16*SCALE) < SCREEN_HEIGHT do
SCALE = SCALE + 1
end
WIDTH = SCREEN_WIDTH/SCALE
HEIGHT = SCREEN_HEIGHT/SCALE
end
function love.quit()
saveSettings()
saveData()
end