/**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
/**** 
* Classes
****/ 
// BearObstacle class (spawns bear image)
var BearObstacle = Container.expand(function () {
	var self = Container.call(this);
	var bear = self.attachAsset('bear', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.radius = bear.width * 0.45;
	self.speed = 0; // Set by game
	// Walking animation: scaleX alternates to simulate walking
	function startBearWalkAnim() {
		// Reset scale
		bear.scaleX = 1;
		// Animate scaleX to 0.85 and back to 1.15, then repeat
		tween(bear, {
			scaleX: 0.85
		}, {
			duration: 120,
			easing: tween.linear,
			onFinish: function onFinish() {
				tween(bear, {
					scaleX: 1.15
				}, {
					duration: 120,
					easing: tween.linear,
					onFinish: startBearWalkAnim
				});
			}
		});
	}
	startBearWalkAnim();
	return self;
});
// Obstacle class (tree or rock)
var Obstacle = Container.expand(function () {
	var self = Container.call(this);
	self.type = Math.random() < 0.6 ? 'tree' : 'rock';
	var assetId = self.type === 'tree' ? 'tree' : 'rock';
	var obs = self.attachAsset(assetId, {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.radius = obs.width * 0.45;
	self.speed = 0; // Set by game
	return self;
});
// Powerup class (shield, boost, or coin)
var Powerup = Container.expand(function () {
	var self = Container.call(this);
	// Set powerup type with reduced shield probability
	var rand = Math.random();
	if (rand < 0.02) {
		// 2% chance for shield (further reduced)
		self.kind = 'shield';
	} else if (rand < 0.15) {
		// 10% chance for boost (reduced)
		self.kind = 'boost';
	} else {
		self.kind = 'coin'; // Default to coin instead of shield
	}
	// Handle coin type if set externally
	if (self.kind === 'coin') {
		self.kind = 'coin';
	}
	var assetId = self.kind === 'coin' ? 'coin' : self.kind === 'shield' ? 'shield' : 'boost';
	var pu = self.attachAsset(assetId, {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.radius = pu.width * 0.45;
	self.speed = 0; // Set by game
	return self;
});
// Rock2Obstacle class (spawns rock2 image)
var Rock2Obstacle = Container.expand(function () {
	var self = Container.call(this);
	var obs = self.attachAsset('rock2', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.radius = obs.width * 0.45;
	self.speed = 0; // Set by game
	return self;
});
// Snowboarder (player) class
var Snowboarder = Container.expand(function () {
	var self = Container.call(this);
	var sb = self.attachAsset('snowboarder', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.radius = sb.width * 0.45; // For collision
	self.hasShield = false;
	self.shieldNode = null;
	// Show shield visual if active
	self.setShield = function (active) {
		self.hasShield = active;
		if (active && !self.shieldNode) {
			self.shieldNode = self.attachAsset('shield', {
				anchorX: 0.5,
				anchorY: 0.5,
				scaleX: 1.3,
				scaleY: 1.3,
				alpha: 0.5
			});
		} else if (!active && self.shieldNode) {
			self.shieldNode.destroy();
			self.shieldNode = null;
		}
	};
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0xffffff // White for snow
});
/**** 
* Game Code
****/ 
// Game constants
// Snowboarder (player)
// Tree obstacle
// Rock obstacle
// Shield powerup
// Speed boost powerup
var GAME_WIDTH = 2048;
var GAME_HEIGHT = 2732;
var PLAY_AREA_MARGIN = 60; // px, left/right margin for obstacles (reduced for denser spread)
var OBSTACLE_MIN_Y_DIST = 320; // Minimum vertical distance between obstacles (denser)
var OBSTACLE_MAX_Y_DIST = 540; // Maximum vertical distance between obstacles (denser)
var OBSTACLE_MIN_X = PLAY_AREA_MARGIN;
var OBSTACLE_MAX_X = GAME_WIDTH - PLAY_AREA_MARGIN;
var POWERUP_CHANCE = 0.12; // Chance to spawn a powerup instead of obstacle
// Intensity increase after 1000 points
var INTENSITY_SCORE_THRESHOLD = 1000;
var INTENSE_OBSTACLE_MIN_Y_DIST = 160; // Denser in intense mode
var INTENSE_OBSTACLE_MAX_Y_DIST = 320;
var INTENSE_POWERUP_CHANCE = 0.16;
// Game state
var snowboarder;
var obstacles = [];
var powerups = [];
var dragNode = null;
var dragOffsetX = 0;
var dragStartX = 0;
var dragStartSnowboarderX = 0;
var lastObstacleY = 0;
var speed = 18; // Initial speed (pixels per frame)
var maxSpeed = 48;
var speedIncreaseEvery = 600; // Increase speed every N ticks
var ticksSinceStart = 0;
var distance = 0; // Distance traveled (score)
var scoreTxt;
var shieldTimer = 0;
var boostTimer = 0;
var isBoosting = false;
// Add tree images to both sides of the screen as static background elements
var leftTrees = [];
var rightTrees = [];
var treeSpacingY = 320 * 0.95; // Increase tree intensity by reducing spacing by 5%
var treeY = 0;
while (treeY < GAME_HEIGHT + 200) {
	// Left side
	var leftTree = LK.getAsset('tree', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: PLAY_AREA_MARGIN / 2,
		y: treeY
	});
	game.addChild(leftTree);
	leftTrees.push(leftTree);
	// Right side
	var rightTree = LK.getAsset('tree', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: GAME_WIDTH - PLAY_AREA_MARGIN / 2,
		y: treeY
	});
	game.addChild(rightTree);
	rightTrees.push(rightTree);
	treeY += treeSpacingY;
}
// GUI: Score
scoreTxt = new Text2('0', {
	size: 120,
	fill: "#222"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// GUI: Lives
var lives = 3;
var livesTxt = new Text2('❤❤❤', {
	size: 100,
	fill: "#d22"
});
// Anchor to right edge, top (anchorX: 1, anchorY: 0)
livesTxt.anchor.set(1, 0);
// Add to top right of GUI
LK.gui.topRight.addChild(livesTxt);
// GUI: Shield Timer
var shieldTimerTxt = new Text2('', {
	size: 80,
	fill: 0x00AAFF
});
// Anchor to right edge, bottom (anchorX: 1, anchorY: 1)
shieldTimerTxt.anchor.set(1, 1);
// Add to bottom right of GUI
LK.gui.bottomRight.addChild(shieldTimerTxt);
// Initialize player
snowboarder = new Snowboarder();
game.addChild(snowboarder);
snowboarder.x = GAME_WIDTH / 2;
snowboarder.y = GAME_HEIGHT * 0.12;
// Start playing action music
LK.playMusic('actionmusic');
// Helper: Clamp value
function clamp(val, min, max) {
	return Math.max(min, Math.min(max, val));
}
// Helper: Distance between two objects
function dist(a, b) {
	var dx = a.x - b.x;
	var dy = a.y - b.y;
	return Math.sqrt(dx * dx + dy * dy);
}
// Spawn an obstacle or powerup
function spawnObstacleOrPowerup(y) {
	// Determine if intensity should be increased
	var scoreVal = Math.floor(distance / 10);
	var minYDist = OBSTACLE_MIN_Y_DIST;
	var maxYDist = OBSTACLE_MAX_Y_DIST;
	var powerupChance = POWERUP_CHANCE;
	if (scoreVal >= INTENSITY_SCORE_THRESHOLD) {
		minYDist = INTENSE_OBSTACLE_MIN_Y_DIST;
		maxYDist = INTENSE_OBSTACLE_MAX_Y_DIST;
		powerupChance = INTENSE_POWERUP_CHANCE;
	}
	if (Math.random() < 0.45) {
		// Coin (collectible for score)
		var coin = new Powerup();
		coin.kind = 'coin'; // Override to be a coin
		coin.x = Math.random() * (OBSTACLE_MAX_X - OBSTACLE_MIN_X) + OBSTACLE_MIN_X;
		coin.y = y;
		coin.speed = speed;
		powerups.push(coin);
		game.addChild(coin);
	} else if (Math.random() < powerupChance) {
		// Powerup
		var pu = new Powerup();
		pu.x = Math.random() * (OBSTACLE_MAX_X - OBSTACLE_MIN_X) + OBSTACLE_MIN_X;
		pu.y = y;
		pu.speed = speed;
		powerups.push(pu);
		game.addChild(pu);
	} else {
		// Obstacle
		var obs;
		if (scoreVal >= 1000 && Math.random() < 0.10) {
			// After 1000 points, 10% chance to spawn bear
			obs = new BearObstacle();
		} else if (scoreVal >= 500 && Math.random() < 0.33) {
			// After 500 points, 33% chance to spawn rock2
			obs = new Rock2Obstacle();
		} else {
			obs = new Obstacle();
		}
		obs.x = Math.random() * (OBSTACLE_MAX_X - OBSTACLE_MIN_X) + OBSTACLE_MIN_X;
		obs.y = y;
		obs.speed = speed;
		obstacles.push(obs);
		game.addChild(obs);
	}
}
// Initial obstacles
lastObstacleY = snowboarder.y - 600;
for (var i = 0; i < 6; i++) {
	lastObstacleY -= Math.random() * (OBSTACLE_MAX_Y_DIST - OBSTACLE_MIN_Y_DIST) + OBSTACLE_MIN_Y_DIST;
	spawnObstacleOrPowerup(lastObstacleY);
}
// Touch/drag controls
game.down = function (x, y, obj) {
	// Only allow drag if touch is on lower 2/3 of screen (to avoid top menu)
	if (y > GAME_HEIGHT * 0.2) {
		dragNode = snowboarder;
		dragStartX = x;
		dragStartSnowboarderX = snowboarder.x;
	}
};
game.move = function (x, y, obj) {
	if (dragNode === snowboarder) {
		var dx = x - dragStartX;
		var newX = clamp(dragStartSnowboarderX + dx, OBSTACLE_MIN_X, OBSTACLE_MAX_X);
		snowboarder.x = newX;
		// Play boarding sound when moving
		if (Math.abs(dx) > 5) {
			LK.getSound('Boarding').play();
		}
		// Rotate snowboarder to face movement direction
		if (Math.abs(dx) > 8) {
			// Limit max angle to 30 degrees (PI/6)
			var maxAngle = Math.PI / 6;
			var angle = clamp(dx / 400, -1, 1) * maxAngle;
			snowboarder.rotation = angle;
		} else {
			snowboarder.rotation = 0;
		}
	}
};
game.up = function (x, y, obj) {
	dragNode = null;
	if (snowboarder) snowboarder.rotation = 0;
};
// Main game loop
game.update = function () {
	ticksSinceStart++;
	// Increase speed over time
	if (ticksSinceStart % speedIncreaseEvery === 0 && speed < maxSpeed) {
		speed += 2;
	}
	// Speed scaling: increase by 20% every 100 points
	var currentScore = LK.getScore();
	if (currentScore >= 100) {
		// Number of 100-point steps
		var speedSteps = Math.floor(currentScore / 100);
		var scaledSpeed = speed * Math.pow(1.2, speedSteps);
		// Apply the scaled speed but don't modify the base speed variable
		// Use currentSpeed calculation below instead
		var gameSpeed = scaledSpeed;
	} else {
		var gameSpeed = speed;
	}
	// If boosting, increase speed temporarily
	var currentSpeed = isBoosting ? gameSpeed * 1.7 : gameSpeed;
	// Move side trees up (reverse flow)
	for (var i = 0; i < leftTrees.length; i++) {
		leftTrees[i].y -= currentSpeed;
		// If tree goes off top, move it to bottom
		if (leftTrees[i].y < -200) {
			leftTrees[i].y += treeSpacingY * leftTrees.length;
		}
	}
	for (var i = 0; i < rightTrees.length; i++) {
		rightTrees[i].y -= currentSpeed;
		if (rightTrees[i].y < -200) {
			rightTrees[i].y += treeSpacingY * rightTrees.length;
		}
	}
	// Move obstacles and powerups up (reverse flow)
	for (var i = obstacles.length - 1; i >= 0; i--) {
		var obs = obstacles[i];
		obs.y -= currentSpeed;
		obs.speed = currentSpeed;
		// If this is a BearObstacle, move it left to right
		if (obs instanceof BearObstacle) {
			// Initialize direction and lastX if not set
			if (typeof obs.bearDirection === "undefined") {
				obs.bearDirection = 1; // 1 = right, -1 = left
			}
			if (typeof obs.lastX === "undefined") {
				obs.lastX = obs.x;
			}
			// Move bear horizontally
			var bearSpeedX = 12; // px per frame, adjust for desired speed
			obs.x += obs.bearDirection * bearSpeedX;
			// Bounce at screen edges
			if (obs.x > OBSTACLE_MAX_X && obs.bearDirection > 0 || obs.x < OBSTACLE_MIN_X && obs.bearDirection < 0) {
				obs.bearDirection *= -1;
				// Clamp to edge
				obs.x = clamp(obs.x, OBSTACLE_MIN_X, OBSTACLE_MAX_X);
			}
			obs.lastX = obs.x;
		}
		// Remove if off screen (now above screen)
		if (obs.y + obs.height / 2 < -100) {
			obs.destroy();
			obstacles.splice(i, 1);
		}
	}
	for (var i = powerups.length - 1; i >= 0; i--) {
		var pu = powerups[i];
		pu.y -= currentSpeed;
		pu.speed = currentSpeed;
		// Remove if off screen (now above screen)
		if (pu.y + pu.height / 2 < -100) {
			pu.destroy();
			powerups.splice(i, 1);
		}
	}
	// Continuously spawn obstacles and powerups as the player progresses (now below player)
	while (lastObstacleY < snowboarder.y + 3000) {
		// Use more intense spawn distances after threshold
		var scoreVal = Math.floor(distance / 10);
		var minYDist = OBSTACLE_MIN_Y_DIST;
		var maxYDist = OBSTACLE_MAX_Y_DIST;
		if (scoreVal >= INTENSITY_SCORE_THRESHOLD) {
			minYDist = INTENSE_OBSTACLE_MIN_Y_DIST;
			maxYDist = INTENSE_OBSTACLE_MAX_Y_DIST;
		}
		lastObstacleY += Math.random() * (maxYDist - minYDist) + minYDist;
		spawnObstacleOrPowerup(lastObstacleY);
	}
	// Obstacles and powerups keep coming endlessly as the player progresses
	// Always ensure obstacles continue to spawn all game, even if the player is not moving
	if (obstacles.length < 8) {
		// If for any reason there are too few obstacles, spawn more to keep the game challenging
		var scoreVal = Math.floor(distance / 10);
		var minYDist = OBSTACLE_MIN_Y_DIST;
		var maxYDist = OBSTACLE_MAX_Y_DIST;
		if (scoreVal >= INTENSITY_SCORE_THRESHOLD) {
			minYDist = INTENSE_OBSTACLE_MIN_Y_DIST;
			maxYDist = INTENSE_OBSTACLE_MAX_Y_DIST;
		}
		lastObstacleY += Math.random() * (maxYDist - minYDist) + minYDist;
		spawnObstacleOrPowerup(lastObstacleY);
	}
	// Collision: obstacles
	var scoreVal = Math.floor(distance / 10);
	// Track if snowboarder was colliding with any obstacle last frame
	if (typeof snowboarder.lastWasHit === "undefined") snowboarder.lastWasHit = false;
	var hitThisFrame = false;
	for (var i = 0; i < obstacles.length; i++) {
		var obs = obstacles[i];
		if (dist(snowboarder, obs) < snowboarder.radius + obs.radius) {
			if (scoreVal < 200) {
				// Protect from collision in first 200 points: ignore collision
				// Optionally, flash snowboarder to indicate invulnerability
				LK.effects.flashObject(snowboarder, 0x66ffcc, 300);
			} else if (snowboarder.hasShield) {
				// Shield protects against ALL obstacles - no damage taken, just flash
				LK.effects.flashObject(snowboarder, 0xffe066, 600);
				// Play appropriate sound even when shielded to give feedback
				for (var j = 0; j < obstacles.length; j++) {
					var shieldObs = obstacles[j];
					if (dist(snowboarder, shieldObs) < snowboarder.radius + shieldObs.radius) {
						if (shieldObs instanceof BearObstacle) {
							LK.getSound('hitbear').play(); // Use bear sound for bear when shielded
						} else if (shieldObs.type === 'tree') {
							LK.getSound('hittree').play();
						} else {
							LK.getSound('hitrock').play();
						}
						break;
					}
				}
			} else {
				hitThisFrame = true;
			}
			// Only check first collision for life loss
			break;
		}
	}
	// Only deduct a life if we were not hit last frame and are hit this frame
	if (!snowboarder.lastWasHit && hitThisFrame) {
		// Play appropriate sound based on obstacle type
		for (var j = 0; j < obstacles.length; j++) {
			var obs = obstacles[j];
			if (dist(snowboarder, obs) < snowboarder.radius + obs.radius) {
				if (obs instanceof BearObstacle) {
					LK.getSound('hitbear').play(); // Use bear sound for bear collision
				} else if (obs.type === 'tree') {
					LK.getSound('hittree').play();
				} else {
					LK.getSound('hitrock').play();
				}
				break;
			}
		}
		lives -= 1;
		// Clamp lives to minimum 0
		if (lives < 0) lives = 0;
		// Update lives display
		var heartStr = '';
		for (var i = 0; i < lives; i++) heartStr += '❤';
		livesTxt.setText(heartStr);
		LK.effects.flashScreen(0xff0000, 900);
		if (lives <= 0) {
			LK.showGameOver();
			return;
		}
	}
	snowboarder.lastWasHit = hitThisFrame;
	// Collision: powerups
	for (var i = powerups.length - 1; i >= 0; i--) {
		var pu = powerups[i];
		if (dist(snowboarder, pu) < snowboarder.radius + pu.radius) {
			if (pu.kind === 'coin') {
				// Increase score by 10 points for coin collection
				LK.setScore(LK.getScore() + 10);
				scoreTxt.setText(LK.getScore());
				LK.effects.flashObject(snowboarder, 0xffd700, 300);
				LK.getSound('collect').play();
			} else if (pu.kind === 'shield') {
				snowboarder.setShield(true);
				shieldTimer = 600; // 10 seconds at 60fps
			} else if (pu.kind === 'boost') {
				isBoosting = true;
				boostTimer = 180; // 3 seconds at 60fps
				// Flash snowboarder red for boost
				LK.effects.flashObject(snowboarder, 0xff3b3b, 400);
				// Play speedup sound when boost is used
				LK.getSound('speedup').play();
			}
			pu.destroy();
			powerups.splice(i, 1);
		}
	}
	// Powerup timers
	if (snowboarder.hasShield) {
		shieldTimer--;
		// Update shield timer display
		var secondsLeft = Math.ceil(shieldTimer / 60);
		shieldTimerTxt.setText('🛡️ ' + secondsLeft);
		// Add pulsing animation to shield timer text
		if (shieldTimer % 30 === 0) {
			tween(shieldTimerTxt, {
				scaleX: 1.2,
				scaleY: 1.2
			}, {
				duration: 150,
				easing: tween.easeOut,
				onFinish: function onFinish() {
					tween(shieldTimerTxt, {
						scaleX: 1,
						scaleY: 1
					}, {
						duration: 150,
						easing: tween.easeIn
					});
				}
			});
		}
		if (shieldTimer <= 0) {
			snowboarder.setShield(false);
			shieldTimerTxt.setText(''); // Clear shield timer text
		}
	} else {
		shieldTimerTxt.setText(''); // Clear shield timer text when no shield
	}
	if (isBoosting) {
		boostTimer--;
		if (boostTimer <= 0) {
			isBoosting = false;
		}
	}
	// Snowboarder stays at the top; do not move snowboarder down the screen (reverse flow)
	// snowboarder.y += currentSpeed;
	// Score: only from coin collection (no distance scoring)
	distance += currentSpeed;
	var scoreVal = LK.getScore();
	// Endless game: no win condition, continues until hit
};
/* End of game code */ /**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
/**** 
* Classes
****/ 
// BearObstacle class (spawns bear image)
var BearObstacle = Container.expand(function () {
	var self = Container.call(this);
	var bear = self.attachAsset('bear', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.radius = bear.width * 0.45;
	self.speed = 0; // Set by game
	// Walking animation: scaleX alternates to simulate walking
	function startBearWalkAnim() {
		// Reset scale
		bear.scaleX = 1;
		// Animate scaleX to 0.85 and back to 1.15, then repeat
		tween(bear, {
			scaleX: 0.85
		}, {
			duration: 120,
			easing: tween.linear,
			onFinish: function onFinish() {
				tween(bear, {
					scaleX: 1.15
				}, {
					duration: 120,
					easing: tween.linear,
					onFinish: startBearWalkAnim
				});
			}
		});
	}
	startBearWalkAnim();
	return self;
});
// Obstacle class (tree or rock)
var Obstacle = Container.expand(function () {
	var self = Container.call(this);
	self.type = Math.random() < 0.6 ? 'tree' : 'rock';
	var assetId = self.type === 'tree' ? 'tree' : 'rock';
	var obs = self.attachAsset(assetId, {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.radius = obs.width * 0.45;
	self.speed = 0; // Set by game
	return self;
});
// Powerup class (shield, boost, or coin)
var Powerup = Container.expand(function () {
	var self = Container.call(this);
	// Set powerup type with reduced shield probability
	var rand = Math.random();
	if (rand < 0.02) {
		// 2% chance for shield (further reduced)
		self.kind = 'shield';
	} else if (rand < 0.15) {
		// 10% chance for boost (reduced)
		self.kind = 'boost';
	} else {
		self.kind = 'coin'; // Default to coin instead of shield
	}
	// Handle coin type if set externally
	if (self.kind === 'coin') {
		self.kind = 'coin';
	}
	var assetId = self.kind === 'coin' ? 'coin' : self.kind === 'shield' ? 'shield' : 'boost';
	var pu = self.attachAsset(assetId, {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.radius = pu.width * 0.45;
	self.speed = 0; // Set by game
	return self;
});
// Rock2Obstacle class (spawns rock2 image)
var Rock2Obstacle = Container.expand(function () {
	var self = Container.call(this);
	var obs = self.attachAsset('rock2', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.radius = obs.width * 0.45;
	self.speed = 0; // Set by game
	return self;
});
// Snowboarder (player) class
var Snowboarder = Container.expand(function () {
	var self = Container.call(this);
	var sb = self.attachAsset('snowboarder', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.radius = sb.width * 0.45; // For collision
	self.hasShield = false;
	self.shieldNode = null;
	// Show shield visual if active
	self.setShield = function (active) {
		self.hasShield = active;
		if (active && !self.shieldNode) {
			self.shieldNode = self.attachAsset('shield', {
				anchorX: 0.5,
				anchorY: 0.5,
				scaleX: 1.3,
				scaleY: 1.3,
				alpha: 0.5
			});
		} else if (!active && self.shieldNode) {
			self.shieldNode.destroy();
			self.shieldNode = null;
		}
	};
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0xffffff // White for snow
});
/**** 
* Game Code
****/ 
// Game constants
// Snowboarder (player)
// Tree obstacle
// Rock obstacle
// Shield powerup
// Speed boost powerup
var GAME_WIDTH = 2048;
var GAME_HEIGHT = 2732;
var PLAY_AREA_MARGIN = 60; // px, left/right margin for obstacles (reduced for denser spread)
var OBSTACLE_MIN_Y_DIST = 320; // Minimum vertical distance between obstacles (denser)
var OBSTACLE_MAX_Y_DIST = 540; // Maximum vertical distance between obstacles (denser)
var OBSTACLE_MIN_X = PLAY_AREA_MARGIN;
var OBSTACLE_MAX_X = GAME_WIDTH - PLAY_AREA_MARGIN;
var POWERUP_CHANCE = 0.12; // Chance to spawn a powerup instead of obstacle
// Intensity increase after 1000 points
var INTENSITY_SCORE_THRESHOLD = 1000;
var INTENSE_OBSTACLE_MIN_Y_DIST = 160; // Denser in intense mode
var INTENSE_OBSTACLE_MAX_Y_DIST = 320;
var INTENSE_POWERUP_CHANCE = 0.16;
// Game state
var snowboarder;
var obstacles = [];
var powerups = [];
var dragNode = null;
var dragOffsetX = 0;
var dragStartX = 0;
var dragStartSnowboarderX = 0;
var lastObstacleY = 0;
var speed = 18; // Initial speed (pixels per frame)
var maxSpeed = 48;
var speedIncreaseEvery = 600; // Increase speed every N ticks
var ticksSinceStart = 0;
var distance = 0; // Distance traveled (score)
var scoreTxt;
var shieldTimer = 0;
var boostTimer = 0;
var isBoosting = false;
// Add tree images to both sides of the screen as static background elements
var leftTrees = [];
var rightTrees = [];
var treeSpacingY = 320 * 0.95; // Increase tree intensity by reducing spacing by 5%
var treeY = 0;
while (treeY < GAME_HEIGHT + 200) {
	// Left side
	var leftTree = LK.getAsset('tree', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: PLAY_AREA_MARGIN / 2,
		y: treeY
	});
	game.addChild(leftTree);
	leftTrees.push(leftTree);
	// Right side
	var rightTree = LK.getAsset('tree', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: GAME_WIDTH - PLAY_AREA_MARGIN / 2,
		y: treeY
	});
	game.addChild(rightTree);
	rightTrees.push(rightTree);
	treeY += treeSpacingY;
}
// GUI: Score
scoreTxt = new Text2('0', {
	size: 120,
	fill: "#222"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// GUI: Lives
var lives = 3;
var livesTxt = new Text2('❤❤❤', {
	size: 100,
	fill: "#d22"
});
// Anchor to right edge, top (anchorX: 1, anchorY: 0)
livesTxt.anchor.set(1, 0);
// Add to top right of GUI
LK.gui.topRight.addChild(livesTxt);
// GUI: Shield Timer
var shieldTimerTxt = new Text2('', {
	size: 80,
	fill: 0x00AAFF
});
// Anchor to right edge, bottom (anchorX: 1, anchorY: 1)
shieldTimerTxt.anchor.set(1, 1);
// Add to bottom right of GUI
LK.gui.bottomRight.addChild(shieldTimerTxt);
// Initialize player
snowboarder = new Snowboarder();
game.addChild(snowboarder);
snowboarder.x = GAME_WIDTH / 2;
snowboarder.y = GAME_HEIGHT * 0.12;
// Start playing action music
LK.playMusic('actionmusic');
// Helper: Clamp value
function clamp(val, min, max) {
	return Math.max(min, Math.min(max, val));
}
// Helper: Distance between two objects
function dist(a, b) {
	var dx = a.x - b.x;
	var dy = a.y - b.y;
	return Math.sqrt(dx * dx + dy * dy);
}
// Spawn an obstacle or powerup
function spawnObstacleOrPowerup(y) {
	// Determine if intensity should be increased
	var scoreVal = Math.floor(distance / 10);
	var minYDist = OBSTACLE_MIN_Y_DIST;
	var maxYDist = OBSTACLE_MAX_Y_DIST;
	var powerupChance = POWERUP_CHANCE;
	if (scoreVal >= INTENSITY_SCORE_THRESHOLD) {
		minYDist = INTENSE_OBSTACLE_MIN_Y_DIST;
		maxYDist = INTENSE_OBSTACLE_MAX_Y_DIST;
		powerupChance = INTENSE_POWERUP_CHANCE;
	}
	if (Math.random() < 0.45) {
		// Coin (collectible for score)
		var coin = new Powerup();
		coin.kind = 'coin'; // Override to be a coin
		coin.x = Math.random() * (OBSTACLE_MAX_X - OBSTACLE_MIN_X) + OBSTACLE_MIN_X;
		coin.y = y;
		coin.speed = speed;
		powerups.push(coin);
		game.addChild(coin);
	} else if (Math.random() < powerupChance) {
		// Powerup
		var pu = new Powerup();
		pu.x = Math.random() * (OBSTACLE_MAX_X - OBSTACLE_MIN_X) + OBSTACLE_MIN_X;
		pu.y = y;
		pu.speed = speed;
		powerups.push(pu);
		game.addChild(pu);
	} else {
		// Obstacle
		var obs;
		if (scoreVal >= 1000 && Math.random() < 0.10) {
			// After 1000 points, 10% chance to spawn bear
			obs = new BearObstacle();
		} else if (scoreVal >= 500 && Math.random() < 0.33) {
			// After 500 points, 33% chance to spawn rock2
			obs = new Rock2Obstacle();
		} else {
			obs = new Obstacle();
		}
		obs.x = Math.random() * (OBSTACLE_MAX_X - OBSTACLE_MIN_X) + OBSTACLE_MIN_X;
		obs.y = y;
		obs.speed = speed;
		obstacles.push(obs);
		game.addChild(obs);
	}
}
// Initial obstacles
lastObstacleY = snowboarder.y - 600;
for (var i = 0; i < 6; i++) {
	lastObstacleY -= Math.random() * (OBSTACLE_MAX_Y_DIST - OBSTACLE_MIN_Y_DIST) + OBSTACLE_MIN_Y_DIST;
	spawnObstacleOrPowerup(lastObstacleY);
}
// Touch/drag controls
game.down = function (x, y, obj) {
	// Only allow drag if touch is on lower 2/3 of screen (to avoid top menu)
	if (y > GAME_HEIGHT * 0.2) {
		dragNode = snowboarder;
		dragStartX = x;
		dragStartSnowboarderX = snowboarder.x;
	}
};
game.move = function (x, y, obj) {
	if (dragNode === snowboarder) {
		var dx = x - dragStartX;
		var newX = clamp(dragStartSnowboarderX + dx, OBSTACLE_MIN_X, OBSTACLE_MAX_X);
		snowboarder.x = newX;
		// Play boarding sound when moving
		if (Math.abs(dx) > 5) {
			LK.getSound('Boarding').play();
		}
		// Rotate snowboarder to face movement direction
		if (Math.abs(dx) > 8) {
			// Limit max angle to 30 degrees (PI/6)
			var maxAngle = Math.PI / 6;
			var angle = clamp(dx / 400, -1, 1) * maxAngle;
			snowboarder.rotation = angle;
		} else {
			snowboarder.rotation = 0;
		}
	}
};
game.up = function (x, y, obj) {
	dragNode = null;
	if (snowboarder) snowboarder.rotation = 0;
};
// Main game loop
game.update = function () {
	ticksSinceStart++;
	// Increase speed over time
	if (ticksSinceStart % speedIncreaseEvery === 0 && speed < maxSpeed) {
		speed += 2;
	}
	// Speed scaling: increase by 20% every 100 points
	var currentScore = LK.getScore();
	if (currentScore >= 100) {
		// Number of 100-point steps
		var speedSteps = Math.floor(currentScore / 100);
		var scaledSpeed = speed * Math.pow(1.2, speedSteps);
		// Apply the scaled speed but don't modify the base speed variable
		// Use currentSpeed calculation below instead
		var gameSpeed = scaledSpeed;
	} else {
		var gameSpeed = speed;
	}
	// If boosting, increase speed temporarily
	var currentSpeed = isBoosting ? gameSpeed * 1.7 : gameSpeed;
	// Move side trees up (reverse flow)
	for (var i = 0; i < leftTrees.length; i++) {
		leftTrees[i].y -= currentSpeed;
		// If tree goes off top, move it to bottom
		if (leftTrees[i].y < -200) {
			leftTrees[i].y += treeSpacingY * leftTrees.length;
		}
	}
	for (var i = 0; i < rightTrees.length; i++) {
		rightTrees[i].y -= currentSpeed;
		if (rightTrees[i].y < -200) {
			rightTrees[i].y += treeSpacingY * rightTrees.length;
		}
	}
	// Move obstacles and powerups up (reverse flow)
	for (var i = obstacles.length - 1; i >= 0; i--) {
		var obs = obstacles[i];
		obs.y -= currentSpeed;
		obs.speed = currentSpeed;
		// If this is a BearObstacle, move it left to right
		if (obs instanceof BearObstacle) {
			// Initialize direction and lastX if not set
			if (typeof obs.bearDirection === "undefined") {
				obs.bearDirection = 1; // 1 = right, -1 = left
			}
			if (typeof obs.lastX === "undefined") {
				obs.lastX = obs.x;
			}
			// Move bear horizontally
			var bearSpeedX = 12; // px per frame, adjust for desired speed
			obs.x += obs.bearDirection * bearSpeedX;
			// Bounce at screen edges
			if (obs.x > OBSTACLE_MAX_X && obs.bearDirection > 0 || obs.x < OBSTACLE_MIN_X && obs.bearDirection < 0) {
				obs.bearDirection *= -1;
				// Clamp to edge
				obs.x = clamp(obs.x, OBSTACLE_MIN_X, OBSTACLE_MAX_X);
			}
			obs.lastX = obs.x;
		}
		// Remove if off screen (now above screen)
		if (obs.y + obs.height / 2 < -100) {
			obs.destroy();
			obstacles.splice(i, 1);
		}
	}
	for (var i = powerups.length - 1; i >= 0; i--) {
		var pu = powerups[i];
		pu.y -= currentSpeed;
		pu.speed = currentSpeed;
		// Remove if off screen (now above screen)
		if (pu.y + pu.height / 2 < -100) {
			pu.destroy();
			powerups.splice(i, 1);
		}
	}
	// Continuously spawn obstacles and powerups as the player progresses (now below player)
	while (lastObstacleY < snowboarder.y + 3000) {
		// Use more intense spawn distances after threshold
		var scoreVal = Math.floor(distance / 10);
		var minYDist = OBSTACLE_MIN_Y_DIST;
		var maxYDist = OBSTACLE_MAX_Y_DIST;
		if (scoreVal >= INTENSITY_SCORE_THRESHOLD) {
			minYDist = INTENSE_OBSTACLE_MIN_Y_DIST;
			maxYDist = INTENSE_OBSTACLE_MAX_Y_DIST;
		}
		lastObstacleY += Math.random() * (maxYDist - minYDist) + minYDist;
		spawnObstacleOrPowerup(lastObstacleY);
	}
	// Obstacles and powerups keep coming endlessly as the player progresses
	// Always ensure obstacles continue to spawn all game, even if the player is not moving
	if (obstacles.length < 8) {
		// If for any reason there are too few obstacles, spawn more to keep the game challenging
		var scoreVal = Math.floor(distance / 10);
		var minYDist = OBSTACLE_MIN_Y_DIST;
		var maxYDist = OBSTACLE_MAX_Y_DIST;
		if (scoreVal >= INTENSITY_SCORE_THRESHOLD) {
			minYDist = INTENSE_OBSTACLE_MIN_Y_DIST;
			maxYDist = INTENSE_OBSTACLE_MAX_Y_DIST;
		}
		lastObstacleY += Math.random() * (maxYDist - minYDist) + minYDist;
		spawnObstacleOrPowerup(lastObstacleY);
	}
	// Collision: obstacles
	var scoreVal = Math.floor(distance / 10);
	// Track if snowboarder was colliding with any obstacle last frame
	if (typeof snowboarder.lastWasHit === "undefined") snowboarder.lastWasHit = false;
	var hitThisFrame = false;
	for (var i = 0; i < obstacles.length; i++) {
		var obs = obstacles[i];
		if (dist(snowboarder, obs) < snowboarder.radius + obs.radius) {
			if (scoreVal < 200) {
				// Protect from collision in first 200 points: ignore collision
				// Optionally, flash snowboarder to indicate invulnerability
				LK.effects.flashObject(snowboarder, 0x66ffcc, 300);
			} else if (snowboarder.hasShield) {
				// Shield protects against ALL obstacles - no damage taken, just flash
				LK.effects.flashObject(snowboarder, 0xffe066, 600);
				// Play appropriate sound even when shielded to give feedback
				for (var j = 0; j < obstacles.length; j++) {
					var shieldObs = obstacles[j];
					if (dist(snowboarder, shieldObs) < snowboarder.radius + shieldObs.radius) {
						if (shieldObs instanceof BearObstacle) {
							LK.getSound('hitbear').play(); // Use bear sound for bear when shielded
						} else if (shieldObs.type === 'tree') {
							LK.getSound('hittree').play();
						} else {
							LK.getSound('hitrock').play();
						}
						break;
					}
				}
			} else {
				hitThisFrame = true;
			}
			// Only check first collision for life loss
			break;
		}
	}
	// Only deduct a life if we were not hit last frame and are hit this frame
	if (!snowboarder.lastWasHit && hitThisFrame) {
		// Play appropriate sound based on obstacle type
		for (var j = 0; j < obstacles.length; j++) {
			var obs = obstacles[j];
			if (dist(snowboarder, obs) < snowboarder.radius + obs.radius) {
				if (obs instanceof BearObstacle) {
					LK.getSound('hitbear').play(); // Use bear sound for bear collision
				} else if (obs.type === 'tree') {
					LK.getSound('hittree').play();
				} else {
					LK.getSound('hitrock').play();
				}
				break;
			}
		}
		lives -= 1;
		// Clamp lives to minimum 0
		if (lives < 0) lives = 0;
		// Update lives display
		var heartStr = '';
		for (var i = 0; i < lives; i++) heartStr += '❤';
		livesTxt.setText(heartStr);
		LK.effects.flashScreen(0xff0000, 900);
		if (lives <= 0) {
			LK.showGameOver();
			return;
		}
	}
	snowboarder.lastWasHit = hitThisFrame;
	// Collision: powerups
	for (var i = powerups.length - 1; i >= 0; i--) {
		var pu = powerups[i];
		if (dist(snowboarder, pu) < snowboarder.radius + pu.radius) {
			if (pu.kind === 'coin') {
				// Increase score by 10 points for coin collection
				LK.setScore(LK.getScore() + 10);
				scoreTxt.setText(LK.getScore());
				LK.effects.flashObject(snowboarder, 0xffd700, 300);
				LK.getSound('collect').play();
			} else if (pu.kind === 'shield') {
				snowboarder.setShield(true);
				shieldTimer = 600; // 10 seconds at 60fps
			} else if (pu.kind === 'boost') {
				isBoosting = true;
				boostTimer = 180; // 3 seconds at 60fps
				// Flash snowboarder red for boost
				LK.effects.flashObject(snowboarder, 0xff3b3b, 400);
				// Play speedup sound when boost is used
				LK.getSound('speedup').play();
			}
			pu.destroy();
			powerups.splice(i, 1);
		}
	}
	// Powerup timers
	if (snowboarder.hasShield) {
		shieldTimer--;
		// Update shield timer display
		var secondsLeft = Math.ceil(shieldTimer / 60);
		shieldTimerTxt.setText('🛡️ ' + secondsLeft);
		// Add pulsing animation to shield timer text
		if (shieldTimer % 30 === 0) {
			tween(shieldTimerTxt, {
				scaleX: 1.2,
				scaleY: 1.2
			}, {
				duration: 150,
				easing: tween.easeOut,
				onFinish: function onFinish() {
					tween(shieldTimerTxt, {
						scaleX: 1,
						scaleY: 1
					}, {
						duration: 150,
						easing: tween.easeIn
					});
				}
			});
		}
		if (shieldTimer <= 0) {
			snowboarder.setShield(false);
			shieldTimerTxt.setText(''); // Clear shield timer text
		}
	} else {
		shieldTimerTxt.setText(''); // Clear shield timer text when no shield
	}
	if (isBoosting) {
		boostTimer--;
		if (boostTimer <= 0) {
			isBoosting = false;
		}
	}
	// Snowboarder stays at the top; do not move snowboarder down the screen (reverse flow)
	// snowboarder.y += currentSpeed;
	// Score: only from coin collection (no distance scoring)
	distance += currentSpeed;
	var scoreVal = LK.getScore();
	// Endless game: no win condition, continues until hit
};
/* End of game code */
:quality(85)/https://cdn.frvr.ai/6838e5d89d3e8227113a3acc.png%3F3) 
 pine tree seen from above. In-Game asset. 2d. High contrast. No shadows
:quality(85)/https://cdn.frvr.ai/6838e69d9d3e8227113a3ad7.png%3F3) 
 snowboarder seen from above. In-Game asset. 2d. High contrast. No shadows
:quality(85)/https://cdn.frvr.ai/6838e7029d3e8227113a3ae2.png%3F3) 
 rock. In-Game asset. 2d. High contrast. No shadows
:quality(85)/https://cdn.frvr.ai/6838e7419d3e8227113a3af0.png%3F3) 
 grey rock. In-Game asset. 2d. High contrast. No shadows
:quality(85)/https://cdn.frvr.ai/683adaf9328f9116c505221f.png%3F3) 
 boost arrow. In-Game asset. 2d. High contrast. No shadows
:quality(85)/https://cdn.frvr.ai/683b39f9fa33db3c2930812c.png%3F3) 
 remove background
:quality(85)/https://cdn.frvr.ai/6865651ee1bcbc2e6b7264a3.png%3F3) 
 yellow gold coin. In-Game asset. 2d. High contrast. No shadows
:quality(85)/https://cdn.frvr.ai/686565f0634ced0409baf120.png%3F3) 
 make blue