/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Coin = Container.expand(function () {
var self = Container.call(this);
var coinGraphics = self.attachAsset('coin', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 4;
self.update = function () {
if (gamePaused) {
return;
} // Freeze movement during quiz
self.y += self.speed;
};
return self;
});
var CrewMember = Container.expand(function () {
var self = Container.call(this);
var crewGraphics = self.attachAsset('crew', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 4;
self.update = function () {
if (gamePaused) {
return;
} // Freeze movement during quiz
self.y += self.speed;
// Breathing animation - expand and shrink
var time = LK.ticks * 0.05;
var breathingScale = 1 + Math.sin(time) * 0.15;
crewGraphics.scaleX = breathingScale;
crewGraphics.scaleY = breathingScale;
};
return self;
});
var Obstacle = Container.expand(function () {
var self = Container.call(this);
var obstacleGraphics = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 1;
self.update = function () {
if (gamePaused) {
return;
} // Freeze movement during quiz
self.y += self.speed;
};
return self;
});
var Pirate = Container.expand(function () {
var self = Container.call(this);
var pirateGraphics = self.attachAsset('pirate', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 6;
self.update = function () {
if (gamePaused) {
return;
} // Freeze movement during quiz
self.y += self.speed;
};
return self;
});
var RainDrop = Container.expand(function () {
var self = Container.call(this);
var rainGraphics = self.attachAsset('rainreal', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.6,
//{X_new}
scaleX: 0.6 + Math.random() * 0.4,
scaleY: 0.8 + Math.random() * 0.6
});
self.speed = 6 + Math.random() * 8;
self.swayAmount = 1 + Math.random() * 2;
self.swaySpeed = 0.015 + Math.random() * 0.025;
self.startX = self.x;
self.baseAlpha = 0.5 + Math.random() * 0.3;
self.dropType = Math.floor(Math.random() * 3);
self.update = function () {
if (gamePaused) {
return;
}
self.y += self.speed;
// Add wind-like horizontal sway for realism
self.x = self.startX + Math.sin(LK.ticks * self.swaySpeed) * self.swayAmount;
// Subtle rotation for falling effect
rainGraphics.rotation = Math.sin(LK.ticks * 0.1 + self.startX * 0.005) * 0.15;
// Dynamic alpha based on distance for depth perception
var distanceFromTop = self.y;
var fadeStartY = 500;
if (self.y > fadeStartY) {
var fadeProgress = (self.y - fadeStartY) / (2800 - fadeStartY);
rainGraphics.alpha = self.baseAlpha * (1 - fadeProgress * 0.7);
} else {
rainGraphics.alpha = self.baseAlpha;
}
// Ensure minimum visibility
if (rainGraphics.alpha < 0.1) {
rainGraphics.alpha = 0.1;
}
};
return self;
});
var Seagull = Container.expand(function () {
var self = Container.call(this);
var seagullGraphics = self.attachAsset('seagullreal', {
anchorX: 0.5,
anchorY: 0.5
});
// Create shadow below seagull
var shadowGraphics = self.attachAsset('seagullreal', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.2,
scaleX: 0.8,
scaleY: 0.4
});
shadowGraphics.tint = 0x000000;
self.speed = 1 + Math.random() * 0.5;
self.wavyPhase = Math.random() * Math.PI * 2;
self.wavySpeed = 0.03 + Math.random() * 0.02;
self.wavyAmount = 8 + Math.random() * 5;
self.startY = self.y;
self.wingFlapPhase = Math.random() * Math.PI * 2;
self.wingFlapSpeed = 0.15 + Math.random() * 0.1;
self.update = function () {
if (gamePaused) {
return;
}
// Move seagull horizontally across screen in straight line
self.x -= self.speed;
// Add wavy animation - sinusoidal vertical movement
var wavyAmount = Math.sin(LK.ticks * self.wavySpeed + self.wavyPhase) * self.wavyAmount;
self.y = self.startY + wavyAmount;
// Add wing flapping animation - scale Y for wing movement
var wingFlap = Math.sin(LK.ticks * self.wingFlapSpeed + self.wingFlapPhase) * 0.08;
seagullGraphics.scaleY = 1 + wingFlap;
// Position shadow below seagull
shadowGraphics.y = 120;
// Wrap around screen
if (self.x < -200) {
self.x = 2248;
self.y = Math.random() * 600 - 200;
self.startY = self.y;
self.wavyPhase = Math.random() * Math.PI * 2;
self.wingFlapPhase = Math.random() * Math.PI * 2;
}
};
return self;
});
var Ship = Container.expand(function () {
var self = Container.call(this);
var shipGraphics = self.attachAsset('ship', {
anchorX: 0.5,
anchorY: 0.5
});
self.baseSpeed = 3;
self.currentSpeed = self.baseSpeed;
self.isShielded = false;
self.shieldTime = 0;
self.stickyTime = 0;
self.isSizeModified = false;
self.sizeTime = 0;
self.originalScale = 1;
var shieldGraphics = self.attachAsset('shield', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.8,
scaleX: 1.2,
scaleY: 1.2
});
shieldGraphics.visible = false;
self.activateShield = function () {
self.isShielded = true;
self.shieldTime = 300;
shieldGraphics.visible = true;
};
self.activateStickyControls = function () {
self.stickyTime = 300;
};
self.setSizeModifier = function (scale, duration) {
self.isSizeModified = true;
self.sizeTime = duration;
tween(shipGraphics, {
scaleX: scale,
scaleY: scale
}, {
duration: 200
});
tween(shieldGraphics, {
scaleX: scale,
scaleY: scale
}, {
duration: 200
});
};
self.update = function () {
if (gamePaused) {
return;
} // Freeze movement when game is paused
// Shield follows ship position smoothly
if (self.isShielded) {
tween(shieldGraphics, {
x: self.x,
y: self.y
}, {
duration: 50,
easing: tween.linear
});
}
if (self.shieldTime > 0) {
self.shieldTime--;
if (self.shieldTime <= 0) {
self.isShielded = false;
shieldGraphics.visible = false;
}
}
if (self.stickyTime > 0) {
self.stickyTime--;
}
if (self.sizeTime > 0) {
self.sizeTime--;
if (self.sizeTime <= 0) {
self.isSizeModified = false;
tween(shipGraphics, {
scaleX: 1,
scaleY: 1
}, {
duration: 200
});
tween(shieldGraphics, {
scaleX: 1,
scaleY: 1
}, {
duration: 200
});
}
}
// Ship stays in place - world moves around it
};
return self;
});
var Stone = Container.expand(function () {
var self = Container.call(this);
var stoneGraphics = self.attachAsset('stone', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 0;
self.update = function () {
if (gamePaused) {
return;
} // Freeze movement during quiz
self.y += self.speed;
stoneGraphics.rotation += 0;
};
return self;
});
var Sunlight = Container.expand(function () {
var self = Container.call(this);
var sunGraphics = self.attachAsset('sunlight', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 1;
self.intensity = 0.4 + Math.random() * 0.3;
self.rayWidth = 0.8 + Math.random() * 0.4;
self.flickerSpeed = 0.03 + Math.random() * 0.02;
self.update = function () {
if (gamePaused) {
return;
}
self.y += self.speed;
// Realistic sunlight ray animation with flickering and depth
var time = LK.ticks * self.flickerSpeed;
var flicker = Math.sin(time + self.x * 0.02) * 0.15;
var depth = Math.sin(time * 0.7 + self.y * 0.001) * 0.1;
// Dynamic alpha for realistic light penetration
sunGraphics.alpha = self.intensity + flicker + depth;
// Width variation for light scattering effect
sunGraphics.scaleX = self.rayWidth + Math.sin(time * 1.2) * 0.2;
// Subtle rotation for light movement
sunGraphics.rotation = Math.sin(time * 0.5) * 0.05;
// Color temperature variation
var warmth = 0.1 + Math.sin(time * 0.3) * 0.05;
if (level === 1) {
sunGraphics.tint = 0xFFFF99; // Bright daylight
} else if (level === 2) {
sunGraphics.tint = 0xFFCC66; // Warm sunset
} else if (level === 3) {
sunGraphics.tint = 0x9999FF; // Cool moonlight
} else {
sunGraphics.tint = 0xCCCCCC; // Storm light
}
};
return self;
});
var WaterTile = Container.expand(function () {
var self = Container.call(this);
var tileGraphics = self.attachAsset('waterTile', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 2;
self.baseColor = 0x0066cc;
self.waveOffset = Math.random() * Math.PI * 2;
self.update = function () {
if (gamePaused) {
return;
}
self.y += self.speed;
// Keep water tiles stable without animation effects
tileGraphics.alpha = 0.85;
// No scale variation
tileGraphics.scaleY = 1;
// No horizontal movement
tileGraphics.x = 0;
};
return self;
});
var Wave = Container.expand(function () {
var self = Container.call(this);
var waveGraphics = self.attachAsset('wave', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 4;
self.wavePhase = Math.random() * Math.PI * 2;
self.waveAmplitude = 0.8 + Math.random() * 0.4;
self.baseScale = 1;
self.update = function () {
if (gamePaused) {
return;
} // Freeze movement during quiz
self.y += self.speed;
// Keep wave at stable normal size - no scaling animations
waveGraphics.scaleX = 1;
waveGraphics.scaleY = 1;
// Stable alpha without crest highlighting
waveGraphics.alpha = 0.85;
// No rotation animation
waveGraphics.rotation = 0;
// Water color based on level - stable coloring
if (level === 1) {
waveGraphics.tint = 0x4A90E2; // Bright blue
} else if (level === 2) {
waveGraphics.tint = 0x3A7BD5; // Darker blue
} else if (level === 3) {
waveGraphics.tint = 0x2A5AA0; // Night blue
} else {
waveGraphics.tint = 0x1A4A80; // Storm blue
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB
});
/****
* Game Code
****/
var ship;
var obstacles = [];
var crewMembers = [];
var coins = [];
var hearts = [];
var waterTiles = [];
var sunlightRays = [];
var level = 1;
var health = 3;
var maxHealth = 4;
var crewCount = 0;
var coinCount = 0;
var distance = 0;
var gamePaused = false;
var gameStarted = false;
var menuContainer = null;
var distanceText = new Text2('Distance: 0m', {
size: 50,
fill: 0x00FFFF,
stroke: 0x000033,
strokeThickness: 2
});
distanceText.anchor.set(0.5, 0);
distanceText.x = 0;
distanceText.y = 120;
LK.gui.top.addChild(distanceText);
var gameSpeed = 2;
var quizActive = false;
var quizTimer = 0;
var nextQuizTime = 480; // Start first quiz after 8 seconds
var doubleCoinsTime = 0;
var extraObstaclesTime = 0;
var clearPathTime = 0;
var scoreFreezeTime = 0;
// Quiz system
var quizQuestions = [{
question: "What does FOB stand for in shipping terms?",
answers: ["Free On Board", "Freight on Boat", "Foreign Object Bureau", "Full Ocean Bill"],
correct: 0
}, {
question: "Which maritime organization sets international shipping standards?",
answers: ["WHO", "IMO", "WTO", "ILO"],
correct: 1
}, {
question: "What is the front of a ship called?",
answers: ["Stern", "Port", "Bow", "Starboard"],
correct: 2
}, {
question: "EXW means the seller delivers when goods are:",
answers: ["At seller's premises", "On the ship", "At destination", "In transit"],
correct: 0
}, {
question: "What does CIF include in shipping terms?",
answers: ["Cost only", "Insurance only", "Freight only", "Cost, Insurance, Freight"],
correct: 3 //{3F_new}
}, {
question: "What is the right side of a ship called?",
answers: ["Port", "Starboard", "Bow", "Stern"],
correct: 1
}, {
question: "DDP means the seller is responsible for:",
answers: ["Delivery at port", "Delivery duty paid", "Dock departure point", "Direct delivery purchase"],
correct: 1
}, {
question: "What does TEU stand for in container shipping?",
answers: ["Total Export Unit", "Twenty-foot Equivalent Unit", "Terminal Exchange Unit", "Transport Equipment Unit"],
correct: 1
}, {
question: "Which term means 'Free Alongside Ship'?",
answers: ["CAS", "FAS", "DAS", "PAS"],
correct: 1 //{3N_fix}
}, {
question: "What is the kitchen area on a ship called?",
answers: ["Mess", "Galley", "Cabin", "Hold"],
correct: 1
}, {
question: "CFR includes which costs?",
answers: ["Cost and freight", "Cost, freight, risk", "Customs, freight, rate", "Container freight rate"],
correct: 0
}, {
question: "What does DAP stand for?",
answers: ["Delivery at place", "Dock arrival point", "Delivered at place", "Direct arrival point"],
correct: 2
}, {
question: "The left side of a ship is called:",
answers: ["Starboard", "Port", "Bow", "Stern"],
correct: 1
}, {
question: "What is a ship's maximum cargo capacity called?",
answers: ["Deadweight", "Gross tonnage", "Net tonnage", "Displacement"],
correct: 0
}, {
question: "FCA means:",
answers: ["Free carrier", "Freight cost allowance", "Full container access", "Forward cargo arrangement"],
correct: 0
}];
var currentQuiz = null;
var quizContainer = null;
var quizTimeRemaining = 600; // 10 seconds
var effectDisplay = null;
var lastAppliedEffect = '';
var effectExpirationDisplay = null;
var atmosphericParticles = [];
var seagulls = [];
var rainActive = false;
var rainDuration = 0;
var nextRainTime = 0;
var nextSeagullTime = 0;
function spawnSeagull() {
var seagull = new Seagull();
seagull.x = Math.random() > 0.5 ? -200 : 2248;
seagull.y = Math.random() * 600 - 200;
seagull.startY = seagull.y;
seagulls.push(seagull);
game.addChild(seagull);
// Move seagull to top of rendering hierarchy to appear above all other assets
if (game.children.length > 0) {
game.setChildIndex(seagull, game.children.length - 1);
}
}
function spawnRain() {
rainActive = true;
rainDuration = 300 + Math.random() * 300; // 5-8 seconds of rain
nextRainTime = LK.ticks + 1800 + Math.random() * 1200; // 30-50 seconds until next rain
// Spawn rain drops separately with staggered timing - increased count for full screen coverage
for (var i = 0; i < 80; i++) {
(function (index) {
LK.setTimeout(function () {
if (!rainActive) {
return;
}
var rainDrop = new RainDrop();
rainDrop.x = Math.random() * 2048;
rainDrop.y = -500 - Math.random() * 500;
rainDrop.startX = rainDrop.x;
atmosphericParticles.push(rainDrop);
game.addChild(rainDrop);
}, index * 8); // Stagger each drop by 8ms for faster, denser coverage
})(i);
}
} //{40_new}
function stopRain() {
rainActive = false;
}
function spawnAtmosphericParticles(weatherType) {
// Clear existing particles
for (var i = atmosphericParticles.length - 1; i >= 0; i--) {
atmosphericParticles[i].destroy();
}
atmosphericParticles = [];
// Spawn new particles based on weather
var particleCount = weatherType === 'storm' ? 8 : 4;
for (var i = 0; i < particleCount; i++) {
var particle = createAtmosphericParticle(weatherType);
atmosphericParticles.push(particle);
game.addChild(particle);
}
}
function createAtmosphericParticle(weatherType) {
var particle = new Container();
var particleGraphics;
if (weatherType === 'day') {
// Light sparkles on water
particleGraphics = particle.attachAsset('sunlight', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.1,
scaleY: 0.3,
alpha: 0.3
});
particleGraphics.tint = 0xFFFFAA;
} else if (weatherType === 'sunset') {
// Warm light reflections
particleGraphics = particle.attachAsset('sunlight', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.15,
scaleY: 0.4,
alpha: 0.4
});
particleGraphics.tint = 0xFF9966;
} else if (weatherType === 'night') {
// Moonlight streaks
particleGraphics = particle.attachAsset('sunlight', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.08,
scaleY: 0.5,
alpha: 0.2
});
particleGraphics.tint = 0xCCDDFF;
} else {
// Storm effects
particleGraphics = particle.attachAsset('sunlight', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.05,
scaleY: 0.8,
alpha: 0.1
});
particleGraphics.tint = 0x888888;
}
particle.x = Math.random() * 2048;
particle.y = Math.random() * 2732;
particle.speed = 0.5 + Math.random() * 1.5;
particle.weatherType = weatherType;
particle.animationOffset = Math.random() * Math.PI * 2;
particle.update = function () {
if (gamePaused) {
return;
}
// Move particles slowly
this.y += this.speed;
if (this.y > 2800) {
this.y = -100;
this.x = Math.random() * 2048;
}
// Animate based on weather type
var time = LK.ticks * 0.02 + this.animationOffset;
if (this.weatherType === 'day') {
particleGraphics.alpha = 0.2 + Math.sin(time * 2) * 0.15;
} else if (this.weatherType === 'sunset') {
particleGraphics.alpha = 0.3 + Math.sin(time * 1.5) * 0.2;
particleGraphics.scaleX = 0.15 + Math.sin(time) * 0.05;
} else if (this.weatherType === 'night') {
particleGraphics.alpha = 0.15 + Math.sin(time * 3) * 0.1;
} else {
particleGraphics.alpha = 0.05 + Math.sin(time * 4) * 0.08;
particleGraphics.rotation = Math.sin(time * 2) * 0.3;
}
};
return particle;
}
// UI Elements - Better separated and positioned
var scoreText = new Text2('Score: 0', {
size: 65,
fill: 0x00FF00,
stroke: 0x000033,
strokeThickness: 2
});
scoreText.anchor.set(0.5, 0);
scoreText.x = 0;
scoreText.y = 20;
LK.gui.top.addChild(scoreText);
var levelText = new Text2('Level: 1', {
size: 60,
fill: 0xFFD700
});
levelText.anchor.set(1, 0);
levelText.x = -20;
levelText.y = 20;
LK.gui.topRight.addChild(levelText);
var crewText = new Text2('Crew: 0', {
size: 50,
fill: 0x00BFFF
});
crewText.anchor.set(0, 1);
crewText.x = 20;
crewText.y = -20;
LK.gui.bottomLeft.addChild(crewText);
var coinText = new Text2('Coins: 0', {
size: 50,
fill: 0xffd700
});
coinText.anchor.set(1, 1);
coinText.x = -20;
coinText.y = -20;
LK.gui.bottomRight.addChild(coinText);
// Initialize pixelated ocean background
createWaterTileGrid();
// Initialize game elements
ship = game.addChild(new Ship());
ship.x = 1024;
ship.y = 2400;
// Show main menu on start
showMainMenu();
// Create hearts display
for (var i = 0; i < 4; i++) {
var heart = LK.getAsset('heart', {
anchorX: 0,
anchorY: 0
});
hearts.push(heart);
LK.gui.topLeft.addChild(heart);
}
function updateScore() {
if (scoreFreezeTime <= 0) {
var score = Math.floor(distance) + crewCount * 100;
LK.setScore(score);
scoreText.setText('Score: ' + score);
}
}
function updateLevel() {
var newLevel = Math.floor(distance / 3000) + 1; // Level up faster for increased difficulty
if (newLevel > level && newLevel <= 4) {
level = newLevel;
levelText.setText('Level: ' + level);
gameSpeed += 0.3; // More moderate speed boost per level
// Change background color and lighting based on level with realistic gradients
if (level === 1) {
game.setBackgroundColor(0x87CEEB); // Day - bright sky blue with gradient feel
updateWaterTileColors(0x0066cc); // Crystal clear tropical water
updateSunlightColors(0xFFF4AA, 0.5); // Warm golden sunlight
// Add atmospheric particles for day
spawnAtmosphericParticles('day');
} else if (level === 2) {
game.setBackgroundColor(0xFF6B47); // Sunset - warm orange with red tints
updateWaterTileColors(0x2E5984); // Sunset reflected water
updateSunlightColors(0xFFB366, 0.6); // Intense sunset rays
// Add atmospheric particles for sunset
spawnAtmosphericParticles('sunset');
} else if (level === 3) {
game.setBackgroundColor(0x0F1B3C); // Deep night - dark navy
updateWaterTileColors(0x1A2E5C); // Moonlit water with silver reflections
updateSunlightColors(0xB8C5FF, 0.3); // Cool moonbeams
// Add atmospheric particles for night
spawnAtmosphericParticles('night');
} else if (level === 4) {
game.setBackgroundColor(0x2C3E50); // Storm - dark slate with green tints
updateWaterTileColors(0x34495E); // Turbulent storm water
updateSunlightColors(0x95A5A6, 0.15); // Harsh storm lighting
// Add atmospheric particles for storm
spawnAtmosphericParticles('storm');
}
}
}
function updateWaterTileColors(color) {
for (var i = 0; i < waterTiles.length; i++) {
if (waterTiles[i] && waterTiles[i].children[0]) {
// Calculate depth-based color variation
var depthVariation = Math.sin(waterTiles[i].x * 0.01 + waterTiles[i].y * 0.005) * 0.1;
var adjustedColor = color;
// Add depth gradient effect
if (level === 1) {
adjustedColor = 0x0066CC + Math.floor(depthVariation * 0x001122);
} else if (level === 2) {
adjustedColor = 0x004499 + Math.floor(depthVariation * 0x001111);
} else if (level === 3) {
adjustedColor = 0x002266 + Math.floor(depthVariation * 0x000011);
} else {
adjustedColor = 0x003344 + Math.floor(depthVariation * 0x000022);
}
tween(waterTiles[i].children[0], {
tint: adjustedColor
}, {
duration: 2000
});
waterTiles[i].baseColor = adjustedColor;
}
}
}
function updateSunlightColors(color, maxAlpha) {
for (var i = 0; i < sunlightRays.length; i++) {
if (sunlightRays[i] && sunlightRays[i].children[0]) {
tween(sunlightRays[i].children[0], {
tint: color
}, {
duration: 2000
});
sunlightRays[i].maxAlpha = maxAlpha;
}
}
}
function createWaterTileGrid() {
// Create a grid of water tiles for pixelated ocean background
for (var x = 0; x < 22; x++) {
// Cover full width with some overlap
for (var y = -5; y < 35; y++) {
// Cover full height with extra tiles
var waterTile = new WaterTile();
waterTile.x = x * 95; // Slight overlap for seamless look
waterTile.y = y * 95;
waterTiles.push(waterTile);
game.addChild(waterTile);
}
}
}
function spawnSunlightRay() {
var sunray = new Sunlight();
sunray.x = Math.random() * 2048;
sunray.y = -400;
sunray.maxAlpha = level === 1 ? 0.4 : level === 2 ? 0.5 : level === 3 ? 0.2 : 0.1;
sunlightRays.push(sunray);
game.addChild(sunray);
}
function spawnObstacle() {
if (clearPathTime > 0) {
return;
}
var obstacleType = Math.floor(Math.random() * 4);
var obstacle;
switch (obstacleType) {
case 0:
obstacle = new Obstacle();
break;
case 1:
obstacle = new Pirate();
break;
case 2:
obstacle = new Wave();
break;
case 3:
obstacle = new Stone();
break;
}
obstacle.x = Math.random() * 1800 + 124;
obstacle.y = -100;
obstacle.speed = obstacle.speed + gameSpeed * 0.6 + level * 0.4; // Much gentler speed increases
obstacles.push(obstacle);
game.addChild(obstacle);
}
function spawnCrewMember() {
var crew = new CrewMember();
crew.x = Math.random() * 1800 + 124;
crew.y = -100;
crew.speed = 3 + gameSpeed;
crewMembers.push(crew);
game.addChild(crew);
}
function spawnCoin() {
var coin = new Coin();
coin.x = Math.random() * 1800 + 124;
coin.y = -100;
coin.speed = 3 + gameSpeed;
coins.push(coin);
game.addChild(coin);
}
function showQuiz() {
if (quizActive) {
return;
}
quizActive = true;
gamePaused = true; // Freeze all game movement
quizTimeRemaining = 1200; // 20 seconds
currentQuiz = quizQuestions[Math.floor(Math.random() * quizQuestions.length)];
quizContainer = game.addChild(new Container());
quizContainer.alpha = 0; // Start invisible for smooth entrance
LK.getSound('tiktoksoundquestion').play();
var bg = quizContainer.attachAsset('quizBg', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1366,
alpha: 0.95
});
// Animate quiz entrance
tween(quizContainer, {
alpha: 1
}, {
duration: 300
});
// Show current active effects
var effectsText = getActiveEffectsText();
if (effectsText) {
var effectDisplay = new Text2(effectsText, {
size: 45,
fill: 0xFFFF00
});
effectDisplay.anchor.set(0.5, 0.5);
effectDisplay.x = 1024;
effectDisplay.y = 900;
quizContainer.addChild(effectDisplay);
}
var questionText = new Text2(currentQuiz.question, {
size: 75,
fill: 0xFFFFFF,
stroke: 0x000033,
strokeThickness: 3,
wordWrap: true,
wordWrapWidth: 1500,
letterSpacing: 2
});
questionText.anchor.set(0.5, 0.5);
questionText.x = 1024;
questionText.y = 1050;
quizContainer.addChild(questionText);
var timerText = new Text2('Time: 20', {
size: 60,
fill: 0xFFFF00,
stroke: 0x000000,
strokeThickness: 3
});
timerText.anchor.set(0.5, 0.5);
timerText.x = 1024;
timerText.y = 950;
quizContainer.addChild(timerText);
quizContainer.timerText = timerText;
// Create answer buttons with improved styling
quizContainer.answerButtons = [];
for (var i = 0; i < 4; i++) {
var answerContainer = new Container();
answerContainer.x = 1024;
answerContainer.y = 1320 + i * 170;
var answerBg = answerContainer.attachAsset('quizBg', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.92,
scaleY: 0.28,
alpha: 0.85
});
var answerText = new Text2(String.fromCharCode(65 + i) + ') ' + currentQuiz.answers[i], {
size: 70,
fill: 0xFFFFFF,
stroke: 0x000033,
strokeThickness: 4,
wordWrap: true,
wordWrapWidth: 1250,
letterSpacing: 1
});
answerText.anchor.set(0.5, 0.5);
answerContainer.addChild(answerText);
// Store references for animations
answerContainer.bg = answerBg;
answerContainer.text = answerText;
answerContainer.answerIndex = i;
// Store index in closure to avoid reference issues
(function (index) {
answerContainer.down = function (x, y, obj) {
// Animate button press - use the stored references instead of obj properties
tween(answerContainer.bg, {
scaleX: 0.95,
scaleY: 0.22
}, {
duration: 100
});
tween(answerContainer.text, {
alpha: 0.8
}, {
duration: 100
});
handleQuizAnswer(index);
};
})(i);
quizContainer.answerButtons.push(answerContainer);
quizContainer.addChild(answerContainer);
}
}
function handleQuizAnswer(answerIndex) {
if (!quizActive) {
return;
}
// Prevent multiple answers
quizActive = false;
var isCorrect = answerIndex === currentQuiz.correct;
if (isCorrect) {
LK.getSound('correctanswer').play();
applyPowerUp();
} else {
LK.getSound('incorrectanswer').play();
applyPenalty();
}
// Show effect feedback for 2 seconds
if (lastAppliedEffect) {
showEffectFeedback(lastAppliedEffect, isCorrect);
}
hideQuiz();
nextQuizTime = LK.ticks + 900; // Every 15 seconds
}
function getActiveEffectsText() {
var effects = [];
if (ship.isShielded) {
effects.push('🛡️ Shield Active');
}
if (doubleCoinsTime > 0) {
effects.push('💰 Double Coins');
}
if (ship.isSizeModified && ship.children[0].scaleX < 1) {
effects.push('⬇️ Smaller Ship');
}
if (ship.isSizeModified && ship.children[0].scaleX > 1) {
effects.push('⬆️ Bigger Ship');
}
if (ship.stickyTime > 0) {
effects.push('🐌 Sticky Controls');
}
if (extraObstaclesTime > 0) {
effects.push('⚠️ Extra Obstacles');
}
if (scoreFreezeTime > 0) {
effects.push('❄️ Score Frozen');
}
if (clearPathTime > 0) {
effects.push('🚫 Clear Path');
}
if (effects.length === 0) {
return null;
}
return 'Active Effects:\n' + effects.join('\n');
}
function applyPowerUp() {
var random = Math.random();
var powerUp;
// Weighted random selection - higher chance of beneficial power-ups
if (random < 0.25) {
powerUp = 'shield';
} else if (random < 0.45) {
powerUp = 'clearPath';
} else if (random < 0.60) {
powerUp = 'smallerShip';
} else if (random < 0.80) {
powerUp = 'doubleCoins';
} else {
powerUp = 'extraLife';
}
switch (powerUp) {
case 'shield':
ship.activateShield();
lastAppliedEffect = '🛡️ Shield Activated!';
break;
case 'doubleCoins':
doubleCoinsTime = 600;
lastAppliedEffect = '💰 Double Coins for 10s!';
break;
case 'extraLife':
if (health < 5) {
health++;
updateHearts();
lastAppliedEffect = '❤️ Extra Life Gained!';
} else {
lastAppliedEffect = '❤️ Life Full Already!';
}
break;
case 'clearPath':
clearPathTime = 240;
lastAppliedEffect = '🚫 Clear Path for 4s!';
// Remove existing obstacles
for (var i = obstacles.length - 1; i >= 0; i--) {
obstacles[i].destroy();
obstacles.splice(i, 1);
}
break;
case 'smallerShip':
ship.setSizeModifier(0.7, 300);
lastAppliedEffect = '⬇️ Smaller Ship for 5s!';
break;
}
}
function applyPenalty() {
var penalties = ['extraObstacles', 'healthLoss', 'stickyControls', 'scoreFreeze', 'biggerShip'];
var penalty = penalties[Math.floor(Math.random() * penalties.length)];
switch (penalty) {
case 'extraObstacles':
extraObstaclesTime = 480;
lastAppliedEffect = '⚠️ Extra Obstacles for 8s!';
break;
case 'healthLoss':
takeDamage();
lastAppliedEffect = '💔 Lost 1 Heart!';
break;
case 'stickyControls':
ship.activateStickyControls();
lastAppliedEffect = '🐌 Sticky Controls for 5s!';
break;
case 'scoreFreeze':
scoreFreezeTime = 300;
lastAppliedEffect = '❄️ Score Frozen for 5s!';
break;
case 'biggerShip':
ship.setSizeModifier(1.4, 240);
lastAppliedEffect = '⬆️ Bigger Ship for 4s!';
break;
}
}
function showEffectExpiration(effectName) {
if (effectExpirationDisplay) {
effectExpirationDisplay.destroy();
}
effectExpirationDisplay = game.addChild(new Container());
var expirationBg = effectExpirationDisplay.attachAsset('quizBg', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 400,
scaleX: 0.5,
scaleY: 0.2,
alpha: 0.8
});
var expirationText = new Text2(effectName + ' Expired!', {
size: 45,
fill: 0xFFAA00
});
expirationText.anchor.set(0.5, 0.5);
expirationText.x = 1024;
expirationText.y = 400;
effectExpirationDisplay.addChild(expirationText);
// Auto-hide after 1.5 seconds
LK.setTimeout(function () {
if (effectExpirationDisplay) {
effectExpirationDisplay.destroy();
effectExpirationDisplay = null;
}
}, 1500);
}
function showEffectFeedback(effectText, isPositive) {
if (effectDisplay) {
effectDisplay.destroy();
}
effectDisplay = game.addChild(new Container());
var feedbackBg = effectDisplay.attachAsset('quizBg', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1366,
scaleX: 0.6,
scaleY: 0.3,
alpha: 0.8
});
var feedbackText = new Text2(effectText, {
size: 60,
fill: isPositive ? 0x00FF00 : 0xFF4444
});
feedbackText.anchor.set(0.5, 0.5);
feedbackText.x = 1024;
feedbackText.y = 1366;
effectDisplay.addChild(feedbackText);
// Auto-hide after 2 seconds
LK.setTimeout(function () {
if (effectDisplay) {
effectDisplay.destroy();
effectDisplay = null;
}
}, 2000);
}
function hideQuiz() {
quizActive = false;
gamePaused = false; // Resume game movement
LK.getSound('tiktoksoundquestion').stop();
if (quizContainer) {
// Animate quiz exit
tween(quizContainer, {
alpha: 0
}, {
duration: 200,
onFinish: function onFinish() {
if (quizContainer) {
quizContainer.destroy();
quizContainer = null;
}
}
});
}
}
function takeDamage() {
if (ship.isShielded) {
return;
}
health--;
updateHearts();
LK.getSound('hit').play();
LK.effects.flashScreen(0xff0000, 500);
if (health <= 0) {
// Freeze the game completely
gameStarted = false;
gamePaused = true;
LK.getSound('died').play();
// Create custom game over display with statistics
var gameOverContainer = game.addChild(new Container());
var gameOverBg = gameOverContainer.attachAsset('quizBg', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1366,
scaleX: 1.2,
scaleY: 1.4,
alpha: 0.95
});
var finalScore = Math.floor(distance) + crewCount * 100;
var statsText = 'GAME OVER\n\n' + 'Final Statistics:\n' + 'Score: ' + finalScore + '\n' + 'Distance: ' + Math.floor(distance) + 'm\n' + 'Crew Members: ' + crewCount + '\n' + 'Coins: ' + coinCount + '\n' + 'Level Reached: ' + level;
var statsDisplay = new Text2(statsText, {
size: 60,
fill: 0xFFFFFF
});
statsDisplay.anchor.set(0.5, 0.5);
statsDisplay.x = 1024;
statsDisplay.y = 1366;
gameOverContainer.addChild(statsDisplay);
// Show standard game over after 3 seconds
LK.setTimeout(function () {
LK.showGameOver();
// Show menu again after game over
LK.setTimeout(function () {
showMainMenu();
}, 1000);
}, 3000);
}
}
function updateHearts() {
for (var i = 0; i < hearts.length; i++) {
hearts[i].visible = i < health;
hearts[i].x = 120 + i * 50;
hearts[i].y = 120;
}
}
var targetX = 1024;
game.move = function (x, y, obj) {
if (!gameStarted || quizActive) {
return;
}
targetX = x;
};
game.update = function () {
if (!gameStarted) {
return;
} // Don't update until game starts
if (quizActive) {
// Update quiz timer
if (quizTimeRemaining > 0) {
quizTimeRemaining--;
var secondsLeft = Math.ceil(quizTimeRemaining / 60);
if (quizContainer && quizContainer.timerText) {
quizContainer.timerText.setText('Time: ' + secondsLeft);
// Change timer color as time runs out
if (secondsLeft <= 5) {
quizContainer.timerText.tint = 0xFF0000; // Red when almost out of time
tween(quizContainer.timerText, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 100
});
tween(quizContainer.timerText, {
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
} else if (secondsLeft <= 10) {
quizContainer.timerText.tint = 0xFFAA00; // Orange warning
} else {
quizContainer.timerText.tint = 0xFFFF00; // Yellow normal
}
}
if (quizTimeRemaining <= 0) {
// Time's up - apply penalty
LK.getSound('timeoutquestion').play();
applyPenalty();
hideQuiz();
nextQuizTime = LK.ticks + 480; // 8 seconds after timeout
}
}
return; // Completely freeze game while quiz is active
}
// Move ship towards target
if (ship.stickyTime <= 0) {
var diff = targetX - ship.x;
ship.x += diff * 0.1;
// Add tilting animation based on movement direction
var shipGraphics = ship.children[0];
if (Math.abs(diff) > 10) {
// Only tilt if moving significantly
if (diff > 0) {
// Moving right - tilt right
tween(shipGraphics, {
rotation: 0.2
}, {
duration: 200,
easing: tween.easeOut
});
} else {
// Moving left - tilt left
tween(shipGraphics, {
rotation: -0.2
}, {
duration: 200,
easing: tween.easeOut
});
}
} else if (Math.abs(diff) < 5) {
// Return to upright position when not moving much
tween(shipGraphics, {
rotation: 0
}, {
duration: 300,
easing: tween.easeOut
});
}
} else {
var stickyDiff = targetX - ship.x;
ship.x += stickyDiff * 0.02; // Much slower movement
// Add tilting animation for sticky controls too
var shipGraphics = ship.children[0];
if (Math.abs(stickyDiff) > 20) {
// Higher threshold for sticky controls
if (stickyDiff > 0) {
// Moving right - tilt right
tween(shipGraphics, {
rotation: 0.15
}, {
duration: 400,
easing: tween.easeOut
});
} else {
// Moving left - tilt left
tween(shipGraphics, {
rotation: -0.15
}, {
duration: 400,
easing: tween.easeOut
});
}
} else if (Math.abs(stickyDiff) < 10) {
// Return to upright position when not moving much
tween(shipGraphics, {
rotation: 0
}, {
duration: 500,
easing: tween.easeOut
});
}
}
// Keep ship in bounds
if (ship.x < 60) {
ship.x = 60;
}
if (ship.x > 1988) {
ship.x = 1988;
}
// Update distance and score
distance += gameSpeed;
updateScore();
updateLevel();
// Update distance display
distanceText.setText('Distance: ' + Math.floor(distance) + 'm');
// Progressive difficulty scaling based on distance - more gradual
var difficultyMultiplier = 1 + Math.floor(distance / 1000) * 0.2; // Increase difficulty every 1000m, smaller increments
gameSpeed = Math.min(5, 2 + difficultyMultiplier); // Cap max speed at 5 instead of 8
// Update timers and show expiration notifications
if (doubleCoinsTime > 0) {
doubleCoinsTime--;
if (doubleCoinsTime === 0) {
showEffectExpiration('💰 Double Coins');
}
}
if (extraObstaclesTime > 0) {
extraObstaclesTime--;
if (extraObstaclesTime === 0) {
showEffectExpiration('⚠️ Extra Obstacles');
}
}
if (clearPathTime > 0) {
clearPathTime--;
if (clearPathTime === 0) {
showEffectExpiration('🛡️ Clear Path');
}
}
if (scoreFreezeTime > 0) {
scoreFreezeTime--;
if (scoreFreezeTime === 0) {
showEffectExpiration('❄️ Score Freeze');
}
}
// Show quiz
if (LK.ticks >= nextQuizTime) {
showQuiz();
}
// Handle random rain effect
if (!rainActive && LK.ticks >= nextRainTime) {
if (Math.random() < 0.3) {
// 30% chance of rain each cycle
spawnRain();
} else {
nextRainTime = LK.ticks + 300 + Math.random() * 300; // Check again soon
}
}
// Spawn rain drops when rain is active
if (rainActive) {
rainDuration--;
if (rainDuration <= 0) {
stopRain();
}
if (LK.ticks % 2 === 0) {
// Spawn rain drops very frequently for dense full-screen effect
for (var i = 0; i < 8; i++) {
var rainDrop = new RainDrop();
rainDrop.x = Math.random() * 2048;
rainDrop.y = -600 - Math.random() * 400;
rainDrop.startX = rainDrop.x;
atmosphericParticles.push(rainDrop);
game.addChild(rainDrop);
}
}
}
// Update rain drops
for (var i = atmosphericParticles.length - 1; i >= 0; i--) {
var drop = atmosphericParticles[i];
if (drop.y > 2900) {
drop.destroy();
atmosphericParticles.splice(i, 1);
continue;
}
}
// Spawn objects - progressive difficulty with gradual obstacle increase
var baseSpawnRate = Math.max(25, 80 - Math.floor(distance / 1500)); // Slightly more frequent as distance increases
var obstacleSpawnRate = Math.max(20, baseSpawnRate - level * 0.5); // Gentle level-based adjustment
if (LK.ticks % obstacleSpawnRate === 0) {
spawnObstacle();
// Spawn additional obstacles based on distance traveled - gradual increase
if (distance > 2000 && LK.ticks % (obstacleSpawnRate * 3) === 0) {
spawnObstacle(); // Extra obstacle after 2000m
}
if (distance > 4000 && LK.ticks % (obstacleSpawnRate * 3.5) === 0) {
spawnObstacle(); // More obstacles after 4000m
}
if (distance > 6000 && LK.ticks % (obstacleSpawnRate * 4) === 0) {
spawnObstacle(); // Even more obstacles after 6000m
} //{9i_ext}
if (extraObstaclesTime > 0 && LK.ticks % Math.max(15, obstacleSpawnRate / 2.5) === 0) {
spawnObstacle(); // Slightly increased extra obstacles during penalty
}
}
if (LK.ticks % 600 === 0) {
// Every 10 seconds - less frequent crew
spawnCrewMember();
}
if (LK.ticks % 150 === 0) {
// Every 2.5 seconds - slightly more frequent coins
spawnCoin();
}
// Update obstacles
for (var i = obstacles.length - 1; i >= 0; i--) {
var obstacle = obstacles[i];
if (obstacle.y > 2800) {
obstacle.destroy();
obstacles.splice(i, 1);
continue;
}
if (ship.intersects(obstacle)) {
obstacle.destroy();
obstacles.splice(i, 1);
// Play different sound based on obstacle type
if (obstacle instanceof Pirate) {
LK.getSound('damage1').play();
} else {
LK.getSound('damage').play();
}
takeDamage();
continue;
}
}
// Update crew members
for (var i = crewMembers.length - 1; i >= 0; i--) {
var crew = crewMembers[i];
if (crew.y > 2800) {
crew.destroy();
crewMembers.splice(i, 1);
continue;
}
if (ship.intersects(crew)) {
crewCount++;
crewText.setText('Crew: ' + crewCount);
crew.destroy();
crewMembers.splice(i, 1);
LK.getSound('crewreceived').play();
continue;
}
}
// Update water tiles for infinite scrolling
for (var i = waterTiles.length - 1; i >= 0; i--) {
var tile = waterTiles[i];
if (tile.y > 2800) {
// Reset tile position to top for infinite scrolling
tile.y = -100;
}
}
// Spawn seagulls periodically for ambiance
if (LK.ticks >= nextSeagullTime) {
if (Math.random() < 0.6) {
// 60% chance to spawn a seagull
spawnSeagull();
}
nextSeagullTime = LK.ticks + 300 + Math.random() * 300; // Every 5-10 seconds
}
// Update seagulls
for (var i = seagulls.length - 1; i >= 0; i--) {
var seagull = seagulls[i];
if (seagull.y < -300 || seagull.y > 2900) {
seagull.destroy();
seagulls.splice(i, 1);
continue;
}
// Ensure seagull stays on top of all other assets
if (game.children.indexOf(seagull) !== game.children.length - 1) {
game.setChildIndex(seagull, game.children.length - 1);
}
}
// Spawn sunlight rays periodically
if (LK.ticks % 480 === 0) {
// Every 8 seconds
spawnSunlightRay();
}
// Update sunlight rays
for (var i = sunlightRays.length - 1; i >= 0; i--) {
var ray = sunlightRays[i];
if (ray.y > 2800) {
ray.destroy();
sunlightRays.splice(i, 1);
continue;
}
// Update alpha based on level and animation
if (ray.children[0]) {
ray.children[0].alpha = (ray.maxAlpha || 0.3) + Math.sin(LK.ticks * 0.05 + ray.x * 0.02) * 0.2;
}
}
// Update coins
for (var i = coins.length - 1; i >= 0; i--) {
var coin = coins[i];
if (coin.y > 2800) {
coin.destroy();
coins.splice(i, 1);
continue;
}
if (ship.intersects(coin)) {
var coinValue = doubleCoinsTime > 0 ? 20 : 10;
coinCount++;
coinText.setText('Coins: ' + coinCount);
if (scoreFreezeTime <= 0) {
distance += coinValue;
}
coin.destroy();
coins.splice(i, 1);
// Play random coin sound
var coinSound = Math.random() < 0.5 ? 'coinreceived' : 'coinreceived1';
LK.getSound(coinSound).play();
continue;
}
}
};
function showMainMenu() {
if (menuContainer) {
return;
}
gameStarted = false;
gamePaused = true;
menuContainer = game.addChild(new Container());
menuContainer.alpha = 0;
// Main background
var menuBg = menuContainer.attachAsset('quizBg', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1366,
scaleX: 1.3,
scaleY: 1.6,
alpha: 0.95
});
// Title
var titleText = new Text2('QUIZ NAVIGATOR', {
size: 120,
fill: 0xFFD700,
stroke: 0x000033,
strokeThickness: 4
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 800;
menuContainer.addChild(titleText);
// Subtitle
var subtitleText = new Text2('Navigate the seas while answering maritime quizzes!', {
size: 45,
fill: 0xFFFFFF,
stroke: 0x000000,
strokeThickness: 2,
wordWrap: true,
wordWrapWidth: 1400
});
subtitleText.anchor.set(0.5, 0.5);
subtitleText.x = 1024;
subtitleText.y = 950;
menuContainer.addChild(subtitleText);
// Instructions
var instructionsText = new Text2('• Drag to move your ship\n• Collect crew members and coins\n• Answer quiz questions correctly for power-ups\n• Wrong answers give penalties\n• Survive as long as possible!', {
size: 40,
fill: 0xCCFFFF,
wordWrap: true,
wordWrapWidth: 1400
});
instructionsText.anchor.set(0.5, 0.5);
instructionsText.x = 1024;
instructionsText.y = 1200;
menuContainer.addChild(instructionsText);
// Start button
var startButton = new Container();
startButton.x = 1024;
startButton.y = 1600;
var startBg = startButton.attachAsset('quizBg', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.3,
scaleY: 0.15,
alpha: 0.9
});
startBg.tint = 0x00AA00;
var startText = new Text2('TAP TO START', {
size: 70,
fill: 0xFFFFFF,
stroke: 0x000000,
strokeThickness: 3
});
startText.anchor.set(0.5, 0.5);
startButton.addChild(startText);
startButton.down = function (x, y, obj) {
tween(startBg, {
scaleX: 0.65,
scaleY: 0.35
}, {
duration: 100
});
tween(startText, {
alpha: 0.7
}, {
duration: 100,
onFinish: function onFinish() {
hideMainMenu();
startGame();
}
});
};
menuContainer.addChild(startButton);
// High score display
var highScore = storage.highScore || 0;
var highScoreText = new Text2('High Score: ' + highScore, {
size: 50,
fill: 0xFFAA00
});
highScoreText.anchor.set(0.5, 0.5);
highScoreText.x = 1024;
highScoreText.y = 1800;
menuContainer.addChild(highScoreText);
// Animate menu entrance
tween(menuContainer, {
alpha: 1
}, {
duration: 500
});
// Animate title
tween(titleText, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 1000,
easing: tween.easeInOut
});
tween(titleText, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 1000,
easing: tween.easeInOut
});
}
function hideMainMenu() {
if (!menuContainer) {
return;
}
tween(menuContainer, {
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
if (menuContainer) {
menuContainer.destroy();
menuContainer = null;
}
}
});
}
function startGame() {
gameStarted = true;
gamePaused = false;
LK.getSound('gamestart').play();
// Reset game state
level = 1;
health = 3;
crewCount = 0;
coinCount = 0;
distance = 0;
gameSpeed = 2;
quizActive = false;
nextQuizTime = 480;
// Initialize rain system
rainActive = false;
rainDuration = 0;
nextRainTime = 1200; // Start first possible rain after 20 seconds
// Initialize seagull system
nextSeagullTime = 600; // Start spawning seagulls after 10 seconds
for (var i = seagulls.length - 1; i >= 0; i--) {
seagulls[i].destroy();
}
seagulls = [];
// Clear all arrays
for (var i = obstacles.length - 1; i >= 0; i--) {
obstacles[i].destroy();
}
obstacles = [];
for (var i = crewMembers.length - 1; i >= 0; i--) {
crewMembers[i].destroy();
}
crewMembers = [];
for (var i = coins.length - 1; i >= 0; i--) {
coins[i].destroy();
}
coins = [];
// Reset ship position
ship.x = 1024;
ship.y = 2400;
// Reset shield state on game start
ship.isShielded = false;
ship.shieldTime = 0;
if (ship.children.length > 1) {
ship.children[1].visible = false;
}
// Update UI
updateScore();
updateHearts();
levelText.setText('Level: ' + level);
crewText.setText('Crew: ' + crewCount);
coinText.setText('Coins: ' + coinCount);
distanceText.setText('Distance: 0m');
// Play background music
LK.playMusic('soundtrack', {
loop: true
});
} /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Coin = Container.expand(function () {
var self = Container.call(this);
var coinGraphics = self.attachAsset('coin', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 4;
self.update = function () {
if (gamePaused) {
return;
} // Freeze movement during quiz
self.y += self.speed;
};
return self;
});
var CrewMember = Container.expand(function () {
var self = Container.call(this);
var crewGraphics = self.attachAsset('crew', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 4;
self.update = function () {
if (gamePaused) {
return;
} // Freeze movement during quiz
self.y += self.speed;
// Breathing animation - expand and shrink
var time = LK.ticks * 0.05;
var breathingScale = 1 + Math.sin(time) * 0.15;
crewGraphics.scaleX = breathingScale;
crewGraphics.scaleY = breathingScale;
};
return self;
});
var Obstacle = Container.expand(function () {
var self = Container.call(this);
var obstacleGraphics = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 1;
self.update = function () {
if (gamePaused) {
return;
} // Freeze movement during quiz
self.y += self.speed;
};
return self;
});
var Pirate = Container.expand(function () {
var self = Container.call(this);
var pirateGraphics = self.attachAsset('pirate', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 6;
self.update = function () {
if (gamePaused) {
return;
} // Freeze movement during quiz
self.y += self.speed;
};
return self;
});
var RainDrop = Container.expand(function () {
var self = Container.call(this);
var rainGraphics = self.attachAsset('rainreal', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.6,
//{X_new}
scaleX: 0.6 + Math.random() * 0.4,
scaleY: 0.8 + Math.random() * 0.6
});
self.speed = 6 + Math.random() * 8;
self.swayAmount = 1 + Math.random() * 2;
self.swaySpeed = 0.015 + Math.random() * 0.025;
self.startX = self.x;
self.baseAlpha = 0.5 + Math.random() * 0.3;
self.dropType = Math.floor(Math.random() * 3);
self.update = function () {
if (gamePaused) {
return;
}
self.y += self.speed;
// Add wind-like horizontal sway for realism
self.x = self.startX + Math.sin(LK.ticks * self.swaySpeed) * self.swayAmount;
// Subtle rotation for falling effect
rainGraphics.rotation = Math.sin(LK.ticks * 0.1 + self.startX * 0.005) * 0.15;
// Dynamic alpha based on distance for depth perception
var distanceFromTop = self.y;
var fadeStartY = 500;
if (self.y > fadeStartY) {
var fadeProgress = (self.y - fadeStartY) / (2800 - fadeStartY);
rainGraphics.alpha = self.baseAlpha * (1 - fadeProgress * 0.7);
} else {
rainGraphics.alpha = self.baseAlpha;
}
// Ensure minimum visibility
if (rainGraphics.alpha < 0.1) {
rainGraphics.alpha = 0.1;
}
};
return self;
});
var Seagull = Container.expand(function () {
var self = Container.call(this);
var seagullGraphics = self.attachAsset('seagullreal', {
anchorX: 0.5,
anchorY: 0.5
});
// Create shadow below seagull
var shadowGraphics = self.attachAsset('seagullreal', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.2,
scaleX: 0.8,
scaleY: 0.4
});
shadowGraphics.tint = 0x000000;
self.speed = 1 + Math.random() * 0.5;
self.wavyPhase = Math.random() * Math.PI * 2;
self.wavySpeed = 0.03 + Math.random() * 0.02;
self.wavyAmount = 8 + Math.random() * 5;
self.startY = self.y;
self.wingFlapPhase = Math.random() * Math.PI * 2;
self.wingFlapSpeed = 0.15 + Math.random() * 0.1;
self.update = function () {
if (gamePaused) {
return;
}
// Move seagull horizontally across screen in straight line
self.x -= self.speed;
// Add wavy animation - sinusoidal vertical movement
var wavyAmount = Math.sin(LK.ticks * self.wavySpeed + self.wavyPhase) * self.wavyAmount;
self.y = self.startY + wavyAmount;
// Add wing flapping animation - scale Y for wing movement
var wingFlap = Math.sin(LK.ticks * self.wingFlapSpeed + self.wingFlapPhase) * 0.08;
seagullGraphics.scaleY = 1 + wingFlap;
// Position shadow below seagull
shadowGraphics.y = 120;
// Wrap around screen
if (self.x < -200) {
self.x = 2248;
self.y = Math.random() * 600 - 200;
self.startY = self.y;
self.wavyPhase = Math.random() * Math.PI * 2;
self.wingFlapPhase = Math.random() * Math.PI * 2;
}
};
return self;
});
var Ship = Container.expand(function () {
var self = Container.call(this);
var shipGraphics = self.attachAsset('ship', {
anchorX: 0.5,
anchorY: 0.5
});
self.baseSpeed = 3;
self.currentSpeed = self.baseSpeed;
self.isShielded = false;
self.shieldTime = 0;
self.stickyTime = 0;
self.isSizeModified = false;
self.sizeTime = 0;
self.originalScale = 1;
var shieldGraphics = self.attachAsset('shield', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.8,
scaleX: 1.2,
scaleY: 1.2
});
shieldGraphics.visible = false;
self.activateShield = function () {
self.isShielded = true;
self.shieldTime = 300;
shieldGraphics.visible = true;
};
self.activateStickyControls = function () {
self.stickyTime = 300;
};
self.setSizeModifier = function (scale, duration) {
self.isSizeModified = true;
self.sizeTime = duration;
tween(shipGraphics, {
scaleX: scale,
scaleY: scale
}, {
duration: 200
});
tween(shieldGraphics, {
scaleX: scale,
scaleY: scale
}, {
duration: 200
});
};
self.update = function () {
if (gamePaused) {
return;
} // Freeze movement when game is paused
// Shield follows ship position smoothly
if (self.isShielded) {
tween(shieldGraphics, {
x: self.x,
y: self.y
}, {
duration: 50,
easing: tween.linear
});
}
if (self.shieldTime > 0) {
self.shieldTime--;
if (self.shieldTime <= 0) {
self.isShielded = false;
shieldGraphics.visible = false;
}
}
if (self.stickyTime > 0) {
self.stickyTime--;
}
if (self.sizeTime > 0) {
self.sizeTime--;
if (self.sizeTime <= 0) {
self.isSizeModified = false;
tween(shipGraphics, {
scaleX: 1,
scaleY: 1
}, {
duration: 200
});
tween(shieldGraphics, {
scaleX: 1,
scaleY: 1
}, {
duration: 200
});
}
}
// Ship stays in place - world moves around it
};
return self;
});
var Stone = Container.expand(function () {
var self = Container.call(this);
var stoneGraphics = self.attachAsset('stone', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 0;
self.update = function () {
if (gamePaused) {
return;
} // Freeze movement during quiz
self.y += self.speed;
stoneGraphics.rotation += 0;
};
return self;
});
var Sunlight = Container.expand(function () {
var self = Container.call(this);
var sunGraphics = self.attachAsset('sunlight', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 1;
self.intensity = 0.4 + Math.random() * 0.3;
self.rayWidth = 0.8 + Math.random() * 0.4;
self.flickerSpeed = 0.03 + Math.random() * 0.02;
self.update = function () {
if (gamePaused) {
return;
}
self.y += self.speed;
// Realistic sunlight ray animation with flickering and depth
var time = LK.ticks * self.flickerSpeed;
var flicker = Math.sin(time + self.x * 0.02) * 0.15;
var depth = Math.sin(time * 0.7 + self.y * 0.001) * 0.1;
// Dynamic alpha for realistic light penetration
sunGraphics.alpha = self.intensity + flicker + depth;
// Width variation for light scattering effect
sunGraphics.scaleX = self.rayWidth + Math.sin(time * 1.2) * 0.2;
// Subtle rotation for light movement
sunGraphics.rotation = Math.sin(time * 0.5) * 0.05;
// Color temperature variation
var warmth = 0.1 + Math.sin(time * 0.3) * 0.05;
if (level === 1) {
sunGraphics.tint = 0xFFFF99; // Bright daylight
} else if (level === 2) {
sunGraphics.tint = 0xFFCC66; // Warm sunset
} else if (level === 3) {
sunGraphics.tint = 0x9999FF; // Cool moonlight
} else {
sunGraphics.tint = 0xCCCCCC; // Storm light
}
};
return self;
});
var WaterTile = Container.expand(function () {
var self = Container.call(this);
var tileGraphics = self.attachAsset('waterTile', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 2;
self.baseColor = 0x0066cc;
self.waveOffset = Math.random() * Math.PI * 2;
self.update = function () {
if (gamePaused) {
return;
}
self.y += self.speed;
// Keep water tiles stable without animation effects
tileGraphics.alpha = 0.85;
// No scale variation
tileGraphics.scaleY = 1;
// No horizontal movement
tileGraphics.x = 0;
};
return self;
});
var Wave = Container.expand(function () {
var self = Container.call(this);
var waveGraphics = self.attachAsset('wave', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 4;
self.wavePhase = Math.random() * Math.PI * 2;
self.waveAmplitude = 0.8 + Math.random() * 0.4;
self.baseScale = 1;
self.update = function () {
if (gamePaused) {
return;
} // Freeze movement during quiz
self.y += self.speed;
// Keep wave at stable normal size - no scaling animations
waveGraphics.scaleX = 1;
waveGraphics.scaleY = 1;
// Stable alpha without crest highlighting
waveGraphics.alpha = 0.85;
// No rotation animation
waveGraphics.rotation = 0;
// Water color based on level - stable coloring
if (level === 1) {
waveGraphics.tint = 0x4A90E2; // Bright blue
} else if (level === 2) {
waveGraphics.tint = 0x3A7BD5; // Darker blue
} else if (level === 3) {
waveGraphics.tint = 0x2A5AA0; // Night blue
} else {
waveGraphics.tint = 0x1A4A80; // Storm blue
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB
});
/****
* Game Code
****/
var ship;
var obstacles = [];
var crewMembers = [];
var coins = [];
var hearts = [];
var waterTiles = [];
var sunlightRays = [];
var level = 1;
var health = 3;
var maxHealth = 4;
var crewCount = 0;
var coinCount = 0;
var distance = 0;
var gamePaused = false;
var gameStarted = false;
var menuContainer = null;
var distanceText = new Text2('Distance: 0m', {
size: 50,
fill: 0x00FFFF,
stroke: 0x000033,
strokeThickness: 2
});
distanceText.anchor.set(0.5, 0);
distanceText.x = 0;
distanceText.y = 120;
LK.gui.top.addChild(distanceText);
var gameSpeed = 2;
var quizActive = false;
var quizTimer = 0;
var nextQuizTime = 480; // Start first quiz after 8 seconds
var doubleCoinsTime = 0;
var extraObstaclesTime = 0;
var clearPathTime = 0;
var scoreFreezeTime = 0;
// Quiz system
var quizQuestions = [{
question: "What does FOB stand for in shipping terms?",
answers: ["Free On Board", "Freight on Boat", "Foreign Object Bureau", "Full Ocean Bill"],
correct: 0
}, {
question: "Which maritime organization sets international shipping standards?",
answers: ["WHO", "IMO", "WTO", "ILO"],
correct: 1
}, {
question: "What is the front of a ship called?",
answers: ["Stern", "Port", "Bow", "Starboard"],
correct: 2
}, {
question: "EXW means the seller delivers when goods are:",
answers: ["At seller's premises", "On the ship", "At destination", "In transit"],
correct: 0
}, {
question: "What does CIF include in shipping terms?",
answers: ["Cost only", "Insurance only", "Freight only", "Cost, Insurance, Freight"],
correct: 3 //{3F_new}
}, {
question: "What is the right side of a ship called?",
answers: ["Port", "Starboard", "Bow", "Stern"],
correct: 1
}, {
question: "DDP means the seller is responsible for:",
answers: ["Delivery at port", "Delivery duty paid", "Dock departure point", "Direct delivery purchase"],
correct: 1
}, {
question: "What does TEU stand for in container shipping?",
answers: ["Total Export Unit", "Twenty-foot Equivalent Unit", "Terminal Exchange Unit", "Transport Equipment Unit"],
correct: 1
}, {
question: "Which term means 'Free Alongside Ship'?",
answers: ["CAS", "FAS", "DAS", "PAS"],
correct: 1 //{3N_fix}
}, {
question: "What is the kitchen area on a ship called?",
answers: ["Mess", "Galley", "Cabin", "Hold"],
correct: 1
}, {
question: "CFR includes which costs?",
answers: ["Cost and freight", "Cost, freight, risk", "Customs, freight, rate", "Container freight rate"],
correct: 0
}, {
question: "What does DAP stand for?",
answers: ["Delivery at place", "Dock arrival point", "Delivered at place", "Direct arrival point"],
correct: 2
}, {
question: "The left side of a ship is called:",
answers: ["Starboard", "Port", "Bow", "Stern"],
correct: 1
}, {
question: "What is a ship's maximum cargo capacity called?",
answers: ["Deadweight", "Gross tonnage", "Net tonnage", "Displacement"],
correct: 0
}, {
question: "FCA means:",
answers: ["Free carrier", "Freight cost allowance", "Full container access", "Forward cargo arrangement"],
correct: 0
}];
var currentQuiz = null;
var quizContainer = null;
var quizTimeRemaining = 600; // 10 seconds
var effectDisplay = null;
var lastAppliedEffect = '';
var effectExpirationDisplay = null;
var atmosphericParticles = [];
var seagulls = [];
var rainActive = false;
var rainDuration = 0;
var nextRainTime = 0;
var nextSeagullTime = 0;
function spawnSeagull() {
var seagull = new Seagull();
seagull.x = Math.random() > 0.5 ? -200 : 2248;
seagull.y = Math.random() * 600 - 200;
seagull.startY = seagull.y;
seagulls.push(seagull);
game.addChild(seagull);
// Move seagull to top of rendering hierarchy to appear above all other assets
if (game.children.length > 0) {
game.setChildIndex(seagull, game.children.length - 1);
}
}
function spawnRain() {
rainActive = true;
rainDuration = 300 + Math.random() * 300; // 5-8 seconds of rain
nextRainTime = LK.ticks + 1800 + Math.random() * 1200; // 30-50 seconds until next rain
// Spawn rain drops separately with staggered timing - increased count for full screen coverage
for (var i = 0; i < 80; i++) {
(function (index) {
LK.setTimeout(function () {
if (!rainActive) {
return;
}
var rainDrop = new RainDrop();
rainDrop.x = Math.random() * 2048;
rainDrop.y = -500 - Math.random() * 500;
rainDrop.startX = rainDrop.x;
atmosphericParticles.push(rainDrop);
game.addChild(rainDrop);
}, index * 8); // Stagger each drop by 8ms for faster, denser coverage
})(i);
}
} //{40_new}
function stopRain() {
rainActive = false;
}
function spawnAtmosphericParticles(weatherType) {
// Clear existing particles
for (var i = atmosphericParticles.length - 1; i >= 0; i--) {
atmosphericParticles[i].destroy();
}
atmosphericParticles = [];
// Spawn new particles based on weather
var particleCount = weatherType === 'storm' ? 8 : 4;
for (var i = 0; i < particleCount; i++) {
var particle = createAtmosphericParticle(weatherType);
atmosphericParticles.push(particle);
game.addChild(particle);
}
}
function createAtmosphericParticle(weatherType) {
var particle = new Container();
var particleGraphics;
if (weatherType === 'day') {
// Light sparkles on water
particleGraphics = particle.attachAsset('sunlight', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.1,
scaleY: 0.3,
alpha: 0.3
});
particleGraphics.tint = 0xFFFFAA;
} else if (weatherType === 'sunset') {
// Warm light reflections
particleGraphics = particle.attachAsset('sunlight', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.15,
scaleY: 0.4,
alpha: 0.4
});
particleGraphics.tint = 0xFF9966;
} else if (weatherType === 'night') {
// Moonlight streaks
particleGraphics = particle.attachAsset('sunlight', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.08,
scaleY: 0.5,
alpha: 0.2
});
particleGraphics.tint = 0xCCDDFF;
} else {
// Storm effects
particleGraphics = particle.attachAsset('sunlight', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.05,
scaleY: 0.8,
alpha: 0.1
});
particleGraphics.tint = 0x888888;
}
particle.x = Math.random() * 2048;
particle.y = Math.random() * 2732;
particle.speed = 0.5 + Math.random() * 1.5;
particle.weatherType = weatherType;
particle.animationOffset = Math.random() * Math.PI * 2;
particle.update = function () {
if (gamePaused) {
return;
}
// Move particles slowly
this.y += this.speed;
if (this.y > 2800) {
this.y = -100;
this.x = Math.random() * 2048;
}
// Animate based on weather type
var time = LK.ticks * 0.02 + this.animationOffset;
if (this.weatherType === 'day') {
particleGraphics.alpha = 0.2 + Math.sin(time * 2) * 0.15;
} else if (this.weatherType === 'sunset') {
particleGraphics.alpha = 0.3 + Math.sin(time * 1.5) * 0.2;
particleGraphics.scaleX = 0.15 + Math.sin(time) * 0.05;
} else if (this.weatherType === 'night') {
particleGraphics.alpha = 0.15 + Math.sin(time * 3) * 0.1;
} else {
particleGraphics.alpha = 0.05 + Math.sin(time * 4) * 0.08;
particleGraphics.rotation = Math.sin(time * 2) * 0.3;
}
};
return particle;
}
// UI Elements - Better separated and positioned
var scoreText = new Text2('Score: 0', {
size: 65,
fill: 0x00FF00,
stroke: 0x000033,
strokeThickness: 2
});
scoreText.anchor.set(0.5, 0);
scoreText.x = 0;
scoreText.y = 20;
LK.gui.top.addChild(scoreText);
var levelText = new Text2('Level: 1', {
size: 60,
fill: 0xFFD700
});
levelText.anchor.set(1, 0);
levelText.x = -20;
levelText.y = 20;
LK.gui.topRight.addChild(levelText);
var crewText = new Text2('Crew: 0', {
size: 50,
fill: 0x00BFFF
});
crewText.anchor.set(0, 1);
crewText.x = 20;
crewText.y = -20;
LK.gui.bottomLeft.addChild(crewText);
var coinText = new Text2('Coins: 0', {
size: 50,
fill: 0xffd700
});
coinText.anchor.set(1, 1);
coinText.x = -20;
coinText.y = -20;
LK.gui.bottomRight.addChild(coinText);
// Initialize pixelated ocean background
createWaterTileGrid();
// Initialize game elements
ship = game.addChild(new Ship());
ship.x = 1024;
ship.y = 2400;
// Show main menu on start
showMainMenu();
// Create hearts display
for (var i = 0; i < 4; i++) {
var heart = LK.getAsset('heart', {
anchorX: 0,
anchorY: 0
});
hearts.push(heart);
LK.gui.topLeft.addChild(heart);
}
function updateScore() {
if (scoreFreezeTime <= 0) {
var score = Math.floor(distance) + crewCount * 100;
LK.setScore(score);
scoreText.setText('Score: ' + score);
}
}
function updateLevel() {
var newLevel = Math.floor(distance / 3000) + 1; // Level up faster for increased difficulty
if (newLevel > level && newLevel <= 4) {
level = newLevel;
levelText.setText('Level: ' + level);
gameSpeed += 0.3; // More moderate speed boost per level
// Change background color and lighting based on level with realistic gradients
if (level === 1) {
game.setBackgroundColor(0x87CEEB); // Day - bright sky blue with gradient feel
updateWaterTileColors(0x0066cc); // Crystal clear tropical water
updateSunlightColors(0xFFF4AA, 0.5); // Warm golden sunlight
// Add atmospheric particles for day
spawnAtmosphericParticles('day');
} else if (level === 2) {
game.setBackgroundColor(0xFF6B47); // Sunset - warm orange with red tints
updateWaterTileColors(0x2E5984); // Sunset reflected water
updateSunlightColors(0xFFB366, 0.6); // Intense sunset rays
// Add atmospheric particles for sunset
spawnAtmosphericParticles('sunset');
} else if (level === 3) {
game.setBackgroundColor(0x0F1B3C); // Deep night - dark navy
updateWaterTileColors(0x1A2E5C); // Moonlit water with silver reflections
updateSunlightColors(0xB8C5FF, 0.3); // Cool moonbeams
// Add atmospheric particles for night
spawnAtmosphericParticles('night');
} else if (level === 4) {
game.setBackgroundColor(0x2C3E50); // Storm - dark slate with green tints
updateWaterTileColors(0x34495E); // Turbulent storm water
updateSunlightColors(0x95A5A6, 0.15); // Harsh storm lighting
// Add atmospheric particles for storm
spawnAtmosphericParticles('storm');
}
}
}
function updateWaterTileColors(color) {
for (var i = 0; i < waterTiles.length; i++) {
if (waterTiles[i] && waterTiles[i].children[0]) {
// Calculate depth-based color variation
var depthVariation = Math.sin(waterTiles[i].x * 0.01 + waterTiles[i].y * 0.005) * 0.1;
var adjustedColor = color;
// Add depth gradient effect
if (level === 1) {
adjustedColor = 0x0066CC + Math.floor(depthVariation * 0x001122);
} else if (level === 2) {
adjustedColor = 0x004499 + Math.floor(depthVariation * 0x001111);
} else if (level === 3) {
adjustedColor = 0x002266 + Math.floor(depthVariation * 0x000011);
} else {
adjustedColor = 0x003344 + Math.floor(depthVariation * 0x000022);
}
tween(waterTiles[i].children[0], {
tint: adjustedColor
}, {
duration: 2000
});
waterTiles[i].baseColor = adjustedColor;
}
}
}
function updateSunlightColors(color, maxAlpha) {
for (var i = 0; i < sunlightRays.length; i++) {
if (sunlightRays[i] && sunlightRays[i].children[0]) {
tween(sunlightRays[i].children[0], {
tint: color
}, {
duration: 2000
});
sunlightRays[i].maxAlpha = maxAlpha;
}
}
}
function createWaterTileGrid() {
// Create a grid of water tiles for pixelated ocean background
for (var x = 0; x < 22; x++) {
// Cover full width with some overlap
for (var y = -5; y < 35; y++) {
// Cover full height with extra tiles
var waterTile = new WaterTile();
waterTile.x = x * 95; // Slight overlap for seamless look
waterTile.y = y * 95;
waterTiles.push(waterTile);
game.addChild(waterTile);
}
}
}
function spawnSunlightRay() {
var sunray = new Sunlight();
sunray.x = Math.random() * 2048;
sunray.y = -400;
sunray.maxAlpha = level === 1 ? 0.4 : level === 2 ? 0.5 : level === 3 ? 0.2 : 0.1;
sunlightRays.push(sunray);
game.addChild(sunray);
}
function spawnObstacle() {
if (clearPathTime > 0) {
return;
}
var obstacleType = Math.floor(Math.random() * 4);
var obstacle;
switch (obstacleType) {
case 0:
obstacle = new Obstacle();
break;
case 1:
obstacle = new Pirate();
break;
case 2:
obstacle = new Wave();
break;
case 3:
obstacle = new Stone();
break;
}
obstacle.x = Math.random() * 1800 + 124;
obstacle.y = -100;
obstacle.speed = obstacle.speed + gameSpeed * 0.6 + level * 0.4; // Much gentler speed increases
obstacles.push(obstacle);
game.addChild(obstacle);
}
function spawnCrewMember() {
var crew = new CrewMember();
crew.x = Math.random() * 1800 + 124;
crew.y = -100;
crew.speed = 3 + gameSpeed;
crewMembers.push(crew);
game.addChild(crew);
}
function spawnCoin() {
var coin = new Coin();
coin.x = Math.random() * 1800 + 124;
coin.y = -100;
coin.speed = 3 + gameSpeed;
coins.push(coin);
game.addChild(coin);
}
function showQuiz() {
if (quizActive) {
return;
}
quizActive = true;
gamePaused = true; // Freeze all game movement
quizTimeRemaining = 1200; // 20 seconds
currentQuiz = quizQuestions[Math.floor(Math.random() * quizQuestions.length)];
quizContainer = game.addChild(new Container());
quizContainer.alpha = 0; // Start invisible for smooth entrance
LK.getSound('tiktoksoundquestion').play();
var bg = quizContainer.attachAsset('quizBg', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1366,
alpha: 0.95
});
// Animate quiz entrance
tween(quizContainer, {
alpha: 1
}, {
duration: 300
});
// Show current active effects
var effectsText = getActiveEffectsText();
if (effectsText) {
var effectDisplay = new Text2(effectsText, {
size: 45,
fill: 0xFFFF00
});
effectDisplay.anchor.set(0.5, 0.5);
effectDisplay.x = 1024;
effectDisplay.y = 900;
quizContainer.addChild(effectDisplay);
}
var questionText = new Text2(currentQuiz.question, {
size: 75,
fill: 0xFFFFFF,
stroke: 0x000033,
strokeThickness: 3,
wordWrap: true,
wordWrapWidth: 1500,
letterSpacing: 2
});
questionText.anchor.set(0.5, 0.5);
questionText.x = 1024;
questionText.y = 1050;
quizContainer.addChild(questionText);
var timerText = new Text2('Time: 20', {
size: 60,
fill: 0xFFFF00,
stroke: 0x000000,
strokeThickness: 3
});
timerText.anchor.set(0.5, 0.5);
timerText.x = 1024;
timerText.y = 950;
quizContainer.addChild(timerText);
quizContainer.timerText = timerText;
// Create answer buttons with improved styling
quizContainer.answerButtons = [];
for (var i = 0; i < 4; i++) {
var answerContainer = new Container();
answerContainer.x = 1024;
answerContainer.y = 1320 + i * 170;
var answerBg = answerContainer.attachAsset('quizBg', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.92,
scaleY: 0.28,
alpha: 0.85
});
var answerText = new Text2(String.fromCharCode(65 + i) + ') ' + currentQuiz.answers[i], {
size: 70,
fill: 0xFFFFFF,
stroke: 0x000033,
strokeThickness: 4,
wordWrap: true,
wordWrapWidth: 1250,
letterSpacing: 1
});
answerText.anchor.set(0.5, 0.5);
answerContainer.addChild(answerText);
// Store references for animations
answerContainer.bg = answerBg;
answerContainer.text = answerText;
answerContainer.answerIndex = i;
// Store index in closure to avoid reference issues
(function (index) {
answerContainer.down = function (x, y, obj) {
// Animate button press - use the stored references instead of obj properties
tween(answerContainer.bg, {
scaleX: 0.95,
scaleY: 0.22
}, {
duration: 100
});
tween(answerContainer.text, {
alpha: 0.8
}, {
duration: 100
});
handleQuizAnswer(index);
};
})(i);
quizContainer.answerButtons.push(answerContainer);
quizContainer.addChild(answerContainer);
}
}
function handleQuizAnswer(answerIndex) {
if (!quizActive) {
return;
}
// Prevent multiple answers
quizActive = false;
var isCorrect = answerIndex === currentQuiz.correct;
if (isCorrect) {
LK.getSound('correctanswer').play();
applyPowerUp();
} else {
LK.getSound('incorrectanswer').play();
applyPenalty();
}
// Show effect feedback for 2 seconds
if (lastAppliedEffect) {
showEffectFeedback(lastAppliedEffect, isCorrect);
}
hideQuiz();
nextQuizTime = LK.ticks + 900; // Every 15 seconds
}
function getActiveEffectsText() {
var effects = [];
if (ship.isShielded) {
effects.push('🛡️ Shield Active');
}
if (doubleCoinsTime > 0) {
effects.push('💰 Double Coins');
}
if (ship.isSizeModified && ship.children[0].scaleX < 1) {
effects.push('⬇️ Smaller Ship');
}
if (ship.isSizeModified && ship.children[0].scaleX > 1) {
effects.push('⬆️ Bigger Ship');
}
if (ship.stickyTime > 0) {
effects.push('🐌 Sticky Controls');
}
if (extraObstaclesTime > 0) {
effects.push('⚠️ Extra Obstacles');
}
if (scoreFreezeTime > 0) {
effects.push('❄️ Score Frozen');
}
if (clearPathTime > 0) {
effects.push('🚫 Clear Path');
}
if (effects.length === 0) {
return null;
}
return 'Active Effects:\n' + effects.join('\n');
}
function applyPowerUp() {
var random = Math.random();
var powerUp;
// Weighted random selection - higher chance of beneficial power-ups
if (random < 0.25) {
powerUp = 'shield';
} else if (random < 0.45) {
powerUp = 'clearPath';
} else if (random < 0.60) {
powerUp = 'smallerShip';
} else if (random < 0.80) {
powerUp = 'doubleCoins';
} else {
powerUp = 'extraLife';
}
switch (powerUp) {
case 'shield':
ship.activateShield();
lastAppliedEffect = '🛡️ Shield Activated!';
break;
case 'doubleCoins':
doubleCoinsTime = 600;
lastAppliedEffect = '💰 Double Coins for 10s!';
break;
case 'extraLife':
if (health < 5) {
health++;
updateHearts();
lastAppliedEffect = '❤️ Extra Life Gained!';
} else {
lastAppliedEffect = '❤️ Life Full Already!';
}
break;
case 'clearPath':
clearPathTime = 240;
lastAppliedEffect = '🚫 Clear Path for 4s!';
// Remove existing obstacles
for (var i = obstacles.length - 1; i >= 0; i--) {
obstacles[i].destroy();
obstacles.splice(i, 1);
}
break;
case 'smallerShip':
ship.setSizeModifier(0.7, 300);
lastAppliedEffect = '⬇️ Smaller Ship for 5s!';
break;
}
}
function applyPenalty() {
var penalties = ['extraObstacles', 'healthLoss', 'stickyControls', 'scoreFreeze', 'biggerShip'];
var penalty = penalties[Math.floor(Math.random() * penalties.length)];
switch (penalty) {
case 'extraObstacles':
extraObstaclesTime = 480;
lastAppliedEffect = '⚠️ Extra Obstacles for 8s!';
break;
case 'healthLoss':
takeDamage();
lastAppliedEffect = '💔 Lost 1 Heart!';
break;
case 'stickyControls':
ship.activateStickyControls();
lastAppliedEffect = '🐌 Sticky Controls for 5s!';
break;
case 'scoreFreeze':
scoreFreezeTime = 300;
lastAppliedEffect = '❄️ Score Frozen for 5s!';
break;
case 'biggerShip':
ship.setSizeModifier(1.4, 240);
lastAppliedEffect = '⬆️ Bigger Ship for 4s!';
break;
}
}
function showEffectExpiration(effectName) {
if (effectExpirationDisplay) {
effectExpirationDisplay.destroy();
}
effectExpirationDisplay = game.addChild(new Container());
var expirationBg = effectExpirationDisplay.attachAsset('quizBg', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 400,
scaleX: 0.5,
scaleY: 0.2,
alpha: 0.8
});
var expirationText = new Text2(effectName + ' Expired!', {
size: 45,
fill: 0xFFAA00
});
expirationText.anchor.set(0.5, 0.5);
expirationText.x = 1024;
expirationText.y = 400;
effectExpirationDisplay.addChild(expirationText);
// Auto-hide after 1.5 seconds
LK.setTimeout(function () {
if (effectExpirationDisplay) {
effectExpirationDisplay.destroy();
effectExpirationDisplay = null;
}
}, 1500);
}
function showEffectFeedback(effectText, isPositive) {
if (effectDisplay) {
effectDisplay.destroy();
}
effectDisplay = game.addChild(new Container());
var feedbackBg = effectDisplay.attachAsset('quizBg', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1366,
scaleX: 0.6,
scaleY: 0.3,
alpha: 0.8
});
var feedbackText = new Text2(effectText, {
size: 60,
fill: isPositive ? 0x00FF00 : 0xFF4444
});
feedbackText.anchor.set(0.5, 0.5);
feedbackText.x = 1024;
feedbackText.y = 1366;
effectDisplay.addChild(feedbackText);
// Auto-hide after 2 seconds
LK.setTimeout(function () {
if (effectDisplay) {
effectDisplay.destroy();
effectDisplay = null;
}
}, 2000);
}
function hideQuiz() {
quizActive = false;
gamePaused = false; // Resume game movement
LK.getSound('tiktoksoundquestion').stop();
if (quizContainer) {
// Animate quiz exit
tween(quizContainer, {
alpha: 0
}, {
duration: 200,
onFinish: function onFinish() {
if (quizContainer) {
quizContainer.destroy();
quizContainer = null;
}
}
});
}
}
function takeDamage() {
if (ship.isShielded) {
return;
}
health--;
updateHearts();
LK.getSound('hit').play();
LK.effects.flashScreen(0xff0000, 500);
if (health <= 0) {
// Freeze the game completely
gameStarted = false;
gamePaused = true;
LK.getSound('died').play();
// Create custom game over display with statistics
var gameOverContainer = game.addChild(new Container());
var gameOverBg = gameOverContainer.attachAsset('quizBg', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1366,
scaleX: 1.2,
scaleY: 1.4,
alpha: 0.95
});
var finalScore = Math.floor(distance) + crewCount * 100;
var statsText = 'GAME OVER\n\n' + 'Final Statistics:\n' + 'Score: ' + finalScore + '\n' + 'Distance: ' + Math.floor(distance) + 'm\n' + 'Crew Members: ' + crewCount + '\n' + 'Coins: ' + coinCount + '\n' + 'Level Reached: ' + level;
var statsDisplay = new Text2(statsText, {
size: 60,
fill: 0xFFFFFF
});
statsDisplay.anchor.set(0.5, 0.5);
statsDisplay.x = 1024;
statsDisplay.y = 1366;
gameOverContainer.addChild(statsDisplay);
// Show standard game over after 3 seconds
LK.setTimeout(function () {
LK.showGameOver();
// Show menu again after game over
LK.setTimeout(function () {
showMainMenu();
}, 1000);
}, 3000);
}
}
function updateHearts() {
for (var i = 0; i < hearts.length; i++) {
hearts[i].visible = i < health;
hearts[i].x = 120 + i * 50;
hearts[i].y = 120;
}
}
var targetX = 1024;
game.move = function (x, y, obj) {
if (!gameStarted || quizActive) {
return;
}
targetX = x;
};
game.update = function () {
if (!gameStarted) {
return;
} // Don't update until game starts
if (quizActive) {
// Update quiz timer
if (quizTimeRemaining > 0) {
quizTimeRemaining--;
var secondsLeft = Math.ceil(quizTimeRemaining / 60);
if (quizContainer && quizContainer.timerText) {
quizContainer.timerText.setText('Time: ' + secondsLeft);
// Change timer color as time runs out
if (secondsLeft <= 5) {
quizContainer.timerText.tint = 0xFF0000; // Red when almost out of time
tween(quizContainer.timerText, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 100
});
tween(quizContainer.timerText, {
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
} else if (secondsLeft <= 10) {
quizContainer.timerText.tint = 0xFFAA00; // Orange warning
} else {
quizContainer.timerText.tint = 0xFFFF00; // Yellow normal
}
}
if (quizTimeRemaining <= 0) {
// Time's up - apply penalty
LK.getSound('timeoutquestion').play();
applyPenalty();
hideQuiz();
nextQuizTime = LK.ticks + 480; // 8 seconds after timeout
}
}
return; // Completely freeze game while quiz is active
}
// Move ship towards target
if (ship.stickyTime <= 0) {
var diff = targetX - ship.x;
ship.x += diff * 0.1;
// Add tilting animation based on movement direction
var shipGraphics = ship.children[0];
if (Math.abs(diff) > 10) {
// Only tilt if moving significantly
if (diff > 0) {
// Moving right - tilt right
tween(shipGraphics, {
rotation: 0.2
}, {
duration: 200,
easing: tween.easeOut
});
} else {
// Moving left - tilt left
tween(shipGraphics, {
rotation: -0.2
}, {
duration: 200,
easing: tween.easeOut
});
}
} else if (Math.abs(diff) < 5) {
// Return to upright position when not moving much
tween(shipGraphics, {
rotation: 0
}, {
duration: 300,
easing: tween.easeOut
});
}
} else {
var stickyDiff = targetX - ship.x;
ship.x += stickyDiff * 0.02; // Much slower movement
// Add tilting animation for sticky controls too
var shipGraphics = ship.children[0];
if (Math.abs(stickyDiff) > 20) {
// Higher threshold for sticky controls
if (stickyDiff > 0) {
// Moving right - tilt right
tween(shipGraphics, {
rotation: 0.15
}, {
duration: 400,
easing: tween.easeOut
});
} else {
// Moving left - tilt left
tween(shipGraphics, {
rotation: -0.15
}, {
duration: 400,
easing: tween.easeOut
});
}
} else if (Math.abs(stickyDiff) < 10) {
// Return to upright position when not moving much
tween(shipGraphics, {
rotation: 0
}, {
duration: 500,
easing: tween.easeOut
});
}
}
// Keep ship in bounds
if (ship.x < 60) {
ship.x = 60;
}
if (ship.x > 1988) {
ship.x = 1988;
}
// Update distance and score
distance += gameSpeed;
updateScore();
updateLevel();
// Update distance display
distanceText.setText('Distance: ' + Math.floor(distance) + 'm');
// Progressive difficulty scaling based on distance - more gradual
var difficultyMultiplier = 1 + Math.floor(distance / 1000) * 0.2; // Increase difficulty every 1000m, smaller increments
gameSpeed = Math.min(5, 2 + difficultyMultiplier); // Cap max speed at 5 instead of 8
// Update timers and show expiration notifications
if (doubleCoinsTime > 0) {
doubleCoinsTime--;
if (doubleCoinsTime === 0) {
showEffectExpiration('💰 Double Coins');
}
}
if (extraObstaclesTime > 0) {
extraObstaclesTime--;
if (extraObstaclesTime === 0) {
showEffectExpiration('⚠️ Extra Obstacles');
}
}
if (clearPathTime > 0) {
clearPathTime--;
if (clearPathTime === 0) {
showEffectExpiration('🛡️ Clear Path');
}
}
if (scoreFreezeTime > 0) {
scoreFreezeTime--;
if (scoreFreezeTime === 0) {
showEffectExpiration('❄️ Score Freeze');
}
}
// Show quiz
if (LK.ticks >= nextQuizTime) {
showQuiz();
}
// Handle random rain effect
if (!rainActive && LK.ticks >= nextRainTime) {
if (Math.random() < 0.3) {
// 30% chance of rain each cycle
spawnRain();
} else {
nextRainTime = LK.ticks + 300 + Math.random() * 300; // Check again soon
}
}
// Spawn rain drops when rain is active
if (rainActive) {
rainDuration--;
if (rainDuration <= 0) {
stopRain();
}
if (LK.ticks % 2 === 0) {
// Spawn rain drops very frequently for dense full-screen effect
for (var i = 0; i < 8; i++) {
var rainDrop = new RainDrop();
rainDrop.x = Math.random() * 2048;
rainDrop.y = -600 - Math.random() * 400;
rainDrop.startX = rainDrop.x;
atmosphericParticles.push(rainDrop);
game.addChild(rainDrop);
}
}
}
// Update rain drops
for (var i = atmosphericParticles.length - 1; i >= 0; i--) {
var drop = atmosphericParticles[i];
if (drop.y > 2900) {
drop.destroy();
atmosphericParticles.splice(i, 1);
continue;
}
}
// Spawn objects - progressive difficulty with gradual obstacle increase
var baseSpawnRate = Math.max(25, 80 - Math.floor(distance / 1500)); // Slightly more frequent as distance increases
var obstacleSpawnRate = Math.max(20, baseSpawnRate - level * 0.5); // Gentle level-based adjustment
if (LK.ticks % obstacleSpawnRate === 0) {
spawnObstacle();
// Spawn additional obstacles based on distance traveled - gradual increase
if (distance > 2000 && LK.ticks % (obstacleSpawnRate * 3) === 0) {
spawnObstacle(); // Extra obstacle after 2000m
}
if (distance > 4000 && LK.ticks % (obstacleSpawnRate * 3.5) === 0) {
spawnObstacle(); // More obstacles after 4000m
}
if (distance > 6000 && LK.ticks % (obstacleSpawnRate * 4) === 0) {
spawnObstacle(); // Even more obstacles after 6000m
} //{9i_ext}
if (extraObstaclesTime > 0 && LK.ticks % Math.max(15, obstacleSpawnRate / 2.5) === 0) {
spawnObstacle(); // Slightly increased extra obstacles during penalty
}
}
if (LK.ticks % 600 === 0) {
// Every 10 seconds - less frequent crew
spawnCrewMember();
}
if (LK.ticks % 150 === 0) {
// Every 2.5 seconds - slightly more frequent coins
spawnCoin();
}
// Update obstacles
for (var i = obstacles.length - 1; i >= 0; i--) {
var obstacle = obstacles[i];
if (obstacle.y > 2800) {
obstacle.destroy();
obstacles.splice(i, 1);
continue;
}
if (ship.intersects(obstacle)) {
obstacle.destroy();
obstacles.splice(i, 1);
// Play different sound based on obstacle type
if (obstacle instanceof Pirate) {
LK.getSound('damage1').play();
} else {
LK.getSound('damage').play();
}
takeDamage();
continue;
}
}
// Update crew members
for (var i = crewMembers.length - 1; i >= 0; i--) {
var crew = crewMembers[i];
if (crew.y > 2800) {
crew.destroy();
crewMembers.splice(i, 1);
continue;
}
if (ship.intersects(crew)) {
crewCount++;
crewText.setText('Crew: ' + crewCount);
crew.destroy();
crewMembers.splice(i, 1);
LK.getSound('crewreceived').play();
continue;
}
}
// Update water tiles for infinite scrolling
for (var i = waterTiles.length - 1; i >= 0; i--) {
var tile = waterTiles[i];
if (tile.y > 2800) {
// Reset tile position to top for infinite scrolling
tile.y = -100;
}
}
// Spawn seagulls periodically for ambiance
if (LK.ticks >= nextSeagullTime) {
if (Math.random() < 0.6) {
// 60% chance to spawn a seagull
spawnSeagull();
}
nextSeagullTime = LK.ticks + 300 + Math.random() * 300; // Every 5-10 seconds
}
// Update seagulls
for (var i = seagulls.length - 1; i >= 0; i--) {
var seagull = seagulls[i];
if (seagull.y < -300 || seagull.y > 2900) {
seagull.destroy();
seagulls.splice(i, 1);
continue;
}
// Ensure seagull stays on top of all other assets
if (game.children.indexOf(seagull) !== game.children.length - 1) {
game.setChildIndex(seagull, game.children.length - 1);
}
}
// Spawn sunlight rays periodically
if (LK.ticks % 480 === 0) {
// Every 8 seconds
spawnSunlightRay();
}
// Update sunlight rays
for (var i = sunlightRays.length - 1; i >= 0; i--) {
var ray = sunlightRays[i];
if (ray.y > 2800) {
ray.destroy();
sunlightRays.splice(i, 1);
continue;
}
// Update alpha based on level and animation
if (ray.children[0]) {
ray.children[0].alpha = (ray.maxAlpha || 0.3) + Math.sin(LK.ticks * 0.05 + ray.x * 0.02) * 0.2;
}
}
// Update coins
for (var i = coins.length - 1; i >= 0; i--) {
var coin = coins[i];
if (coin.y > 2800) {
coin.destroy();
coins.splice(i, 1);
continue;
}
if (ship.intersects(coin)) {
var coinValue = doubleCoinsTime > 0 ? 20 : 10;
coinCount++;
coinText.setText('Coins: ' + coinCount);
if (scoreFreezeTime <= 0) {
distance += coinValue;
}
coin.destroy();
coins.splice(i, 1);
// Play random coin sound
var coinSound = Math.random() < 0.5 ? 'coinreceived' : 'coinreceived1';
LK.getSound(coinSound).play();
continue;
}
}
};
function showMainMenu() {
if (menuContainer) {
return;
}
gameStarted = false;
gamePaused = true;
menuContainer = game.addChild(new Container());
menuContainer.alpha = 0;
// Main background
var menuBg = menuContainer.attachAsset('quizBg', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1366,
scaleX: 1.3,
scaleY: 1.6,
alpha: 0.95
});
// Title
var titleText = new Text2('QUIZ NAVIGATOR', {
size: 120,
fill: 0xFFD700,
stroke: 0x000033,
strokeThickness: 4
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 800;
menuContainer.addChild(titleText);
// Subtitle
var subtitleText = new Text2('Navigate the seas while answering maritime quizzes!', {
size: 45,
fill: 0xFFFFFF,
stroke: 0x000000,
strokeThickness: 2,
wordWrap: true,
wordWrapWidth: 1400
});
subtitleText.anchor.set(0.5, 0.5);
subtitleText.x = 1024;
subtitleText.y = 950;
menuContainer.addChild(subtitleText);
// Instructions
var instructionsText = new Text2('• Drag to move your ship\n• Collect crew members and coins\n• Answer quiz questions correctly for power-ups\n• Wrong answers give penalties\n• Survive as long as possible!', {
size: 40,
fill: 0xCCFFFF,
wordWrap: true,
wordWrapWidth: 1400
});
instructionsText.anchor.set(0.5, 0.5);
instructionsText.x = 1024;
instructionsText.y = 1200;
menuContainer.addChild(instructionsText);
// Start button
var startButton = new Container();
startButton.x = 1024;
startButton.y = 1600;
var startBg = startButton.attachAsset('quizBg', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.3,
scaleY: 0.15,
alpha: 0.9
});
startBg.tint = 0x00AA00;
var startText = new Text2('TAP TO START', {
size: 70,
fill: 0xFFFFFF,
stroke: 0x000000,
strokeThickness: 3
});
startText.anchor.set(0.5, 0.5);
startButton.addChild(startText);
startButton.down = function (x, y, obj) {
tween(startBg, {
scaleX: 0.65,
scaleY: 0.35
}, {
duration: 100
});
tween(startText, {
alpha: 0.7
}, {
duration: 100,
onFinish: function onFinish() {
hideMainMenu();
startGame();
}
});
};
menuContainer.addChild(startButton);
// High score display
var highScore = storage.highScore || 0;
var highScoreText = new Text2('High Score: ' + highScore, {
size: 50,
fill: 0xFFAA00
});
highScoreText.anchor.set(0.5, 0.5);
highScoreText.x = 1024;
highScoreText.y = 1800;
menuContainer.addChild(highScoreText);
// Animate menu entrance
tween(menuContainer, {
alpha: 1
}, {
duration: 500
});
// Animate title
tween(titleText, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 1000,
easing: tween.easeInOut
});
tween(titleText, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 1000,
easing: tween.easeInOut
});
}
function hideMainMenu() {
if (!menuContainer) {
return;
}
tween(menuContainer, {
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
if (menuContainer) {
menuContainer.destroy();
menuContainer = null;
}
}
});
}
function startGame() {
gameStarted = true;
gamePaused = false;
LK.getSound('gamestart').play();
// Reset game state
level = 1;
health = 3;
crewCount = 0;
coinCount = 0;
distance = 0;
gameSpeed = 2;
quizActive = false;
nextQuizTime = 480;
// Initialize rain system
rainActive = false;
rainDuration = 0;
nextRainTime = 1200; // Start first possible rain after 20 seconds
// Initialize seagull system
nextSeagullTime = 600; // Start spawning seagulls after 10 seconds
for (var i = seagulls.length - 1; i >= 0; i--) {
seagulls[i].destroy();
}
seagulls = [];
// Clear all arrays
for (var i = obstacles.length - 1; i >= 0; i--) {
obstacles[i].destroy();
}
obstacles = [];
for (var i = crewMembers.length - 1; i >= 0; i--) {
crewMembers[i].destroy();
}
crewMembers = [];
for (var i = coins.length - 1; i >= 0; i--) {
coins[i].destroy();
}
coins = [];
// Reset ship position
ship.x = 1024;
ship.y = 2400;
// Reset shield state on game start
ship.isShielded = false;
ship.shieldTime = 0;
if (ship.children.length > 1) {
ship.children[1].visible = false;
}
// Update UI
updateScore();
updateHearts();
levelText.setText('Level: ' + level);
crewText.setText('Crew: ' + crewCount);
coinText.setText('Coins: ' + coinCount);
distanceText.setText('Distance: 0m');
// Play background music
LK.playMusic('soundtrack', {
loop: true
});
}
heart, 3d pixel art, no background. In-Game asset. 2d. High contrast. No shadows
2D vector illustration of a ship from top view perspective, minimalistic flat design, clean lines, no background (transparent), realistic ship shape, visible deck, helm, and other top-side details, symmetrical composition.. In-Game asset. High contrast. No shadows
2D vector illustration of a pirate ship from top view perspective, minimalistic flat design, clean lines, no background (transparent), realistic ship shape, visible deck, helm, and other top-side details, symmetrical composition.. In-Game asset.. In-Game asset. 2d. High contrast. No shadows
2D game asset, vector style, high contrast, flat colors, no shadows, single drowning male naval crew member wearing a blue naval uniform and a 2D blue naval hat, struggling in rough ocean waves, broken ship debris nearby, transparent background, PNG format, aimed for top-down 2D game.. In-Game asset. 2d. High contrast. No shadows
2D game asset, vector style, high contrast, flat colors, no shadows, a classic black spherical sea mine with small red spikes (contact horns), suitable for a top-down game, transparent background, PNG format.. In-Game asset. 2d. High contrast. No shadows
2D game asset, vector style, high contrast, flat colors, no shadows, a single long, broken wooden plank with splintered edges, floating horizontally on the surface of blue water, suitable for a top-down game, transparent background, PNG format.. In-Game asset. 2d. High contrast. No shadows
2D game asset, vector style, high contrast, flat colors, no shadows, a rocky outcrop or reef formation with multiple jagged peaks, suitable for a top-down game perspective, transparent background, PNG format.. In-Game asset. 2d. High contrast. No shadows