Compare commits

...

No commits in common. "gh-pages" and "master" have entirely different histories.

78 changed files with 734 additions and 1909 deletions

2
.gitignore vendored
View file

@ -1 +1,3 @@
node_modules node_modules
public/app.js
.Thumbs.db

3
README.md Normal file
View file

@ -0,0 +1,3 @@
1. Install dependencies with `npm install --global`.
2. Run the browser watch with `gulp`.
3. hack hack hack, until the time is over.

954
app.js

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
assets/Sounds/EchoSonar.mp3 Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
assets/Sounds/Silo.mp3 Normal file

Binary file not shown.

Binary file not shown.

BIN
assets/Sounds/Sonde.mp3 Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 891 B

BIN
assets/Terrain/Test 8X8.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 755 B

BIN
assets/Terrain/Thumbs.db Normal file

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

BIN
assets/cube/Thumbs.db Normal file

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
assets/tileset/Thumbs.db Normal file

Binary file not shown.

Binary file not shown.

35
gulpfile.js Normal file
View file

@ -0,0 +1,35 @@
// npm install -g gulp
// npm install --save-dev browser-sync
var gulp = require('gulp');
var coffee = require('gulp-coffee');
var concat = require('gulp-concat');
var uglify = require('gulp-uglify');
var sourcemaps = require('gulp-sourcemaps');
var browserSync = require('browser-sync');
var reload = browserSync.reload;
gulp.task('server', function() {
browserSync({
server: {
baseDir: 'public'
}
});
});
gulp.task('compile', function() {
return gulp.src(['src/entities/*.coffee', 'src/items/*.coffee', , 'src/tiles/*.coffee', 'src/tools.coffee', 'src/app.coffee', 'src/game.coffee', 'src/hud.coffee', 'src/speechbubble.coffee'])
.pipe(sourcemaps.init())
.pipe(coffee({bare: true}))
.pipe(concat('app.js'))
.pipe(sourcemaps.write())
.pipe(gulp.dest('public'));
});
gulp.task('default', ['server'], function() {
gulp.watch(['src/**/*.coffee'], ['compile']);
gulp.watch(['*.html', 'styles.css', 'app.js', 'images/*'], {cwd: 'public'}, reload);
});

7
notes.org Normal file
View file

@ -0,0 +1,7 @@
Title: Entire game on one screen
* TODO
** make video with audio comment :ruben:
** submit to ludum dare :ruben:
** write ludum dare final blogpost :ruben:
** write post-mortem ludum dare blogpost :aaron:ruben:

13
package.json Normal file
View file

@ -0,0 +1,13 @@
{
"name": "arg-games-ld31",
"description": "ARG-Games Lumdum Date 31 Entry",
"version": "0.0.1",
"dependencies": {
"gulp": "*",
"gulp-coffee": "*",
"gulp-concat": "*",
"gulp-uglify": "*",
"gulp-sourcemaps": "*",
"browser-sync": "*"
}
}

File diff suppressed because one or more lines are too long

View file

Before

Width:  |  Height:  |  Size: 662 B

After

Width:  |  Height:  |  Size: 662 B

View file

Before

Width:  |  Height:  |  Size: 187 B

After

Width:  |  Height:  |  Size: 187 B

View file

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

View file

Before

Width:  |  Height:  |  Size: 953 B

After

Width:  |  Height:  |  Size: 953 B

View file

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View file

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View file

Before

Width:  |  Height:  |  Size: 915 B

After

Width:  |  Height:  |  Size: 915 B

View file

Before

Width:  |  Height:  |  Size: 2 KiB

After

Width:  |  Height:  |  Size: 2 KiB

View file

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

View file

Before

Width:  |  Height:  |  Size: 1 KiB

After

Width:  |  Height:  |  Size: 1 KiB

View file

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

View file

Before

Width:  |  Height:  |  Size: 6 KiB

After

Width:  |  Height:  |  Size: 6 KiB

View file

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View file

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View file

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

View file

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

View file

Before

Width:  |  Height:  |  Size: 136 B

After

Width:  |  Height:  |  Size: 136 B

View file

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

View file

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

View file

Before

Width:  |  Height:  |  Size: 9.4 KiB

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

22
src/app.coffee Normal file
View file

@ -0,0 +1,22 @@
app = playground(
width: 8*20,
height: 8*15,
scaleToFit: true,
smoothing: false,
create: ->
@loadImages "layers", "active", "progress", "selected", "entities", "hud", "actions", "speechbubbles", "deadtiles", "layerdetails", "entitydetails", "buildinfo", "cursor", "info", "end", "intro1", "intro2", "intro3", "intro4", "titlescreen"
@currentHoveredTile = new Tile
ready: ->
@game.start()
@setState @game
render: ->
@layer.clear "#00f"
@game.render()
layerIndexToName: (index)->
resTypes = (k for own k of @game.resources)
resTypes[index]
)

