/**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/**** 
* Classes
****/ 
var Badge = Container.expand(function () {
	var self = Container.call(this);
	// Create badge icon
	var badgeGraphic = self.attachAsset('scoreEffect', {
		anchorX: 0.5,
		anchorY: 0.5,
		width: 80,
		height: 80,
		tint: 0xFF0000 // Red color for badge
	});
	// Add a label to indicate what the badge does
	var labelText = self.addChild(new Text2("SPEED BOOST", {
		size: 20,
		fill: 0xFFFFFF,
		stroke: 0x000000,
		strokeThickness: 3
	}));
	labelText.anchor.set(0.5, 0.5);
	labelText.y = 60;
	// Add a timer display
	var timerText = self.addChild(new Text2("", {
		size: 24,
		fill: 0xFFFFFF,
		stroke: 0x000000,
		strokeThickness: 3
	}));
	timerText.anchor.set(0.5, 0.5);
	timerText.y = -60;
	timerText.visible = false;
	self.earned = false; // Whether badge has been earned
	self.active = false;
	self.timerSeconds = 30;
	self.pulseDirection = 1;
	self.originalScale = 1;
	self.visible = false;
	// Animation for when badge is first earned
	self.showEarned = function () {
		self.earned = true;
		self.visible = true;
		self.scale.set(0.1);
		self.alpha = 0;
		// Appear with a bounce effect
		tween(self, {
			alpha: 1,
			scaleX: 1.2,
			scaleY: 1.2
		}, {
			duration: 500,
			easing: tween.elasticOut,
			onFinish: function onFinish() {
				tween(self, {
					scaleX: 1,
					scaleY: 1
				}, {
					duration: 200
				});
			}
		});
	};
	// Activate the badge power
	self.activate = function () {
		if (self.earned && !self.active) {
			self.active = true;
			speedMultiplier = 0.5; // Slow down the road
			timerText.visible = true;
			// Visual feedback - flash effect
			LK.effects.flashScreen(0xFFD700, 300);
			// Start countdown
			self.timerSeconds = 30;
			timerText.setText(self.timerSeconds);
			// Start timer to count down and update display
			var timerInterval = LK.setInterval(function () {
				self.timerSeconds--;
				timerText.setText(self.timerSeconds);
				if (self.timerSeconds <= 0) {
					LK.clearInterval(timerInterval);
				}
			}, 1000);
			// Reset after 30 seconds
			LK.setTimeout(function () {
				speedMultiplier = 1; // Reset speed after 30 seconds
				self.active = false;
				timerText.visible = false;
				// Flash when effect ends
				LK.effects.flashScreen(0x87CEEB, 300);
			}, 30000);
		}
	};
	// Update to pulse the badge when available
	self.update = function () {
		if (self.earned && !self.active) {
			// Pulse effect when ready to use
			if (self.pulseDirection > 0) {
				self.scale.x += 0.005;
				self.scale.y += 0.005;
				if (self.scale.x >= 1.1) {
					self.pulseDirection = -1;
				}
			} else {
				self.scale.x -= 0.005;
				self.scale.y -= 0.005;
				if (self.scale.x <= 0.9) {
					self.pulseDirection = 1;
				}
			}
		} else if (self.active) {
			// Rotate slightly when active
			self.rotation += 0.01;
		}
	};
	return self;
});
var Building = Container.expand(function () {
	var self = Container.call(this);
	var buildingGraphics = self.attachAsset('building', {
		anchorX: 0.5,
		anchorY: 0
	});
	// Randomize building properties
	var shade = Math.floor(Math.random() * 40) + 40;
	buildingGraphics.tint = shade << 16 | shade << 8 | shade;
	buildingGraphics.height = Math.random() * 600 + 400;
	buildingGraphics.width = Math.random() * 100 + 100;
	// Add windows to buildings for a city look
	var windowCount = Math.floor(buildingGraphics.height / 80);
	var windowsPerRow = Math.floor(buildingGraphics.width / 40);
	for (var i = 0; i < windowCount; i++) {
		for (var j = 0; j < windowsPerRow; j++) {
			var windowLight = self.addChild(new Container());
			var windowAsset = windowLight.attachAsset('building', {
				anchorX: 0.5,
				anchorY: 0.5,
				width: 20,
				height: 30,
				tint: 0xFFFF99
			});
			windowLight.x = j * 40 - buildingGraphics.width / 2 + 25;
			windowLight.y = i * 80 + 50;
			windowLight.alpha = Math.random() > 0.3 ? 0.8 : 0;
		}
	}
	self.speed = 10; // Default speed
	self.update = function () {
		self.y += self.speed;
		// Reset building when it goes off screen
		if (self.y > 2732 + buildingGraphics.height) {
			self.y = -buildingGraphics.height;
			// Determine road boundaries to keep buildings off the road
			var road = null;
			for (var i = 0; i < game.children.length; i++) {
				if (game.children[i].asset && game.children[i].asset.id === 'road') {
					road = game.children[i];
					break;
				}
			}
			// Place building only on sidewalks
			var roadLeftEdge = road ? (2048 - road.width) / 2 : 424;
			var roadRightEdge = road ? 2048 - (2048 - road.width) / 2 : 1624;
			// Determine which side to place the building on based on its current side
			if (self.x < roadLeftEdge) {
				// Keep on left side
				self.x = Math.random() * (roadLeftEdge - buildingGraphics.width / 2);
			} else {
				// Keep on right side
				self.x = roadRightEdge + Math.random() * (roadLeftEdge - buildingGraphics.width / 2);
			}
			// Check current environment for building appearance
			if (environment && environment.current === environment.BEACH) {
				// Beach resort buildings - lighter colors, more variation
				var r = Math.floor(Math.random() * 40) + 215; // Bright beige/white
				var g = Math.floor(Math.random() * 40) + 215;
				var b = Math.floor(Math.random() * 40) + 190;
				buildingGraphics.tint = r << 16 | g << 8 | b;
				buildingGraphics.height = Math.random() * 400 + 300; // Beach buildings are shorter
				buildingGraphics.width = Math.random() * 150 + 100; // But wider
			} else if (environment && environment.current === environment.JAPAN) {
				// Traditional Japanese buildings - pagoda style
				var shade = Math.floor(Math.random() * 40) + 40; // Dark base
				// Add red tint for some buildings to simulate temples/shrines
				if (Math.random() > 0.5) {
					buildingGraphics.tint = shade + 150 << 16 | shade << 8 | shade;
					buildingGraphics.height = Math.random() * 500 + 300; // Slightly shorter
				} else {
					buildingGraphics.tint = shade << 16 | shade << 8 | shade;
					buildingGraphics.height = Math.random() * 400 + 200; // Low traditional houses
				}
				buildingGraphics.width = Math.random() * 120 + 100;
			} else {
				// Default city buildings
				var shade = Math.floor(Math.random() * 40) + 40;
				buildingGraphics.tint = shade << 16 | shade << 8 | shade;
				buildingGraphics.height = Math.random() * 600 + 400;
				buildingGraphics.width = Math.random() * 100 + 100;
			}
			// Recreate windows when building resets
			self.removeChildren(1); // Keep only the main building graphic
			var windowCount = Math.floor(buildingGraphics.height / 80);
			var windowsPerRow = Math.floor(buildingGraphics.width / 40);
			for (var i = 0; i < windowCount; i++) {
				for (var j = 0; j < windowsPerRow; j++) {
					var windowLight = self.addChild(new Container());
					var windowAsset = windowLight.attachAsset('building', {
						anchorX: 0.5,
						anchorY: 0.5,
						width: 20,
						height: 30,
						tint: 0xFFFF99
					});
					windowLight.x = j * 40 - buildingGraphics.width / 2 + 25;
					windowLight.y = i * 80 + 50;
					// Randomly light windows
					windowLight.alpha = Math.random() > 0.3 ? 0.8 : 0;
				}
			}
		}
	};
	return self;
});
var Car = Container.expand(function () {
	var self = Container.call(this);
	// Create car body - using just the car asset without additional square
	var carGraphics = self.attachAsset('car', {
		anchorX: 0.5,
		anchorY: 0.5,
		tint: 0x3366CC // Blue car color
	});
	// Add headlights
	var leftHeadlight = self.addChild(new Container());
	var leftHeadlightAsset = leftHeadlight.attachAsset('scoreEffect', {
		anchorX: 0.5,
		anchorY: 0.5,
		width: 40,
		height: 40,
		tint: 0xFFFF00
	});
	leftHeadlight.x = -60;
	leftHeadlight.y = -140;
	var rightHeadlight = self.addChild(new Container());
	var rightHeadlightAsset = rightHeadlight.attachAsset('scoreEffect', {
		anchorX: 0.5,
		anchorY: 0.5,
		width: 40,
		height: 40,
		tint: 0xFFFF00
	});
	rightHeadlight.x = 60;
	rightHeadlight.y = -140;
	// Add light reflection gradient in front of the car
	// Left headlight reflection
	var leftReflection = self.addChild(new Container());
	for (var i = 0; i < 5; i++) {
		var reflectionSegment = leftReflection.attachAsset('scoreEffect', {
			anchorX: 0.5,
			anchorY: 0.5,
			width: 30 - i * 3,
			height: 25 - i * 3,
			tint: 0xFFFF00,
			alpha: 0.4 - i * 0.07
		});
		reflectionSegment.y = -i * 15;
	}
	leftReflection.x = -60;
	leftReflection.y = -170;
	// Right headlight reflection
	var rightReflection = self.addChild(new Container());
	for (var i = 0; i < 5; i++) {
		var reflectionSegment = rightReflection.attachAsset('scoreEffect', {
			anchorX: 0.5,
			anchorY: 0.5,
			width: 30 - i * 3,
			height: 25 - i * 3,
			tint: 0xFFFF00,
			alpha: 0.4 - i * 0.07
		});
		reflectionSegment.y = -i * 15;
	}
	rightReflection.x = 60;
	rightReflection.y = -170;
	self.jumping = false;
	self.jumpHeight = 100;
	self.originalY = 0;
	self.lastY = 0; // Track last Y position for intersection detection
	self.jump = function () {
		if (self.jumping) {
			return;
		}
		self.jumping = true;
		self.originalY = self.y;
		// Play jump sound
		LK.getSound('jump').play();
		// Enhanced neon effect during jump - random bright color
		var randomNeonColor = Math.random() > 0.5 ? 0xFFFFFF : 0x00FFFF;
		// Create a glowing neon effect
		tween(carGraphics, {
			tint: randomNeonColor,
			scaleX: 1.2,
			scaleY: 1.2
		}, {
			duration: 150,
			onFinish: function onFinish() {
				// Return to current neon color after the flash
				tween(carGraphics, {
					tint: self.neonColors[self.currentColorIndex],
					scaleX: 1.0,
					scaleY: 1.0
				}, {
					duration: 450
				});
			}
		});
		// Jump animation using tween
		tween(self, {
			y: self.y - self.jumpHeight
		}, {
			duration: 300,
			easing: tween.easeOut,
			onFinish: function onFinish() {
				// Fall back down
				tween(self, {
					y: self.originalY
				}, {
					duration: 300,
					easing: tween.easeIn,
					onFinish: function onFinish() {
						self.jumping = false;
					}
				});
			}
		});
	};
	self.down = function () {
		self.jump();
	};
	// Set up neon color cycling properties
	self.neonColors = [0x3366CC,
	// Blue
	0xFF00FF,
	// Magenta
	0x00FFFF,
	// Cyan
	0x33CC33,
	// Green
	0xFF6600,
	// Orange
	0xFFFF00,
	// Yellow
	0xFF3366,
	// Pink
	0x9900FF // Purple
	];
	self.currentColorIndex = 0;
	self.colorTransitionTime = 0;
	self.colorTransitionDuration = 60; // About 1 second at 60fps - faster color cycling
	self.update = function () {
		self.lastY = self.y;
		// Create headlight glow effect
		if (LK.ticks % 5 === 0) {
			leftHeadlightAsset.alpha = 0.7 + Math.random() * 0.3;
			rightHeadlightAsset.alpha = 0.7 + Math.random() * 0.3;
			// Animate reflection gradient
			// Loop through each reflection segment container's children
			for (var i = 0; i < 5; i++) {
				if (leftReflection.children[i]) {
					leftReflection.children[i].alpha = (0.4 - i * 0.07) * (0.7 + Math.random() * 0.3);
				}
				if (rightReflection.children[i]) {
					rightReflection.children[i].alpha = (0.4 - i * 0.07) * (0.7 + Math.random() * 0.3);
				}
			}
		}
		// Update neon color effect
		self.colorTransitionTime++;
		if (self.colorTransitionTime >= self.colorTransitionDuration) {
			self.colorTransitionTime = 0;
			self.currentColorIndex = (self.currentColorIndex + 1) % self.neonColors.length;
			// Start transition to the next color
			tween(carGraphics, {
				tint: self.neonColors[self.currentColorIndex]
			}, {
				duration: 1000,
				easing: tween.easeInOut
			});
		}
	};
	return self;
});
var Coin = Container.expand(function () {
	var self = Container.call(this);
	// Create the coin graphic
	var coinGraphic = self.attachAsset('scoreEffect', {
		anchorX: 0.5,
		anchorY: 0.5,
		width: 40,
		height: 40,
		tint: 0xFFFF00 // Bright yellow color for coins
	});
	// Initialize properties
	self.active = false;
	// Animate coin from source to destination
	self.animate = function (startX, startY, destX, destY) {
		self.active = true;
		self.visible = true;
		self.x = startX + (Math.random() * 120 - 60);
		self.y = startY + (Math.random() * 120 - 60);
		self.alpha = 0;
		self.rotation = Math.random() * Math.PI;
		self.scale.set(1);
		// Duration and timing variables
		var duration = 500 + Math.random() * 200;
		// First make the coin appear with a quick flash
		tween(self, {
			alpha: 1.0,
			scaleX: 1.2,
			scaleY: 1.2
		}, {
			duration: 60,
			onFinish: function onFinish() {
				// Add a spin to the coins as they move
				self.rotation = Math.random() * Math.PI * 2;
				// Small initial burst to create a more dynamic feel
				tween(self, {
					y: self.y - 50 - Math.random() * 70,
					x: self.x + (Math.random() * 100 - 50),
					alpha: 1.0,
					rotation: self.rotation + Math.PI * (Math.random() > 0.5 ? 1 : -1)
				}, {
					duration: 150,
					easing: tween.easeOut,
					onFinish: function onFinish() {
						// Now move directly to the score with arc path
						tween(self, {
							x: destX,
							y: destY,
							scaleX: 0.3,
							scaleY: 0.3,
							rotation: self.rotation + Math.PI * 2,
							alpha: 0
						}, {
							duration: duration,
							easing: tween.easeInOut,
							onFinish: function onFinish() {
								// Flash the score text
								tween(scoreText, {
									scaleX: 1.2,
									scaleY: 1.2
								}, {
									duration: 100,
									onFinish: function onFinish() {
										tween(scoreText, {
											scaleX: 1,
											scaleY: 1
										}, {
											duration: 100
										});
									}
								});
								// Reset coin
								self.active = false;
								self.visible = false;
							}
						});
					}
				});
			}
		});
	};
	return self;
});
var Environment = Container.expand(function () {
	var self = Container.call(this);
	// Environment types
	self.CITY = 0;
	self.BEACH = 1;
	self.JAPAN = 2;
	// Current environment
	self.current = self.CITY;
	// Assets for each environment
	self.roadColors = [0x444444, 0xD2B48C, 0x8B4513]; // City, Beach, Japan
	self.sidewalkColors = [0x999999, 0xF5DEB3, 0x7D8570]; // City, Beach, Japan
	self.skyColors = [0x87CEEB, 0x87CEEB, 0xE0FFFF]; // City, Beach, Japan
	// Change environment based on score
	self.update = function (score) {
		var newEnvironment = self.current;
		// Determine environment based on score
		if (score >= 700) {
			newEnvironment = self.JAPAN;
		} else if (score >= 350) {
			newEnvironment = self.BEACH;
		} else {
			newEnvironment = self.CITY;
		}
		// Only update if environment changed
		if (newEnvironment !== self.current) {
			self.current = newEnvironment;
			return true;
		}
		return false;
	};
	// Apply environment changes
	self.apply = function (road, leftSidewalk, rightSidewalk, game) {
		// Update colors based on current environment
		road.tint = self.roadColors[self.current];
		leftSidewalk.tint = self.sidewalkColors[self.current];
		rightSidewalk.tint = self.sidewalkColors[self.current];
		// Update sky color
		game.setBackgroundColor(self.skyColors[self.current]);
		// Apply special transition effect
		LK.effects.flashScreen(0xFFFFFF, 500);
		// Return message to display for level change
		if (self.current === self.BEACH) {
			return "BEACH LEVEL UNLOCKED!";
		} else if (self.current === self.JAPAN) {
			return "JAPAN LEVEL UNLOCKED!";
		}
		return "";
	};
	return self;
});
var Line = Container.expand(function () {
	var self = Container.call(this);
	// Create road line marking
	var lineGraphics = self.attachAsset('line', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	// Make line vertical
	lineGraphics.rotation = Math.PI / 2; // Rotate 90 degrees
	// Road lines have fixed width to better match car size
	lineGraphics.width = 400; // Line length (now vertical)
	lineGraphics.height = 60; // Line thickness (more visible)
	self.lastY = 0; // Track last Y position for intersection detection
	self.speed = 15; // Default speed
	self.active = true; // Whether the line is active for scoring
	self.scored = false; // Whether this line has been scored already
	// Add visual effect to make lines more prominent
	var glowEffect = self.addChild(new Container());
	var glowAsset = glowEffect.attachAsset('line', {
		anchorX: 0.5,
		anchorY: 0.5,
		width: lineGraphics.width + 20,
		height: lineGraphics.height + 20,
		tint: 0xFFFF00,
		alpha: 0.3
	});
	glowAsset.rotation = Math.PI / 2;
	self.update = function () {
		self.lastY = self.y; // Store last position for collision detection
		self.y += self.speed;
		// Pulse glow effect
		if (LK.ticks % 10 === 0) {
			glowAsset.alpha = 0.2 + Math.random() * 0.2;
		}
		// Remove when off screen
		if (self.y > 2732 + lineGraphics.width / 2) {
			self.active = false;
		}
	};
	return self;
});
var ScoreEffect = Container.expand(function () {
	var self = Container.call(this);
	var effectGraphics = self.attachAsset('scoreEffect', {
		anchorX: 0.5,
		anchorY: 0.5,
		alpha: 0.8
	});
	self.show = function (x, y, isPositive) {
		self.x = x;
		self.y = y;
		if (!isPositive) {
			effectGraphics.tint = 0xFF0000;
			// Play penalty sound
			LK.getSound('penalty').play();
		} else {
			effectGraphics.tint = 0x00FF00;
			// Play point sound
			LK.getSound('point').play();
		}
		// Animation for the effect
		tween(self, {
			alpha: 0,
			y: y - 100
		}, {
			duration: 800,
			easing: tween.easeOut,
			onFinish: function onFinish() {
				self.alpha = 1;
				self.visible = false;
			}
		});
		self.visible = true;
	};
	return self;
});
var Store = Container.expand(function () {
	var self = Container.call(this);
	// Create store building
	var storeGraphics = self.attachAsset('building', {
		anchorX: 0.5,
		anchorY: 0,
		width: 200,
		height: 250,
		tint: 0xFAE5D3 // Light beige for store
	});
	// Add store sign
	var storeSign = self.addChild(new Container());
	var storeSignAsset = storeSign.attachAsset('building', {
		anchorX: 0.5,
		anchorY: 0.5,
		width: 180,
		height: 60,
		tint: 0x3498DB // Blue for store sign
	});
	storeSign.y = 40;
	// Add store window
	var storeWindow = self.addChild(new Container());
	var storeWindowAsset = storeWindow.attachAsset('building', {
		anchorX: 0.5,
		anchorY: 0.5,
		width: 120,
		height: 100,
		tint: 0xD6EAF8 // Light blue for window
	});
	storeWindow.y = 120;
	// Add store door
	var storeDoor = self.addChild(new Container());
	var storeDoorAsset = storeDoor.attachAsset('building', {
		anchorX: 0.5,
		anchorY: 0.5,
		width: 60,
		height: 100,
		tint: 0x784212 // Brown for door
	});
	storeDoor.y = 180;
	self.speed = 10; // Default speed
	self.update = function () {
		self.y += self.speed;
		// Reset store when it goes off screen
		if (self.y > 2732 + storeGraphics.height) {
			self.y = -storeGraphics.height;
			// Store types based on environment
			var storeTypes;
			if (environment && environment.current === environment.BEACH) {
				// Beach stores - surf shops, beach bars, cabanas
				storeTypes = [{
					building: 0xF0F8FF,
					// AliceBlue
					sign: 0x00BFFF,
					// DeepSkyBlue
					window: 0xE0FFFF // LightCyan
				}, {
					building: 0xFFEFD5,
					// PapayaWhip
					sign: 0xFF6347,
					// Tomato
					window: 0xFFDAB9 // PeachPuff
				}, {
					building: 0x40E0D0,
					// Turquoise
					sign: 0xFFFFFF,
					// White
					window: 0xAFEEEE // PaleTurquoise
				}, {
					building: 0xF5DEB3,
					// Wheat
					sign: 0x1E90FF,
					// DodgerBlue
					window: 0xFFF5EE // SeaShell
				}];
			} else if (environment && environment.current === environment.JAPAN) {
				// Japanese stores - traditional shops, ramen stands, markets
				storeTypes = [{
					building: 0x8B4513,
					// SaddleBrown (wood)
					sign: 0xFF0000,
					// Red
					window: 0xFFD700 // Gold
				}, {
					building: 0xFFF5EE,
					// SeaShell (white paper walls)
					sign: 0x000000,
					// Black
					window: 0xFFF8DC // Cornsilk
				}, {
					building: 0x2F4F4F,
					// DarkSlateGray
					sign: 0xDC143C,
					// Crimson
					window: 0xF0FFF0 // Honeydew
				}, {
					building: 0xCD853F,
					// Peru (wood)
					sign: 0x4682B4,
					// SteelBlue
					window: 0xF5F5DC // Beige
				}];
			} else {
				// Default city stores
				storeTypes = [{
					building: 0xFAE5D3,
					sign: 0x3498DB,
					window: 0xD6EAF8
				},
				// Blue store
				{
					building: 0xFCF3CF,
					sign: 0xE74C3C,
					window: 0xFADBD8
				},
				// Red store
				{
					building: 0xD5F5E3,
					sign: 0x8E44AD,
					window: 0xEBDEF0
				},
				// Purple store
				{
					building: 0xEAEDED,
					sign: 0xF39C12,
					window: 0xFAE5D3
				} // Orange store
				];
			}
			var type = storeTypes[Math.floor(Math.random() * storeTypes.length)];
			storeGraphics.tint = type.building;
			storeSignAsset.tint = type.sign;
			storeWindowAsset.tint = type.window;
			// Vary store size slightly
			var sizeVar = 0.8 + Math.random() * 0.4;
			storeGraphics.width = 200 * sizeVar;
			storeGraphics.height = 250 * sizeVar;
			storeSign.scale.set(sizeVar);
			storeWindow.scale.set(sizeVar);
			storeDoor.scale.set(sizeVar);
			// Adjust positions based on new size
			storeSign.y = 40 * sizeVar;
			storeWindow.y = 120 * sizeVar;
			storeDoor.y = 180 * sizeVar;
		}
	};
	return self;
});
var StreetLight = Container.expand(function () {
	var self = Container.call(this);
	// Create pole
	var pole = self.addChild(new Container());
	var poleAsset = pole.attachAsset('building', {
		anchorX: 0.5,
		anchorY: 1.0,
		width: 20,
		height: 200,
		tint: 0x555555 // Dark gray for pole
	});
	// Create light
	var light = self.addChild(new Container());
	var lightAsset = light.attachAsset('scoreEffect', {
		anchorX: 0.5,
		anchorY: 0.5,
		width: 40,
		height: 40,
		tint: 0xFFFF99 // Yellow light
	});
	light.y = -200;
	// Light arm
	var arm = self.addChild(new Container());
	var armAsset = arm.attachAsset('building', {
		anchorX: 0,
		anchorY: 0.5,
		width: 40,
		height: 10,
		tint: 0x555555 // Dark gray for arm
	});
	arm.y = -190;
	self.speed = 10; // Default speed
	self.isLit = Math.random() > 0.2; // Most lights are on
	self.update = function () {
		self.y += self.speed;
		// Make light flicker occasionally
		if (self.isLit && LK.ticks % 20 === 0 && Math.random() > 0.7) {
			lightAsset.alpha = 0.6 + Math.random() * 0.4;
		}
		// Reset light when it goes off screen
		if (self.y > 2732 + 200) {
			self.y = -200;
			self.isLit = Math.random() > 0.2;
			lightAsset.alpha = self.isLit ? 1 : 0.2;
		}
	};
	return self;
});
var TapEffect = Container.expand(function () {
	var self = Container.call(this);
	var effectGraphics = self.attachAsset('scoreEffect', {
		anchorX: 0.5,
		anchorY: 0.5,
		width: 300,
		height: 300,
		alpha: 0.6
	});
	self.show = function (x, y, isPositive) {
		self.x = x;
		self.y = y;
		// Set color based on whether it's a positive or negative tap
		if (isPositive) {
			effectGraphics.tint = 0x00FF00; // Green for good taps
			// Play point sound with lower volume to avoid overwhelming
			LK.getSound('point').play({
				volume: 0.3
			});
			// Trigger coin effects separately - they're now handled in the game code
		} else {
			effectGraphics.tint = 0xFF0000; // Red for bad taps
			// Play penalty sound with lower volume to avoid overwhelming
			LK.getSound('penalty').play({
				volume: 0.3
			});
		}
		// Reset properties before animation
		self.alpha = 1;
		effectGraphics.alpha = 0.6;
		effectGraphics.scale.x = 0.5;
		effectGraphics.scale.y = 0.5;
		self.visible = true;
		// Animate the effect - expand and fade out for a nice ripple effect
		tween(effectGraphics, {
			alpha: 0,
			scaleX: 2.5,
			scaleY: 2.5
		}, {
			duration: 800,
			easing: tween.easeOut,
			onFinish: function onFinish() {
				self.visible = false;
				effectGraphics.scale.x = 0.5;
				effectGraphics.scale.y = 0.5;
			}
		});
	};
	return self;
});
var Tree = Container.expand(function () {
	var self = Container.call(this);
	// Create tree trunk
	var trunk = self.addChild(new Container());
	var trunkAsset = trunk.attachAsset('building', {
		anchorX: 0.5,
		anchorY: 1.0,
		width: 40,
		height: 120,
		tint: 0x8B4513 // Brown color for trunk
	});
	// Create tree foliage (multiple layers for depth)
	var foliage1 = self.addChild(new Container());
	var foliageAsset1 = foliage1.attachAsset('scoreEffect', {
		anchorX: 0.5,
		anchorY: 0.8,
		width: 150,
		height: 150,
		tint: 0x228B22 // Forest green
	});
	foliage1.y = -80;
	var foliage2 = self.addChild(new Container());
	var foliageAsset2 = foliage2.attachAsset('scoreEffect', {
		anchorX: 0.5,
		anchorY: 0.7,
		width: 120,
		height: 120,
		tint: 0x32CD32 // Lime green for highlight
	});
	foliage2.y = -100;
	self.speed = 10; // Default speed
	self.update = function () {
		self.y += self.speed;
		// Reset tree when it goes off screen
		if (self.y > 2732 + 150) {
			self.y = -150;
			// Randomize tree appearance when resetting
			trunkAsset.height = 80 + Math.random() * 80;
			trunkAsset.width = 30 + Math.random() * 20;
			var scale = 0.8 + Math.random() * 0.5;
			foliage1.scale.set(scale);
			foliage2.scale.set(scale * 0.9);
			// Check current environment for tree appearance
			if (environment && environment.current === environment.BEACH) {
				// Palm trees for beach
				trunkAsset.tint = 0xA0522D; // Brown trunk for palm trees
				trunkAsset.height *= 1.5; // Make palm tree trunks much taller
				trunkAsset.width *= 0.7; // Make palm tree trunks thinner
				// Change foliage shape and color for palm trees
				foliageAsset1.width = 200; // Wider palm fronds
				foliageAsset1.height = 120; // Shorter palm fronds
				foliageAsset1.tint = 0xFFFF00; // Yellow palm fronds
				foliageAsset2.width = 220; // Even wider top fronds
				foliageAsset2.height = 100; // Shorter top fronds
				foliageAsset2.tint = 0xFFFF80; // Lighter yellow for highlights
				// Position foliage to look like palm fronds
				foliage1.y = -150; // Raise fronds higher for palm tree appearance
				foliage2.y = -170; // Raise top fronds even higher
			} else if (environment && environment.current === environment.JAPAN) {
				// Cherry blossom trees (sakura)
				trunkAsset.tint = 0x8B4513; // Brown trunk
				// More vibrant pink cherry blossoms
				foliageAsset1.width = 170; // Wider, fuller cherry blossom shape
				foliageAsset1.height = 170; // Rounder for blossom shape
				// Pure pink color for cherry blossoms
				foliageAsset1.tint = 0xFF00FF; // Bright pink cherry blossoms
				// Lighter pink for highlights
				foliageAsset2.width = 140; // Slightly smaller top layer
				foliageAsset2.height = 140; // Rounder for blossom shape
				foliageAsset2.tint = 0xFF80FF; // Lighter pink highlights
				// Position foliage to look more like cherry blossom
				foliage1.y = -100; // Position for traditional cherry blossom tree shape
				foliage2.y = -120; // Position for traditional cherry blossom tree shape
			} else {
				// Default city trees
				var greenVariation = Math.floor(Math.random() * 40);
				foliageAsset1.tint = 34 + greenVariation << 16 | 139 + greenVariation << 8 | 34;
				foliageAsset2.tint = 50 + greenVariation << 16 | 205 + greenVariation << 8 | 50;
			}
		}
	};
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x87CEEB
});
/**** 
* Game Code
****/ 
// Game variables
var car;
var lines = [];
var buildings = [];
var trees = [];
var stores = [];
var streetLights = [];
var score = 0;
var scoreText;
var speedMultiplier = 1;
var lineSpawnRate = 60; // Frames between line spawns
var difficulty = 1;
var isGameActive = true;
var scoreEffects = [];
var tapEffects = [];
var coins = []; // Pool of coin objects
var effectIndex = 0;
var tapEffectIndex = 0;
var coinIndex = 0;
var lastJumpScore = 0;
var badge;
var environment;
var levelText;
var levelTextTimer = 0;
// Create a sky background
game.setBackgroundColor(0x87CEEB); // Light blue sky
// Initialize the road
var road = game.addChild(LK.getAsset('road', {
	anchorX: 0.5,
	anchorY: 0.5,
	x: 2048 / 2,
	y: 2732 / 2,
	width: 1200,
	// Make the road narrower than the full width
	tint: 0x444444 // Darker gray for asphalt
}));
// Add road edges/sidewalks
var leftSidewalk = game.addChild(LK.getAsset('building', {
	anchorX: 0,
	anchorY: 0.5,
	width: (2048 - road.width) / 2,
	height: 2732,
	x: 0,
	y: 2732 / 2,
	tint: 0x999999 // Light gray for sidewalk
}));
var rightSidewalk = game.addChild(LK.getAsset('building', {
	anchorX: 1,
	anchorY: 0.5,
	width: (2048 - road.width) / 2,
	height: 2732,
	x: 2048,
	y: 2732 / 2,
	tint: 0x999999 // Light gray for sidewalk
}));
// Initialize score display
scoreText = new Text2('SCORE: 0', {
	size: 80,
	fill: 0xFFFFFF,
	stroke: 0x000000,
	strokeThickness: 5
});
scoreText.anchor.set(0.5, 0);
scoreText.y = 50; // Move down slightly from top
LK.gui.top.addChild(scoreText);
// Initialize level transition text
levelText = new Text2('', {
	size: 100,
	fill: 0xFFFFFF,
	stroke: 0x000000,
	strokeThickness: 8,
	fontWeight: 'bold'
});
levelText.anchor.set(0.5, 0.5);
levelText.visible = false;
LK.gui.center.addChild(levelText);
// Initialize environment
environment = new Environment();
// Add game instructions
var instructionsText = new Text2('Tap when no lines\nAvoid tapping on lines\nScore 1000 to win', {
	size: 70,
	fill: 0xFFFFFF,
	stroke: 0x800080,
	strokeThickness: 10,
	fontWeight: 'bold',
	align: 'center'
});
instructionsText.anchor.set(0.5, 0);
instructionsText.y = 150;
LK.gui.top.addChild(instructionsText);
// Create buildings for city skyline on both sides of the road (not on the road)
for (var i = 0; i < 20; i++) {
	var building = new Building();
	// Position buildings only on the sides, ensuring they stay off the road
	var roadLeftEdge = (2048 - road.width) / 2;
	var roadRightEdge = 2048 - roadLeftEdge;
	if (i % 2 === 0) {
		// Left side only - ensure buildings stay completely on sidewalk
		var buildingWidth = building.children[0].width;
		building.x = Math.random() * (roadLeftEdge - buildingWidth / 2); // Left side only, accounting for building width
	} else {
		// Right side only - ensure buildings stay completely on sidewalk
		var buildingWidth = building.children[0].width;
		building.x = roadRightEdge + Math.random() * (roadLeftEdge - buildingWidth / 2); // Right side only
	}
	building.y = Math.random() * 2732;
	buildings.push(building);
	game.addChild(building);
}
// Add trees along the road
var trees = [];
for (var i = 0; i < 15; i++) {
	var tree = new Tree();
	// Position trees on the sidewalks
	if (i % 2 === 0) {
		// Left side trees - further from road than buildings
		tree.x = (2048 - road.width) / 2 - 250 - Math.random() * 60;
	} else {
		// Right side trees - further from road than buildings
		tree.x = 2048 - (2048 - road.width) / 2 + 250 + Math.random() * 60;
	}
	// Distribute trees along the road
	tree.y = -150 + i * 350 + Math.random() * 200;
	trees.push(tree);
	game.addChild(tree);
}
// Add stores on the sides
var stores = [];
for (var i = 0; i < 8; i++) {
	var store = new Store();
	// Position stores on the sidewalks, further from the road than trees
	if (i % 2 === 0) {
		// Left side stores
		store.x = (2048 - road.width) / 4;
	} else {
		// Right side stores
		store.x = 2048 - (2048 - road.width) / 4;
	}
	// Distribute stores along the road with some spacing
	store.y = -300 + i * 650 + Math.random() * 300;
	stores.push(store);
	game.addChild(store);
}
// Add street lights
var streetLights = [];
for (var i = 0; i < 12; i++) {
	var light = new StreetLight();
	// Position lights on the edge of the road
	if (i % 2 === 0) {
		// Left side lights
		light.x = (2048 - road.width) / 2 - 20;
	} else {
		// Right side lights
		light.x = 2048 - (2048 - road.width) / 2 + 20;
	}
	// Distribute lights evenly
	light.y = -200 + i * 400 + i % 2 * 200;
	streetLights.push(light);
	game.addChild(light);
}
// Create car
car = new Car();
car.x = 2048 / 2;
car.y = 2732 - 400;
game.addChild(car);
// Bring car to front to make sure it appears on top of lines
game.setChildIndex(car, game.children.length - 1);
// Create badge
badge = new Badge();
badge.x = 2048 - 150; // Position on the right side of screen
badge.y = 2732 / 2; // Position in the middle vertically
badge.visible = false; // Hidden until earned
badge.scale.set(0); // Start with zero scale
game.addChild(badge);
for (var i = 0; i < 5; i++) {
	var effect = new ScoreEffect();
	effect.visible = false;
	scoreEffects.push(effect);
	game.addChild(effect);
}
// Create tap effects pool - increased size to handle multiple effects
for (var i = 0; i < 10; i++) {
	var tapEffect = new TapEffect();
	tapEffect.visible = false;
	tapEffects.push(tapEffect);
	game.addChild(tapEffect);
}
// Create coin effects pool
for (var i = 0; i < 15; i++) {
	var coin = new Coin();
	coin.visible = false;
	coin.active = false;
	coins.push(coin);
	game.addChild(coin);
}
// Game click handler
game.down = function (x, y, obj) {
	if (!isGameActive) {
		return;
	}
	// Check if we clicked on the badge
	if (badge.earned && !badge.active && x >= badge.x - badge.width / 2 && x <= badge.x + badge.width / 2 && y >= badge.y - badge.height / 2 && y <= badge.y + badge.height / 2) {
		badge.activate();
		return;
	}
	// Check if car is already jumping
	if (!car.jumping) {
		car.jump();
		// Check if car is over a road line
		var overLine = false;
		for (var i = 0; i < lines.length; i++) {
			// Check if the car intersects with any vertical road line
			if (lines[i].active && car.intersects(lines[i])) {
				overLine = true;
				break;
			}
		}
		// Score or penalty based on jump
		if (overLine) {
			// Penalty for jumping over a line
			score = Math.max(0, score - 10);
			// Show penalty effect
			var effect = scoreEffects[effectIndex];
			effectIndex = (effectIndex + 1) % scoreEffects.length;
			effect.show(car.x, car.y - 50, false);
			// Show tap feedback effect (red for penalty)
			var tapEffect = tapEffects[tapEffectIndex];
			tapEffectIndex = (tapEffectIndex + 1) % tapEffects.length;
			tapEffect.show(x, y, false);
			// Add multiple red effects for stronger visual feedback
			for (var j = 0; j < 2; j++) {
				var extraEffect = tapEffects[tapEffectIndex];
				tapEffectIndex = (tapEffectIndex + 1) % tapEffects.length;
				extraEffect.show(x + (Math.random() * 100 - 50), y + (Math.random() * 100 - 50), false);
			}
			// Flash screen red for bad tap
			LK.effects.flashScreen(0xff0000, 300);
		} else {
			// Points for jumping on empty road
			var pointsGained = 20 * difficulty;
			score += pointsGained;
			lastJumpScore = pointsGained;
			// Show score effect
			var effect = scoreEffects[effectIndex];
			effectIndex = (effectIndex + 1) % scoreEffects.length;
			effect.show(car.x, car.y - 50, true);
			// Show tap feedback effect (green for points)
			var tapEffect = tapEffects[tapEffectIndex];
			tapEffectIndex = (tapEffectIndex + 1) % tapEffects.length;
			tapEffect.show(x, y, true);
			// Add multiple green effects for stronger visual feedback
			for (var j = 0; j < 2; j++) {
				var extraEffect = tapEffects[tapEffectIndex];
				tapEffectIndex = (tapEffectIndex + 1) % tapEffects.length;
				extraEffect.show(x + (Math.random() * 100 - 50), y + (Math.random() * 100 - 50), true);
			}
			// Create coin animation effects
			var coinCount = 3 + Math.floor(Math.random() * 3); // 3-5 coins
			for (var i = 0; i < coinCount; i++) {
				// Get a coin from the pool
				var coin = coins[coinIndex];
				coinIndex = (coinIndex + 1) % coins.length;
				// Only animate if not currently active
				if (!coin.active) {
					// Set destination coordinates (score text position)
					var destX = 2048 / 2; // Center of screen where the score is
					var destY = 50; // Near the top where the score is
					// Animate the coin
					coin.animate(x, y, destX, destY);
				}
			}
		}
		// Update score display
		scoreText.setText(Math.round(score));
		LK.setScore(Math.round(score));
	}
};
// Start background music
LK.playMusic('bgmusic', {
	fade: {
		start: 0,
		end: 0.4,
		duration: 1000
	}
});
// Game update function
game.update = function () {
	if (!isGameActive) {
		return;
	}
	// Update badge
	badge.update();
	// Update car
	car.update();
	// Update all lines
	for (var i = lines.length - 1; i >= 0; i--) {
		lines[i].update();
		// We don't penalize for just passing over a line anymore
		// Only interactions happen when player taps
		if (!lines[i].scored && lines[i].lastY < car.y && lines[i].y >= car.y) {
			lines[i].scored = true; // Mark as scored
		}
		// Remove inactive lines
		if (!lines[i].active) {
			lines[i].destroy();
			lines.splice(i, 1);
		}
	}
	// Update all buildings
	for (var i = 0; i < buildings.length; i++) {
		buildings[i].speed = 5 * speedMultiplier;
		buildings[i].update();
	}
	// Update all trees
	for (var i = 0; i < trees.length; i++) {
		trees[i].speed = 5 * speedMultiplier; // Changed from 7 to 5 to match building speed
		trees[i].update();
	}
	// Update all stores
	for (var i = 0; i < stores.length; i++) {
		stores[i].speed = 5 * speedMultiplier;
		stores[i].update();
	}
	// Update all street lights
	for (var i = 0; i < streetLights.length; i++) {
		streetLights[i].speed = 5 * speedMultiplier; // Changed from 7 to 5 to match building speed
		streetLights[i].update();
	}
	// Create new lines at intervals - always come from center of the screen
	if (LK.ticks % Math.floor(lineSpawnRate / speedMultiplier) === 0) {
		var line = new Line();
		// Position line at the center of the screen
		line.x = 2048 / 2; // Center X coordinate
		line.y = -50;
		line.speed = 15 * speedMultiplier;
		lines.push(line);
		game.addChild(line);
		// Ensure car is always rendered on top of lines
		game.setChildIndex(car, game.children.length - 1);
	}
	// Increase difficulty over time
	if (LK.ticks % 600 === 0) {
		// Every 10 seconds
		difficulty += 0.1;
		// Speed up game after 500 points, but not too much, and slow down a bit after 800
		if (score > 800) {
			// Cap the speedMultiplier to prevent game from becoming too fast
			speedMultiplier = Math.min(1.6, 1 + (difficulty - 1) * 0.6); // Further reduced speed cap
			lineSpawnRate = Math.max(30, 45 - difficulty * 1.5); // More forgiving line spawn rate
		} else if (score > 500) {
			// Cap the speedMultiplier to prevent game from becoming too fast
			speedMultiplier = Math.min(1.5, 1 + (difficulty - 1) * 0.7); // Lower speed cap
			lineSpawnRate = Math.max(25, 40 - difficulty * 2); // More moderate increase in line spawn rate
		} else {
			speedMultiplier = 1 + (difficulty - 1) * 0.5;
			lineSpawnRate = Math.max(15, 60 - difficulty * 5);
		}
	}
	// Check if score has reached 500 to give badge
	if (score >= 500 && !badge.earned) {
		badge.showEarned();
		// Create notification text
		var badgeNotification = new Text2("SPEED BOOST UNLOCKED!", {
			size: 80,
			fill: 0xFFD700,
			stroke: 0x000000,
			strokeThickness: 6
		});
		badgeNotification.anchor.set(0.5, 0.5);
		LK.gui.center.addChild(badgeNotification);
		// Animate notification
		tween(badgeNotification, {
			alpha: 0,
			y: badgeNotification.y - 100
		}, {
			duration: 2000,
			onFinish: function onFinish() {
				badgeNotification.destroy();
			}
		});
	}
	// Handle environment transitions based on score
	if (environment.update(Math.round(score))) {
		var message = environment.apply(road, leftSidewalk, rightSidewalk, game);
		// Show level transition message
		if (message) {
			levelText.setText(message);
			levelText.visible = true;
			levelTextTimer = 120; // Show for 2 seconds (120 frames)
			// Update car and environment elements based on the theme
			if (environment.current === environment.BEACH) {
				// Beach theme colors for buildings and objects
				for (var i = 0; i < buildings.length; i++) {
					var building = buildings[i];
					if (building.children && building.children[0]) {
						var shade = Math.floor(Math.random() * 30) + 220; // Lighter buildings for beach
						building.children[0].tint = shade << 16 | shade << 8 | shade;
					}
				}
			} else if (environment.current === environment.JAPAN) {
				// Japan theme colors for buildings and objects
				for (var i = 0; i < buildings.length; i++) {
					var building = buildings[i];
					if (building.children && building.children[0]) {
						// Reddish pagoda style buildings
						var red = Math.floor(Math.random() * 55) + 200;
						var green = Math.floor(red * 0.5);
						var blue = Math.floor(green * 0.5);
						building.children[0].tint = red << 16 | green << 8 | blue;
					}
				}
			}
		}
	}
	// Update level transition text timer
	if (levelTextTimer > 0) {
		levelTextTimer--;
		if (levelTextTimer === 0) {
			levelText.visible = false;
		}
	}
	// Check for game over condition
	if (score < 0) {
		isGameActive = false;
		LK.showGameOver();
	}
	// Check for win condition (1000 points to win)
	if (score >= 1000) {
		// Only show win screen once
		if (isGameActive) {
			isGameActive = false;
			// Flash screen with celebration colors
			LK.effects.flashScreen(0xFFD700, 400); // Gold flash
			// Create coin shower effect for winning celebration
			LK.setTimeout(function () {
				for (var i = 0; i < 40; i++) {
					var coin = coins[Math.floor(Math.random() * coins.length)];
					if (!coin.active) {
						// Random positions for coins
						var startX = Math.random() * 2048;
						var startY = -100;
						var destX = Math.random() * 2048;
						var destY = Math.random() * 2732;
						coin.animate(startX, startY, destX, destY);
					}
				}
				// Show win screen immediately after coin effect starts
				LK.showYouWin();
			}, 300);
		}
	}
}; /**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/**** 
* Classes
****/ 
var Badge = Container.expand(function () {
	var self = Container.call(this);
	// Create badge icon
	var badgeGraphic = self.attachAsset('scoreEffect', {
		anchorX: 0.5,
		anchorY: 0.5,
		width: 80,
		height: 80,
		tint: 0xFF0000 // Red color for badge
	});
	// Add a label to indicate what the badge does
	var labelText = self.addChild(new Text2("SPEED BOOST", {
		size: 20,
		fill: 0xFFFFFF,
		stroke: 0x000000,
		strokeThickness: 3
	}));
	labelText.anchor.set(0.5, 0.5);
	labelText.y = 60;
	// Add a timer display
	var timerText = self.addChild(new Text2("", {
		size: 24,
		fill: 0xFFFFFF,
		stroke: 0x000000,
		strokeThickness: 3
	}));
	timerText.anchor.set(0.5, 0.5);
	timerText.y = -60;
	timerText.visible = false;
	self.earned = false; // Whether badge has been earned
	self.active = false;
	self.timerSeconds = 30;
	self.pulseDirection = 1;
	self.originalScale = 1;
	self.visible = false;
	// Animation for when badge is first earned
	self.showEarned = function () {
		self.earned = true;
		self.visible = true;
		self.scale.set(0.1);
		self.alpha = 0;
		// Appear with a bounce effect
		tween(self, {
			alpha: 1,
			scaleX: 1.2,
			scaleY: 1.2
		}, {
			duration: 500,
			easing: tween.elasticOut,
			onFinish: function onFinish() {
				tween(self, {
					scaleX: 1,
					scaleY: 1
				}, {
					duration: 200
				});
			}
		});
	};
	// Activate the badge power
	self.activate = function () {
		if (self.earned && !self.active) {
			self.active = true;
			speedMultiplier = 0.5; // Slow down the road
			timerText.visible = true;
			// Visual feedback - flash effect
			LK.effects.flashScreen(0xFFD700, 300);
			// Start countdown
			self.timerSeconds = 30;
			timerText.setText(self.timerSeconds);
			// Start timer to count down and update display
			var timerInterval = LK.setInterval(function () {
				self.timerSeconds--;
				timerText.setText(self.timerSeconds);
				if (self.timerSeconds <= 0) {
					LK.clearInterval(timerInterval);
				}
			}, 1000);
			// Reset after 30 seconds
			LK.setTimeout(function () {
				speedMultiplier = 1; // Reset speed after 30 seconds
				self.active = false;
				timerText.visible = false;
				// Flash when effect ends
				LK.effects.flashScreen(0x87CEEB, 300);
			}, 30000);
		}
	};
	// Update to pulse the badge when available
	self.update = function () {
		if (self.earned && !self.active) {
			// Pulse effect when ready to use
			if (self.pulseDirection > 0) {
				self.scale.x += 0.005;
				self.scale.y += 0.005;
				if (self.scale.x >= 1.1) {
					self.pulseDirection = -1;
				}
			} else {
				self.scale.x -= 0.005;
				self.scale.y -= 0.005;
				if (self.scale.x <= 0.9) {
					self.pulseDirection = 1;
				}
			}
		} else if (self.active) {
			// Rotate slightly when active
			self.rotation += 0.01;
		}
	};
	return self;
});
var Building = Container.expand(function () {
	var self = Container.call(this);
	var buildingGraphics = self.attachAsset('building', {
		anchorX: 0.5,
		anchorY: 0
	});
	// Randomize building properties
	var shade = Math.floor(Math.random() * 40) + 40;
	buildingGraphics.tint = shade << 16 | shade << 8 | shade;
	buildingGraphics.height = Math.random() * 600 + 400;
	buildingGraphics.width = Math.random() * 100 + 100;
	// Add windows to buildings for a city look
	var windowCount = Math.floor(buildingGraphics.height / 80);
	var windowsPerRow = Math.floor(buildingGraphics.width / 40);
	for (var i = 0; i < windowCount; i++) {
		for (var j = 0; j < windowsPerRow; j++) {
			var windowLight = self.addChild(new Container());
			var windowAsset = windowLight.attachAsset('building', {
				anchorX: 0.5,
				anchorY: 0.5,
				width: 20,
				height: 30,
				tint: 0xFFFF99
			});
			windowLight.x = j * 40 - buildingGraphics.width / 2 + 25;
			windowLight.y = i * 80 + 50;
			windowLight.alpha = Math.random() > 0.3 ? 0.8 : 0;
		}
	}
	self.speed = 10; // Default speed
	self.update = function () {
		self.y += self.speed;
		// Reset building when it goes off screen
		if (self.y > 2732 + buildingGraphics.height) {
			self.y = -buildingGraphics.height;
			// Determine road boundaries to keep buildings off the road
			var road = null;
			for (var i = 0; i < game.children.length; i++) {
				if (game.children[i].asset && game.children[i].asset.id === 'road') {
					road = game.children[i];
					break;
				}
			}
			// Place building only on sidewalks
			var roadLeftEdge = road ? (2048 - road.width) / 2 : 424;
			var roadRightEdge = road ? 2048 - (2048 - road.width) / 2 : 1624;
			// Determine which side to place the building on based on its current side
			if (self.x < roadLeftEdge) {
				// Keep on left side
				self.x = Math.random() * (roadLeftEdge - buildingGraphics.width / 2);
			} else {
				// Keep on right side
				self.x = roadRightEdge + Math.random() * (roadLeftEdge - buildingGraphics.width / 2);
			}
			// Check current environment for building appearance
			if (environment && environment.current === environment.BEACH) {
				// Beach resort buildings - lighter colors, more variation
				var r = Math.floor(Math.random() * 40) + 215; // Bright beige/white
				var g = Math.floor(Math.random() * 40) + 215;
				var b = Math.floor(Math.random() * 40) + 190;
				buildingGraphics.tint = r << 16 | g << 8 | b;
				buildingGraphics.height = Math.random() * 400 + 300; // Beach buildings are shorter
				buildingGraphics.width = Math.random() * 150 + 100; // But wider
			} else if (environment && environment.current === environment.JAPAN) {
				// Traditional Japanese buildings - pagoda style
				var shade = Math.floor(Math.random() * 40) + 40; // Dark base
				// Add red tint for some buildings to simulate temples/shrines
				if (Math.random() > 0.5) {
					buildingGraphics.tint = shade + 150 << 16 | shade << 8 | shade;
					buildingGraphics.height = Math.random() * 500 + 300; // Slightly shorter
				} else {
					buildingGraphics.tint = shade << 16 | shade << 8 | shade;
					buildingGraphics.height = Math.random() * 400 + 200; // Low traditional houses
				}
				buildingGraphics.width = Math.random() * 120 + 100;
			} else {
				// Default city buildings
				var shade = Math.floor(Math.random() * 40) + 40;
				buildingGraphics.tint = shade << 16 | shade << 8 | shade;
				buildingGraphics.height = Math.random() * 600 + 400;
				buildingGraphics.width = Math.random() * 100 + 100;
			}
			// Recreate windows when building resets
			self.removeChildren(1); // Keep only the main building graphic
			var windowCount = Math.floor(buildingGraphics.height / 80);
			var windowsPerRow = Math.floor(buildingGraphics.width / 40);
			for (var i = 0; i < windowCount; i++) {
				for (var j = 0; j < windowsPerRow; j++) {
					var windowLight = self.addChild(new Container());
					var windowAsset = windowLight.attachAsset('building', {
						anchorX: 0.5,
						anchorY: 0.5,
						width: 20,
						height: 30,
						tint: 0xFFFF99
					});
					windowLight.x = j * 40 - buildingGraphics.width / 2 + 25;
					windowLight.y = i * 80 + 50;
					// Randomly light windows
					windowLight.alpha = Math.random() > 0.3 ? 0.8 : 0;
				}
			}
		}
	};
	return self;
});
var Car = Container.expand(function () {
	var self = Container.call(this);
	// Create car body - using just the car asset without additional square
	var carGraphics = self.attachAsset('car', {
		anchorX: 0.5,
		anchorY: 0.5,
		tint: 0x3366CC // Blue car color
	});
	// Add headlights
	var leftHeadlight = self.addChild(new Container());
	var leftHeadlightAsset = leftHeadlight.attachAsset('scoreEffect', {
		anchorX: 0.5,
		anchorY: 0.5,
		width: 40,
		height: 40,
		tint: 0xFFFF00
	});
	leftHeadlight.x = -60;
	leftHeadlight.y = -140;
	var rightHeadlight = self.addChild(new Container());
	var rightHeadlightAsset = rightHeadlight.attachAsset('scoreEffect', {
		anchorX: 0.5,
		anchorY: 0.5,
		width: 40,
		height: 40,
		tint: 0xFFFF00
	});
	rightHeadlight.x = 60;
	rightHeadlight.y = -140;
	// Add light reflection gradient in front of the car
	// Left headlight reflection
	var leftReflection = self.addChild(new Container());
	for (var i = 0; i < 5; i++) {
		var reflectionSegment = leftReflection.attachAsset('scoreEffect', {
			anchorX: 0.5,
			anchorY: 0.5,
			width: 30 - i * 3,
			height: 25 - i * 3,
			tint: 0xFFFF00,
			alpha: 0.4 - i * 0.07
		});
		reflectionSegment.y = -i * 15;
	}
	leftReflection.x = -60;
	leftReflection.y = -170;
	// Right headlight reflection
	var rightReflection = self.addChild(new Container());
	for (var i = 0; i < 5; i++) {
		var reflectionSegment = rightReflection.attachAsset('scoreEffect', {
			anchorX: 0.5,
			anchorY: 0.5,
			width: 30 - i * 3,
			height: 25 - i * 3,
			tint: 0xFFFF00,
			alpha: 0.4 - i * 0.07
		});
		reflectionSegment.y = -i * 15;
	}
	rightReflection.x = 60;
	rightReflection.y = -170;
	self.jumping = false;
	self.jumpHeight = 100;
	self.originalY = 0;
	self.lastY = 0; // Track last Y position for intersection detection
	self.jump = function () {
		if (self.jumping) {
			return;
		}
		self.jumping = true;
		self.originalY = self.y;
		// Play jump sound
		LK.getSound('jump').play();
		// Enhanced neon effect during jump - random bright color
		var randomNeonColor = Math.random() > 0.5 ? 0xFFFFFF : 0x00FFFF;
		// Create a glowing neon effect
		tween(carGraphics, {
			tint: randomNeonColor,
			scaleX: 1.2,
			scaleY: 1.2
		}, {
			duration: 150,
			onFinish: function onFinish() {
				// Return to current neon color after the flash
				tween(carGraphics, {
					tint: self.neonColors[self.currentColorIndex],
					scaleX: 1.0,
					scaleY: 1.0
				}, {
					duration: 450
				});
			}
		});
		// Jump animation using tween
		tween(self, {
			y: self.y - self.jumpHeight
		}, {
			duration: 300,
			easing: tween.easeOut,
			onFinish: function onFinish() {
				// Fall back down
				tween(self, {
					y: self.originalY
				}, {
					duration: 300,
					easing: tween.easeIn,
					onFinish: function onFinish() {
						self.jumping = false;
					}
				});
			}
		});
	};
	self.down = function () {
		self.jump();
	};
	// Set up neon color cycling properties
	self.neonColors = [0x3366CC,
	// Blue
	0xFF00FF,
	// Magenta
	0x00FFFF,
	// Cyan
	0x33CC33,
	// Green
	0xFF6600,
	// Orange
	0xFFFF00,
	// Yellow
	0xFF3366,
	// Pink
	0x9900FF // Purple
	];
	self.currentColorIndex = 0;
	self.colorTransitionTime = 0;
	self.colorTransitionDuration = 60; // About 1 second at 60fps - faster color cycling
	self.update = function () {
		self.lastY = self.y;
		// Create headlight glow effect
		if (LK.ticks % 5 === 0) {
			leftHeadlightAsset.alpha = 0.7 + Math.random() * 0.3;
			rightHeadlightAsset.alpha = 0.7 + Math.random() * 0.3;
			// Animate reflection gradient
			// Loop through each reflection segment container's children
			for (var i = 0; i < 5; i++) {
				if (leftReflection.children[i]) {
					leftReflection.children[i].alpha = (0.4 - i * 0.07) * (0.7 + Math.random() * 0.3);
				}
				if (rightReflection.children[i]) {
					rightReflection.children[i].alpha = (0.4 - i * 0.07) * (0.7 + Math.random() * 0.3);
				}
			}
		}
		// Update neon color effect
		self.colorTransitionTime++;
		if (self.colorTransitionTime >= self.colorTransitionDuration) {
			self.colorTransitionTime = 0;
			self.currentColorIndex = (self.currentColorIndex + 1) % self.neonColors.length;
			// Start transition to the next color
			tween(carGraphics, {
				tint: self.neonColors[self.currentColorIndex]
			}, {
				duration: 1000,
				easing: tween.easeInOut
			});
		}
	};
	return self;
});
var Coin = Container.expand(function () {
	var self = Container.call(this);
	// Create the coin graphic
	var coinGraphic = self.attachAsset('scoreEffect', {
		anchorX: 0.5,
		anchorY: 0.5,
		width: 40,
		height: 40,
		tint: 0xFFFF00 // Bright yellow color for coins
	});
	// Initialize properties
	self.active = false;
	// Animate coin from source to destination
	self.animate = function (startX, startY, destX, destY) {
		self.active = true;
		self.visible = true;
		self.x = startX + (Math.random() * 120 - 60);
		self.y = startY + (Math.random() * 120 - 60);
		self.alpha = 0;
		self.rotation = Math.random() * Math.PI;
		self.scale.set(1);
		// Duration and timing variables
		var duration = 500 + Math.random() * 200;
		// First make the coin appear with a quick flash
		tween(self, {
			alpha: 1.0,
			scaleX: 1.2,
			scaleY: 1.2
		}, {
			duration: 60,
			onFinish: function onFinish() {
				// Add a spin to the coins as they move
				self.rotation = Math.random() * Math.PI * 2;
				// Small initial burst to create a more dynamic feel
				tween(self, {
					y: self.y - 50 - Math.random() * 70,
					x: self.x + (Math.random() * 100 - 50),
					alpha: 1.0,
					rotation: self.rotation + Math.PI * (Math.random() > 0.5 ? 1 : -1)
				}, {
					duration: 150,
					easing: tween.easeOut,
					onFinish: function onFinish() {
						// Now move directly to the score with arc path
						tween(self, {
							x: destX,
							y: destY,
							scaleX: 0.3,
							scaleY: 0.3,
							rotation: self.rotation + Math.PI * 2,
							alpha: 0
						}, {
							duration: duration,
							easing: tween.easeInOut,
							onFinish: function onFinish() {
								// Flash the score text
								tween(scoreText, {
									scaleX: 1.2,
									scaleY: 1.2
								}, {
									duration: 100,
									onFinish: function onFinish() {
										tween(scoreText, {
											scaleX: 1,
											scaleY: 1
										}, {
											duration: 100
										});
									}
								});
								// Reset coin
								self.active = false;
								self.visible = false;
							}
						});
					}
				});
			}
		});
	};
	return self;
});
var Environment = Container.expand(function () {
	var self = Container.call(this);
	// Environment types
	self.CITY = 0;
	self.BEACH = 1;
	self.JAPAN = 2;
	// Current environment
	self.current = self.CITY;
	// Assets for each environment
	self.roadColors = [0x444444, 0xD2B48C, 0x8B4513]; // City, Beach, Japan
	self.sidewalkColors = [0x999999, 0xF5DEB3, 0x7D8570]; // City, Beach, Japan
	self.skyColors = [0x87CEEB, 0x87CEEB, 0xE0FFFF]; // City, Beach, Japan
	// Change environment based on score
	self.update = function (score) {
		var newEnvironment = self.current;
		// Determine environment based on score
		if (score >= 700) {
			newEnvironment = self.JAPAN;
		} else if (score >= 350) {
			newEnvironment = self.BEACH;
		} else {
			newEnvironment = self.CITY;
		}
		// Only update if environment changed
		if (newEnvironment !== self.current) {
			self.current = newEnvironment;
			return true;
		}
		return false;
	};
	// Apply environment changes
	self.apply = function (road, leftSidewalk, rightSidewalk, game) {
		// Update colors based on current environment
		road.tint = self.roadColors[self.current];
		leftSidewalk.tint = self.sidewalkColors[self.current];
		rightSidewalk.tint = self.sidewalkColors[self.current];
		// Update sky color
		game.setBackgroundColor(self.skyColors[self.current]);
		// Apply special transition effect
		LK.effects.flashScreen(0xFFFFFF, 500);
		// Return message to display for level change
		if (self.current === self.BEACH) {
			return "BEACH LEVEL UNLOCKED!";
		} else if (self.current === self.JAPAN) {
			return "JAPAN LEVEL UNLOCKED!";
		}
		return "";
	};
	return self;
});
var Line = Container.expand(function () {
	var self = Container.call(this);
	// Create road line marking
	var lineGraphics = self.attachAsset('line', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	// Make line vertical
	lineGraphics.rotation = Math.PI / 2; // Rotate 90 degrees
	// Road lines have fixed width to better match car size
	lineGraphics.width = 400; // Line length (now vertical)
	lineGraphics.height = 60; // Line thickness (more visible)
	self.lastY = 0; // Track last Y position for intersection detection
	self.speed = 15; // Default speed
	self.active = true; // Whether the line is active for scoring
	self.scored = false; // Whether this line has been scored already
	// Add visual effect to make lines more prominent
	var glowEffect = self.addChild(new Container());
	var glowAsset = glowEffect.attachAsset('line', {
		anchorX: 0.5,
		anchorY: 0.5,
		width: lineGraphics.width + 20,
		height: lineGraphics.height + 20,
		tint: 0xFFFF00,
		alpha: 0.3
	});
	glowAsset.rotation = Math.PI / 2;
	self.update = function () {
		self.lastY = self.y; // Store last position for collision detection
		self.y += self.speed;
		// Pulse glow effect
		if (LK.ticks % 10 === 0) {
			glowAsset.alpha = 0.2 + Math.random() * 0.2;
		}
		// Remove when off screen
		if (self.y > 2732 + lineGraphics.width / 2) {
			self.active = false;
		}
	};
	return self;
});
var ScoreEffect = Container.expand(function () {
	var self = Container.call(this);
	var effectGraphics = self.attachAsset('scoreEffect', {
		anchorX: 0.5,
		anchorY: 0.5,
		alpha: 0.8
	});
	self.show = function (x, y, isPositive) {
		self.x = x;
		self.y = y;
		if (!isPositive) {
			effectGraphics.tint = 0xFF0000;
			// Play penalty sound
			LK.getSound('penalty').play();
		} else {
			effectGraphics.tint = 0x00FF00;
			// Play point sound
			LK.getSound('point').play();
		}
		// Animation for the effect
		tween(self, {
			alpha: 0,
			y: y - 100
		}, {
			duration: 800,
			easing: tween.easeOut,
			onFinish: function onFinish() {
				self.alpha = 1;
				self.visible = false;
			}
		});
		self.visible = true;
	};
	return self;
});
var Store = Container.expand(function () {
	var self = Container.call(this);
	// Create store building
	var storeGraphics = self.attachAsset('building', {
		anchorX: 0.5,
		anchorY: 0,
		width: 200,
		height: 250,
		tint: 0xFAE5D3 // Light beige for store
	});
	// Add store sign
	var storeSign = self.addChild(new Container());
	var storeSignAsset = storeSign.attachAsset('building', {
		anchorX: 0.5,
		anchorY: 0.5,
		width: 180,
		height: 60,
		tint: 0x3498DB // Blue for store sign
	});
	storeSign.y = 40;
	// Add store window
	var storeWindow = self.addChild(new Container());
	var storeWindowAsset = storeWindow.attachAsset('building', {
		anchorX: 0.5,
		anchorY: 0.5,
		width: 120,
		height: 100,
		tint: 0xD6EAF8 // Light blue for window
	});
	storeWindow.y = 120;
	// Add store door
	var storeDoor = self.addChild(new Container());
	var storeDoorAsset = storeDoor.attachAsset('building', {
		anchorX: 0.5,
		anchorY: 0.5,
		width: 60,
		height: 100,
		tint: 0x784212 // Brown for door
	});
	storeDoor.y = 180;
	self.speed = 10; // Default speed
	self.update = function () {
		self.y += self.speed;
		// Reset store when it goes off screen
		if (self.y > 2732 + storeGraphics.height) {
			self.y = -storeGraphics.height;
			// Store types based on environment
			var storeTypes;
			if (environment && environment.current === environment.BEACH) {
				// Beach stores - surf shops, beach bars, cabanas
				storeTypes = [{
					building: 0xF0F8FF,
					// AliceBlue
					sign: 0x00BFFF,
					// DeepSkyBlue
					window: 0xE0FFFF // LightCyan
				}, {
					building: 0xFFEFD5,
					// PapayaWhip
					sign: 0xFF6347,
					// Tomato
					window: 0xFFDAB9 // PeachPuff
				}, {
					building: 0x40E0D0,
					// Turquoise
					sign: 0xFFFFFF,
					// White
					window: 0xAFEEEE // PaleTurquoise
				}, {
					building: 0xF5DEB3,
					// Wheat
					sign: 0x1E90FF,
					// DodgerBlue
					window: 0xFFF5EE // SeaShell
				}];
			} else if (environment && environment.current === environment.JAPAN) {
				// Japanese stores - traditional shops, ramen stands, markets
				storeTypes = [{
					building: 0x8B4513,
					// SaddleBrown (wood)
					sign: 0xFF0000,
					// Red
					window: 0xFFD700 // Gold
				}, {
					building: 0xFFF5EE,
					// SeaShell (white paper walls)
					sign: 0x000000,
					// Black
					window: 0xFFF8DC // Cornsilk
				}, {
					building: 0x2F4F4F,
					// DarkSlateGray
					sign: 0xDC143C,
					// Crimson
					window: 0xF0FFF0 // Honeydew
				}, {
					building: 0xCD853F,
					// Peru (wood)
					sign: 0x4682B4,
					// SteelBlue
					window: 0xF5F5DC // Beige
				}];
			} else {
				// Default city stores
				storeTypes = [{
					building: 0xFAE5D3,
					sign: 0x3498DB,
					window: 0xD6EAF8
				},
				// Blue store
				{
					building: 0xFCF3CF,
					sign: 0xE74C3C,
					window: 0xFADBD8
				},
				// Red store
				{
					building: 0xD5F5E3,
					sign: 0x8E44AD,
					window: 0xEBDEF0
				},
				// Purple store
				{
					building: 0xEAEDED,
					sign: 0xF39C12,
					window: 0xFAE5D3
				} // Orange store
				];
			}
			var type = storeTypes[Math.floor(Math.random() * storeTypes.length)];
			storeGraphics.tint = type.building;
			storeSignAsset.tint = type.sign;
			storeWindowAsset.tint = type.window;
			// Vary store size slightly
			var sizeVar = 0.8 + Math.random() * 0.4;
			storeGraphics.width = 200 * sizeVar;
			storeGraphics.height = 250 * sizeVar;
			storeSign.scale.set(sizeVar);
			storeWindow.scale.set(sizeVar);
			storeDoor.scale.set(sizeVar);
			// Adjust positions based on new size
			storeSign.y = 40 * sizeVar;
			storeWindow.y = 120 * sizeVar;
			storeDoor.y = 180 * sizeVar;
		}
	};
	return self;
});
var StreetLight = Container.expand(function () {
	var self = Container.call(this);
	// Create pole
	var pole = self.addChild(new Container());
	var poleAsset = pole.attachAsset('building', {
		anchorX: 0.5,
		anchorY: 1.0,
		width: 20,
		height: 200,
		tint: 0x555555 // Dark gray for pole
	});
	// Create light
	var light = self.addChild(new Container());
	var lightAsset = light.attachAsset('scoreEffect', {
		anchorX: 0.5,
		anchorY: 0.5,
		width: 40,
		height: 40,
		tint: 0xFFFF99 // Yellow light
	});
	light.y = -200;
	// Light arm
	var arm = self.addChild(new Container());
	var armAsset = arm.attachAsset('building', {
		anchorX: 0,
		anchorY: 0.5,
		width: 40,
		height: 10,
		tint: 0x555555 // Dark gray for arm
	});
	arm.y = -190;
	self.speed = 10; // Default speed
	self.isLit = Math.random() > 0.2; // Most lights are on
	self.update = function () {
		self.y += self.speed;
		// Make light flicker occasionally
		if (self.isLit && LK.ticks % 20 === 0 && Math.random() > 0.7) {
			lightAsset.alpha = 0.6 + Math.random() * 0.4;
		}
		// Reset light when it goes off screen
		if (self.y > 2732 + 200) {
			self.y = -200;
			self.isLit = Math.random() > 0.2;
			lightAsset.alpha = self.isLit ? 1 : 0.2;
		}
	};
	return self;
});
var TapEffect = Container.expand(function () {
	var self = Container.call(this);
	var effectGraphics = self.attachAsset('scoreEffect', {
		anchorX: 0.5,
		anchorY: 0.5,
		width: 300,
		height: 300,
		alpha: 0.6
	});
	self.show = function (x, y, isPositive) {
		self.x = x;
		self.y = y;
		// Set color based on whether it's a positive or negative tap
		if (isPositive) {
			effectGraphics.tint = 0x00FF00; // Green for good taps
			// Play point sound with lower volume to avoid overwhelming
			LK.getSound('point').play({
				volume: 0.3
			});
			// Trigger coin effects separately - they're now handled in the game code
		} else {
			effectGraphics.tint = 0xFF0000; // Red for bad taps
			// Play penalty sound with lower volume to avoid overwhelming
			LK.getSound('penalty').play({
				volume: 0.3
			});
		}
		// Reset properties before animation
		self.alpha = 1;
		effectGraphics.alpha = 0.6;
		effectGraphics.scale.x = 0.5;
		effectGraphics.scale.y = 0.5;
		self.visible = true;
		// Animate the effect - expand and fade out for a nice ripple effect
		tween(effectGraphics, {
			alpha: 0,
			scaleX: 2.5,
			scaleY: 2.5
		}, {
			duration: 800,
			easing: tween.easeOut,
			onFinish: function onFinish() {
				self.visible = false;
				effectGraphics.scale.x = 0.5;
				effectGraphics.scale.y = 0.5;
			}
		});
	};
	return self;
});
var Tree = Container.expand(function () {
	var self = Container.call(this);
	// Create tree trunk
	var trunk = self.addChild(new Container());
	var trunkAsset = trunk.attachAsset('building', {
		anchorX: 0.5,
		anchorY: 1.0,
		width: 40,
		height: 120,
		tint: 0x8B4513 // Brown color for trunk
	});
	// Create tree foliage (multiple layers for depth)
	var foliage1 = self.addChild(new Container());
	var foliageAsset1 = foliage1.attachAsset('scoreEffect', {
		anchorX: 0.5,
		anchorY: 0.8,
		width: 150,
		height: 150,
		tint: 0x228B22 // Forest green
	});
	foliage1.y = -80;
	var foliage2 = self.addChild(new Container());
	var foliageAsset2 = foliage2.attachAsset('scoreEffect', {
		anchorX: 0.5,
		anchorY: 0.7,
		width: 120,
		height: 120,
		tint: 0x32CD32 // Lime green for highlight
	});
	foliage2.y = -100;
	self.speed = 10; // Default speed
	self.update = function () {
		self.y += self.speed;
		// Reset tree when it goes off screen
		if (self.y > 2732 + 150) {
			self.y = -150;
			// Randomize tree appearance when resetting
			trunkAsset.height = 80 + Math.random() * 80;
			trunkAsset.width = 30 + Math.random() * 20;
			var scale = 0.8 + Math.random() * 0.5;
			foliage1.scale.set(scale);
			foliage2.scale.set(scale * 0.9);
			// Check current environment for tree appearance
			if (environment && environment.current === environment.BEACH) {
				// Palm trees for beach
				trunkAsset.tint = 0xA0522D; // Brown trunk for palm trees
				trunkAsset.height *= 1.5; // Make palm tree trunks much taller
				trunkAsset.width *= 0.7; // Make palm tree trunks thinner
				// Change foliage shape and color for palm trees
				foliageAsset1.width = 200; // Wider palm fronds
				foliageAsset1.height = 120; // Shorter palm fronds
				foliageAsset1.tint = 0xFFFF00; // Yellow palm fronds
				foliageAsset2.width = 220; // Even wider top fronds
				foliageAsset2.height = 100; // Shorter top fronds
				foliageAsset2.tint = 0xFFFF80; // Lighter yellow for highlights
				// Position foliage to look like palm fronds
				foliage1.y = -150; // Raise fronds higher for palm tree appearance
				foliage2.y = -170; // Raise top fronds even higher
			} else if (environment && environment.current === environment.JAPAN) {
				// Cherry blossom trees (sakura)
				trunkAsset.tint = 0x8B4513; // Brown trunk
				// More vibrant pink cherry blossoms
				foliageAsset1.width = 170; // Wider, fuller cherry blossom shape
				foliageAsset1.height = 170; // Rounder for blossom shape
				// Pure pink color for cherry blossoms
				foliageAsset1.tint = 0xFF00FF; // Bright pink cherry blossoms
				// Lighter pink for highlights
				foliageAsset2.width = 140; // Slightly smaller top layer
				foliageAsset2.height = 140; // Rounder for blossom shape
				foliageAsset2.tint = 0xFF80FF; // Lighter pink highlights
				// Position foliage to look more like cherry blossom
				foliage1.y = -100; // Position for traditional cherry blossom tree shape
				foliage2.y = -120; // Position for traditional cherry blossom tree shape
			} else {
				// Default city trees
				var greenVariation = Math.floor(Math.random() * 40);
				foliageAsset1.tint = 34 + greenVariation << 16 | 139 + greenVariation << 8 | 34;
				foliageAsset2.tint = 50 + greenVariation << 16 | 205 + greenVariation << 8 | 50;
			}
		}
	};
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x87CEEB
});
/**** 
* Game Code
****/ 
// Game variables
var car;
var lines = [];
var buildings = [];
var trees = [];
var stores = [];
var streetLights = [];
var score = 0;
var scoreText;
var speedMultiplier = 1;
var lineSpawnRate = 60; // Frames between line spawns
var difficulty = 1;
var isGameActive = true;
var scoreEffects = [];
var tapEffects = [];
var coins = []; // Pool of coin objects
var effectIndex = 0;
var tapEffectIndex = 0;
var coinIndex = 0;
var lastJumpScore = 0;
var badge;
var environment;
var levelText;
var levelTextTimer = 0;
// Create a sky background
game.setBackgroundColor(0x87CEEB); // Light blue sky
// Initialize the road
var road = game.addChild(LK.getAsset('road', {
	anchorX: 0.5,
	anchorY: 0.5,
	x: 2048 / 2,
	y: 2732 / 2,
	width: 1200,
	// Make the road narrower than the full width
	tint: 0x444444 // Darker gray for asphalt
}));
// Add road edges/sidewalks
var leftSidewalk = game.addChild(LK.getAsset('building', {
	anchorX: 0,
	anchorY: 0.5,
	width: (2048 - road.width) / 2,
	height: 2732,
	x: 0,
	y: 2732 / 2,
	tint: 0x999999 // Light gray for sidewalk
}));
var rightSidewalk = game.addChild(LK.getAsset('building', {
	anchorX: 1,
	anchorY: 0.5,
	width: (2048 - road.width) / 2,
	height: 2732,
	x: 2048,
	y: 2732 / 2,
	tint: 0x999999 // Light gray for sidewalk
}));
// Initialize score display
scoreText = new Text2('SCORE: 0', {
	size: 80,
	fill: 0xFFFFFF,
	stroke: 0x000000,
	strokeThickness: 5
});
scoreText.anchor.set(0.5, 0);
scoreText.y = 50; // Move down slightly from top
LK.gui.top.addChild(scoreText);
// Initialize level transition text
levelText = new Text2('', {
	size: 100,
	fill: 0xFFFFFF,
	stroke: 0x000000,
	strokeThickness: 8,
	fontWeight: 'bold'
});
levelText.anchor.set(0.5, 0.5);
levelText.visible = false;
LK.gui.center.addChild(levelText);
// Initialize environment
environment = new Environment();
// Add game instructions
var instructionsText = new Text2('Tap when no lines\nAvoid tapping on lines\nScore 1000 to win', {
	size: 70,
	fill: 0xFFFFFF,
	stroke: 0x800080,
	strokeThickness: 10,
	fontWeight: 'bold',
	align: 'center'
});
instructionsText.anchor.set(0.5, 0);
instructionsText.y = 150;
LK.gui.top.addChild(instructionsText);
// Create buildings for city skyline on both sides of the road (not on the road)
for (var i = 0; i < 20; i++) {
	var building = new Building();
	// Position buildings only on the sides, ensuring they stay off the road
	var roadLeftEdge = (2048 - road.width) / 2;
	var roadRightEdge = 2048 - roadLeftEdge;
	if (i % 2 === 0) {
		// Left side only - ensure buildings stay completely on sidewalk
		var buildingWidth = building.children[0].width;
		building.x = Math.random() * (roadLeftEdge - buildingWidth / 2); // Left side only, accounting for building width
	} else {
		// Right side only - ensure buildings stay completely on sidewalk
		var buildingWidth = building.children[0].width;
		building.x = roadRightEdge + Math.random() * (roadLeftEdge - buildingWidth / 2); // Right side only
	}
	building.y = Math.random() * 2732;
	buildings.push(building);
	game.addChild(building);
}
// Add trees along the road
var trees = [];
for (var i = 0; i < 15; i++) {
	var tree = new Tree();
	// Position trees on the sidewalks
	if (i % 2 === 0) {
		// Left side trees - further from road than buildings
		tree.x = (2048 - road.width) / 2 - 250 - Math.random() * 60;
	} else {
		// Right side trees - further from road than buildings
		tree.x = 2048 - (2048 - road.width) / 2 + 250 + Math.random() * 60;
	}
	// Distribute trees along the road
	tree.y = -150 + i * 350 + Math.random() * 200;
	trees.push(tree);
	game.addChild(tree);
}
// Add stores on the sides
var stores = [];
for (var i = 0; i < 8; i++) {
	var store = new Store();
	// Position stores on the sidewalks, further from the road than trees
	if (i % 2 === 0) {
		// Left side stores
		store.x = (2048 - road.width) / 4;
	} else {
		// Right side stores
		store.x = 2048 - (2048 - road.width) / 4;
	}
	// Distribute stores along the road with some spacing
	store.y = -300 + i * 650 + Math.random() * 300;
	stores.push(store);
	game.addChild(store);
}
// Add street lights
var streetLights = [];
for (var i = 0; i < 12; i++) {
	var light = new StreetLight();
	// Position lights on the edge of the road
	if (i % 2 === 0) {
		// Left side lights
		light.x = (2048 - road.width) / 2 - 20;
	} else {
		// Right side lights
		light.x = 2048 - (2048 - road.width) / 2 + 20;
	}
	// Distribute lights evenly
	light.y = -200 + i * 400 + i % 2 * 200;
	streetLights.push(light);
	game.addChild(light);
}
// Create car
car = new Car();
car.x = 2048 / 2;
car.y = 2732 - 400;
game.addChild(car);
// Bring car to front to make sure it appears on top of lines
game.setChildIndex(car, game.children.length - 1);
// Create badge
badge = new Badge();
badge.x = 2048 - 150; // Position on the right side of screen
badge.y = 2732 / 2; // Position in the middle vertically
badge.visible = false; // Hidden until earned
badge.scale.set(0); // Start with zero scale
game.addChild(badge);
for (var i = 0; i < 5; i++) {
	var effect = new ScoreEffect();
	effect.visible = false;
	scoreEffects.push(effect);
	game.addChild(effect);
}
// Create tap effects pool - increased size to handle multiple effects
for (var i = 0; i < 10; i++) {
	var tapEffect = new TapEffect();
	tapEffect.visible = false;
	tapEffects.push(tapEffect);
	game.addChild(tapEffect);
}
// Create coin effects pool
for (var i = 0; i < 15; i++) {
	var coin = new Coin();
	coin.visible = false;
	coin.active = false;
	coins.push(coin);
	game.addChild(coin);
}
// Game click handler
game.down = function (x, y, obj) {
	if (!isGameActive) {
		return;
	}
	// Check if we clicked on the badge
	if (badge.earned && !badge.active && x >= badge.x - badge.width / 2 && x <= badge.x + badge.width / 2 && y >= badge.y - badge.height / 2 && y <= badge.y + badge.height / 2) {
		badge.activate();
		return;
	}
	// Check if car is already jumping
	if (!car.jumping) {
		car.jump();
		// Check if car is over a road line
		var overLine = false;
		for (var i = 0; i < lines.length; i++) {
			// Check if the car intersects with any vertical road line
			if (lines[i].active && car.intersects(lines[i])) {
				overLine = true;
				break;
			}
		}
		// Score or penalty based on jump
		if (overLine) {
			// Penalty for jumping over a line
			score = Math.max(0, score - 10);
			// Show penalty effect
			var effect = scoreEffects[effectIndex];
			effectIndex = (effectIndex + 1) % scoreEffects.length;
			effect.show(car.x, car.y - 50, false);
			// Show tap feedback effect (red for penalty)
			var tapEffect = tapEffects[tapEffectIndex];
			tapEffectIndex = (tapEffectIndex + 1) % tapEffects.length;
			tapEffect.show(x, y, false);
			// Add multiple red effects for stronger visual feedback
			for (var j = 0; j < 2; j++) {
				var extraEffect = tapEffects[tapEffectIndex];
				tapEffectIndex = (tapEffectIndex + 1) % tapEffects.length;
				extraEffect.show(x + (Math.random() * 100 - 50), y + (Math.random() * 100 - 50), false);
			}
			// Flash screen red for bad tap
			LK.effects.flashScreen(0xff0000, 300);
		} else {
			// Points for jumping on empty road
			var pointsGained = 20 * difficulty;
			score += pointsGained;
			lastJumpScore = pointsGained;
			// Show score effect
			var effect = scoreEffects[effectIndex];
			effectIndex = (effectIndex + 1) % scoreEffects.length;
			effect.show(car.x, car.y - 50, true);
			// Show tap feedback effect (green for points)
			var tapEffect = tapEffects[tapEffectIndex];
			tapEffectIndex = (tapEffectIndex + 1) % tapEffects.length;
			tapEffect.show(x, y, true);
			// Add multiple green effects for stronger visual feedback
			for (var j = 0; j < 2; j++) {
				var extraEffect = tapEffects[tapEffectIndex];
				tapEffectIndex = (tapEffectIndex + 1) % tapEffects.length;
				extraEffect.show(x + (Math.random() * 100 - 50), y + (Math.random() * 100 - 50), true);
			}
			// Create coin animation effects
			var coinCount = 3 + Math.floor(Math.random() * 3); // 3-5 coins
			for (var i = 0; i < coinCount; i++) {
				// Get a coin from the pool
				var coin = coins[coinIndex];
				coinIndex = (coinIndex + 1) % coins.length;
				// Only animate if not currently active
				if (!coin.active) {
					// Set destination coordinates (score text position)
					var destX = 2048 / 2; // Center of screen where the score is
					var destY = 50; // Near the top where the score is
					// Animate the coin
					coin.animate(x, y, destX, destY);
				}
			}
		}
		// Update score display
		scoreText.setText(Math.round(score));
		LK.setScore(Math.round(score));
	}
};
// Start background music
LK.playMusic('bgmusic', {
	fade: {
		start: 0,
		end: 0.4,
		duration: 1000
	}
});
// Game update function
game.update = function () {
	if (!isGameActive) {
		return;
	}
	// Update badge
	badge.update();
	// Update car
	car.update();
	// Update all lines
	for (var i = lines.length - 1; i >= 0; i--) {
		lines[i].update();
		// We don't penalize for just passing over a line anymore
		// Only interactions happen when player taps
		if (!lines[i].scored && lines[i].lastY < car.y && lines[i].y >= car.y) {
			lines[i].scored = true; // Mark as scored
		}
		// Remove inactive lines
		if (!lines[i].active) {
			lines[i].destroy();
			lines.splice(i, 1);
		}
	}
	// Update all buildings
	for (var i = 0; i < buildings.length; i++) {
		buildings[i].speed = 5 * speedMultiplier;
		buildings[i].update();
	}
	// Update all trees
	for (var i = 0; i < trees.length; i++) {
		trees[i].speed = 5 * speedMultiplier; // Changed from 7 to 5 to match building speed
		trees[i].update();
	}
	// Update all stores
	for (var i = 0; i < stores.length; i++) {
		stores[i].speed = 5 * speedMultiplier;
		stores[i].update();
	}
	// Update all street lights
	for (var i = 0; i < streetLights.length; i++) {
		streetLights[i].speed = 5 * speedMultiplier; // Changed from 7 to 5 to match building speed
		streetLights[i].update();
	}
	// Create new lines at intervals - always come from center of the screen
	if (LK.ticks % Math.floor(lineSpawnRate / speedMultiplier) === 0) {
		var line = new Line();
		// Position line at the center of the screen
		line.x = 2048 / 2; // Center X coordinate
		line.y = -50;
		line.speed = 15 * speedMultiplier;
		lines.push(line);
		game.addChild(line);
		// Ensure car is always rendered on top of lines
		game.setChildIndex(car, game.children.length - 1);
	}
	// Increase difficulty over time
	if (LK.ticks % 600 === 0) {
		// Every 10 seconds
		difficulty += 0.1;
		// Speed up game after 500 points, but not too much, and slow down a bit after 800
		if (score > 800) {
			// Cap the speedMultiplier to prevent game from becoming too fast
			speedMultiplier = Math.min(1.6, 1 + (difficulty - 1) * 0.6); // Further reduced speed cap
			lineSpawnRate = Math.max(30, 45 - difficulty * 1.5); // More forgiving line spawn rate
		} else if (score > 500) {
			// Cap the speedMultiplier to prevent game from becoming too fast
			speedMultiplier = Math.min(1.5, 1 + (difficulty - 1) * 0.7); // Lower speed cap
			lineSpawnRate = Math.max(25, 40 - difficulty * 2); // More moderate increase in line spawn rate
		} else {
			speedMultiplier = 1 + (difficulty - 1) * 0.5;
			lineSpawnRate = Math.max(15, 60 - difficulty * 5);
		}
	}
	// Check if score has reached 500 to give badge
	if (score >= 500 && !badge.earned) {
		badge.showEarned();
		// Create notification text
		var badgeNotification = new Text2("SPEED BOOST UNLOCKED!", {
			size: 80,
			fill: 0xFFD700,
			stroke: 0x000000,
			strokeThickness: 6
		});
		badgeNotification.anchor.set(0.5, 0.5);
		LK.gui.center.addChild(badgeNotification);
		// Animate notification
		tween(badgeNotification, {
			alpha: 0,
			y: badgeNotification.y - 100
		}, {
			duration: 2000,
			onFinish: function onFinish() {
				badgeNotification.destroy();
			}
		});
	}
	// Handle environment transitions based on score
	if (environment.update(Math.round(score))) {
		var message = environment.apply(road, leftSidewalk, rightSidewalk, game);
		// Show level transition message
		if (message) {
			levelText.setText(message);
			levelText.visible = true;
			levelTextTimer = 120; // Show for 2 seconds (120 frames)
			// Update car and environment elements based on the theme
			if (environment.current === environment.BEACH) {
				// Beach theme colors for buildings and objects
				for (var i = 0; i < buildings.length; i++) {
					var building = buildings[i];
					if (building.children && building.children[0]) {
						var shade = Math.floor(Math.random() * 30) + 220; // Lighter buildings for beach
						building.children[0].tint = shade << 16 | shade << 8 | shade;
					}
				}
			} else if (environment.current === environment.JAPAN) {
				// Japan theme colors for buildings and objects
				for (var i = 0; i < buildings.length; i++) {
					var building = buildings[i];
					if (building.children && building.children[0]) {
						// Reddish pagoda style buildings
						var red = Math.floor(Math.random() * 55) + 200;
						var green = Math.floor(red * 0.5);
						var blue = Math.floor(green * 0.5);
						building.children[0].tint = red << 16 | green << 8 | blue;
					}
				}
			}
		}
	}
	// Update level transition text timer
	if (levelTextTimer > 0) {
		levelTextTimer--;
		if (levelTextTimer === 0) {
			levelText.visible = false;
		}
	}
	// Check for game over condition
	if (score < 0) {
		isGameActive = false;
		LK.showGameOver();
	}
	// Check for win condition (1000 points to win)
	if (score >= 1000) {
		// Only show win screen once
		if (isGameActive) {
			isGameActive = false;
			// Flash screen with celebration colors
			LK.effects.flashScreen(0xFFD700, 400); // Gold flash
			// Create coin shower effect for winning celebration
			LK.setTimeout(function () {
				for (var i = 0; i < 40; i++) {
					var coin = coins[Math.floor(Math.random() * coins.length)];
					if (!coin.active) {
						// Random positions for coins
						var startX = Math.random() * 2048;
						var startY = -100;
						var destX = Math.random() * 2048;
						var destY = Math.random() * 2732;
						coin.animate(startX, startY, destX, destY);
					}
				}
				// Show win screen immediately after coin effect starts
				LK.showYouWin();
			}, 300);
		}
	}
};