upload so it isnt lost now

This commit is contained in:
lustlion
2021-10-17 01:06:11 +02:00
commit 966aebf046
258 changed files with 2859 additions and 0 deletions

21
data/scripts/camera.lua Normal file
View File

@@ -0,0 +1,21 @@
Camera = {
pos = {x = 0, y = 0},
width = 0,
height = 0
}
function Camera:CenterAt(x,y,cx,cy)
self.pos.x = x-self.width/2
self.pos.y = y-self.height/2
if not (cx == nil or cy == nil) then
if self.pos.x < 0 then self.pos.x = 0 end
if self.pos.x > cx then self.pos.x = cx end
if self.pos.y < 0 then self.pos.y = 0 end
if self.pos.y > cy then self.pos.y = cy end
end
end
function Camera:ScreenAt(x,y,width,height)
self.pos.x = math.floor(x/width)*width
self.pos.y = math.floor(y/height)*height
end

View File

@@ -0,0 +1,76 @@
Collision = {}
--[[
Collision
[bool] isDisabled
> if true used for collision
[bool] isActive
> if true, this collision is active (on collision, duh)
[bool] isColliding
> if true, this collision is colliding
[2d pos] from - x, y
> top right corner of collision box
[2d pos] to - x, y
> bottom left corner of collision box
[int] width
> width of collision box
[int] height
> height of collision box
--]]
-- can also be called with only ox and oy, where they become the width and height instead
function Collision:new(ox,oy,tx,ty)
local o = {isColliding = false, isDisabled = false, isActive = false}
if tx ~= nil and ty ~= nil then
o.from = {x = ox, y = oy}
o.to = {x = tx, y = ty}
o.width = o.to.x - o.from.x
o.height = o.to.y - o.from.y
else
o.width = ox
o.height = oy
o.from = {x = 0, y = 0}
o.to = {x = 0, y = 0}
end
setmetatable(o, self)
self.__index = self
return o
end
function Collision:CenterAt(x, y)
self.from.x = x-self.width/2
self.from.y = y-self.height/2
self.to.x = x+self.width/2
self.to.y = y+self.height/2
end
function Collision:PlaceAt(x, y)
self.from.x = x or self.from.x
self.from.y = y or self.from.y
self.to.x = self.from.x + self.width
self.to.y = self.from.x + self.height
end
function Collision:Draw(color)
if self.isColliding == true then
love.graphics.setColor(0,1,0,0.5)
elseif self.isActive == 1 then
love.graphics.setColor(0,1,1,0.5)
elseif color == 1 then
love.graphics.setColor(1,0,0,0.5)
elseif color == 2 then
love.graphics.setColor(0,1,1,0.5)
end
love.graphics.rectangle("fill",self.from.x-Camera.pos.x, self.from.y-Camera.pos.y, self.width, self.height)
end

27
data/scripts/debug.lua Normal file
View File