26
src/entities/base.coffee Normal file
View file

@ -0,0 +1,26 @@
class Base
constructor: ->
@frame = 0
window.setInterval @changeAnimation, 500
tick: (tile)->
sprite: ->
[@frame*8, 0, 8, 8]
spritedetail: ->
[0, 0, 16, 16]
isMoveable: ->
false
changeAnimation: =>
if @frame == 3
@frame = 0
else
@frame += 1
spaceProvided: 30
energyProvided: 7
isDockable: true

29
src/entities/miner.coffee Normal file
View file

@ -0,0 +1,29 @@
class Miner
constructor: ->
@frame = 0
window.setInterval @changeAnimation, 500
tick: (tile) ->
tile.click "left"
tile.click "left"
tile.click "left"
tile.click "left"
sprite: ->
[@frame*8, 16, 8, 8]
spritedetail: ->
[0, 16*2, 16, 16]
isMoveable: ->
true
changeAnimation: =>
if @frame == 1
@frame = 0
else
@frame += 1
spaceProvided: 5
energyProvided: 0
isDockable: false

27
src/entities/silo.coffee Normal file
View file

@ -0,0 +1,27 @@
class Silo
constructor: ->
@frame = 0
window.setInterval @changeAnimation, 500
tick: (tile)->
sprite: ->
[@frame*8, 8, 8, 8]
spritedetail: ->
[0, 16, 16, 16]
isMoveable: ->
false
changeAnimation: =>
if @frame == 1
@frame = 0
else
@frame += 1
spaceProvided: 15
energyProvided: 0
isDockable: true

View file

@ -0,0 +1,15 @@
class Solarpanel
tick: (tile)->
sprite: ->
[0, 8*3, 8, 8]
spritedetail: ->
[0, 16*3, 16, 16]
isMoveable: ->
false
spaceProvided: 0
energyProvided: 15
isDockable: true

264
src/game.coffee Normal file
View file

