User prompt
change game name to "What The Duck"
User prompt
the information text in the rules must be red
User prompt
make "Rules" text colour white
User prompt
give the game rules information to players i a new menu part called "rules"
User prompt
Add variety to ducks by introducing 3 different duck types: 1. Golden Duck: - Rare and very fast. - Gives +50 points when hit. 2. Armored Duck: - Needs to be hit twice to fall. - Flash red after first hit. 3. Mini Fast Duck: - Smaller in size and faster than regular ducks. - Worth +25 points. Use different sprites and point values for each duck type. Make sure the duck types appear with increasing frequency in higher levels.
User prompt
Add variety to ducks by introducing 3 different duck types: 1. Golden Duck: - Rare and very fast. - Gives +50 points when hit. 2. Armored Duck: - Needs to be hit twice to fall. - Flash red after first hit. 3. Mini Fast Duck: - Smaller in size and faster than regular ducks. - Worth +25 points. Use different sprites and point values for each duck type. Make sure the duck types appear with increasing frequency in higher levels.
User prompt
Add 3 special power-up weapons that players can unlock or collect: 1. Double Barrel Shotgun: - Shoots a wider bullet spread, hitting 2 ducks at once if they’re close. 2. Slow Time Power-up: - Slows down all ducks for 5 seconds. - Use a retro visual effect during slowdown. 3. Auto-Aim Power-up: - Automatically hits the nearest duck for 3 seconds. - Makes shooting easier in tough levels. Allow these power-ups to appear randomly or be earned by high performance. Show icons for active power-ups on screen with countdown timers.
User prompt
Add 2 new game modes to the game in addition to the classic one: 1. Time Attack Mode: - The player has 30 seconds to hit as many ducks as possible. - Show a countdown timer on the screen. - Final score is based on the number of ducks hit. 2. Endless Mode: - Ducks spawn infinitely. - Bullets are unlimited. - The goal is to hit as many ducks as possible without missing 3 times in a row. - If the player misses 3 times in a row, the game ends. Let the player choose a mode from a main menu before starting the game.
User prompt
give level 1 10 bullets ,give level 2 15 bullets,give level 3 20 bullets, give level 4 30 bullets, give level 5 32 bullets
User prompt
first levels have 6 ducks,level 2 have 12 ducks,level 3 have 20 ducks, first levels have 6 ducks, first level 4 have 30 ducks,level 5 have 40 ducks
User prompt
first levels have 6 ducks,level 2 have 12 ducks,level 3 have 20 ducks, first levels have 6 ducks, first level 4 have 30 ducks,level 5 have 6 ducks
User prompt
level 1 shoot at least 3 beards,level 2 shoot at least 6 beards, level 3 shoot at least 12 beards,level 4 shoot at least 18 beards, level 1 shoot at least 20 beards
User prompt
give level 1 10 bullets ,give level 2 15 bullets,give level 3 20 bullets, give level 4 25 bullets, give level 5 30 bullets
User prompt
level 2,3,4,5 give 15 bullets only
User prompt
fix that extra bullet to 15. not 20!!!
User prompt
first level player must have 15 bullets and each level give player 15 more bullets
User prompt
add new bird to hunt and new levels
User prompt
every level add 20 bullet to player
User prompt
show the bullet amount as a text under the level text
User prompt
after bullets amount is 0 game over
User prompt
after 20 bullet missed say player to warning message
User prompt
What to Fix: Hitting ducks should always work: Even after 1 or more missed shots, the player should still be able to hit ducks. Misses must not disable collision: Make sure that missing does not deactivate the hit detection or event listeners on ducks. Check that each duck’s hitbox remains active throughout its flight. Reset state properly between shots: Ensure the shooting system resets correctly after each shot — whether it’s a hit or miss. Do not block interaction with ducks unless bullets are zero. Ammo Logic: Player can keep shooting until bullets reach 0. Misses should only reduce bullet count, nothing else.
User prompt
add "bullet" text for the bullets amount
User prompt
show the bullets amount under the screen
User prompt
🔫 Ammo Rules: Initial Ammo: On Level 1, give the player 20 bullets. Progressive Ammo per New Game: When the game restarts, the player gets: remaining_bullets_from_last_game + 20 For example: If the player had 5 bullets left when the game ended, the next game starts with 25 bullets. Shooting Logic: Every time the player shoots (whether they hit or miss), subtract 1 bullet. If bullets = 0, prevent shooting until the next game. 📺 Display Ammo Count: Show the current number of bullets on the screen, aligned at the bottom center or bottom left. Use a clear retro-style pixel font or simple icon with text: Example: "Bullets: 18" Update this display live whenever the player shoots.
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1", { highScore: 0 }); /**** * Classes ****/ // Achievement popup class var AchievementPopup = Container.expand(function () { var self = Container.call(this); var txt = new Text2('', { size: 120, fill: 0xFFD700 }); txt.anchor.set(0.5, 0.5); self.addChild(txt); self.visible = false; self.show = function (message, color) { txt.setText(message); if (txt && txt.style) { txt.style.fill = color || 0xFFD700; } self.x = 2048 / 2; self.y = 2732 / 2 - 300; self.visible = true; self.alpha = 1; tween(self, { alpha: 0 }, { duration: 1200, onFinish: function onFinish() { self.visible = false; } }); }; return self; }); // Dog class var Dog = Container.expand(function () { var self = Container.call(this); var dogAsset = self.attachAsset('dog', { anchorX: 0.5, anchorY: 1 }); self.visible = false; // Show dog at (x, y) self.show = function (x, y) { self.x = x; self.y = y; self.visible = true; dogAsset.visible = true; if (self.laughAsset) self.laughAsset.visible = false; // Optionally, you could add a little "pop up" animation here // For example, tween the dog from below the screen to y var startY = 2732 + dogAsset.height; self.y = startY; tween(self, { y: y }, { duration: 350, easing: tween.cubicOut }); }; // Hide dog self.hide = function () { // Animate dog going down before hiding var endY = 2732 + (dogAsset.height || 180); tween(self, { y: endY }, { duration: 350, easing: tween.cubicIn, onFinish: function onFinish() { self.visible = false; dogAsset.visible = false; } }); }; // Show laugh animation self.laugh = function (x, y) { self.x = x; self.y = y; self.visible = true; dogAsset.visible = false; if (!self.laughAsset) { self.laughAsset = self.attachAsset('dog_laugh', { anchorX: 0.5, anchorY: 1 }); } self.laughAsset.visible = true; LK.getSound('dog_laugh').play(); // Hide after 1.2s LK.setTimeout(function () { self.laughAsset.visible = false; self.hide(); }, 1200); }; return self; }); // Duck class var Duck = Container.expand(function () { var self = Container.call(this); // Determine duck type based on level and DUCK_TYPE_CONFIG var duckType = 'normal'; var levelIdx = Math.max(0, Math.min(level - 1, DUCK_TYPE_CONFIG.length - 1)); var config = DUCK_TYPE_CONFIG[levelIdx]; var r = Math.random(); if (r < config.golden) { duckType = 'golden'; } else if (r < config.golden + config.armored) { duckType = 'armored'; } else if (r < config.golden + config.armored + config.mini) { duckType = 'mini'; } else if (Math.random() < 0.25) { duckType = 'fast'; } self.type = duckType; // Asset selection var duckAsset = null; if (duckType === 'golden') { duckAsset = self.attachAsset('duck_golden', { anchorX: 0.5, anchorY: 0.5 }); duckAsset.tint = 0xFFD700; } else if (duckType === 'armored') { duckAsset = self.attachAsset('duck_armored', { anchorX: 0.5, anchorY: 0.5 }); duckAsset.tint = 0x888888; } else if (duckType === 'mini') { duckAsset = self.attachAsset('duck_mini', { anchorX: 0.5, anchorY: 0.5 }); } else { // normal or fast var duckColors = ['duck_green', 'duck_blue', 'duck_red']; var colorIdx = Math.floor(Math.random() * duckColors.length); duckAsset = self.attachAsset(duckColors[colorIdx], { anchorX: 0.5, anchorY: 0.5 }); } // Set initial position and movement self.speed = 6 + Math.random() * 4; // Will be set by level self.angle = 0; // radians, will be set by level self.alive = true; self.hit = false; self.escaped = false; self.armor = duckType === 'armored' ? 2 : 1; // 2 hits for armored self.flashTween = null; // For animation self.flyTween = null; // --- Hitbox properties for all ducks (mini ducks are smaller, fast/golden slightly larger) --- self.getHitboxRadius = function () { var baseRadius = Math.max(duckAsset.width, duckAsset.height) * 0.5; if (self.type === 'mini') { return baseRadius * 0.55; } if (self.type === 'fast' || self.type === 'golden' || self.speed >= 6) { return baseRadius * 0.7; } return baseRadius * 0.55; }; // Head hitbox (top 1/3 of duck) self.isHeadshot = function (x, y) { var dx = self.x - x; var dy = self.y - y; var dist = Math.sqrt(dx * dx + dy * dy); var headRadius = duckAsset.height * 0.18; var headCenterY = self.y - duckAsset.height * 0.22; var headDist = Math.sqrt((self.x - x) * (self.x - x) + (headCenterY - y) * (headCenterY - y)); return headDist < headRadius; }; // Called every tick self.update = function () { if (!self.alive || self.hit) return; self.x += Math.cos(self.angle) * self.speed; self.y += Math.sin(self.angle) * self.speed; if (self.x < -100 || self.x > 2048 + 100 || self.y < -100 || self.y > 2732 + 100) { self.escaped = true; self.alive = false; } }; // Animate duck falling when hit self.fall = function (_onFinish) { self.alive = false; tween(self, { rotation: Math.PI * 1.5, y: self.y + 400 }, { duration: 700, easing: tween.cubicIn, onFinish: function onFinish() { if (_onFinish) _onFinish(); } }); }; // Armored duck: flash red on first hit self.flashRed = function () { if (self.flashTween) { self.flashTween.cancel(); } var origTint = duckAsset.tint; duckAsset.tint = 0xff2222; self.flashTween = tween(duckAsset, {}, { duration: 200, onFinish: function onFinish() { duckAsset.tint = 0x888888; self.flashTween = null; } }); }; return self; }); // Power-up collectible class var PowerupCollectible = Container.expand(function () { var self = Container.call(this); self.type = null; self.icon = null; self.radius = 60; self.speedY = -2 - Math.random() * 2; self.lifetime = 0; self.maxLifetime = 400; // ~6 seconds self.init = function (ptype, x, y) { self.type = ptype; var iconId = ptype === 'doubleBarrel' ? 'powerup_double' : ptype === 'slowTime' ? 'powerup_slow' : 'powerup_auto'; self.icon = self.attachAsset(iconId, { anchorX: 0.5, anchorY: 0.5 }); self.x = x; self.y = y; self.icon.scaleX = self.icon.scaleY = 1.1; self.visible = true; self.alpha = 0.92; }; self.update = function () { self.y += self.speedY; self.lifetime++; // Fade out near end of life if (self.lifetime > self.maxLifetime - 60) { self.alpha = Math.max(0, (self.maxLifetime - self.lifetime) / 60); } // Remove if out of bounds or expired if (self.y < 100 || self.lifetime > self.maxLifetime) { if (self.parent) self.parent.removeChild(self); if (typeof powerupCollectibles !== "undefined") { var idx = powerupCollectibles.indexOf(self); if (idx >= 0) powerupCollectibles.splice(idx, 1); } } }; // Check if tap is within radius self.isHit = function (x, y) { var dx = self.x - x; var dy = self.y - y; return dx * dx + dy * dy < self.radius * self.radius; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x87ceeb // sky blue }); /**** * Game Code ****/ // --- Duck type probabilities and point values --- // Use red as base, gold tint // Use blue as base, gray tint // Use red as base, smaller var DUCK_TYPE_CONFIG = [ // Level 1 { golden: 0.04, // 4% armored: 0.0, mini: 0.0 }, // Level 2 { golden: 0.06, armored: 0.08, mini: 0.04 }, // Level 3 { golden: 0.08, armored: 0.13, mini: 0.08 }, // Level 4 { golden: 0.10, armored: 0.18, mini: 0.13 }, // Level 5+ { golden: 0.13, armored: 0.22, mini: 0.18 }]; var DUCK_TYPE_POINTS = { normal: 10, golden: 50, armored: 20, mini: 25 }; // --- Power-up collectibles array --- // Ducks: 3 colors, 1 dog, 1 bullet, 1 background, 1 crosshair, 1 "laugh" dog // sky blue // Sounds // Music // Power-up icons and retro overlay var powerupCollectibles = []; // Spawn a power-up collectible at a random position function spawnPowerupCollectible(ptype) { var px = 200 + Math.random() * (2048 - 400); var py = 2732 - 200 - Math.random() * 800; var p = new PowerupCollectible(); p.init(ptype, px, py); powerupCollectibles.push(p); game.addChild(p); } // Activate a power-up function activatePowerup(ptype) { if (powerupActive[ptype]) return; powerupActive[ptype] = true; var duration = 0; if (ptype === 'doubleBarrel') duration = 7; if (ptype === 'slowTime') duration = 5; if (ptype === 'autoAim') duration = 3; powerupTimers[ptype] = duration; showPowerupIcon(ptype, duration); // Apply effect if (ptype === 'slowTime') { // Slow all ducks for (var i = 0; i < ducks.length; i++) { ducks[i].speed = ducks[i].speed * 0.35; } // Add retro overlay if (!slowTimeEffectOverlay) { slowTimeEffectOverlay = LK.getAsset('retro_overlay', { anchorX: 0, anchorY: 0, x: 0, y: 0 }); slowTimeEffectOverlay.alpha = 0.22; game.addChild(slowTimeEffectOverlay); } } if (ptype === 'autoAim') { // No immediate effect, handled in shooting logic } if (ptype === 'doubleBarrel') { // No immediate effect, handled in shooting logic } // Set timeout to deactivate if (powerupTimeouts[ptype]) LK.clearTimeout(powerupTimeouts[ptype]); powerupTimeouts[ptype] = LK.setTimeout(function () { powerupActive[ptype] = false; powerupTimers[ptype] = 0; hidePowerupIcon(ptype); if (ptype === 'slowTime') { // Restore duck speed for (var i = 0; i < ducks.length; i++) { ducks[i].speed = ducks[i].speed / 0.35; } // Remove overlay if (slowTimeEffectOverlay && slowTimeEffectOverlay.parent) { slowTimeEffectOverlay.parent.removeChild(slowTimeEffectOverlay); slowTimeEffectOverlay = null; } } }, duration * 1000); } // Show power-up icon in GUI function showPowerupIcon(ptype, duration) { var iconId = ptype === 'doubleBarrel' ? 'powerup_double' : ptype === 'slowTime' ? 'powerup_slow' : 'powerup_auto'; var icon = LK.getAsset(iconId, { anchorX: 0.5, anchorY: 0.5, x: 0, y: 0 }); icon.scaleX = icon.scaleY = 1.1; var timerTxt = new Text2(duration + "s", { size: 60, fill: 0xffffff }); timerTxt.anchor.set(0.5, 0.5); icon.addChild(timerTxt); powerupIcons[ptype] = icon; // Place icons in top left, but not in 0-100px (menu area) var idx = ptype === 'doubleBarrel' ? 0 : ptype === 'slowTime' ? 1 : 2; icon.x = 120 + idx * 120; icon.y = 120; LK.gui.top.addChild(icon); icon._timerTxt = timerTxt; } // Hide power-up icon function hidePowerupIcon(ptype) { if (powerupIcons[ptype] && powerupIcons[ptype].parent) { powerupIcons[ptype].parent.removeChild(powerupIcons[ptype]); powerupIcons[ptype] = null; } } // Game state variables var ducks = []; var bullets = []; var level = 1; var ducksPerLevel = 5; var ducksToHit = 0; var ducksHit = 0; var ducksEscaped = 0; var maxBullets = 3; var bulletsLeft = 3; var timeLimit = 15; // seconds var timeLeft = 15; var gameActive = false; var waveActive = false; var highScore = storage.highScore || 0; var score = 0; var dog = null; var crosshair = null; var timerInterval = null; var levelText = null; var scoreText = null; var timerText = null; var bulletIcons = []; var waveResultTimeout = null; // Track missed shots for warning var missedShots = 0; var missedWarningShown = false; // --- Power-up State --- var powerupActive = { doubleBarrel: false, slowTime: false, autoAim: false }; var powerupTimers = { doubleBarrel: 0, slowTime: 0, autoAim: 0 }; var powerupIcons = { doubleBarrel: null, slowTime: null, autoAim: null }; var powerupTimeouts = { doubleBarrel: null, slowTime: null, autoAim: null }; // For slow time effect var slowTimeEffectOverlay = null; // --- Game Mode State --- var GAME_MODE_CLASSIC = "classic"; var GAME_MODE_TIMEATTACK = "timeattack"; var GAME_MODE_ENDLESS = "endless"; var gameMode = null; // Set by menu var mainMenuContainer = null; var endlessMissStreak = 0; var endlessGameOver = false; // Background var bg = LK.getAsset('bg', { anchorX: 0, anchorY: 0, x: 0, y: 0 }); game.addChild(bg); // --- Main Menu UI --- function showMainMenu() { // Remove previous menu if present if (mainMenuContainer && mainMenuContainer.parent) { mainMenuContainer.parent.removeChild(mainMenuContainer); } mainMenuContainer = new Container(); // Dim background var menuBg = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, scaleX: 16, scaleY: 16, x: 2048 / 2, y: 2732 / 2 }); menuBg.alpha = 0.85; mainMenuContainer.addChild(menuBg); // Title var title = new Text2("Duck Hunt", { size: 220, fill: 0xFFD700, font: "'PressStart2P','GillSans-Bold',Impact,'Arial Black',Tahoma" }); title.anchor.set(0.5, 0); title.x = 2048 / 2; title.y = 400; mainMenuContainer.addChild(title); // Classic Mode Button var btnClassic = new Text2("Classic Mode", { size: 120, fill: 0xFFFFFF, font: "'PressStart2P','GillSans-Bold',Impact,'Arial Black',Tahoma" }); btnClassic.anchor.set(0.5, 0.5); btnClassic.x = 2048 / 2; btnClassic.y = 900; mainMenuContainer.addChild(btnClassic); // Time Attack Button var btnTime = new Text2("Time Attack", { size: 120, fill: 0xFFFFFF, font: "'PressStart2P','GillSans-Bold',Impact,'Arial Black',Tahoma" }); btnTime.anchor.set(0.5, 0.5); btnTime.x = 2048 / 2; btnTime.y = 1100; mainMenuContainer.addChild(btnTime); // Endless Mode Button var btnEndless = new Text2("Endless Mode", { size: 120, fill: 0xFFFFFF, font: "'PressStart2P','GillSans-Bold',Impact,'Arial Black',Tahoma" }); btnEndless.anchor.set(0.5, 0.5); btnEndless.x = 2048 / 2; btnEndless.y = 1300; mainMenuContainer.addChild(btnEndless); // Rules Button var btnRules = new Text2("Rules", { size: 100, fill: 0xFFFFFF, font: "'PressStart2P','GillSans-Bold',Impact,'Arial Black',Tahoma" }); btnRules.anchor.set(0.5, 0.5); btnRules.x = 2048 / 2; btnRules.y = 1450; mainMenuContainer.addChild(btnRules); // Instructions var info = new Text2("Choose a mode to start!", { size: 80, fill: 0xFFFFFF, font: "'GillSans-Bold',Impact,'Arial Black',Tahoma" }); info.anchor.set(0.5, 0.5); info.x = 2048 / 2; info.y = 1550; mainMenuContainer.addChild(info); // --- Rules Popup --- var rulesPopup = null; function showRulesPopup() { if (rulesPopup && rulesPopup.parent) rulesPopup.parent.removeChild(rulesPopup); rulesPopup = new Container(); var popupBg = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, scaleX: 10, scaleY: 10, x: 2048 / 2, y: 2732 / 2 }); popupBg.alpha = 0.96; rulesPopup.addChild(popupBg); var rulesTitle = new Text2("Game Rules", { size: 120, fill: 0xFFD700, font: "'PressStart2P','GillSans-Bold',Impact,'Arial Black',Tahoma" }); rulesTitle.anchor.set(0.5, 0); rulesTitle.x = 2048 / 2; rulesTitle.y = 400; rulesPopup.addChild(rulesTitle); var rulesText = new Text2("Classic Mode:\n" + "- Hit enough ducks with limited bullets to advance.\n" + "- Each level has more ducks and bullets.\n\n" + "Time Attack:\n" + "- 30 seconds to hit as many ducks as possible.\n" + "- Unlimited bullets.\n\n" + "Endless Mode:\n" + "- Ducks spawn forever, unlimited bullets.\n" + "- Game ends if you miss 3 times in a row.\n\n" + "Duck Types:\n" + "- Golden Duck: Fast, +50 points.\n" + "- Armored Duck: Needs 2 hits.\n" + "- Mini Fast Duck: Small, fast, +25 points.\n\n" + "Power-ups:\n" + "- Double Barrel: Hit 2 ducks at once.\n" + "- Slow Time: Ducks move slowly for 5s.\n" + "- Auto-Aim: Instantly hit nearest duck for 3s.\n\n" + "Tap power-up icons to collect. Good luck!", { size: 60, fill: 0xFFFFFF, font: "'GillSans-Bold',Impact,'Arial Black',Tahoma", wordWrap: true, wordWrapWidth: 1600, align: "left" }); rulesText.anchor.set(0.5, 0); rulesText.x = 2048 / 2; rulesText.y = 550; rulesPopup.addChild(rulesText); var btnClose = new Text2("Close", { size: 100, fill: 0xFFD700, font: "'PressStart2P','GillSans-Bold',Impact,'Arial Black',Tahoma" }); btnClose.anchor.set(0.5, 0.5); btnClose.x = 2048 / 2; btnClose.y = 2300; btnClose.interactive = true; btnClose.down = function () { if (rulesPopup.parent) rulesPopup.parent.removeChild(rulesPopup); }; rulesPopup.addChild(btnClose); game.addChild(rulesPopup); } // Button handlers btnClassic.interactive = true; btnClassic.down = function () { gameMode = GAME_MODE_CLASSIC; if (mainMenuContainer.parent) mainMenuContainer.parent.removeChild(mainMenuContainer); startLevel(); }; btnTime.interactive = true; btnTime.down = function () { gameMode = GAME_MODE_TIMEATTACK; if (mainMenuContainer.parent) mainMenuContainer.parent.removeChild(mainMenuContainer); startLevel(); }; btnEndless.interactive = true; btnEndless.down = function () { gameMode = GAME_MODE_ENDLESS; if (mainMenuContainer.parent) mainMenuContainer.parent.removeChild(mainMenuContainer); startLevel(); }; btnRules.interactive = true; btnRules.down = function () { showRulesPopup(); }; // Add to game game.addChild(mainMenuContainer); } // Show menu on load showMainMenu(); // Dog dog = new Dog(); game.addChild(dog); // Achievement popup (always on top) var achievementPopup = new AchievementPopup(); game.addChild(achievementPopup); // Crosshair crosshair = LK.getAsset('crosshair', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 1366 }); crosshair.visible = false; game.addChild(crosshair); // GUI: Level, Score, Timer, Bullets levelText = new Text2('Level 1', { size: 90, fill: 0xFFF000 }); levelText.anchor.set(1, 0); // right align to match high score scoreText = new Text2('Score: 0', { size: 90, fill: 0xFFFFFF }); scoreText.anchor.set(0.5, 0); LK.gui.top.addChild(scoreText); timerText = new Text2('Time: 15', { size: 90, fill: 0xFFFFFF }); timerText.anchor.set(0.5, 0); LK.gui.top.addChild(timerText); // High Score UI var highScoreText = new Text2('High: ' + highScore, { size: 70, fill: 0xFFD700 }); highScoreText.anchor.set(1, 0); // Place high score in top right LK.gui.topRight.addChild(highScoreText); // Place level text directly under high score text in top right LK.gui.topRight.addChild(levelText); // Position GUI // Position GUI scoreText.x = 2048 / 2; timerText.x = 2048 * 3 / 4; highScoreText.x = 0; highScoreText.y = 0; levelText.x = 0; levelText.y = highScoreText.height + 10; // 10px gap below high score // Responsive UI: adjust font size and icon size for mobile function resizeUI() { var w = LK.width || 2048; var h = LK.height || 2732; var scale = Math.min(w / 2048, h / 2732); if (scoreText && scoreText.style) scoreText.style.size = 90 * scale; if (timerText && timerText.style) timerText.style.size = 90 * scale; if (highScoreText && highScoreText.style) highScoreText.style.size = 70 * scale; if (levelText && levelText.style) levelText.style.size = 90 * scale; for (var i = 0; i < bulletIcons.length; i++) { bulletIcons[i].scaleX = bulletIcons[i].scaleY = scale; } } LK.on('resize', resizeUI); resizeUI(); // Bullets GUI (now under the level text in the top right) // Show both bullet icons (bottom) and a text counter (top right under level) var bulletCountText = null; var bulletLabelText = null; function updateBulletIcons() { // Remove old icons for (var i = 0; i < bulletIcons.length; i++) { if (bulletIcons[i].parent) bulletIcons[i].parent.removeChild(bulletIcons[i]); } bulletIcons = []; // Draw new icons (up to 10 for visual clarity, then show text) var maxIcons = Math.min(10, bulletsLeft); // Center the icons under the screen var iconSpacing = 60; var totalWidth = (maxIcons - 1) * iconSpacing; var startX = 2048 / 2 - totalWidth / 2; for (var i = 0; i < maxIcons; i++) { var icon = LK.getAsset('bullet_icon', { anchorX: 0.5, anchorY: 0.5, x: startX + i * iconSpacing, y: 2732 - 120 }); LK.gui.bottom.addChild(icon); bulletIcons.push(icon); } // Remove old text if present if (bulletCountText && bulletCountText.parent) { bulletCountText.parent.removeChild(bulletCountText); } if (bulletLabelText && bulletLabelText.parent) { bulletLabelText.parent.removeChild(bulletLabelText); } // Add "Bullets" label above the count, now in top right under level bulletLabelText = new Text2("Bullets", { size: 60, fill: 0xFFF000, font: "'PressStart2P','GillSans-Bold',Impact,'Arial Black',Tahoma" }); bulletLabelText.anchor.set(1, 0); // right align, top anchor bulletLabelText.x = 0; bulletLabelText.y = levelText.y + levelText.height + 10; LK.gui.topRight.addChild(bulletLabelText); // Show bullet count as text (always, for clarity) bulletCountText = new Text2("" + bulletsLeft, { size: 90, fill: 0xFFF000, font: "'PressStart2P','GillSans-Bold',Impact,'Arial Black',Tahoma" }); bulletCountText.anchor.set(1, 0); // right align, top anchor bulletCountText.x = 0; bulletCountText.y = bulletLabelText.y + bulletLabelText.height + 2; LK.gui.topRight.addChild(bulletCountText); } // Start a new level function startLevel() { ducks = []; bullets = []; ducksHit = 0; ducksEscaped = 0; missedShots = 0; missedWarningShown = false; endlessMissStreak = 0; endlessGameOver = false; // --- Mode-specific setup --- if (gameMode === GAME_MODE_CLASSIC || !gameMode) { // Set ducksPerLevel and ducksToHit per level as per requirements if (level === 1) { ducksPerLevel = 6; ducksToHit = 3; } else if (level === 2) { ducksPerLevel = 12; ducksToHit = 6; } else if (level === 3) { ducksPerLevel = 20; ducksToHit = 12; } else if (level === 4) { ducksPerLevel = 30; ducksToHit = 18; } else if (level === 5) { ducksPerLevel = 40; ducksToHit = 20; } else { ducksPerLevel = Math.min(25, 15 + (level - 5) * 2); ducksToHit = Math.ceil(ducksPerLevel * 0.7); } // Set bulletsLeft per level: 10 for level 1, 15 for level 2, 20 for level 3, 30 for level 4, 32 for level 5 if (level === 1) { bulletsLeft = 10; } else if (level === 2) { bulletsLeft = 15; } else if (level === 3) { bulletsLeft = 20; } else if (level === 4) { bulletsLeft = 30; } else if (level === 5) { bulletsLeft = 32; } else { bulletsLeft = 32 + 2 * (level - 5); } maxBullets = bulletsLeft; timeLimit = Math.max(8, 15 - (level - 1)); timeLeft = timeLimit; levelText.setText('Level ' + level); } else if (gameMode === GAME_MODE_TIMEATTACK) { // 30 seconds, infinite ducks, infinite bullets, score = ducks hit ducksPerLevel = 99999; ducksToHit = 0; bulletsLeft = 99999; maxBullets = bulletsLeft; timeLimit = 30; timeLeft = 30; levelText.setText('Time Attack'); } else if (gameMode === GAME_MODE_ENDLESS) { // Infinite ducks, infinite bullets, game ends on 3 misses in a row ducksPerLevel = 99999; ducksToHit = 0; bulletsLeft = 99999; maxBullets = bulletsLeft; timeLimit = 99999; timeLeft = 99999; levelText.setText('Endless'); } gameActive = true; waveActive = true; updateBulletIcons(); scoreText.setText('Score: ' + score); timerText.setText('Time: ' + timeLeft); // Duck spawn schedule and speed per level/mode var duckSpawnTimer = null; var ducksSpawned = 0; var ducksAtOnce = 1; var duckSpawnInterval = 3000; var duckSpeedMin = 2; var duckSpeedMax = 3.5; if (gameMode === GAME_MODE_CLASSIC || !gameMode) { if (level === 1) { ducksAtOnce = 1; duckSpawnInterval = 3000; duckSpeedMin = 2; duckSpeedMax = 3.5; } else if (level === 2) { ducksAtOnce = 1; duckSpawnInterval = 2000; duckSpeedMin = 3.5; duckSpeedMax = 5; } else if (level === 3) { ducksAtOnce = 2; duckSpawnInterval = 1800; duckSpeedMin = 4.2; duckSpeedMax = 5.8; } else if (level === 4) { ducksAtOnce = 3; duckSpawnInterval = 1500; duckSpeedMin = 5.5; duckSpeedMax = 7.2; } else if (level === 5) { ducksAtOnce = 4; duckSpawnInterval = 1200; duckSpeedMin = 6.5; duckSpeedMax = 8.5; } else { ducksAtOnce = 5; duckSpawnInterval = 1000; duckSpeedMin = 7.5 + (level - 5) * 0.5; duckSpeedMax = 9.5 + (level - 5) * 0.7; } } else if (gameMode === GAME_MODE_TIMEATTACK) { ducksAtOnce = 2; duckSpawnInterval = 900; duckSpeedMin = 4.5; duckSpeedMax = 7.5; } else if (gameMode === GAME_MODE_ENDLESS) { ducksAtOnce = 2; duckSpawnInterval = 900; duckSpeedMin = 4.5; duckSpeedMax = 7.5; } // Clear any previous duck spawn timer if (typeof duckSpawnTimer !== "undefined" && duckSpawnTimer) { LK.clearInterval(duckSpawnTimer); duckSpawnTimer = null; } ducksSpawned = 0; // Function to spawn ducks and power-ups function spawnDucks() { if (!gameActive || !waveActive) return; if ((gameMode === GAME_MODE_CLASSIC || !gameMode) && ducksSpawned >= ducksPerLevel) { if (duckSpawnTimer) { LK.clearInterval(duckSpawnTimer); duckSpawnTimer = null; } return; } var ducksThisWave = gameMode === GAME_MODE_CLASSIC || !gameMode ? Math.min(ducksAtOnce, ducksPerLevel - ducksSpawned) : ducksAtOnce; for (var d = 0; d < ducksThisWave; d++) { var duck = new Duck(); // Randomize start edge: 0=left, 1=right, 2=bottom var edge = Math.floor(Math.random() * 3); var startX, startY, angle; if (edge === 0) { // left startX = -60; startY = 400 + Math.random() * (2732 - 800); angle = Math.random() * Math.PI / 3 - Math.PI / 6; // -30 to +30 deg } else if (edge === 1) { // right startX = 2048 + 60; startY = 400 + Math.random() * (2732 - 800); angle = Math.PI + (Math.random() * Math.PI / 3 - Math.PI / 6); // 150 to 210 deg } else { // bottom startX = 200 + Math.random() * (2048 - 400); startY = 2732 + 60; angle = -Math.PI / 2 + (Math.random() * Math.PI / 4 - Math.PI / 8); // -67 to -23 deg } duck.x = startX; duck.y = startY; duck.angle = angle; // Set duck speed and size based on type if (duck.type === 'golden') { duck.speed = duckSpeedMax + 2 + Math.random() * 1.5; } else if (duck.type === 'armored') { duck.speed = duckSpeedMin + Math.random() * (duckSpeedMax - duckSpeedMin) * 0.7; } else if (duck.type === 'mini') { duck.speed = duckSpeedMax + 1 + Math.random() * 1.2; duck.scaleX = duck.scaleY = 0.6 + Math.random() * 0.2; } else if (duck.type === 'fast') { duck.speed = duckSpeedMax + 0.7 + Math.random() * 0.7; } else { duck.speed = duckSpeedMin + Math.random() * (duckSpeedMax - duckSpeedMin); } ducks.push(duck); // Always add ducks above background and below crosshair/dog/UI game.addChild(duck); // Move dog and crosshair to top of display list if present if (dog && dog.parent) { dog.parent.removeChild(dog); game.addChild(dog); } if (crosshair && crosshair.parent) { crosshair.parent.removeChild(crosshair); game.addChild(crosshair); } LK.getSound('duck_fly').play(); ducksSpawned++; } // --- Power-up spawn logic --- // Power-ups can appear randomly (1 in 7 chance per spawn, but not if already active) if (Math.random() < 1 / 7) { var availablePowerups = []; if (!powerupActive.doubleBarrel) availablePowerups.push('doubleBarrel'); if (!powerupActive.slowTime) availablePowerups.push('slowTime'); if (!powerupActive.autoAim) availablePowerups.push('autoAim'); if (availablePowerups.length > 0) { var which = availablePowerups[Math.floor(Math.random() * availablePowerups.length)]; spawnPowerupCollectible(which); } } } spawnDucks(); // Spawn first batch immediately if ((gameMode === GAME_MODE_CLASSIC || !gameMode) && ducksPerLevel > ducksAtOnce) { duckSpawnTimer = LK.setInterval(spawnDucks, duckSpawnInterval); } else if (gameMode === GAME_MODE_TIMEATTACK || gameMode === GAME_MODE_ENDLESS) { duckSpawnTimer = LK.setInterval(spawnDucks, duckSpawnInterval); } // Start timer if (timerInterval) LK.clearInterval(timerInterval); timerInterval = LK.setInterval(function () { if (!gameActive) return; if (gameMode === GAME_MODE_TIMEATTACK) { timeLeft--; timerText.setText('Time: ' + timeLeft); if (timeLeft <= 0) { endWave(); } } else if (gameMode === GAME_MODE_CLASSIC || !gameMode) { timeLeft--; timerText.setText('Time: ' + timeLeft); if (timeLeft <= 0) { endWave(); } } else if (gameMode === GAME_MODE_ENDLESS) { // No timer, but show "∞" or running time timerText.setText('Endless'); } }, 1000); } // End wave: check results, show dog if needed, advance or game over function endWave() { if (!waveActive) return; waveActive = false; gameActive = false; if (timerInterval) LK.clearInterval(timerInterval); // Remove remaining ducks for (var i = 0; i < ducks.length; i++) { if (ducks[i].parent) ducks[i].parent.removeChild(ducks[i]); } ducks = []; // --- Classic Mode --- if (gameMode === GAME_MODE_CLASSIC || !gameMode) { // Show dog if not enough ducks hit if (ducksHit < ducksToHit) { dog.laugh(2048 / 2, 2732 - 100); LK.effects.flashScreen(0xff0000, 800); // Show final score on Game Over LK.setTimeout(function () { var finalScoreText = new Text2('Final Score: ' + score, { size: 120, fill: 0xFFFF00 }); finalScoreText.anchor.set(0.5, 0.5); finalScoreText.x = 2048 / 2; finalScoreText.y = 2732 / 2; game.addChild(finalScoreText); LK.setTimeout(function () { if (finalScoreText.parent) finalScoreText.parent.removeChild(finalScoreText); LK.showGameOver(); }, 900); }, 400); // Game over after laugh waveResultTimeout = LK.setTimeout(function () { // handled above }, 1300); } else { // Advance to next level after short pause LK.effects.flashObject(levelText, 0x00ff00, 700); LK.setTimeout(function () { var finalScoreText = new Text2('Score: ' + score, { size: 120, fill: 0x00FF00 }); finalScoreText.anchor.set(0.5, 0.5); finalScoreText.x = 2048 / 2; finalScoreText.y = 2732 / 2; game.addChild(finalScoreText); LK.setTimeout(function () { if (finalScoreText.parent) finalScoreText.parent.removeChild(finalScoreText); level++; startLevel(); }, 700); }, 200); } } // --- Time Attack Mode --- else if (gameMode === GAME_MODE_TIMEATTACK) { // Show final score and return to menu LK.effects.flashScreen(0x00ffcc, 800); LK.setTimeout(function () { var finalScoreText = new Text2('Ducks Hit: ' + ducksHit, { size: 120, fill: 0x00FFCC }); finalScoreText.anchor.set(0.5, 0.5); finalScoreText.x = 2048 / 2; finalScoreText.y = 2732 / 2; game.addChild(finalScoreText); LK.setTimeout(function () { if (finalScoreText.parent) finalScoreText.parent.removeChild(finalScoreText); showMainMenu(); }, 1400); }, 400); } // --- Endless Mode --- else if (gameMode === GAME_MODE_ENDLESS) { endlessGameOver = true; LK.effects.flashScreen(0xff2222, 800); LK.setTimeout(function () { var finalScoreText = new Text2('Ducks Hit: ' + ducksHit, { size: 120, fill: 0xFF2222 }); finalScoreText.anchor.set(0.5, 0.5); finalScoreText.x = 2048 / 2; finalScoreText.y = 2732 / 2; game.addChild(finalScoreText); LK.setTimeout(function () { if (finalScoreText.parent) finalScoreText.parent.removeChild(finalScoreText); showMainMenu(); }, 1400); }, 400); } } // Handle tap/click to shoot game.down = function (x, y, obj) { if (!gameActive || !waveActive) return; // --- Power-up collectible check --- for (var i = powerupCollectibles.length - 1; i >= 0; i--) { var p = powerupCollectibles[i]; if (p.isHit(x, y)) { activatePowerup(p.type); if (p.parent) p.parent.removeChild(p); powerupCollectibles.splice(i, 1); LK.effects.flashObject(p, 0xffffff, 300); LK.getSound('hit').play(); return; } } // --- Bullets check --- if ((gameMode === GAME_MODE_CLASSIC || !gameMode) && bulletsLeft <= 0) { LK.getSound('miss').play(); LK.effects.flashScreen(0x888888, 200); // Show reload animation (flash bullet icons red) for (var i = 0; i < bulletIcons.length; i++) { LK.effects.flashObject(bulletIcons[i], 0xff2222, 300); } // Optionally play reload sound if available // LK.getSound('reload').play(); return; } // Only decrement bullets and allow shooting if bulletsLeft > 0 (classic) if (gameMode === GAME_MODE_CLASSIC || !gameMode) { bulletsLeft--; updateBulletIcons(); if (bulletCountText && bulletCountText.setText) { bulletCountText.setText("Bullets: " + bulletsLeft); } // If bullets reach zero after this shot, trigger game over immediately if (bulletsLeft === 0) { LK.setTimeout(function () { LK.showGameOver(); }, 400); // short delay to allow last shot/crosshair to animate return; } } LK.getSound('shoot').play(); // Show crosshair at tap crosshair.x = x; crosshair.y = y; crosshair.visible = true; tween(crosshair, { alpha: 0 }, { duration: 200, onFinish: function onFinish() { crosshair.visible = false; crosshair.alpha = 1; } }); // --- Power-up shooting logic --- // Auto-Aim: instantly hit nearest duck if (powerupActive.autoAim) { var nearestDuck = null; var minDist = 99999; for (var i = 0; i < ducks.length; i++) { var duck = ducks[i]; if (!duck.alive || duck.hit) continue; var dx = duck.x - x; var dy = duck.y - y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < minDist) { minDist = dist; nearestDuck = duck; } } if (nearestDuck) { // Hit the duck nearestDuck.hit = true; nearestDuck.fall(function () { if (nearestDuck.parent) nearestDuck.parent.removeChild(nearestDuck); if (dog) { dog.show(nearestDuck.x, 2732 - 100); LK.getSound('dog_laugh').play(); LK.setTimeout(function () { dog.hide(); }, 2000); } }); ducksHit++; var duckScore = 10; var achievementMsg = ''; var achievementColor = 0xFFD700; if (typeof nearestDuck.type !== "undefined" && nearestDuck.type === 'golden') { duckScore = 50; achievementMsg = 'Golden Duck! +50'; achievementColor = 0xFFD700; LK.effects.flashObject(nearestDuck, 0xffe066, 400); } else { LK.effects.flashObject(nearestDuck, 0xffff00, 300); } // Headshot bonus (auto-aim never headshots) score += duckScore; LK.getSound('hit').play(); if (typeof achievementPopup !== "undefined" && achievementMsg) { achievementPopup.show(achievementMsg, achievementColor); } if (ducksHit === 3 && typeof achievementPopup !== "undefined") { achievementPopup.show('Triple Hit!', 0x00FFCC); } if (ducksHit === ducksToHit && typeof achievementPopup !== "undefined") { achievementPopup.show('Sharp Shooter!', 0x00FF00); } if (score > highScore) { highScore = score; storage.highScore = highScore; if (typeof highScoreText !== "undefined") { highScoreText.setText('High: ' + highScore); } } scoreText.setText('Score: ' + score); if (score > highScore) { highScore = score; storage.highScore = highScore; if (typeof highScoreText !== "undefined") { highScoreText.setText('High: ' + highScore); } } if (gameMode === GAME_MODE_ENDLESS) { endlessMissStreak = 0; } // End wave check var aliveDucks = 0; for (var i = 0; i < ducks.length; i++) { if (ducks[i].alive) aliveDucks++; } if ((gameMode === GAME_MODE_CLASSIC || !gameMode) && (aliveDucks === 0 && bulletsLeft === 0 || aliveDucks === 0 && typeof duckSpawnTimer !== "undefined" && (!duckSpawnTimer || ducks.length === 0))) { endWave(); } return; } } // Double Barrel: shoot a wide spread, hit up to 2 ducks if close if (powerupActive.doubleBarrel) { var hitDucks = []; for (var i = 0; i < ducks.length; i++) { var duck = ducks[i]; if (!duck.alive || duck.hit) continue; var dx = duck.x - x; var dy = duck.y - y; var dist = Math.sqrt(dx * dx + dy * dy); var hitRadius = typeof duck.getHitboxRadius === "function" ? duck.getHitboxRadius() * 1.5 : 120; if (dist < hitRadius) { hitDucks.push({ duck: duck, dist: dist }); } } // Sort by distance, hit up to 2 closest hitDucks.sort(function (a, b) { return a.dist - b.dist; }); hitDucks = hitDucks.slice(0, 2); if (hitDucks.length > 0) { for (var h = 0; h < hitDucks.length; h++) { var hitDuck = hitDucks[h].duck; hitDuck.hit = true; hitDuck.fall(function () { if (hitDuck.parent) hitDuck.parent.removeChild(hitDuck); if (dog) { dog.show(hitDuck.x, 2732 - 100); LK.getSound('dog_laugh').play(); LK.setTimeout(function () { dog.hide(); }, 2000); } }); ducksHit++; var duckScore = 10; var achievementMsg = ''; var achievementColor = 0xFFD700; if (typeof hitDuck.type !== "undefined" && hitDuck.type === 'golden') { duckScore = 50; achievementMsg = 'Golden Duck! +50'; achievementColor = 0xFFD700; LK.effects.flashObject(hitDuck, 0xffe066, 400); } else { LK.effects.flashObject(hitDuck, 0xffff00, 300); } // Headshot bonus var isHeadshot = typeof hitDuck.isHeadshot === "function" && hitDuck.isHeadshot(x, y); if (isHeadshot) { duckScore += 5; achievementMsg = 'Headshot! +' + duckScore; achievementColor = 0xFF2222; LK.effects.flashObject(hitDuck, 0xff2222, 400); } score += duckScore; LK.getSound('hit').play(); if (typeof achievementPopup !== "undefined" && achievementMsg) { achievementPopup.show(achievementMsg, achievementColor); } if (ducksHit === 3 && typeof achievementPopup !== "undefined") { achievementPopup.show('Triple Hit!', 0x00FFCC); } if (ducksHit === ducksToHit && typeof achievementPopup !== "undefined") { achievementPopup.show('Sharp Shooter!', 0x00FF00); } if (score > highScore) { highScore = score; storage.highScore = highScore; if (typeof highScoreText !== "undefined") { highScoreText.setText('High: ' + highScore); } } scoreText.setText('Score: ' + score); if (score > highScore) { highScore = score; storage.highScore = highScore; if (typeof highScoreText !== "undefined") { highScoreText.setText('High: ' + highScore); } } if (gameMode === GAME_MODE_ENDLESS) { endlessMissStreak = 0; } } // End wave check var aliveDucks = 0; for (var i = 0; i < ducks.length; i++) { if (ducks[i].alive) aliveDucks++; } if ((gameMode === GAME_MODE_CLASSIC || !gameMode) && (aliveDucks === 0 && bulletsLeft === 0 || aliveDucks === 0 && typeof duckSpawnTimer !== "undefined" && (!duckSpawnTimer || ducks.length === 0))) { endWave(); } return; } } // --- Normal shooting logic --- // Check if a duck is hit (closest duck under tap, not already hit) var hitDuck = null; var minDist = 99999; for (var i = 0; i < ducks.length; i++) { var duck = ducks[i]; // Only allow hitting ducks that are alive and not hit yet if (!duck.alive || duck.hit) continue; var dx = duck.x - x; var dy = duck.y - y; var hitRadius = typeof duck.getHitboxRadius === "function" ? duck.getHitboxRadius() : 80; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < hitRadius && dist < minDist) { minDist = dist; hitDuck = duck; } } if (hitDuck) { // Armored duck: needs 2 hits if (hitDuck.type === 'armored' && hitDuck.armor > 1) { hitDuck.armor--; hitDuck.flashRed(); LK.effects.flashObject(hitDuck, 0xff2222, 200); LK.getSound('hit').play(); // No score yet, must hit again return; } // Mark duck as hit and start fall animation hitDuck.hit = true; hitDuck.fall(function () { if (hitDuck.parent) hitDuck.parent.removeChild(hitDuck); if (dog) { dog.show(hitDuck.x, 2732 - 100); LK.getSound('dog_laugh').play(); LK.setTimeout(function () { dog.hide(); }, 2000); } }); ducksHit++; // Score system: use DUCK_TYPE_POINTS if (typeof score === "undefined") score = 0; var duckScore = DUCK_TYPE_POINTS[hitDuck.type] || 10; var achievementMsg = ''; var achievementColor = 0xFFD700; if (hitDuck.type === 'golden') { achievementMsg = 'Golden Duck! +50'; achievementColor = 0xFFD700; LK.effects.flashObject(hitDuck, 0xffe066, 400); } else if (hitDuck.type === 'armored') { achievementMsg = 'Armored Duck! +20'; achievementColor = 0x888888; LK.effects.flashObject(hitDuck, 0xcccccc, 400); } else if (hitDuck.type === 'mini') { achievementMsg = 'Mini Fast Duck! +25'; achievementColor = 0x00e6ff; LK.effects.flashObject(hitDuck, 0x00e6ff, 350); } else { LK.effects.flashObject(hitDuck, 0xffff00, 300); } // Headshot bonus var isHeadshot = typeof hitDuck.isHeadshot === "function" && hitDuck.isHeadshot(x, y); if (isHeadshot) { duckScore += 5; achievementMsg = 'Headshot! +' + duckScore; achievementColor = 0xFF2222; LK.effects.flashObject(hitDuck, 0xff2222, 400); } score += duckScore; LK.getSound('hit').play(); // Show achievement popup if any if (typeof achievementPopup !== "undefined" && achievementMsg) { achievementPopup.show(achievementMsg, achievementColor); } // Triple hit achievement (3 ducks in 1 level) if (ducksHit === 3 && typeof achievementPopup !== "undefined") { achievementPopup.show('Triple Hit!', 0x00FFCC); } // Sharp shooter (all ducks hit) if (ducksHit === ducksToHit && typeof achievementPopup !== "undefined") { achievementPopup.show('Sharp Shooter!', 0x00FF00); } // Update high score if needed if (score > highScore) { highScore = score; storage.highScore = highScore; if (typeof highScoreText !== "undefined") { highScoreText.setText('High: ' + highScore); } } scoreText.setText('Score: ' + score); if (score > highScore) { highScore = score; storage.highScore = highScore; if (typeof highScoreText !== "undefined") { highScoreText.setText('High: ' + highScore); } } // Endless mode: reset miss streak if (gameMode === GAME_MODE_ENDLESS) { endlessMissStreak = 0; } } else { // Miss: do nothing to ducks, just play miss sound and flash LK.getSound('miss').play(); LK.effects.flashScreen(0x888888, 120); // Track missed shots and show warning after 20 misses missedShots++; if (missedShots >= 20 && !missedWarningShown) { missedWarningShown = true; if (typeof achievementPopup !== "undefined") { achievementPopup.show("Careful! 20 missed shots!", 0xFF2222); } } // Endless mode: increment miss streak, end game if 3 in a row if (gameMode === GAME_MODE_ENDLESS) { endlessMissStreak++; if (endlessMissStreak >= 3) { endWave(); return; } } } // If all ducks are gone or out of bullets, end wave (classic only) var aliveDucks = 0; for (var i = 0; i < ducks.length; i++) { if (ducks[i].alive) aliveDucks++; } // Only end wave if all ducks are gone AND no more ducks will spawn, or if out of bullets if ((gameMode === GAME_MODE_CLASSIC || !gameMode) && (aliveDucks === 0 && bulletsLeft === 0 || aliveDucks === 0 && typeof duckSpawnTimer !== "undefined" && (!duckSpawnTimer || ducks.length === 0))) { endWave(); } }; // Move handler for crosshair (optional, for desktop) game.move = function (x, y, obj) { // Optionally show crosshair following finger/mouse // crosshair.x = x; // crosshair.y = y; }; // Main update loop game.update = function () { if (!gameActive || !waveActive) return; // Update ducks for (var i = ducks.length - 1; i >= 0; i--) { var duck = ducks[i]; duck.update(); if (duck.escaped && !duck.hit) { ducksEscaped++; if (duck.parent) duck.parent.removeChild(duck); ducks.splice(i, 1); // Endless mode: treat escaped duck as a miss if (gameMode === GAME_MODE_ENDLESS) { endlessMissStreak++; if (endlessMissStreak >= 3) { endWave(); return; } } } } // --- Power-up collectibles update --- for (var i = powerupCollectibles.length - 1; i >= 0; i--) { powerupCollectibles[i].update(); } // --- Power-up timers/icons update --- for (var ptype in powerupActive) { if (powerupActive[ptype] && powerupTimers[ptype] > 0) { // Decrement timer (per second, but update is 60fps) if (LK.ticks % 60 === 0) { powerupTimers[ptype]--; if (powerupIcons[ptype] && powerupIcons[ptype]._timerTxt) { powerupIcons[ptype]._timerTxt.setText(powerupTimers[ptype] + "s"); } } } } // If all ducks gone, end wave (classic only) var aliveDucks = 0; for (var i = 0; i < ducks.length; i++) { if (ducks[i].alive) aliveDucks++; } if ((gameMode === GAME_MODE_CLASSIC || !gameMode) && aliveDucks === 0 && typeof duckSpawnTimer !== "undefined" && (!duckSpawnTimer || ducks.length === 0)) { endWave(); } }; // On game over, reset everything LK.on('gameover', function () { if (timerInterval) LK.clearInterval(timerInterval); if (waveResultTimeout) LK.clearTimeout(waveResultTimeout); if (typeof duckSpawnTimer !== "undefined" && duckSpawnTimer) { LK.clearInterval(duckSpawnTimer); duckSpawnTimer = null; } gameActive = false; waveActive = false; level = 1; ducks = []; bullets = []; ducksHit = 0; ducksEscaped = 0; // Reset bullets to 10 on gameover for level 1 bulletsLeft = 10; score = 0; updateBulletIcons(); levelText.setText('Level 1'); scoreText.setText('Score: ' + score); if (score > highScore) { highScore = score; storage.highScore = highScore; if (typeof highScoreText !== "undefined") { highScoreText.setText('High: ' + highScore); } } timerText.setText('Time: 15'); if (dog) dog.hide(); // Show main menu after short delay LK.setTimeout(function () { showMainMenu(); }, 1200); }); // On you win (if you want to add a win condition, e.g. after level 10) LK.on('youwin', function () { if (timerInterval) LK.clearInterval(timerInterval); if (waveResultTimeout) LK.clearTimeout(waveResultTimeout); if (typeof duckSpawnTimer !== "undefined" && duckSpawnTimer) { LK.clearInterval(duckSpawnTimer); duckSpawnTimer = null; } gameActive = false; waveActive = false; // Show win, then reset LK.setTimeout(function () { level = 1; ducks = []; bullets = []; ducksHit = 0; ducksEscaped = 0; bulletsLeft = 10; score = 0; updateBulletIcons(); levelText.setText('Level 1'); scoreText.setText('Score: ' + score); if (score > highScore) { highScore = score; storage.highScore = highScore; } timerText.setText('Time: 15'); if (dog) dog.hide(); showMainMenu(); }, 1800); }); // Start music LK.playMusic('bgm', { fade: { start: 0, end: 0.5, duration: 1200 } }); // Start first level // (Removed: now handled by showMainMenu)
===================================================================
--- original.js
+++ change.js
@@ -545,9 +545,9 @@
mainMenuContainer.addChild(btnEndless);
// Rules Button
var btnRules = new Text2("Rules", {
size: 100,
- fill: 0xFFD700,
+ fill: 0xFFFFFF,
font: "'PressStart2P','GillSans-Bold',Impact,'Arial Black',Tahoma"
});
btnRules.anchor.set(0.5, 0.5);
btnRules.x = 2048 / 2;
bullet. In-Game asset. 2d. High contrast. No shadows
crosshair. In-Game asset. 2d. High contrast. No shadows
pixart jungle. In-Game asset. 2d. High contrast. No shadows
pixart hunting brown dog with black ears and white mouth holding a gun. In-Game asset. 2d. High contrast. No shadows
pixart brown hunting dog with black ears and white mouth laughing. In-Game asset. 2d. High contrast. No shadows
pixart blue duck flying. In-Game asset. 2d. High contrast. No shadows
pixart green duck flying. In-Game asset. 2d. High contrast. No shadows
pixart red duck flying. In-Game asset. 2d. High contrast. No shadows
pigeon flying. In-Game asset. 2d. High contrast. No shadows
black wall. In-Game asset. 2d. High contrast. No shadows
empty beer glass. In-Game asset. 2d. High contrast. No shadows
pixart sand watch. In-Game asset. 2d. High contrast. No shadows
dalmation dog holding a gun. In-Game asset. 2d. High contrast. No shadows. hunting
labrador dog hold a hunt gun. In-Game asset. 2d. High contrast. No shadows
dalmatian dog laugh. In-Game asset. 2d. High contrast. No shadows
labrador laugh. In-Game asset. 2d. High contrast. No shadows