restructured folder

This commit is contained in:
lustlion
2022-02-12 11:36:43 +01:00
parent e51905de67
commit 8ddf3610ac
33 changed files with 49 additions and 44 deletions

78
code/animation.lua Normal file
View File

@@ -0,0 +1,78 @@
Animation = {}
function Animation:New(anim_data)
local o = {}
o.path = anim_data.path
o.frames = anim_data.frames
o.speed = anim_data.speed
o.imgs = anim_data.imgs
o.subframe = 0
o.frame = 1
setmetatable(o, self)
self.__index = self
return o
end
function Animation:ChangeTo(anim_data)
if anim_data.path == self.path
then
return self
else
return Animation:New(anim_data)
end
end
-- to manually handle what frame
function Animation:DrawFrame(frame, x, y, rotate, sx, sy)
if frame > self.frames then
frame = self.frames
end
local x = x or 0
local y = y or 0
local sx = sx or 1
local sy = sy or 1
love.graphics.draw(
self.imgs[frame],
math.floor(x - Camera.pos.x),
math.floor(y - Camera.pos.y),
rotate,
sx,
sy
)
end
-- to linearly animate
function Animation:Animate()
if self.speed ~= 0 then
-- try to animate
self.subframe = self.subframe + current_dt
if self.subframe > self.speed then
self.frame = self.frame + 1
self.subframe = self.subframe - self.speed
end
-- cycle
if self.frame >= self.frames+1 then
self.frame = self.frame - self.frames
end
end
end
-- to draw the current frame
function Animation:Draw(x, y, rotate, sx, sy)
local x = x or 0
local y = y or 0
local sx = sx or 1
local sy = sy or 1
love.graphics.draw(
self.imgs[self.frame],
math.floor(x),
math.floor(y),
rotate,
sx,
sy
)
end

47
code/audio.lua Normal file
View File

