/**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
/**** 
* Classes
****/ 
var BlockManager = Container.expand(function () {
	var self = Container.call(this);
	var blockRows = [];
	var index = 0;
	for (var i = 0; i < ROW_COUNT; i++) {
		addRow({
			x: game.width / 2,
			y: LAVA_LINE - i * (BLOCK_SIZE * BLOCK_SCALE + BLOCK_MARGIN),
			index: index++
		});
	}
	blockRows[0].blocks[Math.floor(ROW_SPAN / 2)].onLit(true);
	self.update = function () {
		if (blockRows[0].y > game.height) {
			popRow();
		}
	};
	function addRow(settings) {
		var prevRow = blockRows[blockRows.length - 1];
		var newRow = self.addChild(new BlockRow(settings));
		blockRows.push(newRow);
		if (prevRow) {
			newRow.setDown(prevRow);
			prevRow.setUp(newRow);
		}
	}
	function popRow() {
		blockRows.shift().callDestroy();
		blockRows[0].blocks.forEach(function (block) {
			if (block) {
				block.downBlock = undefined;
			}
		});
		addRow({
			x: game.width / 2,
			y: blockRows[blockRows.length - 1].y - BLOCK_SIZE * BLOCK_SCALE - BLOCK_MARGIN,
			index: index++,
			disabled: true
		});
		adjustRowSpeed();
	}
	return self;
});
var ConfigContainer = Container.expand(function (config) {
	var self = Container.call(this);
	config = config || {};
	self.destroyed = false;
	self.tags = {};
	self.x = config.x || 0;
	self.y = config.y || 0;
	self.rotation = config.rotation || 0;
	self.alpha = config.alpha !== undefined ? config.alpha : 1.0;
	if (config.scale !== undefined || config.scaleX !== undefined || config.scaleY !== undefined) {
		var scaleX = config.scaleX !== undefined ? config.scaleX : config.scale !== undefined ? config.scale : 1;
		var scaleY = config.scaleY !== undefined ? config.scaleY : config.scale !== undefined ? config.scale : 1;
		self.scale.set(scaleX, scaleY);
	}
	self.callDestroy = function () {
		if (!self.destroyed) {
			self.destroyed = true;
			self.onDestroy();
			self.destroy();
		}
	};
	self.onDestroy = function () {};
	return self;
});
var PointText = ConfigContainer.expand(function (config) {
	var self = ConfigContainer.call(this, config);
	var text = self.addChild(new BorderedText('+1', {
		anchorX: 0.5,
		anchorY: 0.5,
		size: 100
	}));
	tween(self, {
		y: self.y - 50
	}, {
		duration: 2000
	});
	LK.setTimeout(function () {
		tween(self, {
			alpha: 0
		}, {
			duration: 1000,
			onFinish: function onFinish() {
				self.callDestroy();
			}
		});
	}, 1000);
	return self;
});
var Light = ConfigContainer.expand(function (config) {
	var self = ConfigContainer.call(this, config);
	var lightShape = self.addChild(new Glow({
		y: -LIGHT_OFFSET,
		width: BLOCK_SIZE - 2 * LIGHT_OFFSET - 10,
		height: BLOCK_SIZE - 2 * LIGHT_OFFSET - 10,
		anchorX: 0.5,
		anchorY: 1,
		layers: 5,
		rangeX: 20,
		rangeY: 10,
		tint: 0xFFFFFF,
		scaleX: 0,
		scaleY: 0,
		asset: 'shapeEllipse',
		solid: true
	}));
	tween(lightShape, {
		scaleX: 1,
		scaleY: 1
	}, {
		duration: LIGHT_GROW_SPEED + Math.random() * LIGHT_GROW_VARIANCE,
		onFinish: function onFinish() {
			if (self.parent) {
				config.callback();
			}
		}
	});
	return self;
});
var LavaSlice = ConfigContainer.expand(function (config) {
	var self = ConfigContainer.call(this, config);
	self.attachAsset('lava' + config.index, {
		anchorX: 0.5,
		anchorY: 0,
		width: LAVA_SLICE_WIDTH,
		tint: 0xFFA500
	});
	self.attachAsset('shapeBox', {
		width: LAVA_SLICE_WIDTH,
		height: 10,
		anchorX: 0.5,
		anchorY: 0,
		tint: 0xFF4D00
	});
	self.addChild(new Glow({
		anchorX: 0.5,
		anchorY: 0.75,
		height: 20,
		rangeY: 150,
		width: 3 * LAVA_SLICE_WIDTH,
		alpha: 0.35,
		tint: 0xFF4D00
	}));
	self.update = function () {
		self.y = Math.sin(LK.ticks * LAVA_BOB_PERIOD + config.index * LAVA_BOB_OFFSET) * LAVA_BOB_HEIGHT;
		if (Math.random() < 0.0025) {
			self.parent.particleContainer.addChild(new LavaParticle({
				x: self.x + Math.random() * LAVA_SLICE_WIDTH - LAVA_SLICE_WIDTH / 2,
				y: self.y,
				scale: 1 + Math.random() * 0.5 // Random scale between 1 and 1.5
			}));
		}
	};
	return self;
});
var LavaParticle = ConfigContainer.expand(function (config) {
	var self = ConfigContainer.call(this, config);
	// Attach a glow asset with specified properties
	self.rotation = Math.random() * Math.PI; // Random rotation between 0 and pi
	self.attachAsset('shapeBox', {
		anchorX: 0.5,
		anchorY: 0.5,
		width: 20,
		height: 20,
		tint: 0xFF4D00,
		alpha: 0.5
	});
	// Attach a smaller shapeBox with black tint and 0.5 alpha
	self.attachAsset('shapeBox', {
		anchorX: 0.5,
		anchorY: 0.5,
		width: 10,
		height: 10,
		tint: 0x000000,
		alpha: 0.25
	});
	// Set initial random velocities increased by a factor of 10
	self.vx = (1 - 2 * Math.random()) * 10; // Random x velocity between 10 and -10
	self.vy = (1 - 0.5 * Math.random()) * -8; // Random y velocity between -8 and -4
	// Update function to apply gravity and movement
	self.update = function () {
		self.vy += 0.1; // Gravity effect
		self.vx *= 0.975;
		self.x += self.vx;
		self.y += self.vy;
		// Destroy the particle if it goes below the game height
		if (self.y > LAVA_BOB_HEIGHT) {
			self.callDestroy();
		}
	};
	if (Math.random() < 0.25) {
		var bubbleSounds = ['bubble1', 'bubble2', 'bubble3', 'bubble4', 'bubble5'];
		var randomBubbleSound = bubbleSounds[Math.floor(Math.random() * bubbleSounds.length)];
		LK.getSound(randomBubbleSound).play();
	}
	return self;
});
var Lava = ConfigContainer.expand(function (config) {
	var self = ConfigContainer.call(this, config);
	self.particleContainer = self.addChild(new Container());
	var position = Math.round((-0.5 - LAVA_SLICE_COUNT / 2) * LAVA_SLICE_WIDTH);
	for (var i = 1; i <= LAVA_SLICE_COUNT; i++) {
		var lavaSlice = self.addChild(new LavaSlice({
			x: position += LAVA_SLICE_WIDTH,
			index: i
		}));
	}
	// Function to play the 'flow' sound at random intervals between 5s to 10s
	function playFlowSound() {
		LK.getSound('flow').play();
		var nextInterval = 5000 + Math.random() * 5000; // Random interval between 5000ms (5s) and 10000ms (10s)
		LK.setTimeout(playFlowSound, nextInterval);
	}
	// Start playing the 'flow' sound immediately
	playFlowSound();
	return self;
});
var Glow = ConfigContainer.expand(function (config) {
	var self = ConfigContainer.call(this, config);
	var layers = Math.max(2, config.layers || 10);
	var layerAlpha = 1 / layers;
	var widthStep = (config.rangeX || 0) * layerAlpha;
	var heightStep = (config.rangeY || 0) * layerAlpha;
	for (var i = 0; i < layers; i++) {
		self.attachAsset(config.asset || 'shapeBox', {
			width: config.width + widthStep * i,
			height: config.height + heightStep * i,
			anchorX: config.anchorX,
			anchorY: config.anchorY,
			tint: config.tint,
			alpha: i === 0 && config.solid ? 1 : layerAlpha
		});
	}
	return self;
});
/** 
* var config = {
* 	x        : Number || 0, // See: ConfigContainer
* 	y        : Number || 0, // See: ConfigContainer
* 	rotation : Number || 0, // See: ConfigContainer
* 	anchorX  : Number || 0,
* 	anchorY  : Number || 1,
* 	size     : Number || TEXT_DEFAULT_SIZE,
* 	font     : String || TEXT_DEFAULT_FONT,
* 	fill     : String || TEXT_DEFAULT_FILL,
* 	border   : String || TEXT_DEFAULT_BORDER,
* }
**/ 
var BorderedText = ConfigContainer.expand(function (text, config) {
	var self = ConfigContainer.call(this, config);
	config = config || {};
	var anchorX = config.anchorX !== undefined ? config.anchorX : 0;
	var anchorY = config.anchorY !== undefined ? config.anchorY : 1;
	var size = config.size !== undefined ? config.size : TEXT_DEFAULT_SIZE;
	var font = config.font !== undefined ? config.font : TEXT_DEFAULT_FONT;
	var textFill = config.fill !== undefined ? config.fill : TEXT_DEFAULT_FILL;
	var borderFill = config.border !== undefined ? config.border : TEXT_DEFAULT_BORDER;
	var mainAsset;
	var textAssets = [];
	;
	self.setText = setText;
	self.setFill = setFill;
	;
	function setText(newText) {
		for (var i = 0; i < textAssets.length; i++) {
			textAssets[i].setText(newText);
		}
	}
	function setFill(newFill) {
		textFill = newFill;
		mainAsset.fill = newFill;
	}
	function buildTextAssets(newText) {
		for (var i = 0; i < TEXT_OFFSETS.length; i++) {
			var main = i === TEXT_OFFSETS.length - 1;
			var textAsset = textAssets[i];
			if (textAsset) {
				textAsset.destroy();
			}
			textAsset = self.addChild(new Text2(newText, {
				fill: main ? textFill : borderFill,
				font: font,
				size: size
			}));
			textAsset.anchor = {
				x: anchorX,
				y: anchorY
			}; // NOTE: Cannot be set in config
			textAsset.x = TEXT_OFFSETS[i][0] * TEXT_BORDER_WEIGHT; // NOTE: Cannot be set in config
			textAsset.y = TEXT_OFFSETS[i][1] * TEXT_BORDER_WEIGHT; // NOTE: Cannot be set in config
			textAssets[i] = textAsset;
		}
		mainAsset = textAssets[TEXT_OFFSETS.length - 1];
	}
	;
	buildTextAssets(text);
	return self;
});
/** 
* var config = {
* 	x        : Number || 0,         // See: ConfigContainer
* 	y        : Number || 0,         // See: ConfigContainer
* 	rotation : Number || 0,         // See: ConfigContainer
* 	anchorX  : Number || .5,
* 	anchorY  : Number || .5,
* 	scale    : Number || undefined,
* 	scaleX   : Number || scale,
* 	scaleY   : Number || scale,
* 	width    : Number || undefined, // Auto-calculated if left undefined and height is set
* 	height   : Number || undefined, // Auto-calculated if left undefined and width is set
* 	tint     : String || 0xFFFFFF,  // Not tinted by default
* 	border   : String || TEXT_DEFAULT_BORDER,
* }
**/ 
var BorderedSymbol = ConfigContainer.expand(function (symbol, config) {
	var self = ConfigContainer.call(this, config);
	config = config || {};
	var width = config.width !== undefined ? config.width : undefined;
	var height = config.height !== undefined ? config.height : undefined;
	var scale = config.scale !== undefined ? config.scale : undefined;
	var scaleX = config.scaleX !== undefined ? config.scaleX : scale;
	var scaleY = config.scaleY !== undefined ? config.scaleX : scale;
	var anchorX = config.anchorX !== undefined ? config.anchorX : .5;
	var anchorY = config.anchorY !== undefined ? config.anchorY : .5;
	var symbolTint = config.tint !== undefined ? config.tint : 0xFFFFFF;
	var borderTint = config.border !== undefined ? config.border : TEXT_DEFAULT_BORDER;
	var mainSymbol;
	var symbolAssets = [];
	;
	self.setSymbol = buildSymbolAssets;
	self.setTint = setTint;
	;
	function setTint(newTint) {
		// NOTE: Tinting is currently broken (cannot use string)
		// mainSymbol.tint = newTint;
		// symbolConfig.tint = newTint;
	}
	function buildSymbolAssets(newSymbol) {
		for (var i = 0; i < TEXT_OFFSETS.length; i++) {
			var main = i === TEXT_OFFSETS.length - 1;
			var symbolAsset = symbolAssets[i];
			if (symbolAsset) {
				symbolAsset.destroy();
			}
			symbolAsset = self.attachAsset(newSymbol, {
				// tint: main ? symbolTint : borderTint,
				tint: main ? 0xFFFFFF : 0x000000,
				// NOTE: Tinting is currently broken (cannot use string)
				x: TEXT_OFFSETS[i][0] * TEXT_BORDER_WEIGHT,
				y: TEXT_OFFSETS[i][1] * TEXT_BORDER_WEIGHT,
				anchorX: anchorX,
				anchorY: anchorY
			});
			if (width !== undefined && height === undefined) {
				height = symbolAsset.height * (width / symbolAsset.width);
			} else if (height !== undefined && width === undefined) {
				width = symbolAsset.width * (height / symbolAsset.height);
			}
			symbolAsset.width = width;
			symbolAsset.height = height;
			if (scaleX !== undefined && scaleY !== undefined) {
				symbolAsset.scale.set(scaleX, scaleY);
			}
			symbolAssets[i] = symbolAsset;
		}
		mainSymbol = symbolAssets[TEXT_OFFSETS.length - 1];
	}
	;
	buildSymbolAssets(symbol);
	return self;
});
var Border = ConfigContainer.expand(function (config) {
	var self = ConfigContainer.call(this, config);
	var radius = 70;
	var totalHeight = 0;
	var borderAssets = ['border1', 'border2'];
	while (totalHeight < game.height) {
		var randomAsset = borderAssets[Math.floor(Math.random() * borderAssets.length)];
		var borderSegment = self.attachAsset(randomAsset, {
			anchorX: 0.5,
			anchorY: 0,
			y: totalHeight
		});
		totalHeight += borderSegment.height;
	}
	var borderGear = self.attachAsset('borderGear', {
		width: 2 * radius,
		height: 2 * radius,
		anchorX: 0.5,
		anchorY: 0.5,
		y: LIGHT_LEVEL,
		rotation: Math.random() * Math.PI * 2 // Initialize with random rotation 
	});
	var borderLevel = self.attachAsset('borderLevel', {
		anchorX: 0.15,
		anchorY: 0.85,
		y: LIGHT_LEVEL,
		rotation: Math.PI / 4 // 45 degree rotation
	});
	self.update = function () {
		borderGear.rotation += rowSpeed / radius;
	};
	return self;
});
var BlockSparkParticle = ConfigContainer.expand(function (config) {
	var self = ConfigContainer.call(this, config);
	var shapeBox = self.attachAsset('shapeBox', {
		width: 10,
		height: 10,
		anchorX: 0.5,
		anchorY: 0.5,
		rotation: Math.random() * Math.PI // Random rotation between 0 and pi
	});
	// Set initial random direction and speed
	var angle = Math.random() * 2 * Math.PI;
	var offset = Math.random() * 50; // Random offset between 0 and 50
	self.x += Math.cos(angle) * offset;
	self.y += Math.sin(angle) * offset;
	self.vx = Math.cos(angle) * 10;
	self.vy = Math.sin(angle) * 10;
	// Update function to move the particle
	self.update = function () {
		self.vy += 0.5; // Apply gravity effect
		self.x += self.vx;
		self.y += self.vy;
	};
	// Tween to fade out the particle
	tween(self, {
		alpha: 0
	}, {
		duration: 350,
		onFinish: function onFinish() {
			self.callDestroy();
		}
	});
	return self;
});
var BlockRow = ConfigContainer.expand(function (config) {
	var self = ConfigContainer.call(this, config);
	var blockClasses = generateBlockClasses(config.index);
	self.index = config.index;
	self.disabled = !!config.disabled;
	self.blocks = [];
	for (var i = 0; i < ROW_SPAN; i++) {
		var blockClass = blockClasses[i];
		self.blocks[i] = self.addChild(new blockClass({
			x: (0.5 + i - ROW_SPAN / 2) * (BLOCK_SIZE * BLOCK_SCALE + BLOCK_MARGIN),
			scale: BLOCK_SCALE,
			disabled: self.disabled,
			index: i,
			row: self
		}));
	}
	for (var i = 0; i < ROW_SPAN; i++) {
		var block = self.blocks[i];
		if (i > 0) {
			block.leftBlock = self.blocks[i - 1];
		}
		if (i < ROW_SPAN - 1) {
			block.rightBlock = self.blocks[i + 1];
		}
	}
	self.update = function () {
		self.y += rowSpeed;
		if (self.disabled && self.y > LIGHT_LEVEL - BLOCK_SIZE * BLOCK_SCALE / 2) {
			self.disabled = false;
			self.blocks.forEach(function (block) {
				block.disabled = false;
			});
			self.blocks.forEach(function (block) {
				if (!block.isRotating) {
					block.onSettle();
				}
			});
		}
	};
	self.setUp = function (upRow) {
		for (var i = 0; i < ROW_SPAN; i++) {
			var selfBlock = self.blocks[i];
			var upBlock = upRow.blocks[i];
			upBlock.downBlock = selfBlock;
			selfBlock.upBlock = upBlock;
		}
	};
	self.setDown = function (downRow) {
		for (var i = 0; i < ROW_SPAN; i++) {
			var selfBlock = self.blocks[i];
			var downBlock = downRow.blocks[i];
			downBlock.upBlock = selfBlock;
			selfBlock.downBlock = downBlock;
		}
	};
	self.onDestroy = function () {
		self.blocks.forEach(function (block) {
			block.callDestroy();
		});
	};
	return self;
});
var BlockLitParticle = ConfigContainer.expand(function (config) {
	var self = ConfigContainer.call(this, config);
	var shapeBox = self.attachAsset('particleBlockLit', {
		scaleX: 1.0,
		scaleY: 1.0,
		anchorX: 0.5,
		anchorY: 0.5,
		alpha: 0.1
	});
	tween(shapeBox, {
		scaleX: 2.0,
		scaleY: 2.0,
		alpha: 0.0
	}, {
		duration: 350,
		easing: tween.linear,
		onFinish: function onFinish() {
			self.callDestroy();
		}
	});
	return self;
});
var BlockBreakParticle = ConfigContainer.expand(function (config) {
	var self = ConfigContainer.call(this, config);
	var blockAssets = ['blockX1', 'blockX2', 'blockX3', 'blockX4'];
	var randomAsset = blockAssets[Math.floor(Math.random() * blockAssets.length)];
	var shapeBox = self.attachAsset(randomAsset, {
		anchorX: 0.5,
		anchorY: 0.5,
		scaleX: 1.5,
		scaleY: 1.5,
		rotation: Math.random() * Math.PI * 2
	});
	// Set initial random direction and speed
	var angle = Math.random() * 2 * Math.PI;
	var offset = 50 + Math.random() * 50; // Random offset between 0 and 50
	self.x += Math.cos(angle) * offset;
	self.y += Math.sin(angle) * offset;
	self.vx = Math.cos(angle) * 10;
	self.vy = Math.sin(angle) * 10;
	// Update function to move the particle
	self.update = function () {
		self.vy += 0.5; // Apply gravity effect
		self.x += self.vx;
		self.y += self.vy;
	};
	// Tween to fade out the particle
	tween(self, {
		alpha: 0
	}, {
		duration: 350,
		onFinish: function onFinish() {
			self.callDestroy();
		}
	});
	return self;
});
var Block = ConfigContainer.expand(function (config) {
	var self = ConfigContainer.call(this, config);
	self.isRotating = false;
	self.disabled = config.disabled;
	self.row = config.row;
	self.index = config.index;
	self.orientation = config.orientation !== undefined ? config.orientation : Math.floor(4 * Math.random());
	self.toLight = false;
	self.upPath = false;
	self.rightPath = false;
	self.downPath = false;
	self.leftPath = false;
	self.upBlock;
	self.rightBlock;
	self.downBlock;
	self.leftBlock;
	self.attachAsset('shapeBox', {
		width: BLOCK_SIZE,
		height: BLOCK_SIZE,
		anchorX: 0.5,
		anchorY: 0.5,
		alpha: 0
	});
	self.lightContainer = lightManager.addChild(new ConfigContainer({
		scale: BLOCK_SCALE
	}));
	self.blockContainer = self.addChild(new ConfigContainer({
		rotation: self.orientation * Math.PI / 2
	}));
	self.rotate = function () {
		if (self.lit) {
			self.showLock();
		} else if (!self.isRotating) {
			self.toLight = false;
			self.isRotating = true;
			LK.getSound('rotate').play();
			self.lightContainer.removeChildren();
			tween(self.blockContainer, {
				rotation: self.blockContainer.rotation + Math.PI / 2
			}, {
				duration: BLOCK_ROTATE_SPEED,
				onFinish: function onFinish() {
					if (!self.destroyed) {
						self.isRotating = false;
						self.orientation = (self.orientation + 1) % 4;
						self.onSettle();
					}
				}
			});
		}
	};
	self.update = function () {
		if (self.parent && !self.destroyed) {
			self.y = columns[self.index].y;
			self.lightContainer.x = self.x + self.parent.x;
			self.lightContainer.y = self.y + self.parent.y;
		}
		if (self.toLight && self.row.y >= LIGHT_LEVEL + BLOCK_SCALE * BLOCK_HALFSIZE) {
			self.toLight = false;
			self.onLit();
		}
	};
	self.down = function () {
		self.rotate();
		tween(self.scale, {
			x: 0.9 * BLOCK_SCALE,
			y: 0.9 * BLOCK_SCALE
		}, {
			duration: BLOCK_ROTATE_SPEED / 2,
			onFinish: function onFinish() {
				tween(self.scale, {
					x: BLOCK_SCALE,
					y: BLOCK_SCALE
				}, {
					duration: BLOCK_ROTATE_SPEED / 2
				});
			}
		});
	};
	self.onLit = function (pointless) {
		if (self.row.y < LIGHT_LEVEL + BLOCK_SCALE * BLOCK_HALFSIZE) {
			self.toLight = true;
		} else if (!self.lit && !self.destroyed && (self.upPath || self.downPath || self.leftPath || self.rightPath)) {
			self.lit = true;
			self.lightContainer.removeChildren();
			self.lightContainer.attachAsset('shapeEllipse', {
				width: BLOCK_SIZE - 2 * LIGHT_OFFSET,
				height: BLOCK_SIZE - 2 * LIGHT_OFFSET,
				anchorX: 0.5,
				anchorY: 0.5
			});
			if (self.upPath && (!self.upBlock || !self.upBlock.lit || !self.upBlock.downPath)) {
				makeGlow(0, -BLOCK_SIZE / 2 - BLOCK_MARGIN / 4);
			}
			if (self.rightPath && (!self.rightBlock || !self.rightBlock.lit || !self.rightBlock.leftPath)) {
				makeGlow(BLOCK_SIZE / 2 + BLOCK_MARGIN / 4, 0);
			}
			if (self.downPath && (!self.downBlock || !self.downBlock.lit || !self.downBlock.upPath)) {
				makeGlow(0, BLOCK_SIZE / 2 + BLOCK_MARGIN / 4);
			}
			if (self.leftPath && (!self.leftBlock || !self.leftBlock.lit || !self.leftBlock.rightPath)) {
				makeGlow(-BLOCK_SIZE / 2 - BLOCK_MARGIN / 4, 0);
			}
			if (!pointless) {
				LK.setScore(LK.getScore() + 1);
				scoreText.setText(LK.getScore());
				game.addChild(new BlockLitParticle({
					// Create a BlockLitParticle
					x: self.x + self.parent.x,
					y: self.y + self.parent.y,
					scale: BLOCK_SCALE
				}));
				game.addChild(new PointText({
					x: self.x + self.parent.x,
					y: self.y + self.parent.y
				}));
			}
			lightSources += 1;
			LK.getSound('light').play();
			self.onSettle();
		}
	};
	self.onSettle = function () {
		self.updatePaths();
		if (!self.disabled) {
			var litRotationFactor = self.lit ? 0 : 1;
			var litPositionFactor = self.lit ? 1 : -1;
			[{
				direction: 'up',
				rotation: 0,
				y: 1
			}, {
				direction: 'right',
				rotation: 0.5,
				x: -1
			}, {
				direction: 'down',
				rotation: 1,
				y: -1
			}, {
				direction: 'left',
				rotation: 1.5,
				x: 1
			}].forEach(function (item) {
				if (self[item.direction + 'Path']) {
					var block = self[item.direction + 'Block'];
					if (block && !block.disabled && block.lit !== self.lit && block[COMPLIMENTS[item.direction] + 'Path']) {
						(self.lit ? block : self).lightContainer.addChild(new Light({
							x: (item.x || 0) * litPositionFactor * BLOCK_HALFSIZE,
							y: (item.y || 0) * litPositionFactor * BLOCK_HALFSIZE,
							rotation: Math.PI * (item.rotation + litRotationFactor),
							callback: self.lit ? block.onLit : self.onLit
						}));
					}
				}
			});
		}
	};
	self.showLock = function () {
		// Check and destroy existing lockSymbol before creating a new one
		if (self.lockSymbol) {
			self.lockSymbol.destroy();
		}
		var lockSymbol = self.addChild(LK.getAsset('iconLock', {
			anchorX: 0.5,
			anchorY: 0.5,
			scaleX: 1 / self.scale.x,
			scaleY: 1 / self.scale.y
		}));
		// Play error sound if not already playing
		if (!errorSoundPlaying) {
			errorSoundPlaying = true;
			LK.getSound('error').play();
			LK.setTimeout(function () {
				errorSoundPlaying = false;
			}, 500);
		}
		self.lockSymbol = lockSymbol;
		// Set a timeout to fade out the lockSymbol after 500ms
		LK.setTimeout(function () {
			tween(lockSymbol, {
				alpha: 0
			}, {
				duration: 500,
				onFinish: function onFinish() {
					lockSymbol.destroy();
					self.lockSymbol = null;
				}
			});
		}, 500);
	};
	self.updatePaths = function () {};
	function makeGlow(x, y) {
		var glow = self.lightContainer.addChild(new Glow({
			x: x,
			y: y,
			width: LIGHT_SPILL_SIZE,
			height: LIGHT_SPILL_SIZE,
			anchorX: 0.5,
			anchorY: 0.5,
			rangeX: 20,
			rangeY: 20,
			layers: 4,
			solid: true,
			tint: 0xFFFFFF,
			alpha: 0
		}));
		tween(glow, {
			alpha: 1
		}, {
			duration: 250
		});
	}
	self.onDestroy = function () {
		if (self.lit) {
			lightSources -= 1;
			if (lightSources === 0) {
				LK.getSound('gong').play(); // Play the gong sound
				var gameOverText = game.addChild(new BorderedText("- Your Light is Dead -", {
					size: 150,
					anchorX: 0.5,
					anchorY: 0.5,
					x: game.width / 2,
					y: game.height / 4
				}));
				LK.stopMusic(); // Stop the background music when the game ends
				LK.setTimeout(function () {
					// Delay the game over widget by 1 second
					LK.showGameOver();
				}, 1000);
			}
		}
		if (self.lightContainer) {
			self.lightContainer.destroy();
		}
	};
	return self;
});
var BlockX = Block.expand(function (config) {
	var self = Block.call(this, config);
	var shiftY = 2;
	self.upPath = true;
	self.rightPath = true;
	self.downPath = true;
	self.leftPath = true;
	self.blockContainer.attachAsset('blockX1', {
		x: -BLOCK_HALFSIZE,
		y: -BLOCK_HALFSIZE + shiftY,
		anchorX: 0,
		anchorY: 0
	});
	self.blockContainer.attachAsset('blockX2', {
		x: BLOCK_HALFSIZE,
		y: -BLOCK_HALFSIZE + shiftY,
		anchorX: 1,
		anchorY: 0
	});
	self.blockContainer.attachAsset('blockX3', {
		x: -BLOCK_HALFSIZE,
		y: BLOCK_HALFSIZE + shiftY,
		anchorX: 0,
		anchorY: 1
	});
	self.blockContainer.attachAsset('blockX4', {
		x: BLOCK_HALFSIZE,
		y: BLOCK_HALFSIZE + shiftY,
		anchorX: 1,
		anchorY: 1
	});
	return self;
});
var BlockT = Block.expand(function (config) {
	var self = Block.call(this, config);
	self.blockContainer.attachAsset('blockT1', {
		x: -BLOCK_HALFSIZE,
		y: -BLOCK_HALFSIZE,
		anchorX: 0,
		anchorY: 0
	});
	self.blockContainer.attachAsset('blockT2', {
		x: BLOCK_HALFSIZE,
		y: -BLOCK_HALFSIZE,
		anchorX: 1,
		anchorY: 0
	});
	self.blockContainer.attachAsset('blockT3', {
		y: BLOCK_HALFSIZE,
		anchorX: 0.5,
		anchorY: 1
	});
	self.updatePaths = function () {
		self.downPath = self.orientation !== 0;
		self.leftPath = self.orientation !== 1;
		self.upPath = self.orientation !== 2;
		self.rightPath = self.orientation !== 3;
	};
	self.updatePaths();
	return self;
});
var BlockLine = Block.expand(function (config) {
	var self = Block.call(this, config);
	self.blockContainer.attachAsset('blockLine1', {
		x: -BLOCK_HALFSIZE,
		anchorX: 0,
		anchorY: 0.5,
		height: BLOCK_SIZE
	});
	self.blockContainer.attachAsset('blockLine2', {
		x: BLOCK_HALFSIZE,
		anchorX: 1,
		anchorY: 0.5,
		height: BLOCK_SIZE
	});
	self.updatePaths = function () {
		var vertical = !(self.orientation % 2);
		self.upPath = vertical;
		self.downPath = vertical;
		self.leftPath = !vertical;
		self.rightPath = !vertical;
	};
	self.updatePaths();
	return self;
});
var BlockL = Block.expand(function (config) {
	var self = Block.call(this, config);
	self.blockContainer.attachAsset('blockL1', {
		anchorX: 0.5,
		anchorY: 0.5,
		height: BLOCK_SIZE
	});
	self.blockContainer.attachAsset('blockL2', {
		x: -BLOCK_HALFSIZE,
		y: BLOCK_HALFSIZE,
		anchorX: 0,
		anchorY: 1
	});
	self.updatePaths = function () {
		self.leftPath = self.orientation === 0 || self.orientation === 1;
		self.upPath = self.orientation === 1 || self.orientation === 2;
		self.rightPath = self.orientation === 2 || self.orientation === 3;
		self.downPath = self.orientation === 3 || self.orientation === 0;
	};
	self.updatePaths();
	return self;
});
var BlockBlank = Block.expand(function (config) {
	var self = Block.call(this, config);
	var crackAsset;
	var crackLevel = 0;
	var blockBlankAssets = ['blockBlank1', 'blockBlank2', 'blockBlank3'];
	var randomAsset = blockBlankAssets[Math.floor(Math.random() * blockBlankAssets.length)];
	self.blockContainer.attachAsset(randomAsset, {
		anchorX: 0.5,
		anchorY: 0.5,
		width: BLOCK_SIZE,
		height: BLOCK_SIZE
	});
	self.rotate = function (force) {
		if (force || crackLevel > 0) {
			if (++crackLevel <= 4) {
				if (crackAsset) {
					crackAsset.destroy();
				}
				if (!force) {
					LK.getSound('crack').play();
				}
				crackAsset = self.blockContainer.attachAsset('crack' + crackLevel, {
					anchorX: 0.5,
					anchorY: 0.5,
					rotation: crackLevel === 1 ? Math.random() * Math.PI * 2 : 0 // Random rotation if crackLevel is 1
				});
				// Create BlockSparkParticles
				if (self.parent) {
					for (var i = 0; i < 2 * crackLevel; i++) {
						game.addChild(new BlockSparkParticle({
							x: self.x + self.parent.x,
							y: self.y + self.parent.y
						}));
					}
				}
			} else {
				LK.getSound('break').play();
				var blockClass = randomizeBlockClass({
					index: self.row.index,
					blanks: ROW_SPAN // Prevent spawning blocks
				});
				var newBlock = self.parent.addChild(new blockClass({
					x: self.x,
					y: self.y,
					scale: BLOCK_SCALE,
					index: self.index,
					row: self.row
				}));
				self.row.blocks[self.index] = newBlock;
				// Update block references 
				if (self.upBlock) {
					self.upBlock.downBlock = newBlock;
					newBlock.upBlock = self.upBlock;
				}
				if (self.downBlock) {
					self.downBlock.upBlock = newBlock;
					newBlock.downBlock = self.downBlock;
				}
				if (self.leftBlock) {
					self.leftBlock.rightBlock = newBlock;
					newBlock.leftBlock = self.leftBlock;
				}
				if (self.rightBlock) {
					self.rightBlock.leftBlock = newBlock;
					newBlock.rightBlock = self.rightBlock;
				}
				if (!self.disabled) {
					newBlock.onSettle();
				}
				// Create BlockBreakParticles
				for (var i = 0; i < 6; i++) {
					game.addChild(new BlockBreakParticle({
						x: self.x + self.parent.x,
						y: self.y + self.parent.y
					}));
				}
				self.callDestroy();
			}
		} else {
			self.showLock();
		}
	};
	if (Math.random() < BLOCK_CRACK_CHANCE) {
		self.rotate(true);
	}
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x000000
});
/**** 
* Game Code
****/ 
// Math constants / pre-calculations
var MATH_HALF_ROOT_3 = Math.sqrt(3) / 2; // Required by: TEXT_OFFSETS, BorderedText, BorderedSymbol, SymbolText
;
// Text settings
var TEXT_OFFSETS = [[0, 1], [MATH_HALF_ROOT_3, 0.5], [MATH_HALF_ROOT_3, -0.5], [0, -1], [-MATH_HALF_ROOT_3, -0.5], [-MATH_HALF_ROOT_3, 0.5], [0, 0]]; // Required by: BorderedText, BorderedSymbol, SymbolText
var TEXT_BORDER_WEIGHT = 5; // Required by: BorderedText, BorderedSymbol, SymbolText
var TEXT_DEFAULT_BORDER = '#000000'; // Required by: BorderedText, BorderedSymbol, SymbolText
var TEXT_DEFAULT_FILL = '#FFFFFF'; // Required by: BorderedText, SymbolText
var TEXT_DEFAULT_FONT = 'Arial'; // Required by: BorderedText, SymbolText
var TEXT_DEFAULT_SIZE = 50; // Required by: BorderedText, SymbolText
;
// Other settings
var LAVA_LINE = game.height - 200;
var LAVA_SLICE_COUNT = 18;
var LAVA_SLICE_WIDTH = 128;
var LAVA_BOB_HEIGHT = 10;
var LAVA_BOB_OFFSET = Math.PI / 5;
var LAVA_BOB_PERIOD = Math.PI / 60;
var BLOCK_SCALE = 2.5;
var BLOCK_SIZE = 100;
var BLOCK_MARGIN = 20;
var BLOCK_HALFSIZE = BLOCK_SIZE * 0.5;
var BLOCK_CRACK_CHANCE = 0.45;
var BLOCK_ROTATE_SPEED = 100;
var LIGHT_LEVEL = 800;
var LIGHT_GROW_SPEED = 4500;
var LIGHT_GROW_VARIANCE = 1000;
var LIGHT_SPILL_SIZE = 35;
var LIGHT_OFFSET = 5;
var ROW_SPAN = 7;
var ROW_COUNT = 11;
var ROW_SPEED_BASE = 0.2;
var ROW_SPEED_INCREASE = 0.04;
var ROW_SPEED_INCREASE_MIN = 0.01;
var ROW_SPEED_INCREASE_FACTOR = 0.9;
var COL_SLIP_MIN = 10;
var COL_SLIP_MAX = 30;
var COL_SLIP_TIME = 750;
var COL_TIMEOUT_MIN = 1000;
var COL_TIMEOUT_MAX = 10000;
var COL_RISE_FACTOR = 0.2;
var COMPLIMENTS = {
	up: 'down',
	right: 'left',
	down: 'up',
	left: 'right'
};
var lightSources = 0;
var rowSpeed = ROW_SPEED_BASE;
var rowSpeedIncrease = ROW_SPEED_INCREASE;
var errorSoundPlaying = false;
var columns = [];
for (var i = 0; i < ROW_SPAN; i++) {
	columns.push({
		y: 0,
		timer: false,
		index: i
	});
}
// Play background music on repeat when the game starts
LK.playMusic('background', {
	loop: true
});
game.update = function () {
	for (var i = 1; i < columns.length - 1; i++) {
		var column = columns[i];
		if (!column.timer) {
			if (column.y > 0) {
				column.y = Math.max(0, column.y - rowSpeed * COL_RISE_FACTOR);
			} else {
				startColumnTimer(i);
			}
		}
	}
};
var scoreText = new BorderedText('0', {
	size: 100,
	anchorX: 0.5,
	anchorY: 0
});
LK.gui.top.addChild(scoreText);
var rowSpeedText = LK.gui.topRight.addChild(new Text2((rowSpeed * 60).toFixed(1), {
	size: 50,
	fill: 0xFFFFFF,
	stroke: 0x000000,
	strokeThickness: 5
}));
rowSpeedText.anchor.set(1.0, -0.5);
var speedIcon = LK.gui.topRight.addChild(LK.getAsset('iconGear', {
	anchorX: 0.5,
	anchorY: 0.5,
	x: rowSpeedText.x - rowSpeedText.width - 40,
	y: rowSpeedText.height
}));
var iconRotate = LK.gui.topRight.addChild(new BorderedSymbol('iconRotate', {
	anchorX: 0.2,
	anchorY: 1.0,
	x: speedIcon.x,
	y: speedIcon.y
}));
var lightManager = game.addChild(new Container());
game.addChild(new Glow({
	width: game.width,
	height: LIGHT_LEVEL,
	rangeY: 20,
	layers: 5,
	solid: true
}));
var blockManager = game.addChild(new BlockManager());
var leftBorder = game.addChild(new Border({
	x: 30
}));
var rightBorder = game.addChild(new Border({
	x: game.width - 30,
	scaleX: -1
}));
var lava = game.addChild(new Lava({
	x: game.width / 2,
	y: LAVA_LINE
}));
game.addChild(new Glow({
	x: game.width / 2,
	width: game.width,
	height: 200,
	anchorX: 0.5,
	anchorY: 0,
	rangeY: 200,
	tint: 0x000000,
	alpha: 2.0
}));
var iconLight = game.addChild(LK.getAsset('iconLight', {
	x: game.width / 2,
	y: 100,
	anchorX: 0.5,
	anchorY: 0.5,
	tint: 0xFF4D00
}));
function shuffle(array) {
	var currentIndex = array.length;
	while (currentIndex != 0) {
		var randomIndex = Math.floor(Math.random() * currentIndex);
		currentIndex--;
		var ref = [array[randomIndex], array[currentIndex]];
		array[currentIndex] = ref[0];
		array[randomIndex] = ref[1];
	}
	return array;
}
function generateBlockClasses(index) {
	var settings = {
		index: index,
		blanks: 0,
		xs: 0
	};
	switch (index) {
		case 0:
			return [BlockBlank, BlockBlank, BlockBlank, BlockX, BlockBlank, BlockBlank, BlockBlank];
		case 1:
			settings.blanks = ROW_SPAN;
			settings.xs = 1;
			return [BlockBlank, BlockBlank, randomizeBlockClass(settings), BlockX, randomizeBlockClass(settings), BlockBlank, BlockBlank];
		case 2:
			settings.blanks = ROW_SPAN;
			settings.xs = 1;
			return [BlockBlank, randomizeBlockClass(settings), randomizeBlockClass(settings), BlockX, randomizeBlockClass(settings), randomizeBlockClass(settings), BlockBlank];
		default:
			var blockClasses = [];
			for (var i = 0; i < ROW_SPAN; i++) {
				blockClasses[i] = randomizeBlockClass(settings);
			}
			return shuffle(blockClasses);
	}
}
function adjustRowSpeed() {
	rowSpeed += rowSpeedIncrease;
	rowSpeedText.setText((rowSpeed * 60).toFixed(1));
	rowSpeedIncrease = Math.max(ROW_SPEED_INCREASE_MIN, rowSpeedIncrease * ROW_SPEED_INCREASE_FACTOR);
}
function startColumnTimer(index) {
	var column = columns[index];
	column.timer = true;
	var timeoutDuration = COL_TIMEOUT_MIN + Math.random() * (COL_TIMEOUT_MAX - COL_TIMEOUT_MIN);
	LK.setTimeout(function () {
		var targetY = COL_SLIP_MIN + Math.random() * (COL_SLIP_MAX - COL_SLIP_MIN);
		tween(column, {
			y: targetY
		}, {
			duration: COL_SLIP_TIME,
			easing: tween.easeIn,
			// Apply ease in for the tween
			onFinish: function onFinish() {
				column.timer = false; // Reset the timer to false after tween completes
			}
		});
	}, timeoutDuration);
}
function randomizeBlockClass(settings) {
	var classes = [{
		blockClass: BlockBlank,
		chance: Math.max(0, 1.5 - 0.5 * (settings.blanks || 0))
	}, {
		blockClass: BlockT,
		chance: 1
	}, {
		blockClass: BlockX,
		chance: Math.max(0, 1 - 1 * (settings.xs || 0))
	}, {
		blockClass: BlockLine,
		chance: 1
	}, {
		blockClass: BlockL,
		chance: 1
	}];
	var totalChance = classes.reduce(function (sum, item) {
		return sum + item.chance;
	}, 0);
	var randomValue = Math.random() * totalChance;
	var accumulatedChance = 0;
	var blockClass = BlockBlank;
	for (var i = 0; i < classes.length; i++) {
		accumulatedChance += classes[i].chance;
		if (randomValue < accumulatedChance) {
			blockClass = classes[i].blockClass;
			break;
		}
	}
	switch (blockClass) {
		case BlockBlank:
			settings.blanks = (settings.blanks || 0) + 1;
			break;
		case BlockX:
			settings.xs = (settings.xs || 0) + 1;
			break;
	}
	return blockClass;
} /**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
/**** 
* Classes
****/ 
var BlockManager = Container.expand(function () {
	var self = Container.call(this);
	var blockRows = [];
	var index = 0;
	for (var i = 0; i < ROW_COUNT; i++) {
		addRow({
			x: game.width / 2,
			y: LAVA_LINE - i * (BLOCK_SIZE * BLOCK_SCALE + BLOCK_MARGIN),
			index: index++
		});
	}
	blockRows[0].blocks[Math.floor(ROW_SPAN / 2)].onLit(true);
	self.update = function () {
		if (blockRows[0].y > game.height) {
			popRow();
		}
	};
	function addRow(settings) {
		var prevRow = blockRows[blockRows.length - 1];
		var newRow = self.addChild(new BlockRow(settings));
		blockRows.push(newRow);
		if (prevRow) {
			newRow.setDown(prevRow);
			prevRow.setUp(newRow);
		}
	}
	function popRow() {
		blockRows.shift().callDestroy();
		blockRows[0].blocks.forEach(function (block) {
			if (block) {
				block.downBlock = undefined;
			}
		});
		addRow({
			x: game.width / 2,
			y: blockRows[blockRows.length - 1].y - BLOCK_SIZE * BLOCK_SCALE - BLOCK_MARGIN,
			index: index++,
			disabled: true
		});
		adjustRowSpeed();
	}
	return self;
});
var ConfigContainer = Container.expand(function (config) {
	var self = Container.call(this);
	config = config || {};
	self.destroyed = false;
	self.tags = {};
	self.x = config.x || 0;
	self.y = config.y || 0;
	self.rotation = config.rotation || 0;
	self.alpha = config.alpha !== undefined ? config.alpha : 1.0;
	if (config.scale !== undefined || config.scaleX !== undefined || config.scaleY !== undefined) {
		var scaleX = config.scaleX !== undefined ? config.scaleX : config.scale !== undefined ? config.scale : 1;
		var scaleY = config.scaleY !== undefined ? config.scaleY : config.scale !== undefined ? config.scale : 1;
		self.scale.set(scaleX, scaleY);
	}
	self.callDestroy = function () {
		if (!self.destroyed) {
			self.destroyed = true;
			self.onDestroy();
			self.destroy();
		}
	};
	self.onDestroy = function () {};
	return self;
});
var PointText = ConfigContainer.expand(function (config) {
	var self = ConfigContainer.call(this, config);
	var text = self.addChild(new BorderedText('+1', {
		anchorX: 0.5,
		anchorY: 0.5,
		size: 100
	}));
	tween(self, {
		y: self.y - 50
	}, {
		duration: 2000
	});
	LK.setTimeout(function () {
		tween(self, {
			alpha: 0
		}, {
			duration: 1000,
			onFinish: function onFinish() {
				self.callDestroy();
			}
		});
	}, 1000);
	return self;
});
var Light = ConfigContainer.expand(function (config) {
	var self = ConfigContainer.call(this, config);
	var lightShape = self.addChild(new Glow({
		y: -LIGHT_OFFSET,
		width: BLOCK_SIZE - 2 * LIGHT_OFFSET - 10,
		height: BLOCK_SIZE - 2 * LIGHT_OFFSET - 10,
		anchorX: 0.5,
		anchorY: 1,
		layers: 5,
		rangeX: 20,
		rangeY: 10,
		tint: 0xFFFFFF,
		scaleX: 0,
		scaleY: 0,
		asset: 'shapeEllipse',
		solid: true
	}));
	tween(lightShape, {
		scaleX: 1,
		scaleY: 1
	}, {
		duration: LIGHT_GROW_SPEED + Math.random() * LIGHT_GROW_VARIANCE,
		onFinish: function onFinish() {
			if (self.parent) {
				config.callback();
			}
		}
	});
	return self;
});
var LavaSlice = ConfigContainer.expand(function (config) {
	var self = ConfigContainer.call(this, config);
	self.attachAsset('lava' + config.index, {
		anchorX: 0.5,
		anchorY: 0,
		width: LAVA_SLICE_WIDTH,
		tint: 0xFFA500
	});
	self.attachAsset('shapeBox', {
		width: LAVA_SLICE_WIDTH,
		height: 10,
		anchorX: 0.5,
		anchorY: 0,
		tint: 0xFF4D00
	});
	self.addChild(new Glow({
		anchorX: 0.5,
		anchorY: 0.75,
		height: 20,
		rangeY: 150,
		width: 3 * LAVA_SLICE_WIDTH,
		alpha: 0.35,
		tint: 0xFF4D00
	}));
	self.update = function () {
		self.y = Math.sin(LK.ticks * LAVA_BOB_PERIOD + config.index * LAVA_BOB_OFFSET) * LAVA_BOB_HEIGHT;
		if (Math.random() < 0.0025) {
			self.parent.particleContainer.addChild(new LavaParticle({
				x: self.x + Math.random() * LAVA_SLICE_WIDTH - LAVA_SLICE_WIDTH / 2,
				y: self.y,
				scale: 1 + Math.random() * 0.5 // Random scale between 1 and 1.5
			}));
		}
	};
	return self;
});
var LavaParticle = ConfigContainer.expand(function (config) {
	var self = ConfigContainer.call(this, config);
	// Attach a glow asset with specified properties
	self.rotation = Math.random() * Math.PI; // Random rotation between 0 and pi
	self.attachAsset('shapeBox', {
		anchorX: 0.5,
		anchorY: 0.5,
		width: 20,
		height: 20,
		tint: 0xFF4D00,
		alpha: 0.5
	});
	// Attach a smaller shapeBox with black tint and 0.5 alpha
	self.attachAsset('shapeBox', {
		anchorX: 0.5,
		anchorY: 0.5,
		width: 10,
		height: 10,
		tint: 0x000000,
		alpha: 0.25
	});
	// Set initial random velocities increased by a factor of 10
	self.vx = (1 - 2 * Math.random()) * 10; // Random x velocity between 10 and -10
	self.vy = (1 - 0.5 * Math.random()) * -8; // Random y velocity between -8 and -4
	// Update function to apply gravity and movement
	self.update = function () {
		self.vy += 0.1; // Gravity effect
		self.vx *= 0.975;
		self.x += self.vx;
		self.y += self.vy;
		// Destroy the particle if it goes below the game height
		if (self.y > LAVA_BOB_HEIGHT) {
			self.callDestroy();
		}
	};
	if (Math.random() < 0.25) {
		var bubbleSounds = ['bubble1', 'bubble2', 'bubble3', 'bubble4', 'bubble5'];
		var randomBubbleSound = bubbleSounds[Math.floor(Math.random() * bubbleSounds.length)];
		LK.getSound(randomBubbleSound).play();
	}
	return self;
});
var Lava = ConfigContainer.expand(function (config) {
	var self = ConfigContainer.call(this, config);
	self.particleContainer = self.addChild(new Container());
	var position = Math.round((-0.5 - LAVA_SLICE_COUNT / 2) * LAVA_SLICE_WIDTH);
	for (var i = 1; i <= LAVA_SLICE_COUNT; i++) {
		var lavaSlice = self.addChild(new LavaSlice({
			x: position += LAVA_SLICE_WIDTH,
			index: i
		}));
	}
	// Function to play the 'flow' sound at random intervals between 5s to 10s
	function playFlowSound() {
		LK.getSound('flow').play();
		var nextInterval = 5000 + Math.random() * 5000; // Random interval between 5000ms (5s) and 10000ms (10s)
		LK.setTimeout(playFlowSound, nextInterval);
	}
	// Start playing the 'flow' sound immediately
	playFlowSound();
	return self;
});
var Glow = ConfigContainer.expand(function (config) {
	var self = ConfigContainer.call(this, config);
	var layers = Math.max(2, config.layers || 10);
	var layerAlpha = 1 / layers;
	var widthStep = (config.rangeX || 0) * layerAlpha;
	var heightStep = (config.rangeY || 0) * layerAlpha;
	for (var i = 0; i < layers; i++) {
		self.attachAsset(config.asset || 'shapeBox', {
			width: config.width + widthStep * i,
			height: config.height + heightStep * i,
			anchorX: config.anchorX,
			anchorY: config.anchorY,
			tint: config.tint,
			alpha: i === 0 && config.solid ? 1 : layerAlpha
		});
	}
	return self;
});
/** 
* var config = {
* 	x        : Number || 0, // See: ConfigContainer
* 	y        : Number || 0, // See: ConfigContainer
* 	rotation : Number || 0, // See: ConfigContainer
* 	anchorX  : Number || 0,
* 	anchorY  : Number || 1,
* 	size     : Number || TEXT_DEFAULT_SIZE,
* 	font     : String || TEXT_DEFAULT_FONT,
* 	fill     : String || TEXT_DEFAULT_FILL,
* 	border   : String || TEXT_DEFAULT_BORDER,
* }
**/ 
var BorderedText = ConfigContainer.expand(function (text, config) {
	var self = ConfigContainer.call(this, config);
	config = config || {};
	var anchorX = config.anchorX !== undefined ? config.anchorX : 0;
	var anchorY = config.anchorY !== undefined ? config.anchorY : 1;
	var size = config.size !== undefined ? config.size : TEXT_DEFAULT_SIZE;
	var font = config.font !== undefined ? config.font : TEXT_DEFAULT_FONT;
	var textFill = config.fill !== undefined ? config.fill : TEXT_DEFAULT_FILL;
	var borderFill = config.border !== undefined ? config.border : TEXT_DEFAULT_BORDER;
	var mainAsset;
	var textAssets = [];
	;
	self.setText = setText;
	self.setFill = setFill;
	;
	function setText(newText) {
		for (var i = 0; i < textAssets.length; i++) {
			textAssets[i].setText(newText);
		}
	}
	function setFill(newFill) {
		textFill = newFill;
		mainAsset.fill = newFill;
	}
	function buildTextAssets(newText) {
		for (var i = 0; i < TEXT_OFFSETS.length; i++) {
			var main = i === TEXT_OFFSETS.length - 1;
			var textAsset = textAssets[i];
			if (textAsset) {
				textAsset.destroy();
			}
			textAsset = self.addChild(new Text2(newText, {
				fill: main ? textFill : borderFill,
				font: font,
				size: size
			}));
			textAsset.anchor = {
				x: anchorX,
				y: anchorY
			}; // NOTE: Cannot be set in config
			textAsset.x = TEXT_OFFSETS[i][0] * TEXT_BORDER_WEIGHT; // NOTE: Cannot be set in config
			textAsset.y = TEXT_OFFSETS[i][1] * TEXT_BORDER_WEIGHT; // NOTE: Cannot be set in config
			textAssets[i] = textAsset;
		}
		mainAsset = textAssets[TEXT_OFFSETS.length - 1];
	}
	;
	buildTextAssets(text);
	return self;
});
/** 
* var config = {
* 	x        : Number || 0,         // See: ConfigContainer
* 	y        : Number || 0,         // See: ConfigContainer
* 	rotation : Number || 0,         // See: ConfigContainer
* 	anchorX  : Number || .5,
* 	anchorY  : Number || .5,
* 	scale    : Number || undefined,
* 	scaleX   : Number || scale,
* 	scaleY   : Number || scale,
* 	width    : Number || undefined, // Auto-calculated if left undefined and height is set
* 	height   : Number || undefined, // Auto-calculated if left undefined and width is set
* 	tint     : String || 0xFFFFFF,  // Not tinted by default
* 	border   : String || TEXT_DEFAULT_BORDER,
* }
**/ 
var BorderedSymbol = ConfigContainer.expand(function (symbol, config) {
	var self = ConfigContainer.call(this, config);
	config = config || {};
	var width = config.width !== undefined ? config.width : undefined;
	var height = config.height !== undefined ? config.height : undefined;
	var scale = config.scale !== undefined ? config.scale : undefined;
	var scaleX = config.scaleX !== undefined ? config.scaleX : scale;
	var scaleY = config.scaleY !== undefined ? config.scaleX : scale;
	var anchorX = config.anchorX !== undefined ? config.anchorX : .5;
	var anchorY = config.anchorY !== undefined ? config.anchorY : .5;
	var symbolTint = config.tint !== undefined ? config.tint : 0xFFFFFF;
	var borderTint = config.border !== undefined ? config.border : TEXT_DEFAULT_BORDER;
	var mainSymbol;
	var symbolAssets = [];
	;
	self.setSymbol = buildSymbolAssets;
	self.setTint = setTint;
	;
	function setTint(newTint) {
		// NOTE: Tinting is currently broken (cannot use string)
		// mainSymbol.tint = newTint;
		// symbolConfig.tint = newTint;
	}
	function buildSymbolAssets(newSymbol) {
		for (var i = 0; i < TEXT_OFFSETS.length; i++) {
			var main = i === TEXT_OFFSETS.length - 1;
			var symbolAsset = symbolAssets[i];
			if (symbolAsset) {
				symbolAsset.destroy();
			}
			symbolAsset = self.attachAsset(newSymbol, {
				// tint: main ? symbolTint : borderTint,
				tint: main ? 0xFFFFFF : 0x000000,
				// NOTE: Tinting is currently broken (cannot use string)
				x: TEXT_OFFSETS[i][0] * TEXT_BORDER_WEIGHT,
				y: TEXT_OFFSETS[i][1] * TEXT_BORDER_WEIGHT,
				anchorX: anchorX,
				anchorY: anchorY
			});
			if (width !== undefined && height === undefined) {
				height = symbolAsset.height * (width / symbolAsset.width);
			} else if (height !== undefined && width === undefined) {
				width = symbolAsset.width * (height / symbolAsset.height);
			}
			symbolAsset.width = width;
			symbolAsset.height = height;
			if (scaleX !== undefined && scaleY !== undefined) {
				symbolAsset.scale.set(scaleX, scaleY);
			}
			symbolAssets[i] = symbolAsset;
		}
		mainSymbol = symbolAssets[TEXT_OFFSETS.length - 1];
	}
	;
	buildSymbolAssets(symbol);
	return self;
});
var Border = ConfigContainer.expand(function (config) {
	var self = ConfigContainer.call(this, config);
	var radius = 70;
	var totalHeight = 0;
	var borderAssets = ['border1', 'border2'];
	while (totalHeight < game.height) {
		var randomAsset = borderAssets[Math.floor(Math.random() * borderAssets.length)];
		var borderSegment = self.attachAsset(randomAsset, {
			anchorX: 0.5,
			anchorY: 0,
			y: totalHeight
		});
		totalHeight += borderSegment.height;
	}
	var borderGear = self.attachAsset('borderGear', {
		width: 2 * radius,
		height: 2 * radius,
		anchorX: 0.5,
		anchorY: 0.5,
		y: LIGHT_LEVEL,
		rotation: Math.random() * Math.PI * 2 // Initialize with random rotation 
	});
	var borderLevel = self.attachAsset('borderLevel', {
		anchorX: 0.15,
		anchorY: 0.85,
		y: LIGHT_LEVEL,
		rotation: Math.PI / 4 // 45 degree rotation
	});
	self.update = function () {
		borderGear.rotation += rowSpeed / radius;
	};
	return self;
});
var BlockSparkParticle = ConfigContainer.expand(function (config) {
	var self = ConfigContainer.call(this, config);
	var shapeBox = self.attachAsset('shapeBox', {
		width: 10,
		height: 10,
		anchorX: 0.5,
		anchorY: 0.5,
		rotation: Math.random() * Math.PI // Random rotation between 0 and pi
	});
	// Set initial random direction and speed
	var angle = Math.random() * 2 * Math.PI;
	var offset = Math.random() * 50; // Random offset between 0 and 50
	self.x += Math.cos(angle) * offset;
	self.y += Math.sin(angle) * offset;
	self.vx = Math.cos(angle) * 10;
	self.vy = Math.sin(angle) * 10;
	// Update function to move the particle
	self.update = function () {
		self.vy += 0.5; // Apply gravity effect
		self.x += self.vx;
		self.y += self.vy;
	};
	// Tween to fade out the particle
	tween(self, {
		alpha: 0
	}, {
		duration: 350,
		onFinish: function onFinish() {
			self.callDestroy();
		}
	});
	return self;
});
var BlockRow = ConfigContainer.expand(function (config) {
	var self = ConfigContainer.call(this, config);
	var blockClasses = generateBlockClasses(config.index);
	self.index = config.index;
	self.disabled = !!config.disabled;
	self.blocks = [];
	for (var i = 0; i < ROW_SPAN; i++) {
		var blockClass = blockClasses[i];
		self.blocks[i] = self.addChild(new blockClass({
			x: (0.5 + i - ROW_SPAN / 2) * (BLOCK_SIZE * BLOCK_SCALE + BLOCK_MARGIN),
			scale: BLOCK_SCALE,
			disabled: self.disabled,
			index: i,
			row: self
		}));
	}
	for (var i = 0; i < ROW_SPAN; i++) {
		var block = self.blocks[i];
		if (i > 0) {
			block.leftBlock = self.blocks[i - 1];
		}
		if (i < ROW_SPAN - 1) {
			block.rightBlock = self.blocks[i + 1];
		}
	}
	self.update = function () {
		self.y += rowSpeed;
		if (self.disabled && self.y > LIGHT_LEVEL - BLOCK_SIZE * BLOCK_SCALE / 2) {
			self.disabled = false;
			self.blocks.forEach(function (block) {
				block.disabled = false;
			});
			self.blocks.forEach(function (block) {
				if (!block.isRotating) {
					block.onSettle();
				}
			});
		}
	};
	self.setUp = function (upRow) {
		for (var i = 0; i < ROW_SPAN; i++) {
			var selfBlock = self.blocks[i];
			var upBlock = upRow.blocks[i];
			upBlock.downBlock = selfBlock;
			selfBlock.upBlock = upBlock;
		}
	};
	self.setDown = function (downRow) {
		for (var i = 0; i < ROW_SPAN; i++) {
			var selfBlock = self.blocks[i];
			var downBlock = downRow.blocks[i];
			downBlock.upBlock = selfBlock;
			selfBlock.downBlock = downBlock;
		}
	};
	self.onDestroy = function () {
		self.blocks.forEach(function (block) {
			block.callDestroy();
		});
	};
	return self;
});
var BlockLitParticle = ConfigContainer.expand(function (config) {
	var self = ConfigContainer.call(this, config);
	var shapeBox = self.attachAsset('particleBlockLit', {
		scaleX: 1.0,
		scaleY: 1.0,
		anchorX: 0.5,
		anchorY: 0.5,
		alpha: 0.1
	});
	tween(shapeBox, {
		scaleX: 2.0,
		scaleY: 2.0,
		alpha: 0.0
	}, {
		duration: 350,
		easing: tween.linear,
		onFinish: function onFinish() {
			self.callDestroy();
		}
	});
	return self;
});
var BlockBreakParticle = ConfigContainer.expand(function (config) {
	var self = ConfigContainer.call(this, config);
	var blockAssets = ['blockX1', 'blockX2', 'blockX3', 'blockX4'];
	var randomAsset = blockAssets[Math.floor(Math.random() * blockAssets.length)];
	var shapeBox = self.attachAsset(randomAsset, {
		anchorX: 0.5,
		anchorY: 0.5,
		scaleX: 1.5,
		scaleY: 1.5,
		rotation: Math.random() * Math.PI * 2
	});
	// Set initial random direction and speed
	var angle = Math.random() * 2 * Math.PI;
	var offset = 50 + Math.random() * 50; // Random offset between 0 and 50
	self.x += Math.cos(angle) * offset;
	self.y += Math.sin(angle) * offset;
	self.vx = Math.cos(angle) * 10;
	self.vy = Math.sin(angle) * 10;
	// Update function to move the particle
	self.update = function () {
		self.vy += 0.5; // Apply gravity effect
		self.x += self.vx;
		self.y += self.vy;
	};
	// Tween to fade out the particle
	tween(self, {
		alpha: 0
	}, {
		duration: 350,
		onFinish: function onFinish() {
			self.callDestroy();
		}
	});
	return self;
});
var Block = ConfigContainer.expand(function (config) {
	var self = ConfigContainer.call(this, config);
	self.isRotating = false;
	self.disabled = config.disabled;
	self.row = config.row;
	self.index = config.index;
	self.orientation = config.orientation !== undefined ? config.orientation : Math.floor(4 * Math.random());
	self.toLight = false;
	self.upPath = false;
	self.rightPath = false;
	self.downPath = false;
	self.leftPath = false;
	self.upBlock;
	self.rightBlock;
	self.downBlock;
	self.leftBlock;
	self.attachAsset('shapeBox', {
		width: BLOCK_SIZE,
		height: BLOCK_SIZE,
		anchorX: 0.5,
		anchorY: 0.5,
		alpha: 0
	});
	self.lightContainer = lightManager.addChild(new ConfigContainer({
		scale: BLOCK_SCALE
	}));
	self.blockContainer = self.addChild(new ConfigContainer({
		rotation: self.orientation * Math.PI / 2
	}));
	self.rotate = function () {
		if (self.lit) {
			self.showLock();
		} else if (!self.isRotating) {
			self.toLight = false;
			self.isRotating = true;
			LK.getSound('rotate').play();
			self.lightContainer.removeChildren();
			tween(self.blockContainer, {
				rotation: self.blockContainer.rotation + Math.PI / 2
			}, {
				duration: BLOCK_ROTATE_SPEED,
				onFinish: function onFinish() {
					if (!self.destroyed) {
						self.isRotating = false;
						self.orientation = (self.orientation + 1) % 4;
						self.onSettle();
					}
				}
			});
		}
	};
	self.update = function () {
		if (self.parent && !self.destroyed) {
			self.y = columns[self.index].y;
			self.lightContainer.x = self.x + self.parent.x;
			self.lightContainer.y = self.y + self.parent.y;
		}
		if (self.toLight && self.row.y >= LIGHT_LEVEL + BLOCK_SCALE * BLOCK_HALFSIZE) {
			self.toLight = false;
			self.onLit();
		}
	};
	self.down = function () {
		self.rotate();
		tween(self.scale, {
			x: 0.9 * BLOCK_SCALE,
			y: 0.9 * BLOCK_SCALE
		}, {
			duration: BLOCK_ROTATE_SPEED / 2,
			onFinish: function onFinish() {
				tween(self.scale, {
					x: BLOCK_SCALE,
					y: BLOCK_SCALE
				}, {
					duration: BLOCK_ROTATE_SPEED / 2
				});
			}
		});
	};
	self.onLit = function (pointless) {
		if (self.row.y < LIGHT_LEVEL + BLOCK_SCALE * BLOCK_HALFSIZE) {
			self.toLight = true;
		} else if (!self.lit && !self.destroyed && (self.upPath || self.downPath || self.leftPath || self.rightPath)) {
			self.lit = true;
			self.lightContainer.removeChildren();
			self.lightContainer.attachAsset('shapeEllipse', {
				width: BLOCK_SIZE - 2 * LIGHT_OFFSET,
				height: BLOCK_SIZE - 2 * LIGHT_OFFSET,
				anchorX: 0.5,
				anchorY: 0.5
			});
			if (self.upPath && (!self.upBlock || !self.upBlock.lit || !self.upBlock.downPath)) {
				makeGlow(0, -BLOCK_SIZE / 2 - BLOCK_MARGIN / 4);
			}
			if (self.rightPath && (!self.rightBlock || !self.rightBlock.lit || !self.rightBlock.leftPath)) {
				makeGlow(BLOCK_SIZE / 2 + BLOCK_MARGIN / 4, 0);
			}
			if (self.downPath && (!self.downBlock || !self.downBlock.lit || !self.downBlock.upPath)) {
				makeGlow(0, BLOCK_SIZE / 2 + BLOCK_MARGIN / 4);
			}
			if (self.leftPath && (!self.leftBlock || !self.leftBlock.lit || !self.leftBlock.rightPath)) {
				makeGlow(-BLOCK_SIZE / 2 - BLOCK_MARGIN / 4, 0);
			}
			if (!pointless) {
				LK.setScore(LK.getScore() + 1);
				scoreText.setText(LK.getScore());
				game.addChild(new BlockLitParticle({
					// Create a BlockLitParticle
					x: self.x + self.parent.x,
					y: self.y + self.parent.y,
					scale: BLOCK_SCALE
				}));
				game.addChild(new PointText({
					x: self.x + self.parent.x,
					y: self.y + self.parent.y
				}));
			}
			lightSources += 1;
			LK.getSound('light').play();
			self.onSettle();
		}
	};
	self.onSettle = function () {
		self.updatePaths();
		if (!self.disabled) {
			var litRotationFactor = self.lit ? 0 : 1;
			var litPositionFactor = self.lit ? 1 : -1;
			[{
				direction: 'up',
				rotation: 0,
				y: 1
			}, {
				direction: 'right',
				rotation: 0.5,
				x: -1
			}, {
				direction: 'down',
				rotation: 1,
				y: -1
			}, {
				direction: 'left',
				rotation: 1.5,
				x: 1
			}].forEach(function (item) {
				if (self[item.direction + 'Path']) {
					var block = self[item.direction + 'Block'];
					if (block && !block.disabled && block.lit !== self.lit && block[COMPLIMENTS[item.direction] + 'Path']) {
						(self.lit ? block : self).lightContainer.addChild(new Light({
							x: (item.x || 0) * litPositionFactor * BLOCK_HALFSIZE,
							y: (item.y || 0) * litPositionFactor * BLOCK_HALFSIZE,
							rotation: Math.PI * (item.rotation + litRotationFactor),
							callback: self.lit ? block.onLit : self.onLit
						}));
					}
				}
			});
		}
	};
	self.showLock = function () {
		// Check and destroy existing lockSymbol before creating a new one
		if (self.lockSymbol) {
			self.lockSymbol.destroy();
		}
		var lockSymbol = self.addChild(LK.getAsset('iconLock', {
			anchorX: 0.5,
			anchorY: 0.5,
			scaleX: 1 / self.scale.x,
			scaleY: 1 / self.scale.y
		}));
		// Play error sound if not already playing
		if (!errorSoundPlaying) {
			errorSoundPlaying = true;
			LK.getSound('error').play();
			LK.setTimeout(function () {
				errorSoundPlaying = false;
			}, 500);
		}
		self.lockSymbol = lockSymbol;
		// Set a timeout to fade out the lockSymbol after 500ms
		LK.setTimeout(function () {
			tween(lockSymbol, {
				alpha: 0
			}, {
				duration: 500,
				onFinish: function onFinish() {
					lockSymbol.destroy();
					self.lockSymbol = null;
				}
			});
		}, 500);
	};
	self.updatePaths = function () {};
	function makeGlow(x, y) {
		var glow = self.lightContainer.addChild(new Glow({
			x: x,
			y: y,
			width: LIGHT_SPILL_SIZE,
			height: LIGHT_SPILL_SIZE,
			anchorX: 0.5,
			anchorY: 0.5,
			rangeX: 20,
			rangeY: 20,
			layers: 4,
			solid: true,
			tint: 0xFFFFFF,
			alpha: 0
		}));
		tween(glow, {
			alpha: 1
		}, {
			duration: 250
		});
	}
	self.onDestroy = function () {
		if (self.lit) {
			lightSources -= 1;
			if (lightSources === 0) {
				LK.getSound('gong').play(); // Play the gong sound
				var gameOverText = game.addChild(new BorderedText("- Your Light is Dead -", {
					size: 150,
					anchorX: 0.5,
					anchorY: 0.5,
					x: game.width / 2,
					y: game.height / 4
				}));
				LK.stopMusic(); // Stop the background music when the game ends
				LK.setTimeout(function () {
					// Delay the game over widget by 1 second
					LK.showGameOver();
				}, 1000);
			}
		}
		if (self.lightContainer) {
			self.lightContainer.destroy();
		}
	};
	return self;
});
var BlockX = Block.expand(function (config) {
	var self = Block.call(this, config);
	var shiftY = 2;
	self.upPath = true;
	self.rightPath = true;
	self.downPath = true;
	self.leftPath = true;
	self.blockContainer.attachAsset('blockX1', {
		x: -BLOCK_HALFSIZE,
		y: -BLOCK_HALFSIZE + shiftY,
		anchorX: 0,
		anchorY: 0
	});
	self.blockContainer.attachAsset('blockX2', {
		x: BLOCK_HALFSIZE,
		y: -BLOCK_HALFSIZE + shiftY,
		anchorX: 1,
		anchorY: 0
	});
	self.blockContainer.attachAsset('blockX3', {
		x: -BLOCK_HALFSIZE,
		y: BLOCK_HALFSIZE + shiftY,
		anchorX: 0,
		anchorY: 1
	});
	self.blockContainer.attachAsset('blockX4', {
		x: BLOCK_HALFSIZE,
		y: BLOCK_HALFSIZE + shiftY,
		anchorX: 1,
		anchorY: 1
	});
	return self;
});
var BlockT = Block.expand(function (config) {
	var self = Block.call(this, config);
	self.blockContainer.attachAsset('blockT1', {
		x: -BLOCK_HALFSIZE,
		y: -BLOCK_HALFSIZE,
		anchorX: 0,
		anchorY: 0
	});
	self.blockContainer.attachAsset('blockT2', {
		x: BLOCK_HALFSIZE,
		y: -BLOCK_HALFSIZE,
		anchorX: 1,
		anchorY: 0
	});
	self.blockContainer.attachAsset('blockT3', {
		y: BLOCK_HALFSIZE,
		anchorX: 0.5,
		anchorY: 1
	});
	self.updatePaths = function () {
		self.downPath = self.orientation !== 0;
		self.leftPath = self.orientation !== 1;
		self.upPath = self.orientation !== 2;
		self.rightPath = self.orientation !== 3;
	};
	self.updatePaths();
	return self;
});
var BlockLine = Block.expand(function (config) {
	var self = Block.call(this, config);
	self.blockContainer.attachAsset('blockLine1', {
		x: -BLOCK_HALFSIZE,
		anchorX: 0,
		anchorY: 0.5,
		height: BLOCK_SIZE
	});
	self.blockContainer.attachAsset('blockLine2', {
		x: BLOCK_HALFSIZE,
		anchorX: 1,
		anchorY: 0.5,
		height: BLOCK_SIZE
	});
	self.updatePaths = function () {
		var vertical = !(self.orientation % 2);
		self.upPath = vertical;
		self.downPath = vertical;
		self.leftPath = !vertical;
		self.rightPath = !vertical;
	};
	self.updatePaths();
	return self;
});
var BlockL = Block.expand(function (config) {
	var self = Block.call(this, config);
	self.blockContainer.attachAsset('blockL1', {
		anchorX: 0.5,
		anchorY: 0.5,
		height: BLOCK_SIZE
	});
	self.blockContainer.attachAsset('blockL2', {
		x: -BLOCK_HALFSIZE,
		y: BLOCK_HALFSIZE,
		anchorX: 0,
		anchorY: 1
	});
	self.updatePaths = function () {
		self.leftPath = self.orientation === 0 || self.orientation === 1;
		self.upPath = self.orientation === 1 || self.orientation === 2;
		self.rightPath = self.orientation === 2 || self.orientation === 3;
		self.downPath = self.orientation === 3 || self.orientation === 0;
	};
	self.updatePaths();
	return self;
});
var BlockBlank = Block.expand(function (config) {
	var self = Block.call(this, config);
	var crackAsset;
	var crackLevel = 0;
	var blockBlankAssets = ['blockBlank1', 'blockBlank2', 'blockBlank3'];
	var randomAsset = blockBlankAssets[Math.floor(Math.random() * blockBlankAssets.length)];
	self.blockContainer.attachAsset(randomAsset, {
		anchorX: 0.5,
		anchorY: 0.5,
		width: BLOCK_SIZE,
		height: BLOCK_SIZE
	});
	self.rotate = function (force) {
		if (force || crackLevel > 0) {
			if (++crackLevel <= 4) {
				if (crackAsset) {
					crackAsset.destroy();
				}
				if (!force) {
					LK.getSound('crack').play();
				}
				crackAsset = self.blockContainer.attachAsset('crack' + crackLevel, {
					anchorX: 0.5,
					anchorY: 0.5,
					rotation: crackLevel === 1 ? Math.random() * Math.PI * 2 : 0 // Random rotation if crackLevel is 1
				});
				// Create BlockSparkParticles
				if (self.parent) {
					for (var i = 0; i < 2 * crackLevel; i++) {
						game.addChild(new BlockSparkParticle({
							x: self.x + self.parent.x,
							y: self.y + self.parent.y
						}));
					}
				}
			} else {
				LK.getSound('break').play();
				var blockClass = randomizeBlockClass({
					index: self.row.index,
					blanks: ROW_SPAN // Prevent spawning blocks
				});
				var newBlock = self.parent.addChild(new blockClass({
					x: self.x,
					y: self.y,
					scale: BLOCK_SCALE,
					index: self.index,
					row: self.row
				}));
				self.row.blocks[self.index] = newBlock;
				// Update block references 
				if (self.upBlock) {
					self.upBlock.downBlock = newBlock;
					newBlock.upBlock = self.upBlock;
				}
				if (self.downBlock) {
					self.downBlock.upBlock = newBlock;
					newBlock.downBlock = self.downBlock;
				}
				if (self.leftBlock) {
					self.leftBlock.rightBlock = newBlock;
					newBlock.leftBlock = self.leftBlock;
				}
				if (self.rightBlock) {
					self.rightBlock.leftBlock = newBlock;
					newBlock.rightBlock = self.rightBlock;
				}
				if (!self.disabled) {
					newBlock.onSettle();
				}
				// Create BlockBreakParticles
				for (var i = 0; i < 6; i++) {
					game.addChild(new BlockBreakParticle({
						x: self.x + self.parent.x,
						y: self.y + self.parent.y
					}));
				}
				self.callDestroy();
			}
		} else {
			self.showLock();
		}
	};
	if (Math.random() < BLOCK_CRACK_CHANCE) {
		self.rotate(true);
	}
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x000000
});
/**** 
* Game Code
****/ 
// Math constants / pre-calculations
var MATH_HALF_ROOT_3 = Math.sqrt(3) / 2; // Required by: TEXT_OFFSETS, BorderedText, BorderedSymbol, SymbolText
;
// Text settings
var TEXT_OFFSETS = [[0, 1], [MATH_HALF_ROOT_3, 0.5], [MATH_HALF_ROOT_3, -0.5], [0, -1], [-MATH_HALF_ROOT_3, -0.5], [-MATH_HALF_ROOT_3, 0.5], [0, 0]]; // Required by: BorderedText, BorderedSymbol, SymbolText
var TEXT_BORDER_WEIGHT = 5; // Required by: BorderedText, BorderedSymbol, SymbolText
var TEXT_DEFAULT_BORDER = '#000000'; // Required by: BorderedText, BorderedSymbol, SymbolText
var TEXT_DEFAULT_FILL = '#FFFFFF'; // Required by: BorderedText, SymbolText
var TEXT_DEFAULT_FONT = 'Arial'; // Required by: BorderedText, SymbolText
var TEXT_DEFAULT_SIZE = 50; // Required by: BorderedText, SymbolText
;
// Other settings
var LAVA_LINE = game.height - 200;
var LAVA_SLICE_COUNT = 18;
var LAVA_SLICE_WIDTH = 128;
var LAVA_BOB_HEIGHT = 10;
var LAVA_BOB_OFFSET = Math.PI / 5;
var LAVA_BOB_PERIOD = Math.PI / 60;
var BLOCK_SCALE = 2.5;
var BLOCK_SIZE = 100;
var BLOCK_MARGIN = 20;
var BLOCK_HALFSIZE = BLOCK_SIZE * 0.5;
var BLOCK_CRACK_CHANCE = 0.45;
var BLOCK_ROTATE_SPEED = 100;
var LIGHT_LEVEL = 800;
var LIGHT_GROW_SPEED = 4500;
var LIGHT_GROW_VARIANCE = 1000;
var LIGHT_SPILL_SIZE = 35;
var LIGHT_OFFSET = 5;
var ROW_SPAN = 7;
var ROW_COUNT = 11;
var ROW_SPEED_BASE = 0.2;
var ROW_SPEED_INCREASE = 0.04;
var ROW_SPEED_INCREASE_MIN = 0.01;
var ROW_SPEED_INCREASE_FACTOR = 0.9;
var COL_SLIP_MIN = 10;
var COL_SLIP_MAX = 30;
var COL_SLIP_TIME = 750;
var COL_TIMEOUT_MIN = 1000;
var COL_TIMEOUT_MAX = 10000;
var COL_RISE_FACTOR = 0.2;
var COMPLIMENTS = {
	up: 'down',
	right: 'left',
	down: 'up',
	left: 'right'
};
var lightSources = 0;
var rowSpeed = ROW_SPEED_BASE;
var rowSpeedIncrease = ROW_SPEED_INCREASE;
var errorSoundPlaying = false;
var columns = [];
for (var i = 0; i < ROW_SPAN; i++) {
	columns.push({
		y: 0,
		timer: false,
		index: i
	});
}
// Play background music on repeat when the game starts
LK.playMusic('background', {
	loop: true
});
game.update = function () {
	for (var i = 1; i < columns.length - 1; i++) {
		var column = columns[i];
		if (!column.timer) {
			if (column.y > 0) {
				column.y = Math.max(0, column.y - rowSpeed * COL_RISE_FACTOR);
			} else {
				startColumnTimer(i);
			}
		}
	}
};
var scoreText = new BorderedText('0', {
	size: 100,
	anchorX: 0.5,
	anchorY: 0
});
LK.gui.top.addChild(scoreText);
var rowSpeedText = LK.gui.topRight.addChild(new Text2((rowSpeed * 60).toFixed(1), {
	size: 50,
	fill: 0xFFFFFF,
	stroke: 0x000000,
	strokeThickness: 5
}));
rowSpeedText.anchor.set(1.0, -0.5);
var speedIcon = LK.gui.topRight.addChild(LK.getAsset('iconGear', {
	anchorX: 0.5,
	anchorY: 0.5,
	x: rowSpeedText.x - rowSpeedText.width - 40,
	y: rowSpeedText.height
}));
var iconRotate = LK.gui.topRight.addChild(new BorderedSymbol('iconRotate', {
	anchorX: 0.2,
	anchorY: 1.0,
	x: speedIcon.x,
	y: speedIcon.y
}));
var lightManager = game.addChild(new Container());
game.addChild(new Glow({
	width: game.width,
	height: LIGHT_LEVEL,
	rangeY: 20,
	layers: 5,
	solid: true
}));
var blockManager = game.addChild(new BlockManager());
var leftBorder = game.addChild(new Border({
	x: 30
}));
var rightBorder = game.addChild(new Border({
	x: game.width - 30,
	scaleX: -1
}));
var lava = game.addChild(new Lava({
	x: game.width / 2,
	y: LAVA_LINE
}));
game.addChild(new Glow({
	x: game.width / 2,
	width: game.width,
	height: 200,
	anchorX: 0.5,
	anchorY: 0,
	rangeY: 200,
	tint: 0x000000,
	alpha: 2.0
}));
var iconLight = game.addChild(LK.getAsset('iconLight', {
	x: game.width / 2,
	y: 100,
	anchorX: 0.5,
	anchorY: 0.5,
	tint: 0xFF4D00
}));
function shuffle(array) {
	var currentIndex = array.length;
	while (currentIndex != 0) {
		var randomIndex = Math.floor(Math.random() * currentIndex);
		currentIndex--;
		var ref = [array[randomIndex], array[currentIndex]];
		array[currentIndex] = ref[0];
		array[randomIndex] = ref[1];
	}
	return array;
}
function generateBlockClasses(index) {
	var settings = {
		index: index,
		blanks: 0,
		xs: 0
	};
	switch (index) {
		case 0:
			return [BlockBlank, BlockBlank, BlockBlank, BlockX, BlockBlank, BlockBlank, BlockBlank];
		case 1:
			settings.blanks = ROW_SPAN;
			settings.xs = 1;
			return [BlockBlank, BlockBlank, randomizeBlockClass(settings), BlockX, randomizeBlockClass(settings), BlockBlank, BlockBlank];
		case 2:
			settings.blanks = ROW_SPAN;
			settings.xs = 1;
			return [BlockBlank, randomizeBlockClass(settings), randomizeBlockClass(settings), BlockX, randomizeBlockClass(settings), randomizeBlockClass(settings), BlockBlank];
		default:
			var blockClasses = [];
			for (var i = 0; i < ROW_SPAN; i++) {
				blockClasses[i] = randomizeBlockClass(settings);
			}
			return shuffle(blockClasses);
	}
}
function adjustRowSpeed() {
	rowSpeed += rowSpeedIncrease;
	rowSpeedText.setText((rowSpeed * 60).toFixed(1));
	rowSpeedIncrease = Math.max(ROW_SPEED_INCREASE_MIN, rowSpeedIncrease * ROW_SPEED_INCREASE_FACTOR);
}
function startColumnTimer(index) {
	var column = columns[index];
	column.timer = true;
	var timeoutDuration = COL_TIMEOUT_MIN + Math.random() * (COL_TIMEOUT_MAX - COL_TIMEOUT_MIN);
	LK.setTimeout(function () {
		var targetY = COL_SLIP_MIN + Math.random() * (COL_SLIP_MAX - COL_SLIP_MIN);
		tween(column, {
			y: targetY
		}, {
			duration: COL_SLIP_TIME,
			easing: tween.easeIn,
			// Apply ease in for the tween
			onFinish: function onFinish() {
				column.timer = false; // Reset the timer to false after tween completes
			}
		});
	}, timeoutDuration);
}
function randomizeBlockClass(settings) {
	var classes = [{
		blockClass: BlockBlank,
		chance: Math.max(0, 1.5 - 0.5 * (settings.blanks || 0))
	}, {
		blockClass: BlockT,
		chance: 1
	}, {
		blockClass: BlockX,
		chance: Math.max(0, 1 - 1 * (settings.xs || 0))
	}, {
		blockClass: BlockLine,
		chance: 1
	}, {
		blockClass: BlockL,
		chance: 1
	}];
	var totalChance = classes.reduce(function (sum, item) {
		return sum + item.chance;
	}, 0);
	var randomValue = Math.random() * totalChance;
	var accumulatedChance = 0;
	var blockClass = BlockBlank;
	for (var i = 0; i < classes.length; i++) {
		accumulatedChance += classes[i].chance;
		if (randomValue < accumulatedChance) {
			blockClass = classes[i].blockClass;
			break;
		}
	}
	switch (blockClass) {
		case BlockBlank:
			settings.blanks = (settings.blanks || 0) + 1;
			break;
		case BlockX:
			settings.xs = (settings.xs || 0) + 1;
			break;
	}
	return blockClass;
}