diff --git a/Makefile b/Makefile index 75de35b..7838b61 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ PORTAL_C_ANIM = $(foreach angle, $(shell seq 0 6 359), build/portal-c$(angle).pn PORTAL_D_ANIM = $(foreach angle, $(shell seq 0 6 359), build/portal-d$(angle).png) IMAGES = $(foreach name, apple wall oil key door, public/assets/$(name)32.png) -TILESETS = $(foreach name, hole, public/assets/$(name)-ts.png) +TILESETS = $(foreach name, hole switch spikes, public/assets/$(name)-ts.png) ANIMATIONS = $(foreach name, fire peach-decay peach-rainbow portal-a portal-b portal-c portal-d, public/assets/$(name)-anim.png) JSON = $(foreach name, snake levelList config metaConfig, public/assets/$(name).json) ICON = public/assets/icon32.png public/assets/icon256.png public/favicon.ico diff --git a/assets/levelList.json b/assets/levelList.json index 9683273..2dfca16 100644 --- a/assets/levelList.json +++ b/assets/levelList.json @@ -58,7 +58,7 @@ "levelFilename": "puzzle.json", "levelDisplay": "Level ", "levels": [ - 1, 2 + 1, 2, 3 ], "nextLevel": true } diff --git a/assets/spikes.png b/assets/spikes.png new file mode 100755 index 0000000..0e4d765 Binary files /dev/null and b/assets/spikes.png differ diff --git a/assets/switch.png b/assets/switch.png new file mode 100755 index 0000000..e4e0651 Binary files /dev/null and b/assets/switch.png differ diff --git a/levels/puzzle3.json b/levels/puzzle3.json new file mode 100644 index 0000000..9f3ade7 --- /dev/null +++ b/levels/puzzle3.json @@ -0,0 +1,22 @@ +{ + "world": [ + "A i B", + " i s", + " Cik ", + "SSSSSSSSSSSiiiii", + " i f", + " i ", + " s itttt", + " t wKKKK", + " w ", + " wD " + ], + "snake": [ + [0, 9], + [1, 9], + [2, 9] + ], + "rules": { + "moveCount": 60 + } +} diff --git a/src/js/assets.js b/src/js/assets.js index 44a1b52..8756d63 100644 --- a/src/js/assets.js +++ b/src/js/assets.js @@ -14,6 +14,8 @@ const assetSpecs=[ { name: 'portalD', filename: 'portal-d-anim.png', type: 'image' }, { name: 'key', filename: 'key32.png', type: 'image' }, { name: 'door', filename: 'door32.png', type: 'image' }, + { name: 'switch', filename: 'switch-ts.png', type: 'image' }, + { name: 'spikes', filename: 'spikes-ts.png', type: 'image' }, { name: 'snake', filename: 'snake.json', type: 'json' }, { name: 'levelList', filename: 'levelList.json', type: 'json' }, { name: 'config', filename: 'config.json', type: 'json' }, @@ -28,7 +30,9 @@ const tasks=[ { from: 'portalC', type: 'animation', steps: 3 }, { from: 'portalD', type: 'animation', steps: 3 }, { from: 'superFruit', type: 'animation', steps: 5 }, - { from: 'decayFruit', type: 'animation', steps: 5 } + { from: 'decayFruit', type: 'animation', steps: 5 }, + { from: 'switch', type: 'tileset', steps: 1, tiles: ['on', 'off'] }, + { from: 'spikes', type: 'tileset', steps: 1, tiles: ['off', 'on'] } ]; const cvs=document.createElement('canvas'); diff --git a/src/js/snek.js b/src/js/snek.js index 0d2cc2c..3cf507d 100644 --- a/src/js/snek.js +++ b/src/js/snek.js @@ -1,4 +1,13 @@ -const [EMPTY, FOOD, SUPER_FOOD, DECAY_FOOD, WALL, FIRE, FLAMMABLE, FLAMMABLE_S, HOLE, HOLE_S, PORTAL_A, PORTAL_A_S, PORTAL_B, PORTAL_B_S, PORTAL_C, PORTAL_C_S, PORTAL_D, PORTAL_D_S, KEY, DOOR, SNAKE]=Array(255).keys(); +const [ + EMPTY, SNAKE, + FOOD, SUPER_FOOD, DECAY_FOOD, + WALL, + FIRE, FLAMMABLE, FLAMMABLE_S, + HOLE, HOLE_S, + PORTAL_A, PORTAL_A_S, PORTAL_B, PORTAL_B_S, PORTAL_C, PORTAL_C_S, PORTAL_D, PORTAL_D_S, + KEY, DOOR, + SWITCH_ON, SWITCH_ON_S, SWITCH_OFF, SWITCH_OFF_S, SPIKES_OFF, SPIKES_OFF_S, SPIKES_ON +]=Array(255).keys(); class SnekGame { constructor(settings, canvas, rules) { @@ -32,6 +41,9 @@ class SnekGame { case 'D': return PORTAL_D; case 'k': return KEY; case 'K': return DOOR; + case 's': return SWITCH_OFF; + case 'S': return SPIKES_ON; + case 't': return SPIKES_OFF; } })(); } @@ -109,6 +121,13 @@ class SnekGame { // add the doors if(settings.doors) settings.doors.forEach(([x, y]) => this.world[x][y]=DOOR); + + // add the switches + if(settings.switches) settings.switches.forEach(([x, y]) => this.world[x][y]=SWITCH_OFF); + + // add the spikes + if(settings.spikesOn) settings.spikesOn.forEach(([x, y]) => this.world[x][y]=SPIKES_ON); + if(settings.spikesOff) settings.spikesOff.forEach(([x, y]) => this.world[x][y]=SPIKES_OFF); } // add the snake to the world @@ -235,6 +254,8 @@ class SnekGame { const portalD=assets.get('portalD'); const key=assets.get('key'); const door=assets.get('door'); + const switchTile=assets.get('switch'); + const spikes=assets.get('spikes'); const putTile=(x, y, tile) => this.ctx.drawImage( tile, offsetX+cellSize*x, @@ -316,6 +337,23 @@ class SnekGame { case DOOR: putTile(x, y, door); break; + + case SWITCH_ON: + case SWITCH_ON_S: + putTile(x, y, switchTile.on); + break; + case SWITCH_OFF: + case SWITCH_OFF_S: + putTile(x, y, switchTile.off); + break; + + case SPIKES_ON: + putTile(x, y, spikes.on); + break; + case SPIKES_OFF: + case SPIKES_OFF_S: + putTile(x, y, spikes.off); + break; } } } @@ -511,6 +549,15 @@ class SnekGame { case PORTAL_D_S: this.world[tail[0]][tail[1]]=PORTAL_D; break; + case SWITCH_ON_S: + this.world[tail[0]][tail[1]]=SWITCH_ON; + break; + case SWITCH_OFF_S: + this.world[tail[0]][tail[1]]=SWITCH_OFF; + break; + case SPIKES_OFF_S: + this.world[tail[0]][tail[1]]=SPIKES_OFF; + break; default: this.world[tail[0]][tail[1]]=EMPTY; } @@ -530,6 +577,7 @@ class SnekGame { case WALL: return this.die("thought walls were edible", "hit a wall"); case FIRE: return this.die("burned to a crisp", "hit fire"); case DOOR: return this.die("forgot to OPEN the door", "hit a door"); + case SPIKES_ON: return this.die("thought they were a girl's drink in a nightclub", "hit spikes"); // congratilations, you played yourself! case SNAKE: @@ -539,6 +587,9 @@ class SnekGame { case PORTAL_B_S: case PORTAL_C_S: case PORTAL_D_S: + case SWITCH_OFF_S: + case SWITCH_ON_S: + case SPIKES_OFF_S: return this.die("achieved every dog's dream", "ate their own tail"); // if either 3 consecutive segments or the whole snake is on a hole, you die @@ -571,6 +622,16 @@ class SnekGame { this.getTilesOfType(DOOR).forEach(([x, y]) => this.world[x][y]=EMPTY); break; + // you step on, you trigger + case SWITCH_ON: + case SWITCH_OFF: { + this.world[head[0]][head[1]]=this.world[head[0]][head[1]]==SWITCH_ON?SWITCH_OFF:SWITCH_ON; + if(this.getTilesOfType(SPIKES_OFF_S).length) return this.die("spiked themselves", "activated spikes"); + const oldSpikes=this.getTilesOfType(SPIKES_ON); + this.getTilesOfType(SPIKES_OFF).forEach(([x, y]) => this.world[x][y]=SPIKES_ON); + oldSpikes.forEach(([x, y]) => this.world[x][y]=SPIKES_OFF); + } break; + // you eat, you grow case FOOD: // re-grow the snake partially (can't hit the tail, but it's there for all other intents and purposes @@ -638,6 +699,15 @@ class SnekGame { case PORTAL_D: this.world[head[0]][head[1]]=PORTAL_D_S; break; + case SWITCH_ON: + this.world[head[0]][head[1]]=SWITCH_ON_S; + break; + case SWITCH_OFF: + this.world[head[0]][head[1]]=SWITCH_OFF_S; + break; + case SPIKES_OFF: + this.world[head[0]][head[1]]=SPIKES_OFF_S; + break; default: this.world[head[0]][head[1]]=SNAKE; }