@@ -0,0 +1,27 @@
function DebugUI()
love.graphics.print("time: "..fps_total..", fps: "..fps_draw..", frametime: "..math.floor(current_dt* 1000).."ms", 10*textScale, 0*textScale, 0, textScale)
love.graphics.setColor(1,1,1)
-- lots of variables
love.graphics.print("[main_player]",10*textScale,40*textScale, 0, textScale)
love.graphics.print("position: {"..main_player.pos.x..", "..main_player.pos.y.."}",10*textScale,60*textScale, 0, textScale)
love.graphics.print("velocity: {"..main_player.vel.x..", "..main_player.vel.y.."}",10*textScale,80*textScale, 0, textScale)
love.graphics.print("scale: {"..main_player.scale.x..", "..main_player.scale.y.."}",10*textScale,100*textScale, 0, textScale)
love.graphics.print("sprite: "..tostring(main_player.sprite)..", anim_speed: "..main_player.anim_speed,10*textScale,120*textScale, 0, textScale)
love.graphics.print("booleans: \"isOnGround\": "..tostring(main_player.isOnGround),10*textScale,140*textScale, 0, textScale)
love.graphics.print("[Camera]",10*textScale,160*textScale, 0, textScale)
love.graphics.print("position: {"..Camera.pos.x..", "..Camera.pos.y.."}",10*textScale,180*textScale, 0, textScale)
love.graphics.print("size: {"..Camera.width..", "..Camera.height.."}",10*textScale,200*textScale, 0, textScale)
love.graphics.print(textScale,10*textScale,240*textScale, 0, textScale)
love.graphics.print("Level: "..levelNum.." / "..#levelList.." \""..currLevel.."\"",10*textScale,260*textScale, 0, textScale)
-- player isOnGroundCheck
love.graphics.setColor(1,0,0)
love.graphics.points(-Camera.pos.x + main_player.pos.x, -Camera.pos.y + main_player.pos.y)
end
function DebugColisions()
objects.DrawCollisions()
end

View File

@@ -0,0 +1,205 @@
player = entity:newEntity(x,y)
function InitPlayer(id)
player.health = 3
player.coins = 0
-- physics
player.vel = {
x = 0,
y = 0
}
-- constants
player.acc = 90
player.friction = 20
player.gravity = 9.81
player.climbHeight = 3
player.jumpForce = 5
player.maxSpeed = 600
player.jumpMaxSpeed = 9.5
player.zeroSpeed = 0.001
-- bools
player.isJumping = false
player.isOnGround = false
player.isOnLadder = false
player.canJump = true
player.canFall = true
player.canFriction = true
-- sprite
player.offset = {x = -8, y = -16}
end
function player:DoInput()
-- PLATFORMER INPUT
if self.isOnGround then
-- apply friction
-- horizontal input (slide~~)
if love.keyboard.isDown('a',"left") then
self.vel.x = self.vel.x - self.acc*current_dt
end
if love.keyboard.isDown('d',"right") then
self.vel.x = self.vel.x + self.acc*current_dt
end
if self.canJump then
-- vertical input (jump!)
if love.keyboard.isDown("up", "w") and self.isJumping ~= true then
self.vel.y = self.vel.y - self.jumpForce
self.isOnGround = false
self.isJumping = true
end
end
end
-- fall if down input on platforms
if not isThereCollisionAt(
self.pos.x,
self.pos.y + self.vel.y
) and not isThereLadderAt(
self.pos.x,
self.pos.y + self.vel.y
) and isTherePlatformAt(
self.pos.x,
self.pos.y + self.vel.y
) and love.keyboard.isDown("down", "s")
then
self.pos.y = self.pos.y + tileProperties.height/3
self.isOnGround = false
end
end
function player:HandleAnimation()
-- flip sprite to look in the direction is moving
if self.vel.x ~= 0 then self.flip.x = math.sign(self.vel.x) end
-- animation manager
if self.isOnLadder then
self:LoadAnimation(animation.nancy.jump)
elseif not self.isOnGround and self.isJumping and self.vel.y > 1.25 then
self:LoadAnimation(animation.nancy.fall)
elseif not self.isOnGround and self.vel.y < 0 then
self:LoadAnimation(animation.nancy.jump)
elseif self.vel.x ~= 0 then
self:LoadAnimation(animation.nancy.run)
else
self:LoadAnimation(animation.nancy.idle)
end
-- special case: idle animation gets slower by time
if self.anim_path == animation.nancy.idle.path then
if self.anim_speed < 0.5 then self.anim_speed = self.anim_speed + 0.001 end
end
end
function player:DoPhysics()
-- reset physics resolution
self.canFall = true
self.canJump = true
self.canFriction = true
-- reset flags
self.isOnGround = false
self.isOnLadder = false
-- truncate to max & min values
if math.abs(self.vel.x) > self.maxSpeed then
self.vel.x = self.maxSpeed * math.sign(self.vel.x)
end
if math.abs(self.vel.y) > self.maxSpeed then
self.vel.y = self.maxSpeed * math.sign(self.vel.y)
end
if math.abs(self.vel.x) < self.zeroSpeed then
self.vel.x = 0
end
if math.abs(self.vel.y) < self.zeroSpeed then
self.vel.y = 0
end
-- if on air, say so!
if self.vel.y > 5 then
self.isJumping = true
end
-- if its on ground, then say so.
if self.vel.y > 0 then
if isThereAnyCollisionAt(
self.pos.x,
self.pos.y + self.vel.y
) then
self.isOnGround = true
self.isJumping = false
end
end
-- horizontal collisions
if isThereAnyCollisionAt(self.pos.x + self.vel.x, self.pos.y) then
-- checks for ladders
if isThereLadderAt(self.pos.x + self.vel.x, self.pos.y)
and self.vel.x ~= 0
and not isThereLadderAt(self.pos.x, self.pos.y)
then
self.vel.y = 0
self.vel.x = 0
self.pos.y = self.pos.y - 4*game.scale * current_dt
self.canFall = false
self.canJump = false
self.canFriction = false
self.isOnLadder = true
self.isOnGround = true
end
-- checks for slopes
for i = 1, self.climbHeight do
if not isThereCollisionAt(self.pos.x + self.vel.x, self.pos.y - i * game.scale)
and self.isOnGround then
self.pos.x = self.pos.x + self.vel.x
self.pos.y = self.pos.y - i * game.scale
self.canFriction = false
break
end
end
-- hey, you arent permanently stopped while collisioning, just lose a bit of force!
if self.canFriction then
self.vel.x = self.vel.x * (1 - math.min(current_dt * self.friction/15, 1))
end
else
self.pos.x = self.pos.x + self.vel.x
end
-- vertical collision
if self.vel.y > 0
and isThereAnyCollisionAt(self.pos.x, self.pos.y + self.vel.y) then
self.isOnGround = true
self.isJumping = false
self.vel.y = 0
else
self.pos.y = self.pos.y + self.vel.y
end
-- drop.
if self.canFall then
self.vel.y = self.vel.y + 2*self.gravity * current_dt
end
-- friction hard in ground, soft in air
if self.isOnGround then
self.vel.x = self.vel.x * (1 - math.min(current_dt * self.friction, 1))
else
self.vel.x = self.vel.x * (1 - math.min(current_dt * self.friction/20, 1))
end
end
function player:newPlayer(x,y)
local o = entity:newEntity(x,y)
setmetatable(o, self)
self.__index = self
return o
end

65
data/scripts/entity.lua Normal file
View File

@@ -0,0 +1,65 @@
entity = {class = "entity", anim_subframe = 0, anim_frame = 0, anim_imgs = {}, offset = {x = 0, y = 0}, scale = {x = 1, y = 1}, flip = { x = 1, y = 1}}
function entity:newEntity(x,y)
o = {}
o.pos = {x = x, y = y}
setmetatable(o, self)
self.__index = self
return o
end
function entity:Move(target, speed) -- target = {tx int, ty int} / speed = int
end
function entity:Draw()
if self.sprite ~= nil then
love.graphics.draw(
self.sprite,
self.pos.x - Camera.pos.x + self.offset.x * game.scale * self.scale.x * self.flip.x,
self.pos.y - Camera.pos.y + self.offset.y * game.scale * self.scale.y * self.flip.y,
0,
game.scale * self.scale.x * self.flip.x,
game.scale * self.scale.y * self.flip.y
)
end
end
function entity:Animate()
if game_paused ~= true then
-- try to animate
self.anim_subframe = self.anim_subframe + current_dt
if self.anim_subframe >= self.anim_speed then
self.anim_frame = self.anim_frame + 1
self.anim_subframe = self.anim_subframe - self.anim_speed
end
-- cycle
if self.anim_frame >= self.anim_frames+1 then
self.anim_frame = self.anim_frame - self.anim_frames
end
-- change
self.sprite = self.anim_imgs[self.anim_frame]
end
end
function entity:LoadAnimation(anim,frames,speed)
if self.anim_path ~= anim and self.anim_path ~= anim.path then
if frames ~= nil and speed ~= nil then
self.anim_path = anim or nil
self.anim_frames = frames or 4
self.anim_speed = speed or frames
else
self.anim_path = anim.path
self.anim_frames = anim.frames
self.anim_speed = anim.speed
end
self.anim_imgs = anim.imgs
end
end
require "data/scripts/entities/player"

61
data/scripts/enums.lua Normal file
View File

@@ -0,0 +1,61 @@
image = {
background = love.graphics.newImage("assets/terrain/background.png"),
cartridge = {
nancy = love.graphics.newImage("assets/menu/nancy.png")
}
}
-- animations
animation = {
nancy = {
idle = {
path = "assets/characters/nancy/idle",
frames = 4,
speed = 1/8,
imgs = {}
},
run = {
path = "assets/characters/nancy/run",
frames = 6,
speed = 1/8,
imgs = {}
},
fall = {
path = "assets/characters/nancy/fall",
frames = 3,
speed = 1/8,
imgs = {}
},
jump = {
path = "assets/characters/nancy/jump",
frames = 3,
speed = 1/8,
imgs = {}
}
}
}
for _, object in pairs(animation) do
for _, anim in pairs(object) do
for i = 1, anim.frames do
table.insert(anim.imgs,love.graphics.newImage(anim.path..tostring(i)..".png"))
end
end
end
levelProperties = {
pos = {
x = 0,
y = 0
},
offset = {
x = 0,
y = 0
}
}
tileProperties = {
width = 16,
height = 16,
scale = game.scale,
tileset = love.graphics.newImage("assets/terrain/tileset.png")
}

14
data/scripts/in_out.lua Normal file
View File

@@ -0,0 +1,14 @@
function doOutput(table)
local file = io.open("map.json", "w")
io.output(file)
io.write(json.encode(table))
io.close(file)
end
function getInput(filename)
local file = io.open(filename, "r")
io.input(file)
local content = io.read()
io.close(file)
return content
end

388
data/scripts/json.lua Normal file
View File

@@ -0,0 +1,388 @@
--
-- json.lua
--
-- Copyright (c) 2020 rxi
--
-- Permission is hereby granted, free of charge, to any person obtaining a copy of
-- this software and associated documentation files (the "Software"), to deal in
-- the Software without restriction, including without limitation the rights to
-- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
-- of the Software, and to permit persons to whom the Software is furnished to do
-- so, subject to the following conditions:
--
-- The above copyright notice and this permission notice shall be included in all
-- copies or substantial portions of the Software.
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-- SOFTWARE.
--
local json = { _version = "0.1.2" }
-------------------------------------------------------------------------------
-- Encode
-------------------------------------------------------------------------------
local encode
local escape_char_map = {
[ "\\" ] = "\\",
[ "\"" ] = "\"",
[ "\b" ] = "b",
[ "\f" ] = "f",
[ "\n" ] = "n",
[ "\r" ] = "r",
[ "\t" ] = "t",
}
local escape_char_map_inv = { [ "/" ] = "/" }
for k, v in pairs(escape_char_map) do
escape_char_map_inv[v] = k
end
local function escape_char(c)
return "\\" .. (escape_char_map[c] or string.format("u%04x", c:byte()))
end
local function encode_nil(val)
return "null"
end
local function encode_table(val, stack)
local res = {}
stack = stack or {}
-- Circular reference?
if stack[val] then error("circular reference") end
stack[val] = true
if rawget(val, 1) ~= nil or next(val) == nil then
-- Treat as array -- check keys are valid and it is not sparse
local n = 0
for k in pairs(val) do
if type(k) ~= "number" then
error("invalid table: mixed or invalid key types")
end
n = n + 1
end
if n ~= #val then
error("invalid table: sparse array")
end
-- Encode
for i, v in ipairs(val) do
table.insert(res, encode(v, stack))
end
stack[val] = nil
return "[" .. table.concat(res, ",") .. "]"
else
-- Treat as an object
for k, v in pairs(val) do
if type(k) ~= "string" then
error("invalid table: mixed or invalid key types")
end
table.insert(res, encode(k, stack) .. ":" .. encode(v, stack))
end
stack[val] = nil
return "{" .. table.concat(res, ",") .. "}"
end
end
local function encode_string(val)
return '"' .. val:gsub('[%z\1-\31\\"]', escape_char) .. '"'
end
local function encode_number(val)
-- Check for NaN, -inf and inf
if val ~= val or val <= -math.huge or val >= math.huge then
error("unexpected number value '" .. tostring(val) .. "'")
end
return string.format("%.14g", val)
end
local type_func_map = {
[ "nil" ] = encode_nil,
[ "table" ] = encode_table,
[ "string" ] = encode_string,
[ "number" ] = encode_number,
[ "boolean" ] = tostring,
}
encode = function(val, stack)
local t = type(val)
local f = type_func_map[t]
if f then
return f(val, stack)
end
error("unexpected type '" .. t .. "'")
end
function json.encode(val)
return ( encode(val) )
end
-------------------------------------------------------------------------------
-- Decode
-------------------------------------------------------------------------------
local parse
local function create_set(...)
local res = {}
for i = 1, select("#", ...) do
res[ select(i, ...) ] = true
end
return res
end
local space_chars = create_set(" ", "\t", "\r", "\n")
local delim_chars = create_set(" ", "\t", "\r", "\n", "]", "}", ",")
local escape_chars = create_set("\\", "/", '"', "b", "f", "n", "r", "t", "u")
local literals = create_set("true", "false", "null")
local literal_map = {
[ "true" ] = true,
[ "false" ] = false,
[ "null" ] = nil,
}
local function next_char(str, idx, set, negate)
for i = idx, #str do
if set[str:sub(i, i)] ~= negate then
return i
end
end
return #str + 1
end
local function decode_error(str, idx, msg)
local line_count = 1
local col_count = 1
for i = 1, idx - 1 do
col_count = col_count + 1
if str:sub(i, i) == "\n" then
line_count = line_count + 1
col_count = 1
end
end
error( string.format("%s at line %d col %d", msg, line_count, col_count) )
end
local function codepoint_to_utf8(n)
-- http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=iws-appendixa
local f = math.floor
if n <= 0x7f then
return string.char(n)
elseif n <= 0x7ff then
return string.char(f(n / 64) + 192, n % 64 + 128)
elseif n <= 0xffff then
return string.char(f(n / 4096) + 224, f(n % 4096 / 64) + 128, n % 64 + 128)
elseif n <= 0x10ffff then
return string.char(f(n / 262144) + 240, f(n % 262144 / 4096) + 128,
f(n % 4096 / 64) + 128, n % 64 + 128)
end
error( string.format("invalid unicode codepoint '%x'", n) )
end
local function parse_unicode_escape(s)
local n1 = tonumber( s:sub(1, 4), 16 )
local n2 = tonumber( s:sub(7, 10), 16 )
-- Surrogate pair?
if n2 then
return codepoint_to_utf8((n1 - 0xd800) * 0x400 + (n2 - 0xdc00) + 0x10000)
else
return codepoint_to_utf8(n1)
end
end
local function parse_string(str, i)
local res = ""
local j = i + 1
local k = j
while j <= #str do
local x = str:byte(j)
if x < 32 then
decode_error(str, j, "control character in string")
elseif x == 92 then -- `\`: Escape
res = res .. str:sub(k, j - 1)
j = j + 1
local c = str:sub(j, j)
if c == "u" then
local hex = str:match("^[dD][89aAbB]%x%x\\u%x%x%x%x", j + 1)
or str:match("^%x%x%x%x", j + 1)
or decode_error(str, j - 1, "invalid unicode escape in string")
res = res .. parse_unicode_escape(hex)
j = j + #hex
else
if not escape_chars[c] then
decode_error(str, j - 1, "invalid escape char '" .. c .. "' in string")
end
res = res .. escape_char_map_inv[c]
end
k = j + 1
elseif x == 34 then -- `"`: End of string
res = res .. str:sub(k, j - 1)
return res, j + 1
end
j = j + 1
end
decode_error(str, i, "expected closing quote for string")
end
local function parse_number(str, i)
local x = next_char(str, i, delim_chars)
local s = str:sub(i, x - 1)
local n = tonumber(s)
if not n then
decode_error(str, i, "invalid number '" .. s .. "'")
end
return n, x
end
local function parse_literal(str, i)
local x = next_char(str, i, delim_chars)
local word = str:sub(i, x - 1)
if not literals[word] then
decode_error(str, i, "invalid literal '" .. word .. "'")
end
return literal_map[word], x
end
local function parse_array(str, i)
local res = {}
local n = 1
i = i + 1
while 1 do
local x
i = next_char(str, i, space_chars, true)
-- Empty / end of array?
if str:sub(i, i) == "]" then
i = i + 1
break
end
-- Read token
x, i = parse(str, i)
res[n] = x
n = n + 1
-- Next token
i = next_char(str, i, space_chars, true)
local chr = str:sub(i, i)
i = i + 1
if chr == "]" then break end
if chr ~= "," then decode_error(str, i, "expected ']' or ','") end
end
return res, i
end
local function parse_object(str, i)
local res = {}
i = i + 1
while 1 do
local key, val
i = next_char(str, i, space_chars, true)
-- Empty / end of object?
if str:sub(i, i) == "}" then
i = i + 1
break
end
-- Read key
if str:sub(i, i) ~= '"' then
decode_error(str, i, "expected string for key")
end
key, i = parse(str, i)
-- Read ':' delimiter
i = next_char(str, i, space_chars, true)
if str:sub(i, i) ~= ":" then
decode_error(str, i, "expected ':' after key")
end
i = next_char(str, i + 1, space_chars, true)
-- Read value
val, i = parse(str, i)
-- Set
res[key] = val
-- Next token
i = next_char(str, i, space_chars, true)
local chr = str:sub(i, i)
i = i + 1
if chr == "}" then break end
if chr ~= "," then decode_error(str, i, "expected '}' or ','") end
end
return res, i
end
local char_func_map = {
[ '"' ] = parse_string,
[ "0" ] = parse_number,
[ "1" ] = parse_number,
[ "2" ] = parse_number,
[ "3" ] = parse_number,
[ "4" ] = parse_number,
[ "5" ] = parse_number,
[ "6" ] = parse_number,
[ "7" ] = parse_number,
[ "8" ] = parse_number,
[ "9" ] = parse_number,
[ "-" ] = parse_number,
[ "t" ] = parse_literal,
[ "f" ] = parse_literal,
[ "n" ] = parse_literal,
[ "[" ] = parse_array,
[ "{" ] = parse_object,
}
parse = function(str, idx)
local chr = str:sub(idx, idx)
local f = char_func_map[chr]
if f then
return f(str, idx)
end
decode_error(str, idx, "unexpected character '" .. chr .. "'")
end
function json.decode(str)
if type(str) ~= "string" then
error("expected argument of type string, got " .. type(str))
end
local res, idx = parse(str, next_char(str, 1, space_chars, true))
idx = next_char(str, idx, space_chars, true)
if idx <= #str then
decode_error(str, idx, "trailing garbage")
end
return res
end
return json

493
data/scripts/level.lua Normal file
View File

@@ -0,0 +1,493 @@
function LoadTiles()
LevelInfo = {}
Tiles = dofile("Mothback/data/tiles.lua")
--[[
on level format:
id = tile identifier
depth = order in the render
force = rendering other tile instead of the one in this position
overlay = render another tile id
overlay_depth = foreground/background overlay depth
type = collision type
]]
LevelTiles = json.decode(getInput("Mothback/data/levels/"..currLevel..".json"))
LevelInfo.Width = GetLevelWidth()
LevelInfo.Height = #LevelTiles * tileProperties.height
IndexLevelTiles()
LoadTileObjects()
end
function GetLevelWidth()
local width = 0
for i = 1, #LevelTiles do
if width < #LevelTiles[i] then width = #LevelTiles[i] end
end
return width * tileProperties.width
end
function IndexLevelTiles()
TileIndex = {}
-- number of tiles in tileset!
local width = tileProperties.tileset:getPixelWidth()/tileProperties.width
local height = tileProperties.tileset:getPixelHeight()/tileProperties.height
for i = 0, height do
for j = 0, width do
TileIndex[i*width+j+1] = love.graphics.newQuad(
j*tileProperties.width,
i*tileProperties.height,
tileProperties.width,
tileProperties.height,
tileProperties.tileset:getDimensions()
)
end
end
for _, properties in pairs(Tiles) do
if properties.animation ~= nil then
properties.tileset = love.graphics.newImage("assets/terrain/"..properties.animation..".png")
properties.imgs = {}
properties.current_image = 1
properties.current_subimage = 1
local tileset = properties.tileset
local width = tileset:getPixelWidth()/tileProperties.width
local height = tileset:getPixelHeight()/tileProperties.height
local image_count = 0
for i = 0, height-1 do
for j = 0, width-1 do
local quad =
love.graphics.newQuad(
j*tileProperties.width,
i*tileProperties.height,
tileProperties.width,
tileProperties.height,
tileset:getDimensions()
)
image_count = image_count + 1
table.insert(properties.imgs,quad)
end
end
properties.image_count = image_count
end
end
end
function TilesDisplayFront()
for i = 1, #LevelTiles do
for j = 1, #LevelTiles[i] do
if LevelTiles[i][j] ~= 0 then
local depth = getTileDepth(LevelTiles[i][j])
DrawTile(
LevelTiles[i][j],
tileProperties.scale * j * tileProperties.width + tileProperties.scale * (levelProperties.offset.x - tileProperties.width) - Camera.pos.x,
tileProperties.scale * i * tileProperties.height + tileProperties.scale * (levelProperties.offset.y - tileProperties.height) - Camera.pos.y,
"foreground"
)
end
end
end
end
function TilesDisplayBack()
for i = 1, #LevelTiles do
for j = 1, #LevelTiles[i] do
if LevelTiles[i][j] ~= 0 then
local depth = getTileDepth(LevelTiles[i][j])
DrawTile(
LevelTiles[i][j],
tileProperties.scale * j * tileProperties.width + tileProperties.scale * (levelProperties.offset.x - tileProperties.width) - Camera.pos.x,
tileProperties.scale * i * tileProperties.height + tileProperties.scale * (levelProperties.offset.y - tileProperties.height) - Camera.pos.y,
"background"
)
end
end
end
end
function getTileType(tile_id)
for _, properties in ipairs(Tiles) do
if properties.id == tile_id then
return properties.type
end
end
end
function getTileDepth(tile_id)
for _, properties in ipairs(Tiles) do
if properties.id == tile_id then
return properties.depth
end
end
end
function GridDisplay()
for i = 1, #LevelTiles do
for j = 1, #LevelTiles[i] do
love.graphics.rectangle(
"line",
tileProperties.scale * j * tileProperties.width + tileProperties.scale * (levelProperties.offset.x - tileProperties.width) - Camera.pos.x,
tileProperties.scale * i * tileProperties.height + tileProperties.scale * (levelProperties.offset.y - tileProperties.height) - Camera.pos.y,
tileProperties.scale * tileProperties.width,
tileProperties.scale * tileProperties.height
)
end
end
end
function LoadTileObjects()
objects.collisions = {}
objects.platforms = {}
objects.ladders = {}
for i = 1, #LevelTiles do
for j = 1, #LevelTiles[i] do
if LevelTiles[i][j] ~= 0 then
local type = getTileType(LevelTiles[i][j])
local base_x = tileProperties.scale * j * tileProperties.width + tileProperties.scale * (levelProperties.offset.x - tileProperties.height)
local base_y = tileProperties.scale * i * tileProperties.height + tileProperties.scale * (levelProperties.offset.y - tileProperties.height)
if type == "whole" then
local col = Collision:new(
base_x,
base_y,
base_x + tileProperties.width * tileProperties.scale,
base_y + tileProperties.height * tileProperties.scale
)
table.insert(objects.collisions,col)
elseif type == "half" then
local col = Collision:new(
base_x,
base_y + tileProperties.height/2 * tileProperties.scale,
base_x + tileProperties.width * tileProperties.scale,
base_y + tileProperties.height * tileProperties.scale
)
table.insert(objects.collisions,col)
elseif type == "platform" then
local plat = Collision:new(
base_x,
base_y + tileProperties.scale * 2,
base_x + tileProperties.width * tileProperties.scale,
base_y + tileProperties.height/4 * tileProperties.scale + tileProperties.scale * 2
)
table.insert(objects.platforms,plat)
elseif type == "ramp2_bot_left_whole" then
for k = 1, 8 do
-- do ramp owo
local slope = Collision:new(
base_x,
base_y + k * tileProperties.scale - tileProperties.scale,
base_x + k * 2 * tileProperties.scale,
base_y + k * tileProperties.scale
)
table.insert(objects.collisions,slope)
end
-- fill lower half
local col = Collision:new(
base_x,
base_y + tileProperties.height/2 * tileProperties.scale,
base_x + tileProperties.width * tileProperties.scale,
base_y + tileProperties.height * tileProperties.scale
)
table.insert(objects.collisions,col)
elseif type == "ramp2_bot_left_half" then
for k = 1, 8 do
-- do ramp owo
local slope = Collision:new(
base_x,
base_y + tileProperties.height/2 * tileProperties.scale + k * tileProperties.scale - tileProperties.scale,
base_x + k * 2 * tileProperties.scale,
base_y + tileProperties.height/2 * tileProperties.scale + k * tileProperties.scale
)
table.insert(objects.collisions,slope)
end
elseif type == "ramp2_top_left_whole" then
for k = 1, 8 do
-- do ramp owo
local slope = Collision:new(
base_x,
base_y + tileProperties.height/2 * tileProperties.scale - tileProperties.scale + k * tileProperties.scale,
base_x + tileProperties.width * tileProperties.scale - (k-1) * 2 * tileProperties.scale,
base_y + tileProperties.height/2 * tileProperties.scale - tileProperties.scale + k * tileProperties.scale + tileProperties.scale
)
table.insert(objects.collisions,slope)
end
-- fill higher half
local col = Collision:new(
base_x,
base_y,
base_x + tileProperties.width * tileProperties.scale,
base_y + tileProperties.height/2 * tileProperties.scale
)
table.insert(objects.collisions,col)
elseif type == "ramp2_top_left_half" then
for k = 1, 8 do
-- do ramp owo
local slope = Collision:new(
base_x,
base_y - tileProperties.scale + k * tileProperties.scale,
base_x + tileProperties.width * tileProperties.scale - (k-1) * 2 * tileProperties.scale,
base_y - tileProperties.scale + k * tileProperties.scale + tileProperties.scale
)
table.insert(objects.collisions,slope)
end
elseif type == "ramp2_bot_right_whole" then
for k = 1, 8 do
-- do ramp owo
local slope = Collision:new(
base_x + (k-8) * -2 * tileProperties.scale,
base_y - tileProperties.scale + k * tileProperties.scale,
base_x + tileProperties.width * tileProperties.scale,
base_y - tileProperties.scale + k * tileProperties.scale + tileProperties.scale
)
table.insert(objects.collisions,slope)
end
-- fill lower half
local col = Collision:new(
base_x,
base_y + tileProperties.height/2 * tileProperties.scale,
base_x + tileProperties.width * tileProperties.scale,
base_y + tileProperties.height * tileProperties.scale
)
table.insert(objects.collisions,col)
elseif type == "ramp2_bot_right_half" then
for k = 1, 8 do
-- do ramp owo
local slope = Collision:new(
base_x + (k-8) * -2 * tileProperties.scale,
base_y + tileProperties.height/2 * tileProperties.scale - tileProperties.scale + k * tileProperties.scale,
base_x + tileProperties.width * tileProperties.scale,
base_y + tileProperties.height/2 * tileProperties.scale - tileProperties.scale + k * tileProperties.scale + tileProperties.scale
)
table.insert(objects.collisions,slope)
end
elseif type == "ramp2_top_right_half" then
for k = 1, 8 do
-- do ramp owo
local slope = Collision:new(
base_x + (k-8) * -2 * tileProperties.scale,
base_y + tileProperties.height/2 * tileProperties.scale - k * tileProperties.scale,
base_x + tileProperties.width * tileProperties.scale,
base_y + tileProperties.height/2 * tileProperties.scale - k * tileProperties.scale + tileProperties.scale
)
table.insert(objects.collisions,slope)
end
elseif type == "ramp2_top_right_whole" then
for k = 1, 8 do
-- do ramp owo
local slope = Collision:new(
base_x + (k-8) * -2 * tileProperties.scale,
base_y + tileProperties.height/2 * tileProperties.scale + tileProperties.height/2 * tileProperties.scale - k * tileProperties.scale,
base_x + tileProperties.width * tileProperties.scale,
base_y + tileProperties.height/2 * tileProperties.scale + tileProperties.height/2 * tileProperties.scale - k * tileProperties.scale + tileProperties.scale
)
table.insert(objects.collisions,slope)
end
-- fill higher half
local col = Collision:new(
base_x,
base_y,
base_x + tileProperties.width * tileProperties.scale,
base_y + tileProperties.height/2 * tileProperties.scale
)
table.insert(objects.collisions,col)
elseif type == "ramp1_bot_left" then
for k = 1, 16 do
-- do ramp owo
local slope = Collision:new(
base_x,
base_y + k * tileProperties.scale - tileProperties.scale,
base_x + k * tileProperties.scale,
base_y + k * tileProperties.scale
)
table.insert(objects.collisions,slope)
end
elseif type == "ladder_right" then
local ladder = Collision:new(
base_x + (tileProperties.width-4)* tileProperties.scale,
base_y,
base_x + tileProperties.width * tileProperties.scale,
base_y + tileProperties.height * tileProperties.scale
)
table.insert(objects.ladders,ladder)
elseif type == "ladder_platform_right" then
local ladder = Collision:new(
base_x + (tileProperties.width-4)* tileProperties.scale,
base_y + tileProperties.scale * 2,
base_x + tileProperties.width * tileProperties.scale,
base_y + tileProperties.height * tileProperties.scale
)
table.insert(objects.ladders,ladder)
local plat = Collision:new(
base_x,
base_y + tileProperties.scale * 2,
base_x + tileProperties.width * tileProperties.scale,
base_y + tileProperties.height/4 * tileProperties.scale + tileProperties.scale * 2
)
table.insert(objects.platforms,plat)
elseif type == "ladder_left" then
local ladder = Collision:new(
base_x,
base_y,
base_x + tileProperties.scale * 4,
base_y + tileProperties.height * tileProperties.scale
)
table.insert(objects.ladders,ladder)
elseif type == "ladder_platform_left" then
local ladder = Collision:new(
base_x,
base_y + tileProperties.scale * 2,
base_x + tileProperties.scale * 4,
base_y + tileProperties.height * tileProperties.scale
)
table.insert(objects.ladders,ladder)
local plat = Collision:new(
base_x,
base_y + tileProperties.scale * 2,
base_x + tileProperties.width * tileProperties.scale,
base_y + tileProperties.height/4 * tileProperties.scale + tileProperties.scale * 2
)
table.insert(objects.platforms,plat)
end
end
end
end
end
function AnimateTiles()
for _, properties in pairs(Tiles) do
if properties.animation ~= nil then
-- calculate subimage
properties.current_subimage = properties.current_subimage + current_dt
-- cycle image
if properties.current_subimage >= properties.delay then
properties.current_subimage = properties.current_subimage - properties.delay
properties.current_image = properties.current_image + 1
end
if properties.current_image > properties.image_count then
properties.current_image = properties.current_image - properties.image_count
end
end
end
end
function DrawTile(tile_id,x,y,depth)
for _, properties in pairs(Tiles) do
if tile_id == properties.id then
if properties.animation ~= nil then
if properties.imgs[properties.current_image] ~= nil
and properties.depth == depth
then love.graphics.draw(
properties.tileset,
properties.imgs[properties.current_image],
x,
y,
0,
tileProperties.scale,
tileProperties.scale
) end
elseif properties.depth == depth then
if properties.force ~= nil then
love.graphics.draw(
tileProperties.tileset,
TileIndex[properties.force],
x,
y,
0,
tileProperties.scale,
tileProperties.scale
)
else
love.graphics.draw(
tileProperties.tileset,
TileIndex[properties.id],
x,
y,
0,
tileProperties.scale,
tileProperties.scale
)
end
end
if properties.overlay ~= nil then
if properties.overlay_depth == depth or properties.overlay_depth == nil and properties.depth == depth then
if properties.overlay_animated then
for _, overlay_properties in pairs(Tiles) do
if overlay_properties.id == properties.overlay then
love.graphics.draw(
overlay_properties.tileset,
overlay_properties.imgs[overlay_properties.current_image],
x,
y,
0,
tileProperties.scale,
tileProperties.scale
)
end
end
else
love.graphics.draw(
tileProperties.tileset,
TileIndex[properties.overlay],
x,
y,
0,
tileProperties.scale,
tileProperties.scale
)
end
end
end
end
end
end

9
data/scripts/math.lua Normal file
View File

@@ -0,0 +1,9 @@
function math.sign(x)
if x<0 then
return -1
elseif x>0 then
return 1
else
return 0
end
end

106
data/scripts/objects.lua Normal file
View File

@@ -0,0 +1,106 @@
objects = {
entities = {},
collisions = {},
platforms = {},
ladders = {}
}
-- level functions
function objects.DrawCollisions()
for _, col in pairs(objects.collisions) do
col:Draw(1)
end
for _, plat in pairs(objects.platforms) do
if plat.disable == true then plat:Draw(2) end
if plat.disable == false then plat:Draw(1) end
end
for _, ladder in pairs(objects.ladders) do
ladder:Draw(2)
end
end
-- returns true if theres a collision at that point. also marks collisioned tile as collision true
function isThereCollisionAt(x,y)
local result = false
for _, col in pairs(objects.collisions) do
if x >= col.from.x and x <= col.to.x and y >= col.from.y and y <= col.to.y then
result = true
col.collision = true
end
end
return result
end
function isTherePlatformAt(x,y)
local result = false
for _, col in pairs(objects.platforms) do
if x >= col.from.x and x <= col.to.x and y >= col.from.y and y <= col.to.y and col.disable ~= true then
result = true
col.collision = true
end
end
return result
end
function isThereLadderAt(x,y)
local result = false
for _, col in pairs(objects.ladders) do
if x >= col.from.x and x <= col.to.x and y >= col.from.y and y <= col.to.y and col.disable ~= true then
result = true
col.collision = true
end
end
return result
end
function isThereAnyCollisionAt(x,y)
local result = false
if not result then
for _, col in pairs(objects.collisions) do
if x >= col.from.x and x <= col.to.x and y >= col.from.y and y <= col.to.y then
result = true
col.collision = true
end
end
end
if not result then
for _, col in pairs(objects.ladders) do
if x >= col.from.x and x <= col.to.x and y >= col.from.y and y <= col.to.y and col.disable ~= true then
result = true
col.collision = true
end
end
end
if not result then
for _, col in pairs(objects.platforms) do
if x >= col.from.x and x <= col.to.x and y >= col.from.y and y <= col.to.y and col.disable ~= true then
result = true
col.collision = true
end
end
end
return result
end
-- flags
function SetCollisionFlags(player)
for _, col in pairs(objects.collisions) do
col.collision = false
end
for _, plat in pairs(objects.platforms) do
plat.collision = false
if player.pos.y < plat.from.y then
plat.disable = false
else
plat.disable = true
end
end
for _, ladder in pairs(objects.ladders) do
ladder.collision = false
end
end

60
data/scripts/pause.lua Normal file
View File

@@ -0,0 +1,60 @@
function PauseUI()
--Parameters
local pauseWidth = 640
local pauseHeight = 480
local pauseX = (game.width/2)-(pauseWidth/2)
local pauseY = (game.height/2)-(pauseHeight/2)
local mouse_x, mouse_y = love.mouse.getPosition()
--Base items
love.graphics.setColor(0,0,0,0.3)
love.graphics.rectangle("fill", 0, 0, game.width, game.height)
love.graphics.setColor(1,1,1,1)
love.graphics.rectangle("fill", pauseX, pauseY, pauseWidth, pauseHeight)
--Close buttom
love.graphics.setColor(1,0,0,1)
love.graphics.rectangle("fill", pauseX+pauseWidth-40, pauseY+10, 30, 30)
if love.mouse.isDown(1) then
if mouse_x >= pauseX+pauseWidth-40
and mouse_y >= pauseY+10
and mouse_x <= pauseX+pauseWidth-10
and mouse_y <= pauseY+40 then
do_pause = false
end
end
if pausepage == 1 then
--Game list button
love.graphics.setColor(0.5,0.5,0.5,1)
love.graphics.rectangle("fill", pauseX+(pauseWidth/2)-150, pauseY+100, 300, 40)
love.graphics.setColor(0,0.5,0.5,1)
love.graphics.printf("GAMES", pauseX+(pauseWidth/2), pauseY+100, 150, "left",0,3)
if love.mouse.isDown(1) then
if mouse_x >= pauseX+(pauseWidth/2)-150
and mouse_y >= pauseY+100
and mouse_x <= pauseX+(pauseWidth/2)+150
and mouse_y <= pauseY+140 then
pausepage = 2
end
end
elseif pausepage == 2 then
--Back button
love.graphics.setColor(0.5,0.5,0.5,1)
love.graphics.rectangle("fill", pauseX+10, pauseY+10, 30, 30)
love.graphics.setColor(0,0,0,1)
love.graphics.printf("<", pauseX+10, pauseY+10, 30, "left", 0, 2)
if love.mouse.isDown(1) then
if mouse_x >= pauseX+10
and mouse_y >= pauseY+10
and mouse_x <= pauseX+40
and mouse_y <= pauseY+40 then
pausepage = 1
end
end
love.graphics.setColor(1,1,1,1)
for i=1,2 do
for j=1,3 do
love.graphics.draw(image.cartridge.nancy, j*110, i*85, 0, 100/image.cartridge.nancy:getPixelWidth(), 80/image.cartridge.nancy:getPixelHeight())
end
end
end
end