@ -0,0 +1,264 @@
app.game =
start: ->
for i in [0..20*15-1]
@map[i] = new Tile(i)
@map[20*5+10].entity = new Base
@mouseX = 0
@mouseY = 0
@currentHoveredTile = new Tile(-1)
@currentSelectedTile = null
window.setInterval @tick, 1000
@hud.start()
@speechbubble.start()
@cutScene = false
@intro = false
@titleScreen = true
# TODO: Refactor this whole crap ... I can't belive I am writing this ...
startCutScene: ->
if @titleScreen
@titleScreen = false
@cutScene = true
app.game.cutSceneImage = app.images.intro1
window.setTimeout app.game.cutScene2, 1500
cutScene2: =>
app.game.cutSceneImage = app.images.intro2
window.setTimeout app.game.cutScene3, 2000
cutScene3: =>
app.game.cutSceneImage = app.images.intro3
window.setTimeout app.game.cutScene4, 1500
cutScene4: =>
app.game.cutSceneImage = app.images.intro4
window.setTimeout app.game.cutSceneEnd, 1500
cutSceneEnd: =>
app.game.cutScene = false
app.game.intro = true
app.game.startIntro()
startIntro: ->
@speechbubble.setFix 90, 27
@speechbubble.say 'help', 2000
@timeout = window.setTimeout @intro2, 3000
intro2: =>
app.game.speechbubble.say 'damn', 2000
app.game.timeout = window.setTimeout app.game.intro3, 3000
intro3: =>
app.game.speechbubble.say 'need', 3500
app.game.timeout = window.setTimeout app.game.intro4, 4500
intro4: =>
app.game.speechbubble.say 'collect', 3500
app.game.timeout = window.setTimeout app.game.introEnd, 3500
introEnd: =>
@intro = false
app.game.speechbubble.setMouse()
render: ->
if @titleScreen
app.layer.drawImage app.images.titlescreen, 0, 0, 20*8, 15*8
return
if @cutScene
app.layer.drawImage @cutSceneImage, 0, 0, 20*8, 15*8
return
if @gameEndCheck()
app.layer.drawImage app.images.end, 0, 0, 20*8, 15*8
return
for tile, i in @map
y = Math.floor(i/20)
x = i-(y*20)
tile.render(x, y)
@hud.render()
@speechbubble.render()
mousedown: (event)->
tile = posToTile(Math.floor(event.x/8), Math.floor(event.y/8))
# Can't click on dead tiles
return unless tile and tile.isBuildable
if @isMouseInView event.x/8, event.y/8
switch event.button
when 'left'
if event.x > 143 and event.x < 151 and event.y > 95 and event.y < 106
app.game.hud.showBuildInfo()
else
tile.click(event.button)
@currentSelectedTile.deselect() if @currentSelectedTile
tile.select()
@currentSelectedTile = tile
when 'right'
@currentSelectedTile.deselect() if @currentSelectedTile
@currentSelectedTile = null
mousemove: (event)->
@mouseX = event.x
@mouseY = event.y
if @isMouseInView event.x, event.y
tile = posToTile(Math.floor(event.x/8), Math.floor(event.y/8))
if tile
if tile != @currentHoveredTile
tile.moveIn()
@currentHoveredTile.moveOut() if @currentHoveredTile
@currentHoveredTile = tile
else
@currentHoveredTile.moveOut() if @currentHoveredTile
@currentHoveredTile = null
isMouseInView: (mouseX, mouseY) ->
if mouseX < app.width and mouseX >= 0 and mouseY < app.height and mouseY >= 0
return true
false
keyup: (event) ->
switch event.key
when "enter" then @startCutScene()
when "m" then @createMiner()
when "e" then @createSolarpanel()
when "i" then app.game.hud.showBuildInfo()
when "s" then @createSilo()
when "c" then @cheatah()
when "1" then @releaseRes 'stardust'
when "2" then @releaseRes 'dirt'
when "3" then @releaseRes 'bedrock'
when "4" then @releaseRes 'oxodum'
when "5" then @releaseRes 'lubinit'
when "6" then @releaseRes 'darkana'
when "7" then @releaseRes 'bio'
when "8" then @releaseRes 'notch'
when "9" then @releaseRes 'lava'
when "space"
@currentSelectedTile.deselect() if @currentSelectedTile
@currentSelectedTile = null
releaseRes: (string) ->
@resources[string] = 0
tick: =>
tile.tick() for tile in app.game.map
createMiner: ->
if @currentSelectedTile and !@currentSelectedTile.entity
if @checkResource('lubinit', 5, true)
@currentSelectedTile.entity = new Miner
else
@speechbubble.say 'nores'
else
@speechbubble.say 'nosel'
createSilo: ->
if @currentSelectedTile
if @checkPosition(@currentSelectedTile)
if @checkResource('dirt', 5, true)
@currentSelectedTile.entity = new Silo
else
@speechbubble.say 'nores'
else
@speechbubble.say 'toofar'
else
@speechbubble.say 'nosel'
# TODO: OMG refactor this ...
createSolarpanel: ->
if @currentSelectedTile
if @checkPosition(@currentSelectedTile)
if @checkResource('notch', 30, true)
@currentSelectedTile.entity = new Solarpanel
else
@speechbubble.say 'nores'
else
@speechbubble.say 'toofar'
else
@speechbubble.say 'nosel'
checkResource: (type, amount, drain = false) ->
if @resources[type] >= amount
@resources[type] -= amount if drain
return true
false
checkPosition: (tile)->
return false if tile.entity
# Check all 4 directions
[x, y] = posToXY(tile.position)
# Left
return true if app.game.map[xyToPos(x-1, y)].entity \
and app.game.map[xyToPos(x-1, y)].entity.isDockable \
and x > 0
# Right
return true if app.game.map[xyToPos(x+1, y)].entity \
and app.game.map[xyToPos(x+1, y)].entity.isDockable \
and x < 19
# Top
return true if app.game.map[xyToPos(x, y-1)].entity \
and app.game.map[xyToPos(x, y-1)].entity.isDockable \
and y > 0
# Bottom
return true if app.game.map[xyToPos(x, y+1)].entity \
and app.game.map[xyToPos(x, y+1)].entity.isDockable \
and y < 14
false
cheatah: ->
for type, amount of @resources
@resources[type] = 100
map: []
miners: []
maxTileAmount: 75
availableSiloStorage: ->
space = 0
for tile in app.game.map
space += tile.entity.spaceProvided if tile.entity
space
usedSiloStorage: ->
space = 0
space += amount for resource, amount of @resources
space
solarpanelCount: ->
energy = 0
for tile in app.game.map
# FIXME: Thats not a sane solution hahahah :D
energy += 1 if tile.entity and tile.entity.energyProvided > 10
energy
gameEndCheck: ->
return true if @solarpanelCount() >= 4
false
resources:
stardust: 0
dirt: 0
bedrock: 0
oxodum: 0
lubinit: 0
darkana: 0
bio: 0
notch: 0
lava: 0

