summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAki <nthirtyone@gmail.com>2017-02-26 05:04:34 +0100
committerAki <nthirtyone@gmail.com>2017-02-26 05:04:34 +0100
commit72533c0efb9d5659cd2c1fb0e9f067696d759812 (patch)
tree9fd29c0700c182de5e787af45c4277ee62140787
downloadvisitor-72533c0efb9d5659cd2c1fb0e9f067696d759812.zip
visitor-72533c0efb9d5659cd2c1fb0e9f067696d759812.tar.gz
visitor-72533c0efb9d5659cd2c1fb0e9f067696d759812.tar.bz2
Initial commit, after jam
-rw-r--r--assets/ambient.oggbin0 -> 867212 bytes
-rw-r--r--assets/console.pngbin0 -> 158 bytes
-rw-r--r--assets/door.pngbin0 -> 295 bytes
-rw-r--r--assets/font.pngbin0 -> 1037 bytes
-rw-r--r--assets/fridge.pngbin0 -> 260 bytes
-rw-r--r--assets/outside.pngbin0 -> 3281 bytes
-rw-r--r--assets/outside.xcfbin0 -> 15704 bytes
-rw-r--r--assets/pallete.pngbin0 -> 206 bytes
-rw-r--r--assets/player-idle.jpx1
-rw-r--r--assets/player-idle.pngbin0 -> 203 bytes
-rw-r--r--assets/player-walk.jpx1
-rw-r--r--assets/player-walk.pngbin0 -> 229 bytes
-rw-r--r--assets/player-walk2.jpx1
-rw-r--r--assets/player-walk2.pngbin0 -> 204 bytes
-rw-r--r--assets/player.pngbin0 -> 323 bytes
-rw-r--r--assets/rooms.pngbin0 -> 469 bytes
-rw-r--r--assets/wand.pngbin0 -> 212 bytes
-rw-r--r--concepts.xcfbin0 -> 7315 bytes
-rw-r--r--conf.lua10
-rw-r--r--game.lua154
-rw-r--r--main.lua265
-rw-r--r--message.lua101
-rw-r--r--player.lua85
-rw-r--r--prop.lua93
-rw-r--r--quads.lua93
-rw-r--r--room.lua98
-rw-r--r--run.bat2
27 files changed, 904 insertions, 0 deletions
diff --git a/assets/ambient.ogg b/assets/ambient.ogg
new file mode 100644
index 0000000..9792647
--- /dev/null
+++ b/assets/ambient.ogg
Binary files differ
diff --git a/assets/console.png b/assets/console.png
new file mode 100644
index 0000000..f033c19
--- /dev/null
+++ b/assets/console.png
Binary files differ
diff --git a/assets/door.png b/assets/door.png
new file mode 100644
index 0000000..d594ca3
--- /dev/null
+++ b/assets/door.png
Binary files differ
diff --git a/assets/font.png b/assets/font.png
new file mode 100644
index 0000000..84a1ca3
--- /dev/null
+++ b/assets/font.png
Binary files differ
diff --git a/assets/fridge.png b/assets/fridge.png
new file mode 100644
index 0000000..8a6b2aa
--- /dev/null
+++ b/assets/fridge.png
Binary files differ
diff --git a/assets/outside.png b/assets/outside.png
new file mode 100644
index 0000000..f74153d
--- /dev/null
+++ b/assets/outside.png
Binary files differ
diff --git a/assets/outside.xcf b/assets/outside.xcf
new file mode 100644
index 0000000..4e8b6dd
--- /dev/null
+++ b/assets/outside.xcf
Binary files differ
diff --git a/assets/pallete.png b/assets/pallete.png
new file mode 100644
index 0000000..18f9022
--- /dev/null
+++ b/assets/pallete.png
Binary files differ
diff --git a/assets/player-idle.jpx b/assets/player-idle.jpx
new file mode 100644
index 0000000..7641b9a
--- /dev/null
+++ b/assets/player-idle.jpx
@@ -0,0 +1 @@
+{"w":8,"h":16,"unit":1,"speed":0.4,"animation":1,"frames":[{"layers":[{"name":"Layer #1","visible":true,"color":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAQCAYAAAArij59AAAAUUlEQVQoU2NkYGD4D8Q4ASNMgZV9BljRsYMzUBRTSQHMeJjZyNaAraC+AmTfwK0A2YtsFcwdWN2AYQJIAKQbZgqGLyhXADMe2SRYoKH4giwFALQaUgG7LWbGAAAAAElFTkSuQmCC","alpha":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAQCAYAAAArij59AAAATElEQVQoU2NkYGD4D8Q4ASNMAUwVSAAZUEkBuiOQrQFbQX0FIF/ArIFbAfcO1I8YCtBDCkUBSBLkUJgpGL6gXAHMeGSTYG5C8QVZCgCqrSYBwNeRYwAAAABJRU5ErkJggg=="}],"speed":null},{"layers":[{"name":"Layer #1","visible":true,"color":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAQCAYAAAArij59AAAAU0lEQVQoU2NkYGD4D8Q4ASPRCqzsM8CmHDs4A8U0uAmUKYDphpmNbA3YCpIVIDsWbgLIWGSTYNZgtQLDBJAASDfMFAxHUq4AZjyySbAwQfEFWQoAGr9PAUz5sCwAAAAASUVORK5CYII=","alpha":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAQCAYAAAArij59AAAATUlEQVQoU2NkYGD4D8Q4ASPRCmDGgHQgA7gJlClAdyWyNWArSFYAciTMFLgJ6P7FUIAeUigKQJIgd8BMwXAk5QpgxiObBHMTii/IUgAAwJ8lAacEjUgAAAAASUVORK5CYII="}],"speed":null},{"layers":[{"name":"Layer #1","visible":true,"color":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAQCAYAAAArij59AAAAXElEQVQoU2NkYGD4D8Q4ASPRCqzsM8CmHDs4A8U0uAmUKYDphpmNbA3YCuooABmLbBLMGqxWIHsXRQGyKSgmgHSAjIcpwPAFQQUw3cgKYWECdwPMWGTFIEUEFQAAHkNPAWmUPlMAAAAASUVORK5CYII=","alpha":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAQCAYAAAArij59AAAAU0lEQVQoU62QWwoAIAgE9f6HrhRWNjMKSvBv3IcqIm3sdvQagIxd8ITCG5BTso1b/AFyX9iUFlazBFhlAuzCggJYWhwBXDOId0dIyDKMsP6oHdABxJslAZ5ARJ0AAAAASUVORK5CYII="}],"speed":null},{"layers":[{"name":"Layer #1","visible":true,"color":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAQCAYAAAArij59AAAAUklEQVQoU2NkYGD4D8Q4ASNMgZV9BljRsYMzUBRTSQHMeJxWICtAVwR2A3UUgLyHzS1YrUB2B0o4IJsCCzCsCpBDkzgFIMfBdCGzQW6BO5JsBQC8llIB1TclRwAAAABJRU5ErkJggg==","alpha":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAQCAYAAAArij59AAAAUElEQVQoU62RwQoAIAhD9f8/ujKaLLMOoeBlPNyGKiJt7HUUACgTeIoADpFaxJQMzQw1gNdZHWGTWhizASZYDr7yBI4W8UJaEyKs8A8P+Q10qrEmAdh7RxUAAAAASUVORK5CYII="}],"speed":null}],"palette":[[255,255,255,0],[255,255,255,0],[255,255,255,0],[255,255,255,0],[255,255,255,0],[255,255,255,0],[255,255,255,0],[255,255,255,0],[255,255,255,0],[255,255,255,0],[255,255,255,0],[255,255,255,0],[255,255,255,0],[255,255,255,0],[255,255,255,0],[255,255,255,0],[255,255,255,0],[255,255,255,0],[255,255,255,0],[255,255,255,0],[255,255,255,0],[255,255,255,0],[255,255,255,0],[255,255,255,0],[255,255,255,0],[255,255,255,0],[255,255,255,0],[255,255,255,0],[255,255,255,0],[255,255,255,0]],"tileset":{"w":10,"h":2,"zoom":2,"tiles":[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null]},"background":""} \ No newline at end of file
diff --git a/assets/player-idle.png b/assets/player-idle.png
new file mode 100644
index 0000000..def21c0
--- /dev/null
+++ b/assets/player-idle.png
Binary files differ
diff --git a/assets/player-walk.jpx b/assets/player-walk.jpx
new file mode 100644
index 0000000..abd5faf
--- /dev/null
+++ b/assets/player-walk.jpx
@@ -0,0 +1 @@
+{"w":8,"h":16,"unit":1,"speed":0.1,"animation":1,"frames":[{"layers":[{"name":"Layer #1","visible":true,"color":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAQCAYAAAArij59AAAAUUlEQVQoU2NkYGD4D8Q4ASNMgZV9BljRsYMzUBRTSQHMeJjZyNaAraC+AmTfwK0A2YtsFcwdWN2AYQJIAKQbZgqGLyhXADMe2SRYoKH4giwFALQaUgG7LWbGAAAAAElFTkSuQmCC","alpha":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAQCAYAAAArij59AAAATElEQVQoU2NkYGD4D8Q4ASNMAUwVSAAZUEkBuiOQrQFbQX0FIF/ArIFbAfcO1I8YCtBDCkUBSBLkUJgpGL6gXAHMeGSTYG5C8QVZCgCqrSYBwNeRYwAAAABJRU5ErkJggg=="}],"speed":null},{"layers":[{"name":"Layer #1","visible":true,"color":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAQCAYAAAArij59AAAAT0lEQVQoU2NkYGD4D8Q4ASOyAiv7DLDCYwdnwDVQUQHMeJxWUKYApBvkcpy+QFeA7A6wNwkqgIUKZQGFbA3WoMarACYJcgsyG8RH8QU2BQCCIFIBirWOpgAAAABJRU5ErkJggg==","alpha":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAQCAYAAAArij59AAAATUlEQVQoU2NkYGD4D8Q4ASOyAphKkCAMUFEBskOwWkGZApBuZNdiWIGuAORFmCKwRoIKYIFCWUAhW4MzHGA+wekLkFtgJqFEFrIgugIAM9QmAQcoPDMAAAAASUVORK5CYII="}],"speed":null},{"layers":[{"name":"Layer #1","visible":true,"color":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAQCAYAAAArij59AAAAPUlEQVQoU2NkYGD4D8Q4ASOyAiv7DLDCYwdnwDVQUQHMeJxWDAkFINdTJ6CQgxlkKkZQ41SAzX4UE3ApAAB/XD0Bw4xE9wAAAABJRU5ErkJggg==","alpha":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAQCAYAAAArij59AAAAOElEQVQoU2NkYGD4D8Q4ASOyAphKkCAMUFEBskOwWjEkFIAChjoBhRwGIFMxghqnAmz2o5iASwEAIKgfAcxdPowAAAAASUVORK5CYII="}],"speed":null},{"layers":[{"name":"Layer #1","visible":true,"color":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAQCAYAAAArij59AAAAOElEQVQoU2NkYGD4D8Q4ASOyAiv7DLDCYwdnwDUMLQUwH+D0BeUKQEbTKaBA8QCyChYfGHFBsgIA1+dGAe2wVY4AAAAASUVORK5CYII=","alpha":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAQCAYAAAArij59AAAAMUlEQVQoU2NkYGD4D8Q4ASOyAphKkCAMDC0FyH7F6gvKFYAChk4BBQt7mE8w4oJkBQCTrCIBPrdoZAAAAABJRU5ErkJggg=="}],"speed":null},{"layers":[{"name":"Layer #1","visible":true,"color":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAQCAYAAAArij59AAAAQElEQVQoU2NkYGD4D8Q4ASOyAiv7DLDCYwdnwDVQUQHMeJxWUFcBsjVwXyBbQZ4CkC46BBQsDkBWwdgoviBLAQDs/0YB9m7RZAAAAABJRU5ErkJggg==","alpha":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAQCAYAAAArij59AAAAPElEQVQoU2NkYGD4D8Q4ASOyAphKkCAMUFEBskOwWkFdBSAfwKyB+wI9MEhXADKWDgEFcxjIKqyOJEsBAKuUIgGlr+vKAAAAAElFTkSuQmCC"}],"speed":null}],"palette":[[58,63,104,255],[255,255,255,0],[255,255,255,0],[255,255,255,0],[255,255,255,0],[255,255,255,0],[255,255,255,0],[255,255,255,0],[255,255,255,0],[255,255,255,0]],"tileset":{"w":10,"h":2,"zoom":2,"tiles":[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null]},"background":""} \ No newline at end of file
diff --git a/assets/player-walk.png b/assets/player-walk.png
new file mode 100644
index 0000000..78e4f38
--- /dev/null
+++ b/assets/player-walk.png
Binary files differ
diff --git a/assets/player-walk2.jpx b/assets/player-walk2.jpx
new file mode 100644
index 0000000..8b6b322
--- /dev/null
+++ b/assets/player-walk2.jpx
@@ -0,0 +1 @@
+{"w":8,"h":16,"unit":1,"speed":0.1,"animation":1,"frames":[{"layers":[{"name":"Layer #1","visible":true,"color":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAQCAYAAAArij59AAAAUElEQVQoU2NkYGD4D8Q4ASOyAiv7DLDCYwdnwDVQUQHMeJjZMGvgVlBfAcw3KFaA7EW2CsTH6QYME0ACIN0wUzB8QbkCmPHIJoHYGL4gWQEArAtSAcB+Y3wAAAAASUVORK5CYII=","alpha":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAQCAYAAAArij59AAAAS0lEQVQoU2NkYGD4D8Q4ASOyAphKkCAMUFEBukNg1sCtoL4CkC9AxqNYgeIlbArQQwvFBJAkyKEwUzB8QbkCmPHIJsF8Ag4jshUAAFKtJgEBW2qDAAAAAElFTkSuQmCC"}],"speed":null},{"layers":[{"name":"Layer #1","visible":true,"color":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAQCAYAAAArij59AAAAT0lEQVQoU2NkYGD4D8Q4ASOyAiv7DLDCYwdnwDVQUQHMeJxWUKYApBvkcpy+QFeA7A6wNwkqgIUKZQGFbA3WoMarACYJcgsyG8RH8QU2BQCCIFIBirWOpgAAAABJRU5ErkJggg==","alpha":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAQCAYAAAArij59AAAATUlEQVQoU2NkYGD4D8Q4ASOyAphKkCAMUFEBskOwWkGZApBuZNdiWIGuAORFmCKwRoIKYIFCWUAhW4MzHGA+wekLkFtgJqFEFrIgugIAM9QmAQcoPDMAAAAASUVORK5CYII="}],"speed":null},{"layers":[{"name":"Layer #1","visible":true,"color":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAQCAYAAAArij59AAAAPUlEQVQoU2NkYGD4D8Q4ASOyAiv7DLDCYwdnwDUMKgUwB+J0JB0UgOymTkAhBzPIVIygxqkAm/0oJuBSAAB4VD0B/VkBRwAAAABJRU5ErkJggg==","alpha":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAQCAYAAAArij59AAAAOElEQVQoU2NkYGD4D8Q4ASOyAphKkCAMDCoFyF7B6kg6KAAFDHUCCtkHIFMxghqnAmz2o5iASwEAGLAfATYlRfkAAAAASUVORK5CYII="}],"speed":null},{"layers":[{"name":"Layer #1","visible":true,"color":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAQCAYAAAArij59AAAAQ0lEQVQoU2NkYGD4D8Q4ASOyAiv7DLDCYwdnwDVQUQHMeJxW0FkBsjvg3kR2A1YFIEHqBBQomEEmwYIbxQ0wQeoqAAA/mUkBHqpVagAAAABJRU5ErkJggg==","alpha":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAQCAYAAAArij59AAAAPklEQVQoU2NkYGD4D8Q4ASOyAphKkCAMUFEBskOwWkFnBSAvwtwB9yZ6aGEoAOmiTkDB7MTqBpggyCrqKQAAGqcjAeCTbW8AAAAASUVORK5CYII="}],"speed":null}],"palette":[[58,63,104,255],[255,255,255,0],[255,255,255,0],[255,255,255,0],[255,255,255,0],[255,255,255,0],[255,255,255,0],[255,255,255,0],[255,255,255,0],[255,255,255,0]],"tileset":{"w":10,"h":2,"zoom":2,"tiles":[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null]},"background":""} \ No newline at end of file
diff --git a/assets/player-walk2.png b/assets/player-walk2.png
new file mode 100644
index 0000000..3c661b6
--- /dev/null
+++ b/assets/player-walk2.png
Binary files differ
diff --git a/assets/player.png b/assets/player.png
new file mode 100644
index 0000000..c4b8455
--- /dev/null
+++ b/assets/player.png
Binary files differ
diff --git a/assets/rooms.png b/assets/rooms.png
new file mode 100644
index 0000000..6f4e95e
--- /dev/null
+++ b/assets/rooms.png
Binary files differ
diff --git a/assets/wand.png b/assets/wand.png
new file mode 100644
index 0000000..693a057
--- /dev/null
+++ b/assets/wand.png
Binary files differ
diff --git a/concepts.xcf b/concepts.xcf
new file mode 100644
index 0000000..ee26225
--- /dev/null
+++ b/concepts.xcf
Binary files differ
diff --git a/conf.lua b/conf.lua
new file mode 100644
index 0000000..8852646
--- /dev/null
+++ b/conf.lua
@@ -0,0 +1,10 @@
+function love.conf(t)
+ t.title = "The Visitor (Fermijam)"
+ t.version = "0.10.1"
+ -- t.window.width = 100*6
+ -- t.window.height = 57*6
+ -- t.window.borderless = true
+ t.window.fullscreentype = "desktop"
+ t.window.fullscreen = true
+ -- t.console = true
+end \ No newline at end of file
diff --git a/game.lua b/game.lua
new file mode 100644
index 0000000..1146f1f
--- /dev/null
+++ b/game.lua
@@ -0,0 +1,154 @@
+-- Namespace.
+local Game = {}
+
+-- Import.
+Game.newRoom = require "room"
+Game.newPlayer = require "player"
+Game.newProp = require "prop"
+Game.newMessage = require "message"
+Game.quads = require "quads"
+
+-- Various children.
+Game.sprites = {}
+Game.rooms = {}
+Game.props = {}
+Game.player = nil
+Game.message = nil
+Game.delay = 0.08
+Game.initial = Game.delay
+
+-- Aliases for window size getters.
+Game.getWidth = love.graphics.getWidth
+Game.getHeight = love.graphics.getHeight
+
+-- Loads sprites atlases.
+function Game.load()
+ -- Font
+ Game.font = love.graphics.newImageFont("assets/font.png", " 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.,:;-_/\\!@#$%^&*?=+~`|'\"()[]{}<>", 1)
+ Game.font:setLineHeight(0.875)
+ love.graphics.setFont(Game.font)
+ -- Spritesheets
+ Game.sprites.player = love.graphics.newImage("assets/player.png")
+ Game.sprites.room = love.graphics.newImage("assets/rooms.png")
+ Game.sprites.door = love.graphics.newImage("assets/door.png")
+ Game.sprites.console = love.graphics.newImage("assets/console.png")
+ Game.sprites.fridge = love.graphics.newImage("assets/fridge.png")
+ Game.sprites.outside = love.graphics.newImage("assets/outside.png")
+ Game.sprites.wand = love.graphics.newImage("assets/wand.png")
+ -- Create new player
+ Game.player = Game.newPlayer()
+end
+
+-- Based on current window sizes returns proper scale for elements.
+function Game.getScale()
+ local w,h = Game.getWidth(), Game.getHeight()
+ local scale_w = math.ceil(w / 100)
+ local scale_h = math.ceil(h / 75)
+ return math.max(scale_w, scale_h)
+end
+
+-- Get current offsets.
+function Game.getOffsets()
+ local scale, width, height, mouse_x, mouse_y, player_x, offset_x, offset_y
+ scale = Game.getScale()
+ width, height = Game.getWidth(), Game.getHeight()
+ mouse_x, mouse_y = love.mouse.getPosition()
+ player_x = Game.player.x * scale
+ mouse_x = (mouse_x - width / 2)*.02
+ mouse_y = (mouse_y - height / 2)*.01
+ offset_x = width/2 - player_x - mouse_x
+ offset_y = (height - (32 * scale))/2 - mouse_y
+ return offset_x, offset_y
+end
+
+-- Returns mouse position in game world.
+function Game.getMousePosition(x, y)
+ local scale = Game.getScale()
+ if not x and not y then
+ local x, y = love.mouse.getPosition()
+ end
+ local ox, oy = Game.getOffsets()
+ x = math.floor((x - ox)/scale)
+ y = math.floor((y - oy)/scale)
+ return x, y
+end
+
+-- Returns double true if given position is inside any Room.
+function Game.inRange(x, y)
+ local horizontal, vertical = false, false
+ if y > 0 and y < 32 then
+ vertical = true
+ end
+ local width = 0
+ for _,room in pairs(Game.rooms) do
+ if room.discovered then
+ width = width + room:getDimensions()
+ end
+ end
+ if x > 2 and x < width-1 then
+ horizontal = true
+ end
+ return horizontal, vertical
+end
+
+-- Tests if given position is inside any Prop.
+function Game.testPosition(x, y)
+ for _,prop in pairs(Game.props) do
+ local test = prop:testPosition(x, y)
+ if test then
+ return test
+ end
+ end
+end
+
+-- Returns player. The only one.
+function Game.getPlayer()
+ return Game.player
+end
+
+-- Returns current message, beep.
+function Game.getMessage()
+ return Game.message
+end
+
+-- Inserts new Room.
+function Game.insertRoom(width, height)
+ local x, y
+ local last = Game.rooms[#Game.rooms]
+ if last then
+ local lw, lh = last:getDimensions()
+ local lx, ly = last:getPosition()
+ x, y = lx + lw, ly
+ end
+ local room = Game.newRoom():setDimensions(width, height):setPosition(x, y)
+ table.insert(Game.rooms, room)
+ return room
+end
+function Game.insertDoor(room)
+ local x, y = room:getPosition()
+ local w, h = room:getDimensions()
+ local door = Game.insertProp():setPosition(x+w-5,10):setDimensions(10,18)
+ return door
+end
+
+-- Inserts new Prop.
+function Game.insertProp(prop)
+ local prop = prop
+ if not prop then
+ prop = Game.newProp()
+ end
+ table.insert(Game.props, prop)
+ return prop
+end
+
+-- Sets given or empty message as current message.
+function Game.setMessage(message)
+ local message = message
+ if not message then
+ message = Game.newMessage()
+ end
+ Game.message = message
+ return message
+end
+
+return Game \ No newline at end of file
diff --git a/main.lua b/main.lua
new file mode 100644
index 0000000..10dcbb5
--- /dev/null
+++ b/main.lua
@@ -0,0 +1,265 @@
+-- Import.
+Game = require "game"
+
+-- LÖVE2D Callbacks.
+function love.load()
+ -- Initialization
+ love.graphics.setBackgroundColor(2,2,5)
+ love.graphics.setDefaultFilter("nearest", "nearest")
+ love.graphics.setLineStyle("rough")
+ math.randomseed(os.time())
+ print("Initializing...")
+ Game.load()
+ -- Game
+ local ambient = love.audio.newSource("assets/ambient.ogg", "static")
+ ambient:setLooping(true)
+ ambient:setVolume(0.9)
+ ambient:play()
+ local tutorial = Game.setMessage():setText("", "Click to move, interact with an object or close a message."):setUse(function () Game.setMessage():setText("THE VISITOR", "Game made for Fermi Paradox Jam") end)
+ local r = {
+ Game.insertRoom(36):setStyle("start"):discover(),
+ Game.insertRoom():setOutside(1),
+ Game.insertRoom():setOutside(2),
+ Game.insertRoom():setOutside(3),
+ Game.insertRoom():setOutside(4),
+ Game.insertRoom():setOutside(5),
+ Game.insertRoom():setOutside(6),
+ Game.insertRoom():setOutside(7),
+ Game.insertRoom(57):setStyle("finish"),
+ }
+ -- Doors
+ local d = {
+ Game.insertDoor(r[1]):setUse(function (self)
+ if self.animation == "closed" then
+ r[2]:discover(true)
+ self:changeAnimation("opening")
+ Game.setMessage():setText("Me:", "I'm still a little bit confused after waking up. This console may have some useful information.")
+ end
+ end),
+ Game.insertDoor(r[2]):setUse(function (self)
+ if self.animation == "closed" then
+ r[3]:discover(true)
+ self:changeAnimation("opening")
+ Game.setMessage():setText("Me:", "What the actual..."):setUse(function ()
+ Game.setMessage():setText("Me:", "This does not look normal. The view from next room's window is a totally different view compared to this room's view.")
+ end)
+ end
+ if self.animation == "locked" then
+ Game.setMessage():setText("Me:", "This door seems locked.")
+ end
+ end):changeAnimation("locked"),
+ Game.insertDoor(r[3]):setUse(function (self)
+ if self.animation == "closed" then
+ r[4]:discover(true)
+ self:changeAnimation("opening")
+ Game.setMessage():setText("Me:", "Same thing.")
+ end
+ end),
+ Game.insertDoor(r[4]):setUse(function (self)
+ if self.animation == "closed" then
+ r[5]:discover(true)
+ self:changeAnimation("opening")
+ Game.setMessage():setText("Me:", "Well, this is different. This time it is a star.")
+ end
+ end),
+ Game.insertDoor(r[5]):setUse(function (self)
+ if self.animation == "closed" then
+ Game.setMessage():setText("Me:", "Let's hope I will find anything in the next room. Something other than: window, door, console.")
+ r[6]:discover(true)
+ self:changeAnimation("opening")
+ end
+ end),
+ Game.insertDoor(r[6]):setUse(function (self)
+ if self.animation == "closed" then
+ r[7]:discover(true)
+ self:changeAnimation("opening")
+ end
+ if self.animation == "locked" then
+ Game.setMessage():setText("Me:", "This door seems locked.")
+ end
+ end),
+ Game.insertDoor(r[7]):setUse(function (self)
+ if self.animation == "closed" then
+ r[8]:discover(true)
+ self:changeAnimation("opening")
+ end
+ if self.animation == "locked" then
+ Game.setMessage():setText("Me:", "This door seems locked.")
+ end
+ end),
+ Game.insertDoor(r[8]):setUse(function (self)
+ if self.animation == "closed" then
+ r[9]:discover(true)
+ self:changeAnimation("opening")
+ Game.setMessage():setText("Me:", "This room is different.")
+ end
+ if self.animation == "locked" then
+ Game.setMessage():setText("Me:", "This door seems locked.")
+ end
+ end),
+ }
+ -- 1:
+ Game.insertProp():setPosition(3,12):setDimensions(9,16):setStyle("fridge"):setUse(function () Game.setMessage():setText("Me:", "It's the cryocapsule I have just left."):show() end):changeAnimation("open")
+ Game.insertProp():setPosition(14,12):setDimensions(9,16):setStyle("fridge"):setUse(function () Game.setMessage():setText("Me:", "This one is closed and I can't see if it is empty or not."):show() end):changeAnimation("closed")
+ -- 2:
+ Game.insertProp():setPosition(r[2]:randomX(20),19):setDimensions(7,9):setStyle("console"):changeAnimation("working"):setUse(function (self)
+ Game.setMessage():setText("Console:", "Planet: 00AE30F63CC50BEC\nLife found: false\n(...)"):show():setUse(function ()
+ Game.setMessage():setText("Me:", "There is plenty of information about this planet in the console. Nothing feels really useful but it seems there is also an unlock button for the door."):setUse(function ()
+ if d[2].animation == "locked" then d[2]:changeAnimation("closed") end
+ end)
+ end)
+ end)
+ -- 3:
+ Game.insertProp():setPosition(r[3]:randomX(7),19):setDimensions(7,9):setStyle("console"):changeAnimation("working"):setUse(function (self)
+ Game.setMessage():setText("Console:", "Planet: 0054500436450A2D\nLife found: false\n(...)"):show():setUse(function ()
+ Game.setMessage():setText("Console:", "(...)\nIt is worth mentioning that this planet may develop life in future. Probe has decided to leave Watcher-Child here for further observation.\n(...)"):setUse(function ()
+ Game.setMessage():setText("Me:", "Interesting. While I have no knowledge of this facility I recall being told what are the Probes. I think they were some kind of self-replicating entities.")
+ end)
+ end)
+ end)
+ -- 4:
+ Game.insertProp():setPosition(r[4]:randomX(7),19):setDimensions(7,9):setStyle("console"):changeAnimation("working"):setUse(function (self)
+ Game.setMessage():setText("Console:", "Planet: 000021B533252BAB\nLife found: true, bacteria-like\n(...)"):show():setUse(function ()
+ Game.setMessage():setText("Me:", "Wait... Could it be that behind every window there is planet described in the console?\nIt seems impossible but..."):setUse(function ()
+ Game.setMessage():setText("Console:", "(...)\nPlanet's atmosphere has been destroyed due to increasing activity of system's star. Watcher has decided to go into lower activity state.\n(...)"):setUse(function ()
+ Game.setMessage():setText("Console:", "(...)\nNo further sings of life on planet. Watcher has decided to leave planet due to star activity. Moving away from the star.\n(...)")
+ end)
+ end)
+ end)
+ end)
+ -- 5:
+ Game.insertProp():setPosition(r[5]:randomX(7),19):setDimensions(7,9):setStyle("console"):changeAnimation("working"):setUse(function (self)
+ Game.setMessage():setText("Console:", "Star: B94DC4A0\nPlanets: none\nLeaving Watcher-Child for observation."):show():setUse(function ()
+ Game.setMessage():setText("Me:", "This one is somehow disappointing..."):setUse(function ()
+ Game.setMessage():setText("Me:", "...")
+ end)
+ end)
+ end)
+ -- 6:
+ Game.insertProp():setPosition(r[6]:randomX(7),19):setDimensions(7,9):setStyle("console"):changeAnimation("working"):setUse(function (self)
+ Game.setMessage():setText("Console:", "Data unaccessible.\n\nMemory storage damaged."):show():setUse(function ()
+ Game.setMessage():setText("Me:", "And this is somehow interesting.\nYet it doesn't seem like I could do anything with it. I haven't got access to any proper tools from here.")
+ end)
+ end)
+ --- 7:
+ Game.insertProp():setPosition(r[7]:randomX(7),19):setDimensions(7,9):setStyle("console"):changeAnimation("working"):setUse(function (self)
+ Game.setMessage():setText("Console:", "Planet: 00A687B4D7EA9567\nLife found: true, intelligent\n(...)"):show():setUse(function ()
+ Game.setMessage():setText("Console:", "(...)\nProbe can't decide on normal conditions. Probe has sent data to Home.\n(...)"):setUse(function ()
+ Game.setMessage():setText("Console:", "(...)\nWaiting for responce...\nWaiting for responce...\n(...)"):setUse(function ()
+ Game.setMessage():setText("Console:", "(...)Home Personality has been woken up but is unresponsible. Possible personality damage. Attempting repairs...\n"):setUse(function ()
+ Game.setMessage():setText("Me:", "And... Wait, that's it? Where is the rest of the log files?")
+ end)
+ end)
+ end)
+ end)
+ end)
+ -- 8:
+ Game.insertProp():setPosition(r[8]:randomX(7),19):setDimensions(7,9):setStyle("console"):changeAnimation("working"):setUse(function (self)
+ Game.setMessage():setText("Console:", "Planet: 00B4CDDA64E73009\nLife found: true, bacteria-like(...)"):show():setUse(function ()
+ Game.setMessage():setText("Console:", "(...)\nHigh radiation level in atmosphere. Radiation is natural due to planet natural resources.\n(...)"):setUse(function ()
+ Game.setMessage():setText("Console:", "(...)\nThere are no signs of evolution. Only one species with no reproduction abilities. There is also no sign of death among them."):setUse(function ()
+ Game.setMessage():setText("Me:", "Immortaility, huh? Quite impressing but along with all other things listed in the log... It will just be there untill star will burn out.")
+ end)
+ end)
+ end)
+ end)
+ -- 9:
+ Game.insertProp():setPosition(r[9].x+22,19):setDimensions(7,9):setStyle("console"):changeAnimation("working"):setUse(function (self)
+ if Game.decision then return end
+ Game.setMessage():setText("Console:", "Case: intelligent life on 00A687B4D7EA9567\n(...)"):show():setUse(function ()
+ Game.setMessage():setText("Me:", "Wait..."):setUse(function ()
+ Game.setMessage():setText("Me:", "This would mean that I am the Personality..."):setUse(function ()
+ Game.setMessage():setText("Console:", "(...)\nAfter several repairs performed on brain memory sectors Personality could be started. Its purpose is to determine whenever listed case of life can be classified as intelligent lifeform.\n(...)"):setUse(function ()
+ Game.setMessage():setText("Console:", "(...)\nLife-like mass found on planet is changing its chemical properties in mostly random ways. It does not show any signs of communication with Probe.\n(...)"):setUse(function ()
+ Game.setMessage():setText("Console:", "(...)\nThose chemical patterns could be translated to 7-dimensional space with various objects that seem to perform actions. It is not sure if it is not overinterpretation of simple patterns.\n(...)"):setUse(function ()
+ Game.setMessage():setText("Console:", "(...)\nThese \"objects\" don't hold their shape for long time, but they seem not to disappear without certain few conditions.\n(...)"):setUse(function ()
+ Game.setMessage():setText("Me:", "And there is more... Raport is about 1,200 pages long, not mentioning raw data..."):setUse(function ()
+ Game.setMessage():setText("", "With given description select whenever it is intelligent life or not.")
+ Game.decision = true
+ end)
+ end)
+ end)
+ end)
+ end)
+ end)
+ end)
+ end)
+ end)
+ Game.fincryo = Game.insertProp():setPosition(r[9].x+38,12):setDimensions(9,16):setStyle("fridge"):changeAnimation("closed"):setUse(function (self)
+ if self.animation == "open" then
+ Game.setMessage():setText("", "Click again to enter cryocapsule and quit the game."):show():setUse(function ()
+ Game.rooms = {}
+ Game.player.y = -50
+ Game.setMessage():setText("", "After you enter non-existent cryocapsule in the non-existent space your virtually managed personality is put to standby mode.\nYour memories keep leaking out of the data storage as semi-AI can't perform proper repairs.\nGoodnight, Visitor."):show():setUse(function ()
+ love.event.quit()
+ end)
+ end)
+ else
+ Game.setMessage():setText("Me:", "It is closed."):show()
+ end
+ end)
+ Game.insertProp():setPosition(r[9].x+31,20):setDimensions(2,8):setStyle("wand"):changeAnimation("yes"):setUse(function (self)
+ if Game.decision then
+ Game.setMessage():setText("", "Yes."):show():setUse(function (self)
+ Game.fincryo:changeAnimation("open") end)
+ else
+ Game.setMessage():setText("", "Use console first."):show()
+ end
+ end)
+ Game.insertProp():setPosition(r[9].x+34,20):setDimensions(2,8):setStyle("wand"):changeAnimation("no"):setUse(function (self)
+ if Game.decision then
+ Game.setMessage():setText("", "No."):show():setUse(function (self)
+ Game.fincryo:changeAnimation("open") end)
+ else
+ Game.setMessage():setText("", "Use console first."):show()
+ end
+ end)
+end
+function love.update(dt)
+ Game.delay = Game.delay - dt
+ if Game.delay < 0 then
+ Game.delay = Game.delay + Game.initial
+ for _,room in pairs(Game.rooms) do room:update() end
+ for _,prop in pairs(Game.props) do prop:update() end
+ local player, message = Game.getPlayer(), Game.getMessage()
+ if player then player:update() end
+ if message then message:update() end
+ end
+end
+function love.draw()
+ local scale = Game.getScale()
+ local offset_x, offset_y = Game.getOffsets()
+ love.graphics.translate(offset_x, offset_y)
+ for _,room in pairs(Game.rooms) do
+ room:draw(scale, offset_x, offset_y)
+ end
+ for _,prop in pairs(Game.props) do
+ prop:draw(scale)
+ end
+ if Game.getPlayer() then
+ Game.getPlayer():draw(scale)
+ end
+ if Game.getMessage() then
+ Game.getMessage():draw(scale)
+ end
+end
+function love.quit()
+ print("Quiting...")
+end
+function love.mousepressed(x, y, button, istouch)
+ local x, y = Game.getMousePosition(x, y)
+ if button == 1 then
+ if Game.getMessage() and Game.getMessage():isVisible() then
+ print("Message is active; using...")
+ Game.getMessage():click()
+ elseif Game.getPlayer() then
+ Game.getPlayer():setTarget(x, y, Game.testPosition(x, y))
+ print("No message active, setting target for player...")
+ end
+ end
+end
+function love.keypressed(key)
+ if key == "escape" then
+ love.event.quit()
+ end
+end \ No newline at end of file
diff --git a/message.lua b/message.lua
new file mode 100644
index 0000000..24662fc
--- /dev/null
+++ b/message.lua
@@ -0,0 +1,101 @@
+-- Metatable.
+local Message = {
+ text, -- actually added in constructor
+ opacity = 0, -- [0..3]
+ visible = true,
+}
+Message.__index = Message
+
+-- Constructor.
+local function newMessage()
+ return setmetatable({text = love.graphics.newText(Game.font)}, Message)
+end
+
+-- Dimensions related functions.
+function Message:getDimensions()
+ local width = Game.getWidth() / self:getScale()
+ local height = 0
+ if self.text then
+ height = self.text:getHeight()
+ end
+ return width, height
+end
+
+-- Position related functions.
+function Message:getPosition(scale)
+ local w, h = self:getDimensions()
+ local x = 2 * scale
+ local y = Game.getHeight() - (h+2) * scale
+ return x, y
+end
+
+-- Internal scale for Message's text.
+function Message:getScale()
+ return math.min(7, math.ceil(Game.getWidth() / 190))
+end
+
+-- Text, set it, motherfucker.
+function Message:setText(speaker, content)
+ local width = self:getDimensions()
+ if self.text and speaker and content then
+ self.text:setf({{240,100,100}, speaker .. "\n" , {240,240,240}, content},width, "left")
+ end
+ return self
+end
+
+-- Also set use, not seduce.
+function Message:setUse(func)
+ if type(func) == "function" then
+ self.use = func
+ end
+ return self
+end
+
+-- Manages Message's visibility.
+function Message:isVisible()
+ if self.opacity > 0 then
+ return true
+ end
+ return false
+end
+function Message:hide()
+ self.visible = false
+ return self
+end
+function Message:show()
+ self.visible = true
+ return self
+end
+
+-- Callback when mouse is pressed.
+function Message:click()
+ self:hide()
+end
+function Message:use()
+end
+
+-- LÖVE2D callbacks.
+function Message:update(dt)
+ if self.visible and self.opacity < 3 then
+ self.opacity = self.opacity + 1
+ end
+ if not self.visible and self.opacity > 0 then
+ self.opacity = self.opacity - 1
+ end
+ if not self.visible and self.opacity == 0 then
+ self:use()
+ end
+end
+function Message:draw(scale)
+ if not self:isVisible() then return end
+ local scale = self:getScale()
+ local x,y = self:getPosition(scale)
+ local w, h = self:getDimensions()
+ love.graphics.push()
+ love.graphics.origin()
+ love.graphics.setColor(255,255,255,255/3*self.opacity)
+ love.graphics.draw(self.text, x,y, 0, scale, scale)
+ love.graphics.pop()
+end
+
+return newMessage \ No newline at end of file
diff --git a/player.lua b/player.lua
new file mode 100644
index 0000000..e4ef8f6
--- /dev/null
+++ b/player.lua
@@ -0,0 +1,85 @@
+-- Metatable.
+local Player = {
+ x = 14,
+ y = 12,
+ frame = 1,
+ animation = "idle",
+ moved = false,
+ target_x = 14,
+ call,
+}
+Player.__index = Player
+
+-- Craete new empty Player object.
+local function newPlayer()
+ return setmetatable({}, Player)
+end
+
+-- Position related functions.
+function Player:getPosition()
+ return self.x, self.y
+end
+function Player:setPosition(x, y)
+ self.x, self.y = x, y
+ return self
+end
+
+-- Facing.
+function Player:getFacing()
+ if self.animation == "walk" then
+ if (self.target_x - self.x) < 0 then
+ return -1
+ end
+ end
+ return 1
+end
+
+-- Target.
+function Player:setTarget(x, y, prop)
+ if Game.inRange(x, y) then
+ self.target_x = x
+ self.prop = prop
+ end
+end
+
+-- Change animation.
+function Player:changeAnimation(name)
+ if self.animation ~= name then
+ self.animation = name
+ self.frame = 1
+ end
+ return self
+end
+
+-- LÖVE2D callbacks.
+function Player:update()
+ -- Animation.
+ local frames = #Game.quads.player[self.animation]
+ self.frame = (self.frame%frames)+1
+ -- Movement towards target.
+ self.moved = false
+ if math.abs(self.x - self.target_x) > 2 then
+ self:changeAnimation("walk")
+ else
+ self:changeAnimation("idle")
+ if self.prop then
+ print("Using prop...")
+ self.prop:use()
+ self.prop = nil
+ end
+ end
+ -- Walking.
+ if self.animation == "walk" and not self.moved and (self.frame == 1 or self.frame == 3 or self.frame == 5) then
+ self.x = self.x + self:getFacing()
+ self.moved = true
+ end
+end
+function Player:draw(scale)
+ local quad = Game.quads.player[self.animation][self.frame]
+ local sprite = Game.sprites.player
+ local x, y = self:getPosition()
+ love.graphics.setColor(255,255,255)
+ love.graphics.draw(sprite, quad, (x)*scale, (y)*scale, 0, scale*self:getFacing(), scale, 4)
+end
+
+return newPlayer \ No newline at end of file
diff --git a/prop.lua b/prop.lua
new file mode 100644
index 0000000..67358e1
--- /dev/null
+++ b/prop.lua
@@ -0,0 +1,93 @@
+-- Metatable.
+local Prop = {
+ x = 0,
+ y = 0,
+ width = 0,
+ height = 0,
+ frame = 1,
+ animation = "closed",
+ style = "door",
+}
+Prop.__index = Prop
+
+-- Constructor.
+local function newProp()
+ return setmetatable({}, Prop)
+end
+
+-- Dimensions related functions.
+function Prop:getDimensions()
+ return self.width, self.height
+end
+function Prop:setDimensions(width, height)
+ self.width, self.height = width, height
+ return self
+end
+
+-- Position related functions.
+function Prop:getPosition()
+ return self.x, self.y
+end
+function Prop:setPosition(x, y)
+ self.x, self.y = x, y
+ return self
+end
+
+-- Don't mistake with seduce.
+function Prop:setUse(func)
+ if type(func) == "function" then
+ self.use = func
+ end
+ return self
+end
+
+-- Animation.
+function Prop:changeAnimation(name)
+ if self.animation ~= name and name then
+ self.animation = name
+ self.frame = 1
+ end
+ return self
+end
+
+-- Stylish.
+function Prop:setStyle(style)
+ if self.style ~= style and style then
+ self.style = style
+ end
+ return self
+end
+
+-- Returns true if given position is inside Prop's hitbox.
+function Prop:testPosition(x, y)
+ local px, py = self:getPosition()
+ local w, h = self:getDimensions()
+ if x > px and x < px+w and y > py and y < py+h then
+ return self
+ end
+end
+
+-- Being used by player callback.
+function Prop:use() end
+
+-- LÖVE2D callbacks.
+function Prop:update()
+ -- Animations
+ local frames = #Game.quads[self.style][self.animation]
+ self.frame = (self.frame%frames)+1
+ -- Automatic animation changes
+ if self.animation == "opening" and self.frame == 7 then
+ self:changeAnimation("open")
+ end
+end
+function Prop:draw(scale)
+ local x,y = self:getPosition()
+ if Game.inRange(x, y) then
+ local sprite = Game.sprites[self.style]
+ local quad = Game.quads[self.style][self.animation][self.frame]
+ love.graphics.setColor(255,255,255)
+ love.graphics.draw(sprite, quad, (x)*scale, (y)*scale, 0, scale, scale)
+ end
+end
+
+return newProp \ No newline at end of file
diff --git a/quads.lua b/quads.lua
new file mode 100644
index 0000000..f97e3fc
--- /dev/null
+++ b/quads.lua
@@ -0,0 +1,93 @@
+-- Namespace.
+local Quads = {}
+
+-- Player animations
+Quads.player = {}
+Quads.player.idle = {
+ love.graphics.newQuad( 0, 0, 8,16, 40,32),
+ love.graphics.newQuad( 0, 0, 8,16, 40,32),
+ love.graphics.newQuad( 0, 0, 8,16, 40,32),
+ love.graphics.newQuad( 0, 0, 8,16, 40,32),
+ love.graphics.newQuad( 8, 0, 8,16, 40,32),
+ love.graphics.newQuad( 8, 0, 8,16, 40,32),
+ love.graphics.newQuad( 8, 0, 8,16, 40,32),
+ love.graphics.newQuad( 8, 0, 8,16, 40,32),
+ love.graphics.newQuad(16, 0, 8,16, 40,32),
+ love.graphics.newQuad(16, 0, 8,16, 40,32),
+ love.graphics.newQuad(16, 0, 8,16, 40,32),
+ love.graphics.newQuad(16, 0, 8,16, 40,32),
+ love.graphics.newQuad(24, 0, 8,16, 40,32),
+ love.graphics.newQuad(24, 0, 8,16, 40,32),
+ love.graphics.newQuad(24, 0, 8,16, 40,32),
+ love.graphics.newQuad(24, 0, 8,16, 40,32),
+}
+Quads.player.walk = {
+ love.graphics.newQuad( 0,16, 8,16, 40,32),
+ love.graphics.newQuad( 8,16, 8,16, 40,32),
+ love.graphics.newQuad(16,16, 8,16, 40,32),
+ love.graphics.newQuad(24,16, 8,16, 40,32),
+ love.graphics.newQuad(32,16, 8,16, 40,32),
+}
+
+-- Room types
+Quads.room = {}
+Quads.room.start = { love.graphics.newQuad( 0, 0, 36,32, 157,32) }
+Quads.room.planet = { love.graphics.newQuad(36, 0, 64,32, 157,32) }
+Quads.room.finish = { love.graphics.newQuad(100, 0, 57,32, 157,32) }
+
+-- Door animations
+Quads.door = {}
+Quads.door.locked = {
+ love.graphics.newQuad( 0, 0, 10,18, 80,18)
+}
+Quads.door.closed = {
+ love.graphics.newQuad(10, 0, 10,18, 80,18)
+}
+Quads.door.opening = {
+ love.graphics.newQuad(10, 0, 10,18, 80,18),
+ love.graphics.newQuad(20, 0, 10,18, 80,18),
+ love.graphics.newQuad(30, 0, 10,18, 80,18),
+ love.graphics.newQuad(40, 0, 10,18, 80,18),
+ love.graphics.newQuad(50, 0, 10,18, 80,18),
+ love.graphics.newQuad(60, 0, 10,18, 80,18),
+ love.graphics.newQuad(70, 0, 10,18, 80,18),
+}
+Quads.door.open = {
+ love.graphics.newQuad(70, 0, 10,18, 80,18)
+}
+
+-- Console
+Quads.console = {}
+Quads.console.working = {
+ love.graphics.newQuad( 0, 0, 7,9, 14,9),
+ love.graphics.newQuad( 7, 0, 7,9, 14,9),
+}
+
+-- Fridge
+Quads.fridge = {}
+Quads.fridge.open = {
+ love.graphics.newQuad( 0, 0, 9,16, 18,16),
+}
+Quads.fridge.closed = {
+ love.graphics.newQuad( 9, 0, 9,16, 18,16),
+}
+
+-- Outside
+Quads.outside = {
+ { love.graphics.newQuad( 0, 0,100,75,900,75), },
+ { love.graphics.newQuad(100, 0,100,75,900,75), },
+ { love.graphics.newQuad(200, 0,100,75,900,75), },
+ { love.graphics.newQuad(300, 0,100,75,900,75), },
+ { love.graphics.newQuad(400, 0,100,75,900,75), },
+ { love.graphics.newQuad(500, 0,100,75,900,75), },
+ { love.graphics.newQuad(600, 0,100,75,900,75), },
+ { love.graphics.newQuad(700, 0,100,75,900,75), },
+ { love.graphics.newQuad(800, 0,100,75,900,75), },
+}
+
+-- Wands
+Quads.wand = {}
+Quads.wand.yes = { love.graphics.newQuad(0,0, 2,8, 4,8) }
+Quads.wand.no = { love.graphics.newQuad(2,0, 2,8, 4,8) }
+
+return Quads \ No newline at end of file
diff --git a/room.lua b/room.lua
new file mode 100644
index 0000000..b7f5206
--- /dev/null
+++ b/room.lua
@@ -0,0 +1,98 @@
+-- Metatable.
+local Room = {
+ x = 0,
+ y = 0,
+ width = 64,
+ height = 32,
+ discovered = false,
+ style = "planet",
+ seed = 0,
+ opacity = 255,
+ outside = 1,
+}
+Room.__index = Room
+
+-- Create new empty Room with given dimensions.
+local function newRoom()
+ return setmetatable({seed = math.random(1,65535)}, Room)
+end
+
+-- Sets style of a Room.
+function Room:setStyle(style)
+ self.style = style
+ return self
+end
+function Room:setOutside(outside)
+ self.outside = outside
+ return self
+end
+
+-- Dimensions related functions.
+function Room:getDimensions()
+ return self.width, self.height
+end
+function Room:setDimensions(width, height)
+ self.width, self.height = width, height
+ return self
+end
+
+-- Position related functions.
+function Room:getPosition()
+ return self.x, self.y
+end
+function Room:setPosition(x, y)
+ self.x, self.y = x, y
+ return self
+end
+function Room:randomX(w)
+ local x = self:getPosition()
+ local width = self:getDimensions()
+ return x+math.random(3, width-3-w)
+end
+
+-- Discovers room.
+function Room:discover(animate)
+ self.discovered = true
+ if animate then
+ self.opacity = 0
+ end
+ return self
+end
+
+-- Drawing functions
+function Room:drawOutside(scale, offset_x, offset_y)
+ local x, y = self:getPosition()
+ local width, height = self:getDimensions()
+ love.graphics.push()
+ love.graphics.origin()
+ love.graphics.setScissor((x+1)*scale + offset_x, (y+1)*scale + offset_y, (width-2)*scale, (height-2)*scale)
+ love.graphics.setColor(self.opacity,self.opacity,self.opacity)
+ love.graphics.draw(Game.sprites.outside, Game.quads.outside[self.outside][1], 0, Game.getHeight()/2, 0, scale, scale, 0, 75/2)
+ love.graphics.setScissor()
+ love.graphics.pop()
+end
+function Room:drawInside(scale)
+ local x, y = self:getPosition()
+ local width, height = self:getDimensions()
+ local sprite = Game.sprites.room
+ local quad = Game.quads.room[self.style]
+ love.graphics.setColor(self.opacity,self.opacity,self.opacity)
+ love.graphics.draw(sprite, quad[1], (x)*scale, (y)*scale, 0, scale, scale)
+end
+
+-- LÖVE2D callbacks.
+function Room:update()
+ if self.opacity < 255 then
+ self.opacity = math.min(255, self.opacity + 64)
+ end
+end
+function Room:draw(scale, offset_x, offset_y)
+ if self.discovered then
+ if self.style == "planet" then
+ self:drawOutside(scale, offset_x, offset_y)
+ end
+ self:drawInside(scale)
+ end
+end
+
+return newRoom \ No newline at end of file
diff --git a/run.bat b/run.bat
new file mode 100644
index 0000000..055d6d1
--- /dev/null
+++ b/run.bat
@@ -0,0 +1,2 @@
+@echo off
+"F:\love\love-0.10.1-win64\love.exe" %CD%