|  |  |  | @ -1,9 +1,12 @@ | 
			
		
	
		
			
				
					|  |  |  |  | const [EMPTY, FOOD, SUPER_FOOD, DECAY_FOOD, WALL, FIRE, FLAMMABLE, FLAMMABLE_S, HOLE, HOLE_S, SNAKE]=Array(255).keys(); | 
			
		
	
		
			
				
					|  |  |  |  | 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, SNAKE]=Array(255).keys(); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | class SnekGame { | 
			
		
	
		
			
				
					|  |  |  |  | 	constructor(settings, canvas, rules) { | 
			
		
	
		
			
				
					|  |  |  |  | 		// setup the delay
 | 
			
		
	
		
			
				
					|  |  |  |  | 		this.delay=settings.delay; | 
			
		
	
		
			
				
					|  |  |  |  | 		this.delay=settings.delay || Infinity; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 		// score starts at 0
 | 
			
		
	
		
			
				
					|  |  |  |  | 		this.score=0; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 		// world is given in the level
 | 
			
		
	
		
			
				
					|  |  |  |  | 		if(settings.world) { // explicitly
 | 
			
		
	
	
		
			
				
					|  |  |  | @ -23,6 +26,10 @@ class SnekGame { | 
			
		
	
		
			
				
					|  |  |  |  | 							case 'o': return HOLE; | 
			
		
	
		
			
				
					|  |  |  |  | 							case 'i': return FIRE; | 
			
		
	
		
			
				
					|  |  |  |  | 							case 'I': return FLAMMABLE; | 
			
		
	
		
			
				
					|  |  |  |  | 							case 'A': return PORTAL_A; | 
			
		
	
		
			
				
					|  |  |  |  | 							case 'B': return PORTAL_B; | 
			
		
	
		
			
				
					|  |  |  |  | 							case 'C': return PORTAL_C; | 
			
		
	
		
			
				
					|  |  |  |  | 							case 'D': return PORTAL_D; | 
			
		
	
		
			
				
					|  |  |  |  | 						} | 
			
		
	
		
			
				
					|  |  |  |  | 					})(); | 
			
		
	
		
			
				
					|  |  |  |  | 				} | 
			
		
	
	
		
			
				
					|  |  |  | @ -32,22 +39,21 @@ class SnekGame { | 
			
		
	
		
			
				
					|  |  |  |  | 			this.dimensions=[this.world.length, this.world[0].length]; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 			// extract the fruits
 | 
			
		
	
		
			
				
					|  |  |  |  | 			this.fruits=[]; | 
			
		
	
		
			
				
					|  |  |  |  | 			this.world | 
			
		
	
		
			
				
					|  |  |  |  | 				.forEach((l, x) => l.forEach( | 
			
		
	
		
			
				
					|  |  |  |  | 					(c, y) => { | 
			
		
	
		
			
				
					|  |  |  |  | 						if(c==FOOD) this.fruits.push([x, y]); | 
			
		
	
		
			
				
					|  |  |  |  | 					} | 
			
		
	
		
			
				
					|  |  |  |  | 				)); | 
			
		
	
		
			
				
					|  |  |  |  | 			this.fruits=this.getTilesOfType(FOOD); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 			// extract the decaying fruits
 | 
			
		
	
		
			
				
					|  |  |  |  | 			this.decayFood=[]; | 
			
		
	
		
			
				
					|  |  |  |  | 			this.world | 
			
		
	
		
			
				
					|  |  |  |  | 				.forEach((l, x) => l.forEach( | 
			
		
	
		
			
				
					|  |  |  |  | 					(c, y) => { | 
			
		
	
		
			
				
					|  |  |  |  | 						if(c==DECAY_FOOD) this.decaying.push([x, y, 0]); | 
			
		
	
		
			
				
					|  |  |  |  | 					} | 
			
		
	
		
			
				
					|  |  |  |  | 				)); | 
			
		
	
		
			
				
					|  |  |  |  | 			this.decayFood=this.getTilesOfType(DECAY_FOOD); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 			// extract the portals
 | 
			
		
	
		
			
				
					|  |  |  |  | 			this.portals={}; | 
			
		
	
		
			
				
					|  |  |  |  | 			this.world.forEach((l, x) => | 
			
		
	
		
			
				
					|  |  |  |  | 				l.forEach((c, y) => { | 
			
		
	
		
			
				
					|  |  |  |  | 					if(c==PORTAL_A) this.portals.a=[x, y]; | 
			
		
	
		
			
				
					|  |  |  |  | 					if(c==PORTAL_B) this.portals.b=[x, y]; | 
			
		
	
		
			
				
					|  |  |  |  | 					if(c==PORTAL_C) this.portals.c=[x, y]; | 
			
		
	
		
			
				
					|  |  |  |  | 					if(c==PORTAL_D) this.portals.d=[x, y]; | 
			
		
	
		
			
				
					|  |  |  |  | 				}) | 
			
		
	
		
			
				
					|  |  |  |  | 			); | 
			
		
	
		
			
				
					|  |  |  |  | 		} else { // dimension and objects
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 			// get the dimensions
 | 
			
		
	
	
		
			
				
					|  |  |  | @ -84,6 +90,17 @@ class SnekGame { | 
			
		
	
		
			
				
					|  |  |  |  | 			} else { | 
			
		
	
		
			
				
					|  |  |  |  | 				this.decayFood=[]; | 
			
		
	
		
			
				
					|  |  |  |  | 			} | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 			// add the portals
 | 
			
		
	
		
			
				
					|  |  |  |  | 			if(settings.portals) { | 
			
		
	
		
			
				
					|  |  |  |  | 				if(settings.portals.a) this.world[settings.portals.a[0]][settings.portals.a[1]]=PORTAL_A; | 
			
		
	
		
			
				
					|  |  |  |  | 				if(settings.portals.b) this.world[settings.portals.b[0]][settings.portals.b[1]]=PORTAL_B; | 
			
		
	
		
			
				
					|  |  |  |  | 				if(settings.portals.c) this.world[settings.portals.c[0]][settings.portals.c[1]]=PORTAL_C; | 
			
		
	
		
			
				
					|  |  |  |  | 				if(settings.portals.d) this.world[settings.portals.d[0]][settings.portals.d[1]]=PORTAL_D; | 
			
		
	
		
			
				
					|  |  |  |  | 				this.portals={...settings.portals}; | 
			
		
	
		
			
				
					|  |  |  |  | 			} else { | 
			
		
	
		
			
				
					|  |  |  |  | 				this.portals={}; | 
			
		
	
		
			
				
					|  |  |  |  | 			} | 
			
		
	
		
			
				
					|  |  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 		// add the snake to the world
 | 
			
		
	
	
		
			
				
					|  |  |  | @ -121,8 +138,20 @@ class SnekGame { | 
			
		
	
		
			
				
					|  |  |  |  | 			scoreSystem: 'fruit', | 
			
		
	
		
			
				
					|  |  |  |  | 			fireTickSpeed: 10, | 
			
		
	
		
			
				
					|  |  |  |  | 			autoSizeGrow: false, | 
			
		
	
		
			
				
					|  |  |  |  | 			autoSpeedIncrease: false | 
			
		
	
		
			
				
					|  |  |  |  | 			autoSpeedIncrease: false, | 
			
		
	
		
			
				
					|  |  |  |  | 			timeFlow: true | 
			
		
	
		
			
				
					|  |  |  |  | 		}, rules, settings.rules || {}); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 		// reset direction if time doesn't flow
 | 
			
		
	
		
			
				
					|  |  |  |  | 		if(!this.rules.timeFlow) { | 
			
		
	
		
			
				
					|  |  |  |  | 			this.lastDirection=[0, 0]; | 
			
		
	
		
			
				
					|  |  |  |  | 			this.direction=[0, 0]; | 
			
		
	
		
			
				
					|  |  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 		// set score if move-based
 | 
			
		
	
		
			
				
					|  |  |  |  | 		if(this.rules.scoreSystem=='moves') { | 
			
		
	
		
			
				
					|  |  |  |  | 			this.score=this.rules.moveCount; | 
			
		
	
		
			
				
					|  |  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	get playTime() { | 
			
		
	
	
		
			
				
					|  |  |  | @ -192,6 +221,10 @@ class SnekGame { | 
			
		
	
		
			
				
					|  |  |  |  | 		const flammable=assets.get('flammable'); | 
			
		
	
		
			
				
					|  |  |  |  | 		const superFruit=assets.get('superFruit'); | 
			
		
	
		
			
				
					|  |  |  |  | 		const decayFruit=assets.get('decayFruit'); | 
			
		
	
		
			
				
					|  |  |  |  | 		const portalA=assets.get('portalA'); | 
			
		
	
		
			
				
					|  |  |  |  | 		const portalB=assets.get('portalB'); | 
			
		
	
		
			
				
					|  |  |  |  | 		const portalC=assets.get('portalC'); | 
			
		
	
		
			
				
					|  |  |  |  | 		const portalD=assets.get('portalD'); | 
			
		
	
		
			
				
					|  |  |  |  | 		const putTile=(x, y, tile) => this.ctx.drawImage( | 
			
		
	
		
			
				
					|  |  |  |  | 			tile, | 
			
		
	
		
			
				
					|  |  |  |  | 			offsetX+cellSize*x, | 
			
		
	
	
		
			
				
					|  |  |  | @ -249,6 +282,23 @@ class SnekGame { | 
			
		
	
		
			
				
					|  |  |  |  | 					case SUPER_FOOD: | 
			
		
	
		
			
				
					|  |  |  |  | 						putTileAnim(x, y, superFruit); | 
			
		
	
		
			
				
					|  |  |  |  | 						break; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 					case PORTAL_A: | 
			
		
	
		
			
				
					|  |  |  |  | 					case PORTAL_A_S: | 
			
		
	
		
			
				
					|  |  |  |  | 						putTileAnim(x, y, portalA); | 
			
		
	
		
			
				
					|  |  |  |  | 						break; | 
			
		
	
		
			
				
					|  |  |  |  | 					case PORTAL_B: | 
			
		
	
		
			
				
					|  |  |  |  | 					case PORTAL_B_S: | 
			
		
	
		
			
				
					|  |  |  |  | 						putTileAnim(x, y, portalB); | 
			
		
	
		
			
				
					|  |  |  |  | 						break; | 
			
		
	
		
			
				
					|  |  |  |  | 					case PORTAL_C: | 
			
		
	
		
			
				
					|  |  |  |  | 					case PORTAL_C_S: | 
			
		
	
		
			
				
					|  |  |  |  | 						putTileAnim(x, y, portalC); | 
			
		
	
		
			
				
					|  |  |  |  | 						break; | 
			
		
	
		
			
				
					|  |  |  |  | 					case PORTAL_D: | 
			
		
	
		
			
				
					|  |  |  |  | 					case PORTAL_D_S: | 
			
		
	
		
			
				
					|  |  |  |  | 						putTileAnim(x, y, portalD); | 
			
		
	
		
			
				
					|  |  |  |  | 						break; | 
			
		
	
		
			
				
					|  |  |  |  | 				} | 
			
		
	
		
			
				
					|  |  |  |  | 			} | 
			
		
	
		
			
				
					|  |  |  |  | 		} | 
			
		
	
	
		
			
				
					|  |  |  | @ -258,6 +308,32 @@ class SnekGame { | 
			
		
	
		
			
				
					|  |  |  |  | 			putTileAnimPercent(x, y, decayFruit, (this.playTime-birth)/2000) | 
			
		
	
		
			
				
					|  |  |  |  | 		); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 		// draw the lines between portals
 | 
			
		
	
		
			
				
					|  |  |  |  | 		if(Object.keys(this.portals).length) { | 
			
		
	
		
			
				
					|  |  |  |  | 			this.ctx.strokeStyle='rgba(128, 128, 128, 20%)'; | 
			
		
	
		
			
				
					|  |  |  |  | 			this.ctx.lineCap='round'; | 
			
		
	
		
			
				
					|  |  |  |  | 			this.ctx.lineWidth=cellSize*.15; | 
			
		
	
		
			
				
					|  |  |  |  | 			const drawTunnel=([xa, ya], [xb, yb]) => { | 
			
		
	
		
			
				
					|  |  |  |  | 				const angle=(Math.floor(Date.now()/10)%360)*(Math.PI/180); | 
			
		
	
		
			
				
					|  |  |  |  | 				for(let i=0; i<=1; i++) { | 
			
		
	
		
			
				
					|  |  |  |  | 					const dx=cellSize/3*Math.cos(angle+i*Math.PI); | 
			
		
	
		
			
				
					|  |  |  |  | 					const dy=cellSize/3*Math.sin(angle+i*Math.PI); | 
			
		
	
		
			
				
					|  |  |  |  | 					this.ctx.beginPath(); | 
			
		
	
		
			
				
					|  |  |  |  | 					this.ctx.moveTo( | 
			
		
	
		
			
				
					|  |  |  |  | 						offsetX+cellSize*(xa+1/2)+dx, | 
			
		
	
		
			
				
					|  |  |  |  | 						offsetY+cellSize*(ya+1/2)+dy | 
			
		
	
		
			
				
					|  |  |  |  | 					); | 
			
		
	
		
			
				
					|  |  |  |  | 					this.ctx.lineTo( | 
			
		
	
		
			
				
					|  |  |  |  | 						offsetX+cellSize*(xb+1/2)+dx, | 
			
		
	
		
			
				
					|  |  |  |  | 						offsetY+cellSize*(yb+1/2)+dy | 
			
		
	
		
			
				
					|  |  |  |  | 					); | 
			
		
	
		
			
				
					|  |  |  |  | 					this.ctx.stroke(); | 
			
		
	
		
			
				
					|  |  |  |  | 				} | 
			
		
	
		
			
				
					|  |  |  |  | 			}; | 
			
		
	
		
			
				
					|  |  |  |  | 			if(this.portals.a && this.portals.b) drawTunnel(this.portals.a, this.portals.b); | 
			
		
	
		
			
				
					|  |  |  |  | 			if(this.portals.c && this.portals.d) drawTunnel(this.portals.c, this.portals.d); | 
			
		
	
		
			
				
					|  |  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 		// draw our snake (it gets drawn completely differently, so here it goes)
 | 
			
		
	
		
			
				
					|  |  |  |  | 		const snake=assets.get('snake'); | 
			
		
	
		
			
				
					|  |  |  |  | 		this.ctx.fillStyle=snake.color; | 
			
		
	
	
		
			
				
					|  |  |  | @ -381,10 +457,21 @@ class SnekGame { | 
			
		
	
		
			
				
					|  |  |  |  | 		this.lastDirection=this.direction; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 		// compute our new head
 | 
			
		
	
		
			
				
					|  |  |  |  | 		const head=[ | 
			
		
	
		
			
				
					|  |  |  |  | 			this.snake[0][0]+this.direction[0], | 
			
		
	
		
			
				
					|  |  |  |  | 			this.snake[0][1]+this.direction[1] | 
			
		
	
		
			
				
					|  |  |  |  | 		]; | 
			
		
	
		
			
				
					|  |  |  |  | 		let head; | 
			
		
	
		
			
				
					|  |  |  |  | 		if(!this.portaled && [PORTAL_A_S, PORTAL_B_S, PORTAL_C_S, PORTAL_D_S].includes(this.world[this.snake[0][0]][this.snake[0][1]])) { | 
			
		
	
		
			
				
					|  |  |  |  | 			const tile=this.world[this.snake[0][0]][this.snake[0][1]]; | 
			
		
	
		
			
				
					|  |  |  |  | 			if(tile==PORTAL_A_S) head=this.portals.b; | 
			
		
	
		
			
				
					|  |  |  |  | 			if(tile==PORTAL_B_S) head=this.portals.a; | 
			
		
	
		
			
				
					|  |  |  |  | 			if(tile==PORTAL_C_S) head=this.portals.d; | 
			
		
	
		
			
				
					|  |  |  |  | 			if(tile==PORTAL_D_S) head=this.portals.c; | 
			
		
	
		
			
				
					|  |  |  |  | 			this.portaled=true; | 
			
		
	
		
			
				
					|  |  |  |  | 		} else { | 
			
		
	
		
			
				
					|  |  |  |  | 			head=[ | 
			
		
	
		
			
				
					|  |  |  |  | 				this.snake[0][0]+this.direction[0], | 
			
		
	
		
			
				
					|  |  |  |  | 				this.snake[0][1]+this.direction[1] | 
			
		
	
		
			
				
					|  |  |  |  | 			]; | 
			
		
	
		
			
				
					|  |  |  |  | 			this.portaled=false; | 
			
		
	
		
			
				
					|  |  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 		// get our tail out of the way
 | 
			
		
	
		
			
				
					|  |  |  |  | 		const tail=this.snake.pop(); | 
			
		
	
	
		
			
				
					|  |  |  | @ -395,6 +482,18 @@ class SnekGame { | 
			
		
	
		
			
				
					|  |  |  |  | 			case FLAMMABLE_S: | 
			
		
	
		
			
				
					|  |  |  |  | 				this.world[tail[0]][tail[1]]=FLAMMABLE; | 
			
		
	
		
			
				
					|  |  |  |  | 				break; | 
			
		
	
		
			
				
					|  |  |  |  | 			case PORTAL_A_S: | 
			
		
	
		
			
				
					|  |  |  |  | 				this.world[tail[0]][tail[1]]=PORTAL_A; | 
			
		
	
		
			
				
					|  |  |  |  | 				break; | 
			
		
	
		
			
				
					|  |  |  |  | 			case PORTAL_B_S: | 
			
		
	
		
			
				
					|  |  |  |  | 				this.world[tail[0]][tail[1]]=PORTAL_B; | 
			
		
	
		
			
				
					|  |  |  |  | 				break; | 
			
		
	
		
			
				
					|  |  |  |  | 			case PORTAL_C_S: | 
			
		
	
		
			
				
					|  |  |  |  | 				this.world[tail[0]][tail[1]]=PORTAL_C; | 
			
		
	
		
			
				
					|  |  |  |  | 				break; | 
			
		
	
		
			
				
					|  |  |  |  | 			case PORTAL_D_S: | 
			
		
	
		
			
				
					|  |  |  |  | 				this.world[tail[0]][tail[1]]=PORTAL_D; | 
			
		
	
		
			
				
					|  |  |  |  | 				break; | 
			
		
	
		
			
				
					|  |  |  |  | 			default: | 
			
		
	
		
			
				
					|  |  |  |  | 				this.world[tail[0]][tail[1]]=EMPTY; | 
			
		
	
		
			
				
					|  |  |  |  | 		} | 
			
		
	
	
		
			
				
					|  |  |  | @ -416,6 +515,10 @@ class SnekGame { | 
			
		
	
		
			
				
					|  |  |  |  | 			case SNAKE: | 
			
		
	
		
			
				
					|  |  |  |  | 			case HOLE_S: | 
			
		
	
		
			
				
					|  |  |  |  | 			case FLAMMABLE_S: | 
			
		
	
		
			
				
					|  |  |  |  | 			case PORTAL_A_S: | 
			
		
	
		
			
				
					|  |  |  |  | 			case PORTAL_B_S: | 
			
		
	
		
			
				
					|  |  |  |  | 			case PORTAL_C_S: | 
			
		
	
		
			
				
					|  |  |  |  | 			case PORTAL_D_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
 | 
			
		
	
	
		
			
				
					|  |  |  | @ -498,6 +601,18 @@ class SnekGame { | 
			
		
	
		
			
				
					|  |  |  |  | 			case FLAMMABLE: | 
			
		
	
		
			
				
					|  |  |  |  | 				this.world[head[0]][head[1]]=FLAMMABLE_S; | 
			
		
	
		
			
				
					|  |  |  |  | 				break; | 
			
		
	
		
			
				
					|  |  |  |  | 			case PORTAL_A: | 
			
		
	
		
			
				
					|  |  |  |  | 				this.world[head[0]][head[1]]=PORTAL_A_S; | 
			
		
	
		
			
				
					|  |  |  |  | 				break; | 
			
		
	
		
			
				
					|  |  |  |  | 			case PORTAL_B: | 
			
		
	
		
			
				
					|  |  |  |  | 				this.world[head[0]][head[1]]=PORTAL_B_S; | 
			
		
	
		
			
				
					|  |  |  |  | 				break; | 
			
		
	
		
			
				
					|  |  |  |  | 			case PORTAL_C: | 
			
		
	
		
			
				
					|  |  |  |  | 				this.world[head[0]][head[1]]=PORTAL_C_S; | 
			
		
	
		
			
				
					|  |  |  |  | 				break; | 
			
		
	
		
			
				
					|  |  |  |  | 			case PORTAL_D: | 
			
		
	
		
			
				
					|  |  |  |  | 				this.world[head[0]][head[1]]=PORTAL_D_S; | 
			
		
	
		
			
				
					|  |  |  |  | 				break; | 
			
		
	
		
			
				
					|  |  |  |  | 			default: | 
			
		
	
		
			
				
					|  |  |  |  | 				this.world[head[0]][head[1]]=SNAKE; | 
			
		
	
		
			
				
					|  |  |  |  | 		} | 
			
		
	
	
		
			
				
					|  |  |  | @ -538,6 +653,12 @@ class SnekGame { | 
			
		
	
		
			
				
					|  |  |  |  | 			this.getTilesOfType(FLAMMABLE).filter(touchingFire).forEach(([x, y]) => this.world[x][y]=FIRE); | 
			
		
	
		
			
				
					|  |  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 		// THE WORLD!
 | 
			
		
	
		
			
				
					|  |  |  |  | 		if(!this.rules.timeFlow) { | 
			
		
	
		
			
				
					|  |  |  |  | 			this.lastDirection=[0, 0]; | 
			
		
	
		
			
				
					|  |  |  |  | 			this.direction=[0, 0]; | 
			
		
	
		
			
				
					|  |  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 		// victory condition
 | 
			
		
	
		
			
				
					|  |  |  |  | 		if(this.rules.winCondition=='fruit') { | 
			
		
	
		
			
				
					|  |  |  |  | 			if(!this.fruits.length) return this.win(); | 
			
		
	
	
		
			
				
					|  |  |  | @ -548,6 +669,9 @@ class SnekGame { | 
			
		
	
		
			
				
					|  |  |  |  | 		if(this.rules.winCondition=='score') { | 
			
		
	
		
			
				
					|  |  |  |  | 			if(this.score>=this.rules.scoreObjective) return this.win(); | 
			
		
	
		
			
				
					|  |  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  |  | 		if(this.rules.scoreSystem=='moves') { | 
			
		
	
		
			
				
					|  |  |  |  | 			if(this.score) this.score--; | 
			
		
	
		
			
				
					|  |  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	tick() { | 
			
		
	
	
		
			
				
					|  |  |  | @ -555,10 +679,13 @@ class SnekGame { | 
			
		
	
		
			
				
					|  |  |  |  | 		if(!this.lastStep) this.lastStep=this.firstStep; | 
			
		
	
		
			
				
					|  |  |  |  | 		this.draw(); | 
			
		
	
		
			
				
					|  |  |  |  | 		if(this.callback) this.callback('tick'); | 
			
		
	
		
			
				
					|  |  |  |  | 		if(this.lastStep+this.delay<Date.now()) { | 
			
		
	
		
			
				
					|  |  |  |  | 		if(this.rules.timeFlow && this.lastStep+this.delay<Date.now()) { | 
			
		
	
		
			
				
					|  |  |  |  | 			this.lastStep+=this.delay; | 
			
		
	
		
			
				
					|  |  |  |  | 			this.step(); | 
			
		
	
		
			
				
					|  |  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  |  | 		if(!this.rules.timeFlow && (this.direction[0]!=0 || this.direction[1]!=0)) { | 
			
		
	
		
			
				
					|  |  |  |  | 			this.step(); | 
			
		
	
		
			
				
					|  |  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  |  | 		requestAnimationFrame(() => this.tick()); | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
	
		
			
				
					|  |  |  | @ -615,7 +742,6 @@ class SnekGame { | 
			
		
	
		
			
				
					|  |  |  |  | 		this.firstStep=Date.now(); | 
			
		
	
		
			
				
					|  |  |  |  | 		this.tickId=0; | 
			
		
	
		
			
				
					|  |  |  |  | 		this.playing=true; | 
			
		
	
		
			
				
					|  |  |  |  | 		this.score=0; | 
			
		
	
		
			
				
					|  |  |  |  | 		requestAnimationFrame(() => this.tick()); | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
	
		
			
				
					|  |  |  | 
 |