125
src/hud.coffee Normal file
View file

@ -0,0 +1,125 @@
app.game.hud =
start: ->
resTypes = (k for own k of app.game.resources)
@position = x: 45, y: 103
@buildinfo = false
@itemArrow = new AnimatedItem maxFrames: 10, image: app.images.actions, speed: 50
@resources = []
for restype, i in resTypes
@resources[restype] = new Tilelayer(
type: restype,
depth: i
)
render: ->
panelusage = 'resources'
app.layer.drawImage app.images.hud, 0, 11*8
app.layer.drawImage app.images.info, 143, 95
# cursor
# app.layer.drawImage app.images.cursor, app.game.mouseX, app.game.mouseY
if @buildinfo
app.layer.drawRegion app.images.buildinfo, [0, 0, 106, 10], 1, 1
app.layer.drawRegion app.images.buildinfo, [0, 10, 106, 10], 1, 12
app.layer.drawRegion app.images.buildinfo, [0, 20, 106, 10], 1, 23
app.layer.drawRegion app.images.buildinfo, [0, 30, 106, 10], 1, 34
currentSelectedTile = app.game.currentSelectedTile
if currentSelectedTile != null
panelusage = 'tile'
if currentSelectedTile.entity
panelusage = 'entity'
app.layer.drawRegion app.images.entitydetails, currentSelectedTile.entity.spritedetail(), 12, 95
else
app.layer.drawRegion app.images.layerdetails, currentSelectedTile.getCurrentLayer().spritedetail, 12, 95
# silo capacity
usedSiloStoragePercent = Math.round((100 / app.game.availableSiloStorage()) * app.game.usedSiloStorage())
for f in [0..100]
resourcePanelColor = "#333"
if f <= usedSiloStoragePercent
colorStep = Math.round((usedSiloStoragePercent/100)*5)
resourcePanelColor = ["#0a0", "#0a0", "#aa0", "#f60", "#a00", "#f00"][colorStep]
x = 44+f
y = 112
app.layer.setPixel(resourcePanelColor, x, y)
# Energy production (47)
length = Math.round(((25*app.game.solarpanelCount())*45)/100)
for i in [0..length]
app.layer.setPixel("#228ca5", 49+i, 91)
app.layer.setPixel("#8ddaed", 50+i, 92)
app.layer.setPixel("#228ca5", 49+i, 93)
switch panelusage
when 'tile'
@showResources()
when 'entity'
#app.layer.drawRegion app.images.entities, currentSelectedTile.entity.sprite(), 44, 102
if currentSelectedTile.entity.isMoveable()
app.layer.drawRegion @itemArrow.image, @itemArrow.sprite(), 44, 102
when 'resources'
@showResources()
showBuildInfo: ->
clearTimeout(@timeout) if @timeout
@buildinfo = true
@timeout = window.setTimeout @hideBuildInfo, 6000
hideBuildInfo: ->
app.game.hud.buildinfo = false
showResources: ->
# resources
i = 0
for type, amount of app.game.resources
if amount > 0
tileLayer = @resources[type]
spritePosition = {
x: i*9+@position.x
y: @position.y
}
app.layer.drawRegion app.images.layers, tileLayer.hudSprite, spritePosition.x, spritePosition.y
amountByTwenty = Math.floor(amount/20)
amountLeft = amount - amountByTwenty*20
for e in [0..amountLeft]
color = "#0a0"
color = "#0f0" if e == amountLeft
if e < 6
x = spritePosition.x-1+e
y = spritePosition.y-1
else if e < 10
x = spritePosition.x+4
y = spritePosition.y-1+e-5
else if e < 15
x = spritePosition.x+14-e
y = spritePosition.y+4
else
x = spritePosition.x-1
y = spritePosition.y+19-e
app.layer.setPixel(color, x, y)
for f in [0..amountByTwenty]
if f > 0
color = "#0000ff"
x = spritePosition.x-2+f
y = spritePosition.y+7
app.layer.setPixel(color, x, y)
i++

View file

@ -0,0 +1,15 @@
class AnimatedItem
constructor: (options) ->
{@maxFrames, @image, @speed} = options
@frame = 0
window.setInterval @changeAnimation, @speed
sprite: ->
[@frame*8, 0, 8, 8]
changeAnimation: =>
if @frame == @maxFrames
@frame = 0
else
@frame += 1