@@ -0,0 +1,47 @@
-- snippet from
-- https://love2d.org/wiki/Minimalist_Sound_Manager
-- <3
do
-- will hold the currently playing sources
local sources = {}
-- check for sources that finished playing and remove them
-- add to love.update
function love.audio.update()
local remove = {}
for _,s in pairs(sources) do
if not s:isPlaying() then
remove[#remove + 1] = s
end
end
for i,s in ipairs(remove) do
sources[s] = nil
end
end
-- overwrite love.audio.play to create and register source if needed
local play = love.audio.play
function love.audio.play(audio)
local what = audio.path
local how = audio.type
local loop = audio.loop
local src = what
if type(what) ~= "userdata" or not what:typeOf("Source") then
src = love.audio.newSource(what, how)
src:setLooping(loop or false)
end
play(src)
sources[src] = src
return src
end
-- stops a source
local stop = love.audio.stop
function love.audio.stop(src)
if not src then return end
stop(src)
sources[src] = nil
end
end

21
code/camera.lua Normal file
View File

@@ -0,0 +1,21 @@
Camera = {
pos = {x = 0, y = 0},
width = 0,
height = 0
}
function Camera:ConfineToLevel()
self.pos.x = math.max(0,math.min(self.pos.x,LevelData.Width-self.width/game.scale))
self.pos.y = math.max(0,math.min(self.pos.y,LevelData.Height-self.height/game.scale))
end
function Camera:positionCenterAt(x,y)
self.pos.x = x-self.width/game.scale/2
self.pos.y = y-self.height/game.scale/2
self:ConfineToLevel()
end
function Camera:positionAt(x,y)
self.pos.x = math.floor((x/self.width)*self.width)
self.pos.y = math.floor((y/self.height)*self.height)
end

73
code/collision.lua Normal file
View File

@@ -0,0 +1,73 @@
Collision = {}
--[[
Collision
[bool flag] isDisabled
> if true used for collision
[bool flag] isColliding
> if true, this collision is colliding
[vec2 position] from - x, y
> top right corner of collision box
[vec2 position] to - x, y
> bottom left corner of collision box
[int property] width
> width of collision box
[int property] 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}
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 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)
love.graphics.setColor(0,1,90,0.5)
love.graphics.rectangle("line",self.from.x-Camera.pos.x, self.from.y-Camera.pos.y, self.width, self.height)
end

98
code/debug.lua Normal file
View File

@@ -0,0 +1,98 @@
function DebugUI()
local mouse_x, mouse_y = love.mouse.getPosition()
for _, light in pairs(Lights) do
love.graphics.print(light.pos.x,light.pos.x,light.pos.y)
love.graphics.print(light.pos.y,light.pos.x,light.pos.y+20)
love.graphics.print(light.pos.x,light.pos.x,light.pos.y+40)
end
love.graphics.print("time: "..fps_total..", fps: "..fps_draw..", frametime: "..math.floor(current_dt* 1000).."ms", 10*textScale, 0*textScale, 0, textScale)
love.graphics.print(--[["CPUtime: "..checkCPUTime("total")..", CPU: "..(math.floor(checkCPUTime("get")*10000)/100).."%,]] "memoryUsage: "..memoryUsage.."kB", 10*textScale, 20*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.sprite_scale.x..", "..main_Player.sprite_scale.y.."}",10*textScale,100*textScale, 0, textScale)
love.graphics.print("states: \"isOnGround\": "..tostring(main_Player.isOnGround),10*textScale,120*textScale, 0, textScale)
love.graphics.print("\"coyoteValue\": "..tostring(main_Player.coyoteValue),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("[Cursor]",10*textScale,220*textScale, 0, textScale)
love.graphics.print("position: {"..mouse_x+Camera.pos.x..", "..mouse_y+Camera.pos.y.."}",10*textScale,240*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)
end
function DebugColisions()
LoadedObjects.DrawCollisions()
end
function DebugEntities()
for _, particle in pairs(LoadedParticles) do
particle:Debug()
end
for _, enty in pairs(LoadedObjects.Entities) do
enty:Debug()
end
end
--[[CPUUsage = {}
function checkCPUTime(action, name)
if name then
if action == "start" then
if CPUUsage.name == nil then CPUUsage.name = {} end
CPUUsage.name.start = os.clock()
elseif action == "fin" then
CPUUsage.name.fin = os.clock()
CPUUsage.name.use = CPUUsage.name.fin - CPUUsage.name.start
if CPUUsage.name.total == nil then CPUUsage.name.total = 0 end
CPUUsage.name.total = CPUUsage.name.total + CPUUsage.name.use
print(CPUUsage.name.fin.." : "..CPUUsage.name.use.." : "..CPUUsage.name.total)
elseif action == "get" then
return CPUUsage.name.use
elseif action == "total" then
return CPUUsage.name.total
else
return CPUUsage.name.use
end
-- Totals
else
if action == "get" then
local currentTotalCPU = 0
for _, timings in ipairs(CPUUsage) do
currentTotalCPU = currentTotalCPU + CPUUsage.timings.use
end
return currentTotalCPU
elseif action == "total" then
local currentTotalCPU = 0
for _, timings in ipairs(CPUUsage) do
currentTotalCPU = currentTotalCPU + CPUUsage.timings.total
end
return currentTotalCPU
else
local currentTotalCPU = 0
for _, timings in ipairs(CPUUsage) do
currentTotalCPU = currentTotalCPU + CPUUsage.timings.use
end
return currentTotalCPU
end
end
end]]
function logPrint(string)
if logging then print(string) end
logWrite(string)
end
function logWrite(string)
if logging then logFile:write(string.."\n") end
end

237
code/editor.lua Normal file
View File

@@ -0,0 +1,237 @@
function EditorStep()
palette = palette or false
AnimateTiles()
if Keybind:HasPressed(Keybind.editor.palette) then
if palette then
palette = false
palette_scroll_x = nil
palette_scroll_y = nil
else
palette = true
palette_scroll_x = 0
palette_scroll_y = 0
end
end
if love.keyboard.isDown('a',"left") then
Camera.pos.x = Camera.pos.x - 3*game.scale
end
if love.keyboard.isDown('d',"right") then
Camera.pos.x = Camera.pos.x + 3*game.scale
end
if love.keyboard.isDown("up", "w") then
Camera.pos.y = Camera.pos.y - 3*game.scale
end
if love.keyboard.isDown("down", "s") then
Camera.pos.y = Camera.pos.y + 3*game.scale
end
if palette then
if Keybind:HasPressed(Keybind.debug.debug) then
local next = false
local export = nil
for k, v in pairs(tileset) do
if export == nil then
export = v
end
if next then
LevelData.tileset = v
next = false
break
end
if v == LevelData.tileset then
next = true
end
end
if next then
LevelData.tileset = export
end
LevelGetTileData()
LevelIndexTiles()
end
end
if Keybind:HasPressed(Keybind.debug.reload) then
ExportLevel("test")
end
if Keybind:HasPressed(Keybind.debug.editor) then
editor_mode = false
TileCreateObjects()
end
end
function EditorScroll(y)
if palette then
if love.keyboard.isDown("lshift") then
palette_scroll_y = palette_scroll_y + y
else
palette_scroll_x = palette_scroll_x + y
end
else
local oscale = game.scale
game.scale = math.max(0.1,game.scale + y/16)
end
end
function EditorDraw()
GameworldDrawPrepare()
GameworldDrawBackground()
GridDisplay()
GameworldDrawForeground()
GameworldDrawEnd()
EditorDoEdit()
DrawSelectingPaletteTile()
if palette then
EditorDoPalette()
end
end
function EditorDoEdit()
local mouse_x = love.mouse.getX()
local mouse_y = love.mouse.getY()
local horizontal = 1+math.floor(((mouse_x/game.scale) / tileProperties.width) + (Camera.pos.x / tileProperties.width))
local vertical = 1+math.floor(((mouse_y/game.scale) / tileProperties.height) + (Camera.pos.y / tileProperties.height))
local expand_h = 0
local expand_v = 0
local LevelWidth = LevelGetTileWidth()
local LevelHeight = LevelGetTileHeight()
if horizontal > LevelWidth then
expand_h = horizontal-LevelWidth
elseif horizontal < 0 then
expand_h = horizontal
end
if vertical > LevelHeight then
expand_v = vertical-LevelHeight
elseif vertical < 0 then
expand_v = vertical
end
love.graphics.print("> " .. horizontal .. ", " .. vertical .. "; " .. math.floor(mouse_x / game.scale + Camera.pos.x) .. ", " .. math.floor(mouse_y / game.scale + Camera.pos.y))
love.graphics.print("> " .. LevelWidth .. "(" .. expand_h .. "), " .. LevelHeight .. "(".. expand_v .. ")", 0, 10)
if not palette then
if LevelTiles[vertical] ~= nil
and LevelTiles[vertical][horizontal] ~= nil
and love.keyboard.isDown("lshift") ~= true
and love.keyboard.isDown("lctrl") ~= true
then
if Keybind:CheckDown(Keybind.generic.lclick)
and selecting_tile ~= nil
then
SetTile(vertical,horizontal,selecting_tile)
elseif Keybind:CheckDown(Keybind.generic.rclick) then
SetTile(vertical,horizontal,0)
end
LevelReloadTiles()
elseif Keybind:HasPressed(Keybind.generic.lshift) then
LevelExpandCanvas(math.sign(expand_h),math.sign(expand_v))
LevelReloadTiles()
elseif Keybind:HasPressed(Keybind.generic.lctrl) then
LevelReduceCanvas(math.sign(expand_h),math.sign(expand_v))
LevelReloadTiles()
end
end
end
function DrawSelectingPaletteTile()
if selecting_tile ~= nil and selecting_tile ~= 0 then
local mouse_x = love.mouse.getX()
local mouse_y = love.mouse.getY()
local horizontal = math.floor(((mouse_x/game.scale) / tileProperties.width) + (Camera.pos.x / tileProperties.width))
local vertical = math.floor(((mouse_y/game.scale) / tileProperties.height) + (Camera.pos.y / tileProperties.height))
local draw_x = tileProperties.width * horizontal - Camera.pos.x
local draw_y = tileProperties.height * vertical - Camera.pos.y
love.graphics.draw(
LevelData.tileset,
TileIndex[selecting_tile],
draw_x,
draw_y
)
end
end
function EditorDoPalette()
local width = LevelData.tileset:getPixelWidth()/tileProperties.width
local height = LevelData.tileset:getPixelHeight()/tileProperties.height
love.graphics.setColor(0,0,0,1)
love.graphics.rectangle(
"fill",
(palette_scroll_x + 1) * (tileProperties.width+1),
(palette_scroll_y + 1) * (tileProperties.height+1),
1 + LevelData.tileset:getPixelWidth() * ((tileProperties.width+1) / tileProperties.width),
1 + LevelData.tileset:getPixelHeight()* ((tileProperties.height+1) / tileProperties.height)
)
love.graphics.setColor(1,1,1,1)
local position_x = 1
local position_y = 1
for i = 1, #TileIndex-width-1 do
local tile_x = (palette_scroll_x + position_x) * (tileProperties.width+1)
local tile_y = (palette_scroll_y + position_y) * (tileProperties.height+1)
love.graphics.draw(
LevelData.tileset,
TileIndex[i],
tile_x,
tile_y,
0,
1,
1
)
if Keybind:CheckDown(Keybind.generic.lclick) then
local mouse_x = love.mouse.getX()
local mouse_y = love.mouse.getY()
if mouse_x > (tile_x) * game.scale
and mouse_x < (tile_x + tileProperties.width) * game.scale
and mouse_y > (tile_y) * game.scale
and mouse_y < (tile_y + tileProperties.height) * game.scale
then
selecting_tile = position_x + ((position_y-1) * width)
love.graphics.print(selecting_tile .. " | " .. tile_x .. ", " .. tile_y, 0, 20)
end
end
if Keybind:CheckDown(Keybind.generic.rclick) then
selecting_tile = nil
end
if selecting_tile ~= nil and selecting_tile ~= 0 and i == selecting_tile then
love.graphics.setColor(1,0,1,1)
love.graphics.rectangle(
"line",
tile_x,
tile_y,
tileProperties.width,
tileProperties.height
)
love.graphics.setColor(1,1,1,1)
end
position_x = position_x + 1
if position_x > width then
position_x = position_x - width
position_y = position_y + 1
end
end
love.graphics.rectangle(
"line",
(palette_scroll_x + 1) * (tileProperties.width+1),
(palette_scroll_y + 1) * (tileProperties.height+1),
1 + LevelData.tileset:getPixelWidth() * ((tileProperties.width+1) / tileProperties.width),
1 + LevelData.tileset:getPixelHeight()* ((tileProperties.height+1) / tileProperties.height)
)
end

78
code/entities/arrow.lua Normal file
View File

@@ -0,0 +1,78 @@
Arrow = Entity:New(x,y)
function Arrow:New(x,y,rotation,speed)
local o = Entity:New(x,y)
o.type = "arrow"
o.pos = {x = x, y = y}
o.speed = speed or 0
o.sprite_rotation = rotation or 0
o.vel = {
x = o.speed * math.cos(o.sprite_rotation),
y = o.speed * math.sin(o.sprite_rotation)
}
o.sprite_offset = {x = 13, y = 1}
o.stuck = false
o.illuminated = true
-- animations
o.body = Animation:New(animation.kupo.arrow)
table.insert(LoadedObjects.Entities,o)
o.id = #LoadedObjects.Entities
setmetatable(o, self)
self.__index = self
return o
end
function Arrow:HandleAnimation()
self:Draw(self.body)
end
function Arrow:DoPhysics()
if not self.stuck then
-- horizontal collisions
if not isThereAnyCollisionAt(
self.pos.x + self.vel.x,
self.pos.y
) then
self.pos.x = self.pos.x + self.vel.x
else
while not isThereObjectAt(
self.pos.x + math.sign(self.vel.x),
self.pos.y,
LoadedObjects.Collisions
) do
self.pos.x = self.pos.x + math.sign(self.vel.x)
end
self.stuck = true
end
-- vertical collision
if not isThereAnyCollisionAt(
self.pos.x,
self.pos.y + self.vel.y
) then
self.pos.y = self.pos.y + self.vel.y
else
while not isThereObjectAt(
self.pos.x,
self.pos.y + math.sign(self.vel.y),
LoadedObjects.Collisions
) do
self.pos.y = self.pos.y + math.sign(self.vel.y)
end
self.stuck = true
end
-- stuck into collisions
if self.stuck then
--lets allow the arrow to tip a bit into the thing
self.pos.x = self.pos.x + self.vel.x / 5
self.pos.y = self.pos.y + self.vel.y / 5
self.vel.x = 0
self.vel.y = 0
self.illuminated = false
end
end
end

View File

@@ -0,0 +1,119 @@
CursedBook = Entity:New(x,y)
function CursedBook:New(x,y)
local o = Entity:New(x,y)
o.type = "cursed_book"
-- behaviour
o.pos = {x = x, y = y}
o.speed = 0.01
o.range = 20
o.target = {x = x, y = y}
o.status = 0
-- 0 - sleep
-- 1 - getting up
-- 2 - flying
-- 3 - attack windup
-- 4 - attack
o.spawn_range = 100
o.attack_range = 50
-- animations
o.body = Animation:New(animation.cursed_book.spawn)
o.sprite_tint = {0.7,0.7,0.7}
o:centerOffset(o.body)
o:getBoundingBox(o.body)
-- light
o.light_range = 500
o.light = CreateLight(o.pos.x,o.pos.y,o.light_range,2,HEX2RGB("#fe00d1"))
table.insert(LoadedObjects.Entities,o)
o.id = #LoadedObjects.Entities
setmetatable(o, self)
self.__index = self
return o
end
function CursedBook:Smart()
self.target.x = main_Player.pos.x - main_Player.target_offset.x
self.target.y = main_Player.pos.y - main_Player.target_offset.y
local distance_x = self.target.x - self.pos.x
local distance_y = self.target.y - self.pos.y
local angle = GetAngleFromVector(distance_x,distance_y)
local distance = math.sqrt(distance_x ^ 2 + distance_y ^ 2)
if self.status == 0 then
if distance < self.spawn_range then
self.status = 1
end
elseif self.status == -1 then
if distance < self.range then
self.vel.x = 0
self.vel.y = 0
else
self.vel.x = math.cos(angle)*self.speed*distance
self.vel.y = math.sin(angle)*self.speed*distance
end
elseif self.status == 2 then
if distance < self.attack_range then
self.status = 3
end
elseif self.status == 4 then
end
end
function CursedBook:HandleAnimation()
if self.status == 1 then
if self.body.path == "assets/entities/cursed_book/spawn" then
self.body.speed = 1/3
local tint = 0.7 + 0.3 * (self.body.frame-1)/self.body.frames
self.sprite_tint = {tint,tint,tint}
if self.body.frame == self.body.frames then
self.status = 2
self.body = self.body:ChangeTo(animation.cursed_book.flying)
self.sprite_tint = {1,1,1}
--self:getBoundingBox(self.body,2,2,-2,-2)
self:centerOffset(self.body)
end
end
elseif self.status == 3 then
if self.body.path == "assets/entities/cursed_book/flying" then
self.body = self.body:ChangeTo(animation.cursed_book.attack_transition)
self.body.speed = 1/3
self:centerOffset(self.body)
if self.body.frame == self.body.frames then
self.status = 4
self.body = self.body:ChangeTo(animation.cursed_book.attack_loop)
self:centerOffset(self.body)
end
end
end
self.body:Animate()
self:Draw(self.body)
end
function CursedBook:DoPhysics()
if self.isFlying then
local random_x = math.random(-4, 4)/100
local random_y = math.random(-4, 4)/100
self.vel.x = self.vel.x + random_x
self.vel.y = self.vel.y + random_y
end
-- move
self:CollisionMove()
self:LightAdjust()
end
function CursedBook:Debug()
-- draw center GREEN
love.graphics.setColor(0,1,0)
love.graphics.circle("line", -Camera.pos.x + self.pos.x, -Camera.pos.y + self.pos.y, self.spawn_range)
love.graphics.setColor(1,0,0)
love.graphics.circle("line", -Camera.pos.x + self.pos.x, -Camera.pos.y + self.pos.y, self.attack_range)
Entity.Debug(self)
end

View File

@@ -0,0 +1,34 @@
Decoration = Entity:New(x,y)
function Decoration:New(x,y,animation,lightRange)
local o = Entity:New(x,y)
o.type = "decoration"
o.pos = {x = x, y = y}
-- animations
o.body = Animation:New(animation)
o:centerOffset(o.body)
o:getBoundingBox(o.body)
if lightRange ~= nil then
o.lightRange = lightRange
o.light = CreateLight(o.pos.x,o.pos.y,o.lightRange)
end
table.insert(LoadedObjects.Entities,o)
o.id = #LoadedObjects.Entities
setmetatable(o, self)
self.__index = self
return o
end
function Decoration:HandleAnimation()
self.body:Animate()
self:Draw(self.body)
end
function Decoration:DoPhysics()
end

115
code/entities/fairy.lua Normal file
View File

@@ -0,0 +1,115 @@
Fairy = Entity:New(x,y)
function Fairy:New(x,y)
local o = Entity:New(x,y)
o.type = "fairy"
-- behaviour
o.pos = {x = x, y = y}
o.speed = 1.4
o.range = 20
o.vision_range = 120
o.target = {x = x, y = y}
o.hover_distance = 60
-- animations
o.body = Animation:New(animation.fairy.flying)
o:centerOffset(o.body)
o:getBoundingBox(o.body)
-- light
o.light_range = 80
o.light = CreateLight(o.pos.x,o.pos.y,o.light_range,nil,HEX2RGB("#fed100"))
-- timer
o.particle_timer = 0
o.particle_time = 5
table.insert(LoadedObjects.Entities,o)
o.id = #LoadedObjects.Entities
setmetatable(o, self)
self.__index = self
return o
end
function Fairy:Smart()
if self:CheckVisionLine(main_Player,self.vision_range) then
self.target.x = main_Player.pos.x + main_Player.target_offset.x
self.target.y = main_Player.pos.y + main_Player.target_offset.y
local below = 1
while not isThereObjectAt(
self.target.x,
self.target.y + below * game.scale,
LoadedObjects.Collisions
) do
below = below + 1
if below >= self.hover_distance then break end
end
local top = 1
while not isThereObjectAt(
self.target.x,
self.target.y - top * game.scale,
LoadedObjects.Collisions
) do
top = top + 1
if top >= self.hover_distance then break end
end
self.target.y = self.target.y - top + below
end
local distance_x = self.target.x - self.pos.x
local distance_y = self.target.y - self.pos.y
local angle = GetAngleFromVector(distance_x,distance_y)
local distance = math.sqrt(distance_x ^ 2 + distance_y ^ 2)
if distance < self.range then
self.vel.x = 0
self.vel.y = 0
else
self.vel.x = math.cos(angle)*self.speed
self.vel.y = math.sin(angle)*self.speed
end
self.particle_timer = self.particle_timer + 1
if self.particle_timer >= self.particle_time then
self.particle_timer = 0
local particle_data = {
animation = animation.particle.simple,
sprite_tint = HEX2RGB("#fed100"),
direction = angle-math.rad(180+math.random(60)-30),
speed = 0.8*(distance/50),
speed_increase = -0.01,
}
Particle:New(self.pos.x,self.pos.y,particle_data)
end
end
function Fairy:HandleAnimation()
self.body:Animate()
--if self:isCollidingWith(main_Player) then self.sprite_tint = {1,0,0} else self.sprite_tint = {1,1,1} end
self:Draw(self.body)
end
function Fairy:DoPhysics()
local random_x = math.random(-4, 4)/10
local random_y = math.random(-4, 4)/10
self.vel.x = self.vel.x + random_x
self.vel.y = self.vel.y + random_y
self:CollisionMove()
self.vel.x = 0
self.vel.y = 0
self:LightAdjust()
end
function Fairy:Debug()
Entity.Debug(self)
self:CheckVisionLineDebug(main_Player,self.vision_range)
end

168
code/entities/kupo.lua Normal file
View File

@@ -0,0 +1,168 @@
Kupo = Entity:New(x,y)
function Kupo:New(x,y)
local o = Entity:New(x,y)
o.type = "kupo"
o.pos = {x = x, y = y}
o.speed = 20
o.range = 200
o.target = {x = x, y = y}
o.sprite_offset = {x = 8, y = 5}
-- animations
o.body = Animation:New(animation.kupo.body)
o.bow = Animation:New(animation.kupo.bow)
-- bow
o.bow_flip = 1
o.bow_rotation = 0
o.bow_frame = 1
o.bow_subframe = 1
o.bow_aim_frame = 0
o.bow_speed = 1/10
o.bow_frames = 6
o.bow_extraframes = 18
o.bow_aim_frames = 8
o.hostile = true
o.lightRange = o.range/2
o.light = CreateLight(o.pos.x,o.pos.y,o.lightRange)
table.insert(LoadedObjects.Entities,o)
o.id = #LoadedObjects.Entities
setmetatable(o, self)
self.__index = self
return o
end
function Kupo:Smart()
self.light.pos.x = self.pos.x-self.target_offset.x
self.light.pos.y = self.pos.y-self.target_offset.y
self.target.x = main_Player.pos.x - main_Player.target_offset.x
self.target.y = main_Player.pos.y - main_Player.target_offset.y
local distance_x = self.target.x - self.pos.x
local distance_y = self.target.y - self.pos.y
local distance = math.sqrt(distance_x ^ 2 + distance_y ^ 2)
local angle = GetAngleFromVector(distance_x,distance_y)
self.draw_bow = false
if distance <= self.range then
if self.hostile == true then
self.draw_bow = true
-- fix so it can rotate from 0 to 360
if math.deg(self.bow_rotation - angle) < 0 then
self.bow_rotation = self.bow_rotation + math.rad(360)
end
-- fix so it can rotate from 360 to 0
if math.deg(self.bow_rotation - angle) > 180 then
self.bow_rotation = self.bow_rotation - math.rad(360)
end
-- actual rotation
if self.bow_rotation < angle then
self.bow_rotation = self.bow_rotation + math.rad(2)
else
self.bow_rotation = self.bow_rotation - math.rad(2)
end
--set in place
if math.abs(math.deg(self.bow_rotation) - math.deg(angle)) < 2 then
self.bow_rotation = angle
end
-- holding tight dispersion -- also affects arrows
if self.bow_rotation == angle then
self.bow_rotation = self.bow_rotation + math.rad(math.random(math.abs(math.floor(self.bow_frame-self.bow_aim_frames-self.bow_frames)/2)))
end
-- AIMING AI
self.bow_subframe = self.bow_subframe + current_dt
if self.bow_subframe > self.bow_speed then
self.bow_subframe = self.bow_subframe - self.bow_speed
if self.bow_frame == 3 then
self.bow_aim_frame = self.bow_aim_frame + 1
if self.bow_aim_frame > self.bow_aim_frames then
self.bow_aim_frame = self.bow_aim_frame - self.bow_aim_frames
self.bow_frame = self.bow_frame + 1
Arrow:New(self.pos.x,self.pos.y,self.bow_rotation,15)
end
else
self.bow_frame = self.bow_frame + 1
end
if self.bow_frame > self.bow_frames + self.bow_extraframes then
self.bow_frame = self.bow_frame - self.bow_frames - self.bow_extraframes
end
end
end
else
self.bow_frame = 6
-- rest bow animation
if distance_x > 0 then
if self.bow_rotation > math.rad(45) then
self.bow_rotation = self.bow_rotation - math.rad(3)
elseif self.bow_rotation < math.rad(45) then
self.bow_rotation = self.bow_rotation + math.rad(3)
end
-- set in place
if math.abs(math.deg(self.bow_rotation) - 45) < 3 then
self.bow_rotation = math.rad(45)
end
self.sprite_flip.x = 1
else
if self.bow_rotation > math.rad(135) then
self.bow_rotation = self.bow_rotation - math.rad(3)
elseif self.bow_rotation < math.rad(135) then
self.bow_rotation = self.bow_rotation + math.rad(3)
end
-- set in place
if math.abs(math.deg(self.bow_rotation) - 135) < 3 then
self.bow_rotation = math.rad(135)
end
self.sprite_flip.x = -1
end
end
self.angle = angle
end
function Kupo:HandleAnimation()
local distance_x = self.target.x - self.pos.x
local distance_y = self.target.y - self.pos.y
if distance_x > 0 then
self.sprite_flip.x = 1
else
self.sprite_flip.x = -1
end
-- flip sprite to look in the direction is moving
if self.vel.x ~= 0 then self.sprite_flip.x = math.sign(self.vel.x) end
self.body:Animate()
self:Draw(self.body)
if self.draw_bow == true then
self.bow:DrawFrame(
math.min(self.bow_frame,self.bow_frames),
self.pos.x + ( 8 * math.sin(self.bow_rotation)),
self.pos.y + (2 - 6 * math.cos(self.bow_rotation)),
self.bow_rotation
)
end
end
function Kupo:DoPhysics()
-- horizontal collisions
if not isThereAnyCollisionAt(self.pos.x + self.vel.x, self.pos.y) then
self.pos.x = self.pos.x + self.vel.x
end
if not isThereAnyCollisionAt(self.pos.x, self.pos.y + self.vel.y) then
self.pos.y = self.pos.y + self.vel.y
end
end

View File

@@ -0,0 +1,99 @@
Particle = Entity:New(x,y)
function Particle:New(x,y,particle_data)
local o = Entity:New(x,y)
o.pos = {x = x, y = y}
o.speed = particle_data.speed or 0
o.direction = particle_data.direction or o.direction
o.sprite_rotation = particle_data.sprite_rotation or o.sprite_rotation
o.sprite_offset = particle_data.sprite_offset or o.sprite_offset
o.sprite_scale = particle_data.sprite_scale or o.sprite_scale
o.sprite_tint = particle_data.sprite_tint or o.sprite_tint
o.sprite_alpha = particle_data.sprite_alpha or o.sprite_alpha
o.sprite_alpha_base = o.sprite_alpha
o.sprite_flip = particle_data.sprite_flip or o.sprite_flip
o.animation_active = particle_data.animation_active or false
o.time = 0.5
o.timer = 0
o.vel = {
x = o.speed * math.cos(o.direction),
y = o.speed * math.sin(o.direction)
}
o.speed_increase = particle_data.speed_increase or 0
if particle_data.light ~= nil then
o.lightRange = particle_data.light
local flicker = particle_data.light_flicker or nil
local color = particle_data.light_color or nil
o.light = CreateLight(o.pos.x,o.pos.y,o.lightRange,flicker,color)
end
-- animations
if particle_data.animation ~= nil then
o.body = Animation:New(particle_data.animation)
o:centerOffset(o.body)
o:getBoundingBox(o.body)
if not o.animation_active then
o.body.speed = 0
end
end
table.insert(LoadedParticles,o)
o.id = #LoadedParticles
setmetatable(o, self)
self.__index = self
return o
end
function Particle:Kill()
if self.light ~= nil then
KillLight(self.light)
end
if self.id ~= nil then
for _, e in pairs(LoadedParticles) do
if e.id > self.id then
e.id = e.id - 1
end
end
table.remove(LoadedParticles,self.id)
end
self = nil
end
function Particle:HandleAnimation()
self.timer = self.timer + current_dt
self.sprite_alpha = self.sprite_alpha_base*(self.time-self.timer)/self.time
if self.light ~= nil then
self:LightAdjust()
self.light.range = self.lightRange * self.sprite_alpha/2
end
if self.sprite_alpha < 0 then self:Kill() end
if self.body ~= nil then
self.body:Animate()
self:Draw(self.body)
end
end
function Particle:DoPhysics()
-- adjust speed
if self.speed_increase ~= 0 then
self.speed = self.speed + self.speed_increase
self.vel.x = self.speed * math.cos(self.direction)
self.vel.y = self.speed * math.sin(self.direction)
end
-- move
self:CollisionMove()
end
function Particle:Debug()
-- draw center CYAN
love.graphics.setColor(0,1,1)
love.graphics.circle("fill", -Camera.pos.x + self.pos.x, -Camera.pos.y + self.pos.y, 1)
end

280
code/entities/player.lua Normal file
View File

@@ -0,0 +1,280 @@
Player = Entity:New(x,y)
function Player:New(x,y)
local o = Entity:New(x,y)
o.type = "player"
-- physics
o.moveSpeed = 1.3 -- gameworld pixels
o.zeroSpeed = 0.01 -- gameworld pixels
o.move_x = 0 -- gameworld pixels
o.airFriction = 0.01 -- gameworld pixels
o.groundFriction = 0.3 -- gameworld pixels
o.jumpImpulse = 3.5 -- gameworld pixels
o.coyoteAmount = 5 -- int
o.coyoteValue = 5 -- frames
o.dashCooldownTime = 0.1 -- seconds
o.dashCooldownTimer = 0 -- seconds
-- dash values
o.dashTimer = 0 -- seconds
o.dashTime = 0.15 -- seconds
o.dashDistance = 40 -- gameworld pixels
o.dashSpeed = o.dashDistance / (o.dashTime*60) -- pixels
o.dashCount = 1 -- int
o.dashAmount = 10 -- int
-- hook values
o.hookDistance = 100
o.hookedDistance = 80
o.hookAnchor = {
x = nil,
y = nil
}
o.boxCollision = {
from = {x = -8, y = -16}, --gameworld pixels
to = {x = 8, y = 0} -- gameworld pixels
}
o.lightRange = 10 -- screen pixels
-- status
o.isDashing = false
o.isJumping = false
o.isHooked = false
o.isOnGround = true
o.isOnLadder = false
o.canJump = true
o.canFall = true
o.canFriction = true
o.maskType = animation.moth_mask
o.anchorRespawn = {
x = o.pos.x,
y = o.pos.y
}
-- sprite
o.target_offset = {x = 0, y = 0}
o.body = Animation:New(animation.nancy.idle)
o.mask = Animation:New(animation.moth_mask.idle)
o:centerOffset(o.body)
o:getBoundingBox(o.body,0,3,-1,-3)
-- lights
o.light = CreateLight(o.pos.x,o.pos.y,o.lightRange)
table.insert(LoadedObjects.Entities,o)
o.id = #LoadedObjects.Entities
setmetatable(o, self)
self.__index = self
return o
end
function Player:Smart()
self:LightAdjust(self.target_offset.x,self.target_offset.y)
-- reset coyoteValue
if self.isOnGround then
self.coyoteValue = self.coyoteAmount
elseif self.coyoteValue > 0 then
self.coyoteValue = self.coyoteValue - 1
end
if self.dashTimer <= 0 then
-- horizontal movement
if Keybind:CheckDown(Keybind.move.left) then
self.move_x = -self.moveSpeed
elseif Keybind:CheckDown(Keybind.move.right) then
self.move_x = self.moveSpeed
end
-- jump if on ground (coyotevalue)
if Keybind:CheckDown(Keybind.move.jump) then
if self.coyoteValue > 0 then
self.vel.y = -self.jumpImpulse
self.coyoteValue = 0
end
end
end
-- dash timer
self.dashCooldownTimer = math.max(0,self.dashCooldownTimer - current_dt)
-- try to dash
if Keybind:CheckDown(Keybind.move.dash) then
if self.dashCooldownTimer == 0
and not self.isDashing
and self.dashCount > 0 then
-- state player
self.dashCount = self.dashCount - 1
self.isDashing = true
-- get dash direction
local vertical = 0
if Keybind:CheckDown(Keybind.move.down) then vertical = vertical + 1 end
if Keybind:CheckDown(Keybind.move.up) then vertical = vertical - 1 end
local horizontal = 0
if Keybind:CheckDown(Keybind.move.right) then horizontal = horizontal + 1 end
if Keybind:CheckDown(Keybind.move.left) then horizontal = horizontal - 1 end
-- if no direction, then dash forward
if horizontal == 0 and vertical == 0 then
horizontal = self.sprite_flip.x
end
-- set dash values
self.dashDirection = GetAngleFromVector(horizontal, vertical)
self.dashTimer = self.dashTime
end
else
-- not dashing!
self.isDashing = false
end
if Keybind:CheckDown(Keybind.move.hook) then
local anchor = self:CheckNearest("decoration",self.hookDistance)
if anchor then
self.isHooked = true
self.hookAnchor = {
x = anchor.pos.x,
y = anchor.pos.y
}
end
else
self.isHooked = false
end
end
function Player:DoPhysics()
if self.dashTimer <= 0 then
if self.isOnGround then
self.vel.x = self.vel.x * (1-self.groundFriction)
else
self.vel.x = self.vel.x * (1-self.airFriction)
end
if math.abs(self.vel.x) < self.zeroSpeed then self.vel.x = 0 end
end
-- reset state
self.canFall = true
self.isOnGround = false
-- adjust timers
self.dashTimer = self.dashTimer - current_dt
-- DASH STATE
if self.dashTimer > 0 then
self.canFall = false
-- dash particle
local particle_data = {
animation = self.body,
sprite_tint = HEX2RGB("#fed100"),
sprite_alpha = 0.5,
sprite_flip = {
x = self.sprite_flip.x,
y = self.sprite_flip.y
}
}
Particle:New(self.pos.x,self.pos.y,particle_data)
self.dashCooldownTimer = self.dashCooldownTime
-- dash movement
self.vel.x = self.dashSpeed * math.cos(self.dashDirection)
self.vel.y = self.dashSpeed * math.sin(self.dashDirection)
end
-- hook state
if self.isHooked then
local hook = Vector(self.pos.x, self.pos.y, self.hookAnchor.x, self.hookAnchor.y)
if GetVectorValue(hook) > self.hookedDistance then
local hook_angle = GetAngleFromVector(hook[1],hook[2])
local pos_x = self.hookAnchor.x + self.hookedDistance * math.cos(-math.rad(180)+hook_angle)
local pos_y = self.hookAnchor.y + self.hookedDistance * math.sin(-math.rad(180)+hook_angle)
self.vel.x = self.vel.x + pos_x - self.pos.x
self.vel.y = self.vel.y + pos_y - self.pos.y
end
end
if self.canFall then
-- not in dash or hook; fall normally
self.dashTimer = 0
self.vel.y = self.vel.y + gravity
end
-- horizontal collision
if not self:isCollidingAt(self.pos.x + self.vel.x + self.move_x, self.pos.y, LoadedObjects.Collisions) then
self.pos.x = self.pos.x + self.vel.x + self.move_x
else
self.vel.x = 0
end
-- vertical collision
if not self:isCollidingAt(self.pos.x, self.pos.y + self.vel.y, LoadedObjects.Collisions) then
self.pos.y = self.pos.y + self.vel.y
else
if self.vel.y > 0 then
self.isOnGround = true
self.dashCount = self.dashAmount
end
self.vel.y = 0
end
-- if u collision w hazard, respawn
if self:isCollidingAt(self.pos.x, self.pos.y, LoadedObjects.Hazards) then
self:Respawn()
end
end
function Player:Respawn()
self.pos.x = self.anchorRespawn.x
self.pos.y = self.anchorRespawn.y
end
function Player:HandleAnimation()
-- flip sprite to look in the direction is moving
if self.move_x ~= 0 then self.sprite_flip.x = math.sign(self.move_x) end
-- animation priority
self.body = self.body:ChangeTo(animation.nancy.fall)
if self.vel.y > 1.25 then
self.mask = self.mask:ChangeTo(self.maskType.fall)
elseif self.vel.y < 0 then
self.body = self.body:ChangeTo(animation.nancy.jump)
self.mask = self.mask:ChangeTo(self.maskType.jump)
elseif self.vel.x + self.move_x ~= 0 then
self.body = self.body:ChangeTo(animation.nancy.run)
self.mask = self.mask:ChangeTo(self.maskType.run)
else
self.body = self.body:ChangeTo(animation.nancy.idle)
self.mask = self.mask:ChangeTo(self.maskType.idle)
end
-- special case: idle animation gets slower by time
if self.body.anim_path == animation.nancy.idle.path then
if self.body.anim_speed < 0.5 then self.body.anim_speed = self.body.anim_speed + 0.001 end
end
if self.isHooked then
love.graphics.line(
-Camera.pos.x + self.pos.x,
-Camera.pos.y + self.pos.y,
-Camera.pos.x + self.hookAnchor.x,
-Camera.pos.y + self.hookAnchor.y
)
end
self.body:Animate()
self:Draw(self.body)
if self.dashCount > 0 then
self:Draw(self.mask)
end
self.move_x = 0
end

257
code/entity.lua Normal file
View File

@@ -0,0 +1,257 @@
Entity = {class = "Entity"}
function Entity:New(x,y)
o = {}
o.pos = {x = x, y = y}
o.vel = {x = 0, y = 0}
o.direction = 0
o.boxCollision = {
from = {x = x, y = y},
to = {x = x, y = y},
}
o.target_offset = {x = 0, y = 0}
o.sprite_offset = {x = 0, y = 0}
o.sprite_scale = {x = 1, y = 1}
o.sprite_rotation = math.rad(0)
o.sprite_tint = {1,1,1}
o.sprite_alpha = 1
o.sprite_flip = { x = 1, y = 1}
o.illuminated = false
setmetatable(o, self)
self.__index = self
return o
end
function Entity:CheckNearest(type,maxdistance)
local return_entity = nil
local shortest = -1
for _, entity in pairs(LoadedObjects.Entities) do
if not type or entity.type == type then
local distance_x = entity.pos.x - self.pos.x
local distance_y = entity.pos.y - self.pos.y
local distance = math.sqrt(distance_x ^ 2 + distance_y ^ 2)
if not maxdistance or distance < maxdistance then
if shortest == -1 or distance < shortest then
shortest = distance
return_entity = entity
end
end
end
end
return return_entity
end
function Entity:Smart()
end
function Entity:Move()
self.pos.x = self.pos.x + self.vel.x
self.pos.y = self.pos.y + self.vel.y
end
function Entity:CollisionMove()
if not self:isCollidingAt(self.pos.x + self.vel.x, self.pos.y, LoadedObjects.Collisions) then
self.pos.x = self.pos.x + self.vel.x
else
self.vel.x = 0
end
if not self:isCollidingAt(self.pos.x, self.pos.y + self.vel.y, LoadedObjects.Collisions) then
self.pos.y = self.pos.y + self.vel.y
else
self.vel.y = 0
end
end
function Entity:LightAdjust(x,y)
if self.light ~= nil then
local x = x or 0
local y = y or 0
self.light.pos.x = self.pos.x
self.light.pos.y = self.pos.y
end
end
function Entity:Kill()
if self.light ~= nil then
KillLight(self.light)
end
if self.id ~= nil then
for _, e in pairs(LoadedObjects.Entities) do
if e.id > self.id then
e.id = e.id - 1
end
end
table.remove(LoadedObjects.Entities,self.id)
end
self = nil
end
function Entity:CheckVisionLine(entity,range)
local target_x = entity.pos.x + entity.target_offset.x
local target_y = entity.pos.y + entity.target_offset.y
local distance_x = target_x - self.pos.x
local distance_y = target_y - self.pos.y
local angle = GetAngleFromVector(distance_x,distance_y)
local distance = math.sqrt(distance_x ^ 2 + distance_y ^ 2)
local is_colliding = true
if distance < range then
is_colliding = false
for i=1, distance, game.scale do
if isThereObjectAt(
self.pos.x+math.cos(angle)*i,
self.pos.y+math.sin(angle)*i,
LoadedObjects.Collisions
) then
is_colliding = true
end
end
end
return not is_colliding
end
function Entity:Draw(animation)
local c1, c2, c3, a = love.graphics.getColor()
love.graphics.setColor(self.sprite_tint[1],self.sprite_tint[2],self.sprite_tint[3],self.sprite_alpha)
animation:Draw(
self.pos.x - Camera.pos.x - ( (self.sprite_offset.x) * math.cos(self.sprite_rotation) - (self.sprite_offset.y) * math.sin(self.sprite_rotation)) * self.sprite_scale.x * self.sprite_flip.x,
self.pos.y - Camera.pos.y - ( (self.sprite_offset.x) * math.sin(self.sprite_rotation) + (self.sprite_offset.y) * math.cos(self.sprite_rotation)) * self.sprite_scale.y * self.sprite_flip.y,
self.sprite_rotation,
self.sprite_scale.x * self.sprite_flip.x,
self.sprite_scale.y * self.sprite_flip.y
)
love.graphics.setColor(c1,c2,c3,a)
end
function Entity:centerOffset(animation,x,y)
local x = x or 0
local y = y or 0
self.sprite_offset.x = animation.imgs[1]:getWidth()/2 + x
self.sprite_offset.y = animation.imgs[1]:getHeight()/2 + y
end
function Entity:getBoundingBox(animation,top,left,bottom,right)
local left = left or 0
local right = right or 0
local top = top or 0
local bottom = bottom or 0
self.boxCollision.from.x = -animation.imgs[1]:getWidth()/2 + left
self.boxCollision.to.x = animation.imgs[1]:getWidth()/2 + right
self.boxCollision.from.y = -animation.imgs[1]:getHeight()/2 + top
self.boxCollision.to.y = animation.imgs[1]:getHeight()/2 + bottom
end
-- returns true if theres a collision at that point. also marks collisioned tile as collision true
function Entity:isCollidingAt(x,y,object)
for _, collision in pairs(object) do
if collision.disable then
-- Dont calculate if disabled
elseif x + self.boxCollision.from.x < collision.to.x
and x + self.boxCollision.to.x > collision.from.x
and y + self.boxCollision.from.y < collision.to.y
and y + self.boxCollision.to.y > collision.from.y
then
collision.isColliding = true
return true
end
end
return false
end
function Entity:isCollidingWith(entity)
return self.pos.x + self.boxCollision.from.x < entity.pos.x + entity.boxCollision.to.x
and entity.pos.x + entity.boxCollision.from.x < self.pos.x + self.boxCollision.to.x
and self.pos.y + self.boxCollision.from.y < entity.pos.y + entity.boxCollision.to.y
and entity.pos.y + entity.boxCollision.from.y < self.pos.y + self.boxCollision.to.y
end
function Entity:isCollidingAtAll(x,y)
local result = false
if not result then
result = self:isCollidingAt(x,y,objects.collisions)
end
if not result then
result = self:isCollidingAt(x,y,objects.ladders)
end
if not result then
result = self:isCollidingAt(x,y,objects.platforms)
end
return result
end
function Entity:CheckVisionLineDebug(entity,range)
local c1, c2, c3, a = love.graphics.getColor()
local target_x = entity.pos.x + entity.target_offset.x
local target_y = entity.pos.y + entity.target_offset.y
local distance_x = target_x - self.pos.x
local distance_y = target_y - self.pos.y
local angle = GetAngleFromVector(distance_x,distance_y)
local distance = math.sqrt(distance_x ^ 2 + distance_y ^ 2)
if distance < range then
for i=1, distance, game.scale do
if isThereObjectAt(
self.pos.x+math.cos(angle)*i,
self.pos.y+math.sin(angle)*i,
LoadedObjects.Collisions
) then
love.graphics.setColor(1,0,0)
else
love.graphics.setColor(0,1,0)
end
love.graphics.line(
self.pos.x+math.cos(angle)*i-1 - Camera.pos.x,
self.pos.y+math.sin(angle)*i-1 - Camera.pos.y,
self.pos.x+math.cos(angle)*i - Camera.pos.x,
self.pos.y+math.sin(angle)*i - Camera.pos.y
)
end
end
love.graphics.setColor(c1,c2,c3,a)
end
function Entity:Debug()
-- draw center GREEN
love.graphics.setColor(0,1,0)
love.graphics.circle("fill", -Camera.pos.x + self.pos.x, -Camera.pos.y + self.pos.y, 1)
-- draw collision box PURPLE
love.graphics.setColor(1,0,1)
love.graphics.rectangle(
"line",
-Camera.pos.x + self.pos.x + self.boxCollision.from.x,
-Camera.pos.y + self.pos.y + self.boxCollision.from.y,
-Camera.pos.x + self.pos.x + self.boxCollision.to.x -(-Camera.pos.x + self.pos.x + self.boxCollision.from.x),
-Camera.pos.y + self.pos.y + self.boxCollision.to.y -(-Camera.pos.y + self.pos.y + self.boxCollision.from.y)
)
if self.target ~= nil then
love.graphics.line(
-Camera.pos.x + self.pos.x,
-Camera.pos.y + self.pos.y,
-Camera.pos.x + self.target.x,
-Camera.pos.y + self.target.y
)
end
end
require "code/entities/kupo"
require "code/entities/arrow"
require "code/entities/decoration"
require "code/entities/player"
require "code/entities/fairy"
require "code/entities/cursed_book"
require "code/entities/particle"

72
code/game.lua Normal file
View File

@@ -0,0 +1,72 @@
function GameStep()
SetCollisionFlags()
if menu_type == "no" then
for _, particle in pairs(LoadedParticles) do
particle:Smart()
end
for _, enty in pairs(LoadedObjects.Entities) do
enty:Smart()
end
end
for _, particle in pairs(LoadedParticles) do
particle:DoPhysics()
end
for _, enty in pairs(LoadedObjects.Entities) do
enty:DoPhysics()
end
AnimateTiles()
Camera:positionCenterAt(main_Player.pos.x, main_Player.pos.y)
--camera:positionAt(main_Player.pos.x, main_Player.pos.y,game.width,game.height)
if Keybind:HasPressed(Keybind.debug.debug) then
if debug then
debug = false
debug_collision = true
elseif debug_collision then
debug_collision = false
else
debug = true
end
end
if Keybind:HasPressed(Keybind.debug.reposition) then
if not editor_mode then
main_Player.pos.x, main_Player.pos.y = 16,-10
end
end
if Keybind:HasPressed(Keybind.debug.reload) then
MenuClear()
menu_type = "dialog"
MenuInit("dialog",DialogSequence.Example)
end
if Keybind:HasPressed(Keybind.debug.editor) then
editor_mode = true
end
end
function GameDraw()
GameworldDrawPrepare()
GameworldDrawBackground()
GameworldDrawForeground()
if LevelData.properties.darkness then
GameworldDrawLighting()
end
GameworldDrawParticles()
GameworldDrawEntities()
GameworldDrawEnd()
-- hud
textScale = 0.5
-- debug
if debug then DebugUI() end
if debug_collision then
DebugColisions()
DebugEntities()
end
end

89
code/gameworld.lua Normal file
View File

@@ -0,0 +1,89 @@
function GameworldDrawPrepare()
if game_resize then
Camera.height = game.height
Camera.width = game.width
end
pcr, pcg, pcb, pca = love.graphics.getColor()
love.graphics.scale(game.scale,game.scale)
love.graphics.setColor(1,1,1,1)
end
function GameworldDrawEnd()
love.graphics.setColor(pcr, pcg, pcb, pca)
pcr, pcg, pcb, pca = nil, nil, nil, nil
end
function GameworldDrawBackground()
-- obscure a bit
love.graphics.setColor(0.7,0.7,0.7)
for i = 1, #LevelTiles do
for j = 1, #LevelTiles[i] do
if LevelTiles[i][j].id ~= 0 then
local depth = TileData[LevelTiles[i][j].id].depth
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 GameworldDrawParticles()
love.graphics.setColor(0.7,0.7,0.7)
for _, particle in pairs(LoadedParticles) do
particle:HandleAnimation()
end
end
function GameworldDrawEntities()
love.graphics.setColor(1,1,1)
for _, enty in pairs(LoadedObjects.Entities) do
enty:HandleAnimation()
end
end
function GameworldDrawForeground()
love.graphics.setColor(1,1,1)
for i = 1, #LevelTiles do
for j = 1, #LevelTiles[i] do
if LevelTiles[i][j].id ~= 0 then
local depth = TileData[LevelTiles[i][j].id].depth
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 GameworldDrawLighting()
if game_resize then
Canvas.Darkness:release()
Canvas.Darkness = CreateDarkness()
love.graphics.setCanvas(Canvas.Darkness)
SetDarkness()
love.graphics.setCanvas()
end
-- work on lighting canvas
love.graphics.setCanvas(Canvas.Darkness)
SetDarkness()
DoLights()
DoBorder()
-- apply to game canvas
love.graphics.setColor(1,1,1,1)
love.graphics.scale(game.scale,game.scale)
love.graphics.setCanvas()
DrawDarkness()
love.graphics.scale(1/game.scale,1/game.scale)
end

30
code/hex.lua Normal file
View File

@@ -0,0 +1,30 @@
function HEX2RGB(color)
local r1 = HEX2DEX(color:sub(2,2))
local r2 = HEX2DEX(color:sub(3,3))
local g1 = HEX2DEX(color:sub(4,4))
local g2 = HEX2DEX(color:sub(5,5))
local b1 = HEX2DEX(color:sub(6,6))
local b2 = HEX2DEX(color:sub(7,7))
return {(r1*16 + r2)/255, (g1*16 + g2)/255, (b1*16 + b2)/255}
end
function HEX2DEX(hex)
if hex == "0" then return 0
elseif hex == "1" then return 1
elseif hex == "2" then return 2
elseif hex == "3" then return 3
elseif hex == "4" then return 4
elseif hex == "5" then return 5
elseif hex == "6" then return 6
elseif hex == "7" then return 7
elseif hex == "8" then return 8
elseif hex == "9" then return 9
elseif hex == "a" then return 10
elseif hex == "b" then return 11
elseif hex == "c" then return 12
elseif hex == "d" then return 13
elseif hex == "e" then return 14
elseif hex == "f" then return 15
end
end

87
code/in_out.lua Normal file
View File

@@ -0,0 +1,87 @@
function ExportLevel(levelname, filename)
os.execute( "mkdir \"./export\"" )
filename = filename or "output.lua"
filename = "export/"..filename
exportFile = io.open(filename, "w+")
if exportFile then
logPrint("Exporting level \"".. levelname .. "\"...")
exportFile:write("return {")
logPrint("- level name")
exportFile:write("\n name = \"" .. levelname .. "\",")
logPrint("- tileset")
for k, v in pairs(tileset) do
if v == LevelData.tileset then
exportFile:write("\n tileset = tileset." .. k .. ",")
end
end
logPrint("- properties")
exportFile:write("\n properties = {")
exportFile:write("\n darkness = true")
exportFile:write("\n },")
logPrint("- tiles")
exportFile:write("\n tiles = {")
local rows = #LevelTiles
for i = 1, #LevelTiles do
exportFile:write("\n { ")
logPrint(" - Row "..i.."/"..rows.." "..math.floor(100*((i-1)*100/rows))/100 .."%")
for j = 1, #LevelTiles[i] do
if j ~= 1 then
exportFile:write(", ")
end
exportFile:write(tostring(LevelTiles[i][j].id))
end
exportFile:write("}")
if i ~= #LevelTiles then
exportFile:write(", ")
end
end
logPrint(" - All rows 100%")
exportFile:write("\n },")
logPrint("- objects")
exportFile:write("\n objects = {}")
logPrint("Exporting complete.")
exportFile:write("\n}")
exportFile:close()
end
end
-- Source https://stackoverflow.com/a/11130774
function scandir(directory)
local i, t, popen = 0, {}, io.popen
local pfile = popen('ls "'..directory..'"')
for filename in pfile:lines() do
i = i + 1
t[i] = filename
end
pfile:close()
return t
end
--[[
return {
name = "level1",
tileset = tileset.library,
tiles = {
{13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 5,25,26, 6,25,26, 7, 0, 5,25,26, 7, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 5,37,38, 6,37,38, 7, 0, 5,37,38, 7, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 5,37,38, 6,37,38, 7, 0, 5,37,38, 7, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 5,49,50, 6,49,50, 7, 0, 5,49,50, 7, 0, 0, 0, 0, 0, 0},
{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
},
objects = {}
}
]]
if logging then
-- Make log stuff
os.execute( "mkdir \"./logs\"" )
logFile = io.open("logs/mothback_"..os.date("%Y-%m-%d_%H-%M-%S")..".log", "a+")
end

83
code/keybind.lua Normal file
View File

@@ -0,0 +1,83 @@
Keybind = {}
Keybind.move = {}
Keybind.menu = {}
Keybind.debug = {}
Keybind.editor = {}
Keybind.generic = {}
function Keybind:CheckDown(action)
for _, keyname in pairs(action.keys) do
if type(keyname) == "string" then
if love.keyboard.isDown(keyname) then return true end
else
if love.mouse.isDown(keyname) then return true end
end
end
return false
end
function Keybind:HasPressed(action)
if Keybind:CheckDown(action) then
if not action.pressed then
action.pressed = true
return true
end
else
action.pressed = nil
end
return false
end
function Keybind:CheckCollision(cat, key)
for _, action in pairs(cat) do
for _, keyname in pairs(action.keys) do
if key == keyname then return true end
end
end
return false
end
function Keybind:AddKey(action, key)
table.insert(action.keys, key)
end
function Keybind:ChangeKey(action, position, key)
action.keys[position] = key
end
function Keybind:RemoveKeys(action)
action.keys = {}
end
function Keybind:Default()
--Menu
Keybind.menu.pause= { keys = {"escape"}}
Keybind.menu.confirm= { keys = {"z", "space", 1}}
--Move
Keybind.move.left = { keys = {"left", "a"}}
Keybind.move.right = { keys = {"right", "d"}}
Keybind.move.up = { keys = {"up", "w"}}
Keybind.move.down = { keys = {"down", "s"}}
Keybind.move.jump = { keys = {"z", "space"}}
Keybind.move.hook = { keys = {"x", 1}}
Keybind.move.dash = { keys = {"c", 2}}
--Debug
Keybind.debug.debug = { keys = {"f1"}}
Keybind.debug.reposition = { keys = {"f2"}}
Keybind.debug.reload = { keys = {"f3"}}
Keybind.debug.editor = { keys = {"f4"}}
-- Editor
Keybind.editor.palette = { keys = {"tab"}}
-- Generic
Keybind.generic.lclick = { keys = {1}}
Keybind.generic.rclick = { keys = {2}}
Keybind.generic.lshift = { keys = {"lshift"}}
Keybind.generic.lctrl = { keys = {"lctrl"}}
end
-- Set default values at start
Keybind:Default()

741
code/level.lua Normal file
View File

@@ -0,0 +1,741 @@
function LevelLoadTiles()
LevelData = dofile("data/levels/"..currLevel)
--[[
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 or, if multiple tiles {id, id, id,}, choose at random
overlay_depth = foreground/background overlay depth
type = collision type
]]
LevelGetTileData()
LevelTiles = LevelData.tiles
LevelUpdateDimensions()
LevelIndexTiles()
TileCreateObjects()
end
function LevelExpandCanvas(horizontal,vertical)
local horizontal = horizontal or 0
local vertical = vertical or 0
local h = LevelGetTileWidth()
local v = LevelGetTileHeight()
-- get new canvas size
local newCanvasH = h + math.abs(horizontal)
local newCanvasV = v + math.abs(vertical)
-- lets make a new temporal canvas
local ExpandedLevel = {}
for i = 1, newCanvasV do
ExpandedLevel[i] = {}
for j = 1, newCanvasH do
ExpandedLevel[i][j] = InstanceTile(0)
end
end
-- lets guess how the new canvas and positions are offset
local expand_h = 0
if horizontal < 0 then
expand_h = -horizontal
end
local expand_v = 0
if vertical < 0 then
expand_v = -vertical
end
-- get data from old canvas to new canvas
for i = 1, #LevelTiles do
for j = 1, #LevelTiles[i] do
ExpandedLevel[i+expand_v][j+expand_h] = InstanceTile(LevelTiles[i][j].id)
end
end
-- use new canvas
LevelTiles = ExpandedLevel
end
function LevelReduceCanvas(horizontal,vertical)
local horizontal = horizontal or 0
local vertical = vertical or 0
local h = LevelGetTileWidth()
local v = LevelGetTileHeight()
-- get new canvas size
local newCanvasH = h - math.abs(horizontal)
local newCanvasV = v - math.abs(vertical)
-- lets make a new temporal canvas
local ExpandedLevel = {}
for i = 1, newCanvasV do
ExpandedLevel[i] = {}
for j = 1, newCanvasH do
ExpandedLevel[i][j] = InstanceTile(0)
end
end
-- lets guess how the new canvas and positions are offset
local expand_h = 0
if horizontal < 0 then
expand_h = -horizontal
end
local expand_v = 0
if vertical < 0 then
expand_v = -vertical
end
-- get data from old canvas to new canvas
for i = 1, #ExpandedLevel do
for j = 1, #ExpandedLevel[i] do
ExpandedLevel[i][j] = InstanceTile(LevelTiles[i+expand_v][j+expand_h].id)
end
end
-- use new canvas
LevelTiles = ExpandedLevel
LevelExpandCanvas()
end
function LevelGetTileData()
for k, v in pairs(tileset) do
if v == LevelData.tileset then
TileData = dofile("data/tileset/"..k..".lua")
end
end
end
function LevelReloadTiles()
LevelUpdateDimensions()
end
function LevelUpdateDimensions()
LevelData.Width = LevelGetWidth()
LevelData.Height = LevelGetHeight()
end
function LevelGetTileHeight()
return #LevelTiles
end
function LevelGetTileWidth()
local width = 0
for i = 1, #LevelTiles do
if width < #LevelTiles[i] then width = #LevelTiles[i] end
end
return width
end
function LevelGetHeight()
return LevelGetTileHeight() * tileProperties.height
end
function LevelGetWidth()
return LevelGetTileWidth() * tileProperties.width
end
function LevelIndexTiles()
TileIndex = {}
-- index from tileset
local width = LevelData.tileset:getPixelWidth()/tileProperties.width
local height = LevelData.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,
LevelData.tileset:getDimensions()
)
end
end
TileDataInitialize()
-- instance level tiles according to the Properties
for i = 1, #LevelTiles do
for j = 1, #LevelTiles[i] do
SetTile(i,j,LevelTiles[i][j])
end
end
end
function TileDataInitialize()
for _, Properties in pairs(TileData) 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 InstanceTile(id)
local tile = {}
tile.id = id
local Properties = TileData[tile.id]
if Properties ~= nil then
if type(Properties.overlay) == "table" then
tile.display_overlay = Properties.overlay[math.random(#Properties.overlay)]
else
tile.display_overlay = Properties.overlay
end
if type(Properties.force) == "table" then
tile.display = Properties.force[math.random(#Properties.force)]
else
tile.display = Properties.force
end
end
return tile
end
function SetTile(i,j,id)
LevelTiles[i][j] = InstanceTile(id)
end
function GridDisplay()
for i = 1, #LevelTiles do
for j = 1, #LevelTiles[i] do
love.graphics.rectangle(
"line",
tileProperties.scale * (j * tileProperties.width + (levelProperties.offset.x - tileProperties.width)) - Camera.pos.x,
tileProperties.scale * (i * tileProperties.height + (levelProperties.offset.y - tileProperties.height)) - Camera.pos.y,
tileProperties.scale * tileProperties.width,
tileProperties.scale * tileProperties.height
)
end
end
end
function TileOptimizeObjects()
logPrint("Optimizing Objects...")
local unoptimized = 0
local isTileOptimized = {}
for i = 1, #LevelTiles do
isTileOptimized[i] = {}
for j= 1, #LevelTiles[i] do
isTileOptimized[i][j] = false
end
end
for i = 1, #LevelTiles do
for j = 1, #LevelTiles[i] do
if LevelTiles[i][j].id ~= 0 then
local type = TileData[LevelTiles[i][j].id].type
if type == "whole" and not isTileOptimized[i][j] then
isTileOptimized[i][j] = true
local n = 1
local check = true
while check do
check = false
if LevelTiles[i][j+n] ~= nil
and TileData[LevelTiles[i][j+n].id] ~= nil
then
local type_check = TileData[LevelTiles[i][j+n].id].type
if type_check == "whole"
and not isTileOptimized[i][j+n]
then
check = true
isTileOptimized[i][j+n] = true
n = n + 1
end
end
end
local m = 1
local check = true
while check do
check = false
local checkline = true
for l = 0, n-1 do
checkline = false
if LevelTiles[i+m] ~= nil
and LevelTiles[i+m][j+l] ~= nil
and TileData[LevelTiles[i+m][j+l].id] ~= nil
then
local type_check = TileData[LevelTiles[i+m][j+l].id].type
if type_check == "whole"
and not isTileOptimized[i+m][j+l]
then
checkline = true
else
break
end
end
end
if checkline then
check = true
for l = 0, n-1 do
isTileOptimized[i+m][j+l] = true
end
m = m + 1
else
check = false
end
end
logPrint("- Group size: "..m.."x"..n)
unoptimized = unoptimized + m * n
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)
local col = Collision:New(
base_x,
base_y,
base_x + tileProperties.width * tileProperties.scale * n,
base_y + tileProperties.height * tileProperties.scale * m
)
table.insert(LoadedObjects.Collisions,col)
end
end
end
end
logPrint("collisions optimized from " .. unoptimized .. " to " .. #LoadedObjects.Collisions)
end
function TileCreateObjects()
LoadedObjects.Collisions = {}
LoadedObjects.Platforms = {}
LoadedObjects.Ladders = {}
LoadedObjects.Hazards = {}
TileOptimizeObjects()
for i = 1, #LevelTiles do
for j = 1, #LevelTiles[i] do
if LevelTiles[i][j].id ~= 0 then
local type = TileData[LevelTiles[i][j].id].type
local light = TileData[LevelTiles[i][j].id].light
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 light ~= 0 and light ~= nil then
CreateLight(
base_x + tileProperties.width/2 * tileProperties.scale,
base_y + tileProperties.height/2 * tileProperties.scale,
light
)
end
-- wholes are handled in optimization now
--[[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(LoadedObjects.Collisions,col)
else]]if type == "half_bottom" 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(LoadedObjects.Collisions,col)
elseif type == "half_top" then
local col = Collision:New(
base_x,
base_y ,
base_x + tileProperties.width * tileProperties.scale,
base_y + tileProperties.height/2 * tileProperties.scale
)
table.insert(LoadedObjects.Collisions,col)
elseif type == "half_right" then
local col = Collision:New(
base_x + tileProperties.height/2 * tileProperties.scale,
base_y,
base_x + tileProperties.width * tileProperties.scale,
base_y + tileProperties.height * tileProperties.scale
)
table.insert(LoadedObjects.Collisions,col)
elseif type == "half_left" then
local col = Collision:New(
base_x,
base_y,
base_x + tileProperties.height/2 * tileProperties.scale,
base_y + tileProperties.height * tileProperties.scale
)
table.insert(LoadedObjects.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(LoadedObjects.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(LoadedObjects.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(LoadedObjects.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(LoadedObjects.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(LoadedObjects.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(LoadedObjects.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(LoadedObjects.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(LoadedObjects.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(LoadedObjects.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(LoadedObjects.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(LoadedObjects.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(LoadedObjects.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(LoadedObjects.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(LoadedObjects.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(LoadedObjects.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(LoadedObjects.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(LoadedObjects.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(LoadedObjects.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(LoadedObjects.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(LoadedObjects.Platforms,plat)
elseif type == "bottom_hazard" then
local hazard = Collision:New(
base_x,
base_y + tileProperties.height * 12/16 * tileProperties.scale,
base_x + tileProperties.width * tileProperties.scale,
base_y + tileProperties.height * tileProperties.scale
)
table.insert(LoadedObjects.Hazards,hazard)
end
end
end
end
end
function AnimateTiles()
for _, Properties in pairs(TileData) do
if Properties ~= nil then
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
end
function DrawTile(tile,x,y,depth)
local Properties = TileData[tile.id]
if Properties ~= nil 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
if Properties.force ~= 0 then
love.graphics.draw(
LevelData.tileset,
TileIndex[tile.display],
x,
y,
0,
tileProperties.scale,
tileProperties.scale
)
end
else
love.graphics.draw(
LevelData.tileset,
TileIndex[tile.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
local overlay_properties = TileData[Properties.overlay]
love.graphics.draw(
overlay_properties.tileset,
overlay_properties.imgs[overlay_properties.current_image],
x,
y,
0,
tileProperties.scale,
tileProperties.scale
)
else
love.graphics.draw(
LevelData.tileset,
TileIndex[tile.display_overlay],
x,
y,
0,
tileProperties.scale,
tileProperties.scale
)
end
end
end
--[[
love.graphics.setColor(0,0,1)
love.graphics.print(tostring(tile.display),x+16,y)
love.graphics.setColor(1,1,1)
]]
end
end

133
code/lights.lua Normal file
View File

@@ -0,0 +1,133 @@
Lights = {}
LightTimer = 0
function CreateDarkness()
return love.graphics.newCanvas(game.width/game.scale, game.height/game.scale)
end
function CreateLight(x,y,range,flicker,color,lum)
local o = {}
o.pos = {
x = x,
y = y
}
o.range = range
o.lum = lum or 1
o.color = color or {1,1,1}
o.flicker_value = flicker or 2
o.flicker = 0
o.dim = 0
o.flicker_speed = flicker_speed or 60/12
o.flicker_time = 0
table.insert(Lights,o)
o.id = #Lights
return o
end
function KillLight(light)
if light.id ~= nil then
for _, e in pairs(Lights) do
if e.id > light.id then
e.id = e.id - 1
end
end
table.remove(Lights,light.id)
end
light = nil
end
function SetDarkness()
love.graphics.setCanvas(Canvas.Darkness)
love.graphics.setColor(0,0,0,1)
love.graphics.rectangle("fill",0,0,game.width ,game.height)
love.graphics.setCanvas()
end
function DoLights()
love.graphics.setCanvas(Canvas.Darkness)
for _, light in pairs(Lights) do
light.flicker_time = light.flicker_time + 1
if light.flicker_time >= light.flicker_speed then
light.flicker_time = light.flicker_time - light.flicker_speed
light.flicker = 0 + math.random(0,1)
light.flicker = math.min(math.max(light.flicker, -light.flicker_value),light.flicker_value)
end
end
love.graphics.setBlendMode("replace")
for _, light in pairs(Lights) do
if light.range ~= 0 then
love.graphics.setColor(light.color[1],light.color[2],light.color[3],1)
local position = {
x = (light.pos.x - Camera.pos.x) / game.scale,
y = (light.pos.y - Camera.pos.y) / game.scale
}
local range = (1 + light.range + light.flicker) / game.scale
love.graphics.circle(
"fill",
position.x,
position.y,
range
)
end
end
love.graphics.setColor(0,0,0,0)
for _, light in pairs(Lights) do
if light.range ~= 0 then
local position = {
x = (light.pos.x - Camera.pos.x) / game.scale,
y = (light.pos.y - Camera.pos.y) / game.scale
}
local range = (light.range + light.flicker) / game.scale
love.graphics.circle(
"fill",
position.x,
position.y,
range
)
end
end
love.graphics.setBlendMode("alpha")
love.graphics.setColor(0,0,0,1)
Shaders.InsideLight:send("game_scale", game.scale)
for _, light in pairs(Lights) do
if light.range ~= 0 then
local position = {
x = (light.pos.x - Camera.pos.x) / game.scale,
y = (light.pos.y - Camera.pos.y) / game.scale
}
local range = (light.range + light.flicker) / game.scale
Shaders.InsideLight:send("light_color", light.color)
Shaders.InsideLight:send("light_pos", {position.x*game.scale, position.y*game.scale})
Shaders.InsideLight:send("range", range)
love.graphics.setShader(Shaders.InsideLight)
love.graphics.circle(
"fill",
position.x,
position.y,
range
)
love.graphics.setShader()
end
end
love.graphics.setCanvas()
end
function DoBorder()
love.graphics.setCanvas(Canvas.Darkness)
love.graphics.setCanvas()
end
function DrawDarkness()
love.graphics.draw(Canvas.Darkness, 0, 0, 0, 1/game.scale)
end

5
code/locale.lua Normal file
View File

@@ -0,0 +1,5 @@
function LocaleLoad(ISO639)
local ISO639 = ISO639 or "ENG"
dofile("data/locale/"..ISO639..".lua")
dofile("data/dialog_sequences.lua")
end

27
code/math.lua Normal file
View File

@@ -0,0 +1,27 @@
function math.sign(x)
if x<0 then
return -1
elseif x>0 then
return 1
else
return 0
end
end
function Vector(init_x, init_y, final_x, final_y)
local distance_x = final_x - init_x
local distance_y = final_y - init_y
return {distance_x, distance_y}
end
function GetVectorValue(vector)
return math.sqrt(vector[1] ^ 2 + vector[2] ^ 2)
end
function GetAngleFromVector(x,y)
local reduce = 0
if x < 0 then
reduce = math.rad(180)
end
return math.atan(y/x) - reduce
end

146
code/menu.lua Normal file
View File

@@ -0,0 +1,146 @@
function MenuDraw(menu)
local font = love.graphics.getFont()
love.graphics.setFont(LocaleFont)
-- Set scale to 1
love.graphics.scale(0.5,0.5)
if menu == "pause" then
MenuDrawPauseScreen()
elseif menu == "dialog" then
MenuDrawDialog()
end
for _, element in pairs(UIElement) do
element:Draw()
end
-- Reset scale
love.graphics.scale(2,2)
love.graphics.setFont(font)
end
function MenuDrawPauseScreen()
-- 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)
end
function MenuDrawDialog()
end
function MenuStep(menu)
-- first get mouse
local mouse_x, mouse_y = love.mouse.getPosition()
for _, element in pairs(UIElement) do
if element.type == "Button" then
element:checkMouse(mouse_x, mouse_y)
elseif element.type == "Dialog" then
element:checkConfirm()
end
end
if menu == 0 then
elseif menu == "pause" then
MenuStepPauseScreen()
elseif menu == "dialog" then
MenuStepDialog()
end
end
function MenuStepPauseScreen()
if PauseResume:getVariable() == true then
PauseResume = nil
PauseOptions = nil
PauseExit = nil
MenuExit()
elseif PauseExit:getVariable() == true then
love.event.quit()
end
end
function MenuStepDialog()
if DialogContainer.value >= DialogContainer.target_value then
DialogContainer = nil
MenuExit()
end
end
function MenuClear()
for _, element in pairs(UIElement) do
element = nil
end
UIElement = {}
end
function MenuExit(to)
MenuClear()
local to = to or "no"
menu_type = to
end
function MenuInit(menu,parameter)
-- main menu
if menu == "pause" then
MenuInitPauseScreen()
elseif menu == "dialog" then
if parameter == nil then
parameter = DialogSequence.Example
end
MenuInitDialog(parameter)
end
end
function MenuInitDialog(parameter)
DialogContainer = interfaceDialog:New()
DialogContainer:loadSequence(parameter)
end
function MenuInitPauseScreen()
local buttonStandard = {width = 200, height = 30, separation = 10}
-- elements
PauseResume = interfaceButton:New(
game.width/2,
game.height/2-buttonStandard.height-buttonStandard.separation,
buttonStandard.width,
buttonStandard.height,
{false,true},
1,
{
text = Locale.ui.pause_screen_resume,
color = {0,0,0.5},
color2 = {1,1,1}
}
)
PauseOptions = interfaceButton:New(
game.width/2,
game.height/2,
buttonStandard.width,
buttonStandard.height,
{false,true},
1,
{
text = Locale.ui.pause_screen_options,
color = {0,0,0.5},
color2 = {1,1,1}
}
)
PauseExit = interfaceButton:New(
game.width/2,
game.height/2+buttonStandard.height+buttonStandard.separation,
buttonStandard.width,
buttonStandard.height,
{false,true},
1,
{
text = Locale.ui.pause_screen_exit,
color = {0,0,0.5},
color2 = {1,1,1}
}
)
end

88
code/objects.lua Normal file
View File

@@ -0,0 +1,88 @@
LoadedObjects = {
Entities = {},
Collisions = {},
Platforms = {},
Ladders = {},
Hazards = {}
}
-- level functions
function LoadedObjects.DrawCollisions()
for _, collision in pairs(LoadedObjects.Collisions) do
collision:Draw(1)
end
for _, platform in pairs(LoadedObjects.Platforms) do
if platform.disable == true then platform:Draw(2) end
if platform.disable == false then platform:Draw(1) end
end
for _, ladder in pairs(LoadedObjects.Ladders) do
ladder:Draw(2)
end
for _, hazard in pairs(LoadedObjects.Hazards) do
hazard:Draw(1)
end
end
-- returns true if theres a collision at that point
function isThereObjectAt(x,y,objectType)
for _, collision in pairs(objectType) do
if collision.disable then
-- Dont calculate if dissabled
elseif x >= collision.from.x
and x <= collision.to.x
and y >= collision.from.y
and y <= collision.to.y then
collision.isColliding = true
return true
end
end
return false
end
function isThereAnyCollisionAt(x,y)
local Check = {
LoadedObjects.Collisions,
LoadedObjects.Ladders,
LoadedObjects.Platforms
}
for _, type in pairs(Check) do
local result = isThereObjectAt(x,y,type)
if result then
return result
end
end
return false
end
-- flags
function SetCollisionFlags()
local Check = {
LoadedObjects.Collisions,
LoadedObjects.Ladders,
LoadedObjects.Platforms,
LoadedObjects.Hazards
}
for _, type in pairs(Check) do
for _, object in pairs(type) do
object.isColliding = false
end
end
for _, platform in pairs(LoadedObjects.Platforms) do
if main_Player.pos.y < platform.from.y then
platform.disable = false
else
platform.disable = true
end
end
for _, platform in pairs(LoadedObjects.Hazards) do
if main_Player.isOnGround then
platform.disable = true
else
platform.disable = false
end
end
end

82
code/particle.lua Normal file
View File

@@ -0,0 +1,82 @@
Particle = Entity:New(x,y)
function Particle:New(x,y,particle_data)
local o = Entity:New(x,y)
o.pos = {x = x, y = y}
o.speed = particle_data.speed or 0
o.direction = particle_data.direction or o.direction
o.sprite_rotation = particle_data.sprite_rotation or o.sprite_rotation
o.sprite_offset = particle_data.sprite_offset or o.sprite_offset
o.sprite_scale = particle_data.sprite_scale or o.sprite_scale
o.sprite_tint = particle_data.sprite_tint or o.sprite_tint
o.sprite_alpha = particle_data.sprite_alpha or o.sprite_alpha
o.sprite_alpha_base = o.sprite_alpha
o.sprite_flip = particle_data.sprite_flip or o.sprite_flip
o.animation_active = particle_data.animation_active or false
o.time = 0.5
o.timer = 0
o.vel = {
x = o.speed * math.cos(o.direction),
y = o.speed * math.sin(o.direction)
}
if particle_data.light ~= nil then
o.lightRange = particle_data.light
o.light = CreateLight(o.pos.x,o.pos.y,o.lightRange)
end
-- animations
o.body = Animation:New(particle_data.animation)
o:centerOffset(o.body)
if not o.animation_active then
o.body.speed = 0
end
table.insert(LoadedParticles,o)
o.id = #LoadedParticles
setmetatable(o, self)
self.__index = self
return o
end
function Particle:Kill()
if self.light ~= nil then
KillLight(self.light)
end
if self.id ~= nil then
for _, e in pairs(LoadedParticles) do
if e.id > self.id then
e.id = e.id - 1
end
end
table.remove(LoadedParticles,self.id)
end
self = nil
end
function Particle:HandleAnimation()
self.body:Animate()
self.timer = self.timer + current_dt
self.sprite_alpha = self.sprite_alpha_base*(self.time-self.timer)/self.time
if self.light ~= nil then
self.light.range = self.lightRange * self.sprite_alpha/2
end
if self.sprite_alpha < 0 then self:Kill() end
self:Draw(self.body)
end
function Particle:DoPhysics()
if not self:isCollidingAt(self.pos.x + self.vel.x, self.pos.y, objects.collisions) then
self.pos.x = self.pos.x + self.vel.x
end
if not self:isCollidingAt(self.pos.x, self.pos.y + self.vel.y, objects.collisions) then
self.pos.y = self.pos.y + self.vel.y
end
end

33
code/require.lua Normal file
View File

@@ -0,0 +1,33 @@
-- data
require "data/animations"
require "data/shaders"
require "data/tiledata"
require "data/music"
require "data/sfx"
require "code/locale"
-- support functions
require "code/math"
require "code/hex"
require "code/in_out"
-- classes
require "code/audio"
require "code/entity"
require "code/animation"
require "code/collision"
require "code/level"
require "code/camera"
require "code/lights"
require "code/objects"
-- UI functions
require "code/debug"
require "code/keybind"
require "code/menu"
require "code/ui"
-- game loop
require "code/game"
require "code/gameworld"
require "code/editor"

9
code/ui.lua Normal file
View File

@@ -0,0 +1,9 @@
UIElement = {}
function AddElement(self)
table.insert(UIElement,self)
self.id = #UIElement
end
require "code/ui/button"
require "code/ui/dialog"

101
code/ui/button.lua Normal file
View File

@@ -0,0 +1,101 @@
interfaceButton = {type = "Button"}
-- centered buttons
function interfaceButton:New(x,y,w,h,table_values,value,style)
o = {}
o.pos = {
x = x,
y = y
}
o.size = {
w = w,
h = h
}
o.values = table_values or {false,true}
o.value = value or 1
o.target_variable = o.values[o.value]
o.clicked = false
o.style = {
text = style.text or nil,
color = style.color or {1,1,1},
color2 = style.color2 or {0,0,0},
--color3 = style.color3 or style.color2 or {0,0,0},
alpha = style.alpha or 1,
scale = style.scale or 1,
scale_x = style.scale_x or 1,
scale_y = style.scale_y or 1,
scale_proportion = 1
}
o.style.unselected = {
scale_proportion = o.style.scale_proportion
}
o.style.selected = {
scale_proportion = 1.5
}
AddElement(o)
setmetatable(o, self)
self.__index = self
return o
end
function interfaceButton:getVariable()
return self.target_variable
end
function interfaceButton:checkMouse(mouse_x, mouse_y)
if not self.clicked
and mouse_x < self.pos.x + self.size.w/2
and mouse_x > self.pos.x - self.size.w/2
and mouse_y < self.pos.y + self.size.h/2
and mouse_y > self.pos.y - self.size.h/2 then
self.style.scale_proportion = o.style.selected.scale_proportion
if love.mouse.isDown(1) then
self.clicked = true
self.value = self.value + 1
if self.value > #self.values then
self.value = 1
end
self.target_variable = self.values[self.value]
end
elseif not love.mouse.isDown(1) then
self.style.scale_proportion = o.style.unselected.scale_proportion
self.clicked = false
end
end
function interfaceButton:Draw()
local c1, c2, c3, a = love.graphics.getColor()
love.graphics.setColor(self.style.color[1],self.style.color[2],self.style.color[3],self.style.alpha)
love.graphics.rectangle(
"fill",
self.pos.x-(self.size.w/2)*self.style.scale_x*self.style.scale_proportion,
self.pos.y-(self.size.h/2)*self.style.scale_y*self.style.scale_proportion,
self.size.w *self.style.scale_x*self.style.scale_proportion,
self.size.h *self.style.scale_y*self.style.scale_proportion)
love.graphics.setColor(self.style.color2[1],self.style.color2[2],self.style.color2[3],self.style.alpha)
love.graphics.rectangle(
"line",
self.pos.x-(self.size.w/2)*self.style.scale_x*self.style.scale_proportion,
self.pos.y-(self.size.h/2)*self.style.scale_y*self.style.scale_proportion,
self.size.w *self.style.scale_x*self.style.scale_proportion,
self.size.h *self.style.scale_y*self.style.scale_proportion)
if self.style.text ~= nil then
love.graphics.print(self.style.text,self.pos.x,self.pos.y)
else
love.graphics.print(tostring(self.target_variable),self.pos.x,self.pos.y)
end
love.graphics.setColor(c1,c2,c3,a)
end

97
code/ui/dialog.lua Normal file
View File

@@ -0,0 +1,97 @@
interfaceDialog = {type = "Dialog"}
-- dialog boxes
function interfaceDialog:New(style)
o = {}
o.pos = {
x = 0,
y = game.height*80/100
}
o.size = {
w = game.width,
h = game.height*20/100
}
o.value = 0
o.target_value = 0
local style = {}
o.style = {
content = style.content or nil,
color = style.color or {1,1,1},
color2 = style.color2 or {0,0,0},
--color3 = style.color3 or style.color2 or {0,0,0},
alpha = style.alpha or 1,
scale = style.scale or 1,
scale_x = style.scale_x or 1,
scale_y = style.scale_y or 1,
scale_proportion = 1
}
AddElement(o)
setmetatable(o, self)
self.__index = self
return o
end
function interfaceDialog:updateContents()
if self.value < self.target_value then
self.contents = self.sequence[self.value]
if self.contents[1] == nil then self.contents[1] = "" end
if self.contents[2] == nil then self.contents[2] = "" end
if self.contents[3] == nil then self.contents[3] = "" end
end
end
function interfaceDialog:loadSequence(sequence)
self.sequence = sequence
self.value = 1
self.target_value = 1+#sequence
self:updateContents()
end
function interfaceDialog:checkConfirm()
if not self.clicked then
if love.mouse.isDown(1) then
self.clicked = true
self.value = self.value + 1
logPrint("Dialog: "..self.value.." of "..self.target_value)
self:updateContents()
end
elseif not love.mouse.isDown(1) then
self.clicked = false
end
end
function interfaceDialog:Draw()
local c1, c2, c3, a = love.graphics.getColor()
love.graphics.setColor(self.style.color[1],self.style.color[2],self.style.color[3],self.style.alpha)
love.graphics.rectangle(
"fill",
self.pos.x*self.style.scale_x*self.style.scale_proportion,
self.pos.y*self.style.scale_y*self.style.scale_proportion,
self.size.w*self.style.scale_x*self.style.scale_proportion,
self.size.h*self.style.scale_y*self.style.scale_proportion)
love.graphics.setColor(self.style.color2[1],self.style.color2[2],self.style.color2[3],self.style.alpha)
love.graphics.rectangle(
"line",
self.pos.x*self.style.scale_x*self.style.scale_proportion,
self.pos.y*self.style.scale_y*self.style.scale_proportion,
self.size.w*self.style.scale_x*self.style.scale_proportion,
self.size.h*self.style.scale_y*self.style.scale_proportion)
if self.contents ~= nil then
love.graphics.printf(self.contents[2],self.pos.x+10,self.pos.y+(self.size.h/2),100,"left")
love.graphics.printf(self.contents[1],self.pos.x+(self.size.w/2),self.pos.y+(self.size.h/2),100,"center")
love.graphics.printf(self.contents[3],self.pos.x+(self.size.w)-10,self.pos.y+(self.size.h/2),100,"right")
else
love.graphics.printf("ERROR",self.pos.x+(self.size.w/2),self.pos.y+(self.size.h/2),100,"center")
end
love.graphics.setColor(c1,c2,c3,a)
end