42
src/speechbubble.coffee Normal file
View file

@ -0,0 +1,42 @@
app.game.speechbubble =
start: ->
@sprite = [0, 0, 27, 13]
@positioning = 'mouse'
setFix: (x, y) ->
@x = x
@y = y
@positioning = 'fixed'
setMouse: ->
@positioning = 'mouse'
say: (text, timeout = 1000) ->
clearTimeout(@timeout) if @timeout
switch text
when 'help' then @sprite = [0, 0, 27, 13]
when 'toofar' then @sprite = [0, 13, 90, 13]
when 'nores' then @sprite = [0, 26, 90, 13]
when 'nosel' then @sprite = [0, 39, 90, 13]
when 'damn' then @sprite = [0, 52, 90, 13]
when 'need' then @sprite = [0, 65, 90, 13]
when 'collect' then @sprite = [0, 78, 90, 13]
@visible = true
@timeout = window.setTimeout @hide, timeout
hide: =>
app.game.speechbubble.visible = false
render: ->
switch @positioning
when 'mouse'
x = app.game.mouseX+5
y = app.game.mouseY-15
when 'fixed'
x = @x
y = @y
app.layer.drawRegion app.images.speechbubbles, @sprite, x, y if @visible

81
src/tiles/tile.coffee Normal file
View file

@ -0,0 +1,81 @@
class Tile
constructor: (position)->
@position = position
@layers = []
for restype, i in allResourceTypes()
@layers.push new Tilelayer(
type: restype,
depth: i,
amount: Math.round(Math.random()*app.game.maxTileAmount)+1
)
@currentLayer = 0
@empty = false
@entity = null
@isActive = false
@isBuildable = !(Math.round(Math.random()*10) == 5)
@isBuildable = true if @position == 20*5+10
@randomSeed = Math.round(Math.random()*10)
click: (button)->
# Some tiles are not buildable
return unless @isBuildable
if button == "left" and !@empty
if (app.game.availableSiloStorage() - app.game.usedSiloStorage()) > 0
if @layers[@currentLayer].collect()
name = app.layerIndexToName(@currentLayer)
app.game.resources[name] += 1
else
@currentLayer += 1
if @currentLayer == allResourceTypes().length-1
# If we reach the bottom, the entity on top dies.
@entity = null
@empty = true
tick: ->
@entity.tick @ if @entity
moveIn: ->
@isActive = true
moveOut: ->
@isActive = false
select: ->
@isSelected = true
deselect: ->
@isSelected = false
getCurrentLayer: ->
@layers[@currentLayer]
render: (x, y)->
tileLayer = @getCurrentLayer()
app.layer.drawRegion app.images.layers, tileLayer.sprite, x*8, y*8
unless @isBuildable
app.layer.drawRegion app.images.deadtiles, [8*@randomSeed, 0, 8, 8], x*8, y*8
return
if @entity
app.layer.drawRegion app.images.entities, @entity.sprite(), x*8, y*8
if (@entity and @entity.isMoveable()) or @isActive
# Draw the status indicator.
app.layer.drawImage app.images.progress, x*8, y*8
numPercent = Math.floor((tileLayer.amount*6)/app.game.maxTileAmount)
for i in [0..numPercent]
color = ["#f00", "#a00", "#f60", "#aa0", "#0a0", "#0a0"][numPercent]
color = ["#f00", "#f00", "#f80", "#ff0", "#0f0", "#0f0"][numPercent] if i == numPercent
app.layer.setPixel(color, x*8+1+i, y*8+6)
if @isActive
app.layer.drawImage app.images.active, x*8, y*8
if @isSelected
app.layer.drawImage app.images.selected, x*8, y*8

View file

@ -0,0 +1,11 @@
class Tilelayer
constructor: (options)->
{@type, @depth, @amount} = options
@randomFactor = getRandomInt 0, 4
@sprite = [@randomFactor*8, @depth*8, 8, 8]
@spritedetail = [0, @depth*16, 16, 16]
@hudSprite = [@randomFactor*8, @depth*8, 4, 4]
collect: ->
return false if @amount == 0
@amount -= 1

16
src/tools.coffee Normal file
View file

@ -0,0 +1,16 @@
getRandomInt = (min, max) ->
Math.floor(Math.random() * (max - min + 1)) + min;
allResourceTypes = ->
(k for own k of app.game.resources)
posToTile = (x, y)->
app.game.map[xyToPos(x, y)]
posToXY = (pos)->
y = Math.floor(pos/20)
x = pos-(y*20)
[x, y]
xyToPos = (x, y)->
y*20 + x