/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var BossRewardWheel = Container.expand(function () { var self = Container.call(this); // Create wheel outer ring for better definition var outerRing = self.attachAsset('wheel', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.6, scaleY: 1.6 }); outerRing.tint = 0x8E44AD; // Create wheel background var wheelBg = self.attachAsset('wheel', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.4, scaleY: 1.4 }); wheelBg.tint = 0x9B59B6; // Create inner circle for depth var innerCircle = self.attachAsset('wheel', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.3, scaleY: 0.3 }); innerCircle.tint = 0x6C3483; // Create wheel sections self.sections = []; self.rewards = [{ type: 'coins', amount: 1000 }, { type: 'knife', id: 'golden' }, { type: 'coins', amount: 2000 }, { type: 'knife', id: 'ruby' }, { type: 'coins', amount: 1500 }, { type: 'knife', id: 'emerald' }, { type: 'coins', amount: 3000 }, { type: 'knife', id: 'katana' }]; var sectionColors = [0xFF6B6B, 0x4ECDC4, 0x45B7D1, 0x96CEB4, 0xFECA57, 0xFF9FF3, 0x54A0FF, 0x5F27CD]; for (var i = 0; i < 8; i++) { var section = self.attachAsset('wheelSection', { anchorX: 0, anchorY: 0.5, x: 0, y: 0, scaleX: 2.0, scaleY: 4, rotation: i * Math.PI * 2 / 8 }); section.tint = sectionColors[i]; self.sections.push(section); // Add different icons based on reward type if (self.rewards[i].type === 'knife') { var knifeIcon = self.attachAsset('knife', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.6, scaleY: 0.6, rotation: Math.PI / 2 }); knifeIcon.x = Math.cos(i * Math.PI * 2 / 8) * 150; knifeIcon.y = Math.sin(i * Math.PI * 2 / 8) * 150; // Color the knife icon based on type var knifeColors = { 'golden': 0xFFD700, 'ruby': 0xFF0000, 'emerald': 0x00FF00, 'sapphire': 0x0000FF, 'katana': 0x8B0000 }; knifeIcon.tint = knifeColors[self.rewards[i].id]; self.addChild(knifeIcon); } else { var coinIcon = self.attachAsset('coin', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.8, scaleY: 0.8 }); coinIcon.x = Math.cos(i * Math.PI * 2 / 8) * 150; coinIcon.y = Math.sin(i * Math.PI * 2 / 8) * 150; self.addChild(coinIcon); } // Add reward text with better styling var rewardText = new Text2(self.rewards[i].type === 'knife' ? self.rewards[i].id.toUpperCase() : self.rewards[i].amount.toString(), { size: 40, fill: 0xFFFFFF }); rewardText.anchor.set(0.5, 0.5); rewardText.x = Math.cos(i * Math.PI * 2 / 8) * 220; rewardText.y = Math.sin(i * Math.PI * 2 / 8) * 220; self.addChild(rewardText); } // Create decorative border lines for (var j = 0; j < 8; j++) { var borderLine = self.attachAsset('wheelSection', { anchorX: 0, anchorY: 0.5, x: 0, y: 0, scaleX: 2.2, scaleY: 0.1, rotation: j * Math.PI * 2 / 8 }); borderLine.tint = 0x6C3483; } // Create pointer with enhanced design var pointer = self.attachAsset('pointer', { anchorX: 0.5, anchorY: 1, y: -450, scaleX: 2.0, scaleY: 2.0 }); pointer.tint = 0x8E44AD; // Add pointer shadow for depth var pointerShadow = self.attachAsset('pointer', { anchorX: 0.5, anchorY: 1, y: -445, x: 5, scaleX: 2.0, scaleY: 2.0 }); pointerShadow.tint = 0x000000; pointerShadow.alpha = 0.3; self.isSpinning = false; self.spinSpeed = 0; self.finalAngle = 0; self.spin = function () { if (self.isSpinning) return; self.isSpinning = true; self.spinSpeed = 0.3; self.finalAngle = Math.random() * Math.PI * 2 + Math.PI * 12; var currentRotation = self.rotation; // Add anticipation animation before spinning tween(self, { scaleX: 1.1, scaleY: 1.1 }, { duration: 200, easing: tween.easeOut, onFinish: function onFinish() { // Scale back and start main spin tween(self, { scaleX: 1.0, scaleY: 1.0 }, { duration: 100 }); // Main spinning animation with enhanced easing tween(self, { rotation: currentRotation + self.finalAngle }, { duration: 4000, easing: tween.easeOut, onFinish: function onFinish() { self.isSpinning = false; // Add small bounce effect when stopping tween(self, { scaleX: 1.05, scaleY: 1.05 }, { duration: 150, easing: tween.easeOut, onFinish: function onFinish() { tween(self, { scaleX: 1.0, scaleY: 1.0 }, { duration: 150, easing: tween.easeOut, onFinish: function onFinish() { self.giveReward(); } }); } }); } }); } }); }; self.giveReward = function () { var normalizedAngle = (self.rotation % (Math.PI * 2) + Math.PI * 2) % (Math.PI * 2); var sectionIndex = Math.floor(normalizedAngle / (Math.PI * 2 / 8)); var reward = self.rewards[sectionIndex]; if (reward.type === 'knife') { // Give knife reward if (!storage.ownedItems) storage.ownedItems = {}; storage.ownedItems[reward.id] = true; storage.equippedKnife = reward.id; // Flash the won knife name var winText = new Text2('NEW KNIFE: ' + reward.id.toUpperCase(), { size: 80, fill: 0xFF69B4 }); winText.anchor.set(0.5, 0.5); winText.x = 1024; winText.y = 1366; game.addChild(winText); tween(winText, { y: 1200, alpha: 0 }, { duration: 2000, onFinish: function onFinish() { winText.destroy(); } }); } else { // Give coin reward coins += reward.amount; storage.coins = coins; coinsText.setText('Coins: ' + coins); // Flash the won amount var winText = new Text2('+' + reward.amount, { size: 80, fill: 0xFFD700 }); winText.anchor.set(0.5, 0.5); winText.x = 1024; winText.y = 1366; game.addChild(winText); tween(winText, { y: 1200, alpha: 0 }, { duration: 2000, onFinish: function onFinish() { winText.destroy(); } }); } }; return self; }); var Circle = Container.expand(function () { var self = Container.call(this); var circleGraphics = self.attachAsset('circle', { anchorX: 0.5, anchorY: 0.5 }); self.rotationSpeed = 0.02; self.shield = null; self.hasShield = false; self.update = function () { self.rotation += self.rotationSpeed; // Level 5 boss mechanics - add shield if (currentLevel % 5 === 0 && currentLevel !== 10 && !self.hasShield) { self.hasShield = true; self.shield = new Shield(); self.shield.x = self.x; self.shield.y = self.y; self.parent.addChild(self.shield); } // Update shield position if it exists if (self.shield && !self.shield.isDestroyed) { self.shield.x = self.x; self.shield.y = self.y; } // Level 10 special boss mechanics - alternating fast/slow speed if (currentLevel === 10) { if (!self.level10CycleStarted) { self.level10CycleStarted = true; self.startLevel10Cycle(); } } // Boss level special effects - random direction changes (less frequent) if (currentLevel % 5 === 0 && currentLevel !== 10 && LK.ticks % 300 === 0) { // Reverse rotation direction randomly for boss levels (reduced chance) if (Math.random() < 0.2) { self.rotationSpeed *= -1; // Visual feedback for direction change tween(self, { scaleX: 1.4, scaleY: 1.4 }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { tween(self, { scaleX: 1.2, scaleY: 1.2 }, { duration: 300, easing: tween.easeOut }); } }); } } }; self.startLevel10Cycle = function () { var baseSpeed = Math.abs(self.rotationSpeed); var fastSpeed = baseSpeed * 2; var slowSpeed = baseSpeed * 0.5; // Start with fast speed tween(self, { rotationSpeed: self.rotationSpeed > 0 ? fastSpeed : -fastSpeed }, { duration: 2000, easing: tween.easeInOut, onFinish: function onFinish() { // Slow down tween(self, { rotationSpeed: self.rotationSpeed > 0 ? slowSpeed : -slowSpeed }, { duration: 2000, easing: tween.easeInOut, onFinish: function onFinish() { // Speed up again and repeat cycle if (currentLevel === 10) { self.startLevel10Cycle(); } } }); } }); }; return self; }); var Knife = Container.expand(function () { var self = Container.call(this); // Create knife blade var blade = self.attachAsset('knife', { anchorX: 0.5, anchorY: 0.5, rotation: Math.PI / 2 }); // Create knife handle var handle = self.attachAsset('handle', { anchorX: 0.5, anchorY: 0.5, y: 50, rotation: Math.PI / 2 }); self.isThrown = false; self.isStuck = false; self.speed = 200; self.targetDistance = 0; self.stuckAngle = 0; self.update = function () { if (self.isThrown && !self.isStuck) { self.y -= self.speed; // Create trailing effect particles for all knives while moving if (LK.ticks % 8 === 0) { var particle = LK.getAsset('coin', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.2, scaleY: 0.2 }); particle.tint = self.children[0].tint || 0xC0C0C0; particle.alpha = 0.6; particle.x = self.x + (Math.random() - 0.5) * 15; particle.y = self.y + 30 + (Math.random() - 0.5) * 15; game.addChild(particle); // Animate particles with fade and scale effect tween(particle, { y: particle.y + 100, alpha: 0, scaleX: 0.05, scaleY: 0.05 }, { duration: 600, easing: tween.easeOut, onFinish: function onFinish() { particle.destroy(); } }); } // Special fire effects for fire knife if (self.children[0].tint === 0xFF4500 && LK.ticks % 4 === 0) { var fireParticle = LK.getAsset('coin', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.15, scaleY: 0.15 }); fireParticle.tint = Math.random() > 0.5 ? 0xFF4500 : 0xFFFF00; fireParticle.alpha = 0.8; fireParticle.x = self.x + (Math.random() - 0.5) * 25; fireParticle.y = self.y + 35 + (Math.random() - 0.5) * 25; game.addChild(fireParticle); // Animate fire particles with flickering effect tween(fireParticle, { y: fireParticle.y + 80, alpha: 0, scaleX: 0.05, scaleY: 0.05, tint: 0xFF0000 }, { duration: 400, easing: tween.easeOut, onFinish: function onFinish() { fireParticle.destroy(); } }); } // Special ice effects for ice knife if (self.children[0].tint === 0x00FFFF && LK.ticks % 5 === 0) { var iceParticle = LK.getAsset('coin', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.12, scaleY: 0.12 }); iceParticle.tint = Math.random() > 0.5 ? 0x00FFFF : 0xFFFFFF; iceParticle.alpha = 0.9; iceParticle.x = self.x + (Math.random() - 0.5) * 20; iceParticle.y = self.y + 35 + (Math.random() - 0.5) * 20; game.addChild(iceParticle); // Animate ice particles with crystalline effect tween(iceParticle, { y: iceParticle.y + 60, alpha: 0, scaleX: 0.03, scaleY: 0.03, rotation: Math.PI * 2 }, { duration: 500, easing: tween.easeOut, onFinish: function onFinish() { iceParticle.destroy(); } }); } // Special rainbow effects for rainbow knife with color cycling if (self.children[0].originalTint === 0xFF69B4) { // Cycle through rainbow colors continuously var rainbowColors = [0xFF0000, 0xFF8000, 0xFFFF00, 0x80FF00, 0x00FF00, 0x00FF80, 0x00FFFF, 0x0080FF, 0x0000FF, 0x8000FF, 0xFF00FF, 0xFF0080]; var colorIndex = Math.floor(LK.ticks / 10) % rainbowColors.length; self.children[0].tint = rainbowColors[colorIndex]; // Rainbow particle effects if (LK.ticks % 6 === 0) { var rainbowParticle = LK.getAsset('coin', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.18, scaleY: 0.18 }); rainbowParticle.tint = rainbowColors[Math.floor(Math.random() * rainbowColors.length)]; rainbowParticle.alpha = 0.8; rainbowParticle.x = self.x + (Math.random() - 0.5) * 30; rainbowParticle.y = self.y + 35 + (Math.random() - 0.5) * 30; game.addChild(rainbowParticle); // Animate rainbow particles with sparkle effect tween(rainbowParticle, { y: rainbowParticle.y + 90, alpha: 0, scaleX: 0.08, scaleY: 0.08, rotation: Math.PI * 3 }, { duration: 700, easing: tween.easeOut, onFinish: function onFinish() { rainbowParticle.destroy(); } }); } } // Check collision with all stuck knives immediately for (var i = 0; i < knives.length; i++) { var otherKnife = knives[i]; if (otherKnife.isStuck && otherKnife !== self) { var distance = Math.sqrt(Math.pow(self.x - otherKnife.x, 2) + Math.pow(self.y - otherKnife.y, 2)); if (distance < 80) { LK.effects.flashScreen(0xff0000, 1000); LK.showGameOver(); return; } } } // Check if knife reached the circle var distanceToCenter = Math.sqrt(Math.pow(self.x - circle.x, 2) + Math.pow(self.y - circle.y, 2)); if (distanceToCenter <= 200) { self.stickToCircle(); } } else if (self.isStuck) { // Rotate with the circle var angle = self.stuckAngle + circle.rotation; self.x = circle.x + Math.cos(angle) * self.targetDistance; self.y = circle.y + Math.sin(angle) * self.targetDistance; self.rotation = angle + Math.PI / 2; } }; self.stickToCircle = function () { // Check if circle has a shield first if (circle.shield && !circle.shield.isDestroyed) { // Hit the shield instead var shieldDestroyed = circle.shield.takeDamage(); if (shieldDestroyed) { circle.shield = null; } // Destroy the knife that hit the shield self.destroy(); // Remove from knives array for (var i = 0; i < knives.length; i++) { if (knives[i] === self) { knives.splice(i, 1); break; } } LK.getSound('hit').play(); return; } self.isStuck = true; var angle = Math.atan2(self.y - circle.y, self.x - circle.x); self.stuckAngle = angle - circle.rotation; self.targetDistance = Math.sqrt(Math.pow(self.x - circle.x, 2) + Math.pow(self.y - circle.y, 2)); self.rotation = angle + Math.PI / 2; knivesStuck++; LK.setScore(knivesStuck); scoreText.setText('Knives: ' + knivesStuck + '/7'); if (knivesStuck >= 7) { showLevelComplete(); } LK.getSound('hit').play(); }; return self; }); var LevelComplete = Container.expand(function () { var self = Container.call(this); // Semi-transparent background var bg = LK.getAsset('background', { width: 2048, height: 2732, color: 0x000000, shape: 'box', alpha: 0.8 }); self.addChild(bg); // Check if this is a boss level var isBossLevel = currentLevel % 5 === 0; // Level complete text var titleText = new Text2('LEVEL ' + currentLevel + ' COMPLETE!' + (isBossLevel ? ' BOSS DEFEATED!' : ''), { size: isBossLevel ? 80 : 100, fill: isBossLevel ? 0xFF4757 : 0xFFD700 }); titleText.anchor.set(0.5, 0.5); titleText.x = 1024; titleText.y = 600; self.addChild(titleText); // Create different wheels based on level type if (isBossLevel) { // Create special boss reward wheel self.wheel = new BossRewardWheel(); } else { // Create normal wheel self.wheel = new WheelReward(); } self.wheel.x = 1024; self.wheel.y = 1366; self.wheel.alpha = 0; self.wheel.scaleX = 0.3; self.wheel.scaleY = 0.3; self.addChild(self.wheel); // Animate wheel entrance tween(self.wheel, { alpha: 1, scaleX: 1.0, scaleY: 1.0 }, { duration: 800, easing: tween.easeOut }); // Spin button var spinText = new Text2(isBossLevel ? 'TAP FOR BOSS REWARD!' : 'TAP TO SPIN!', { size: isBossLevel ? 50 : 60, fill: isBossLevel ? 0xFF69B4 : 0xFFFFFF }); spinText.anchor.set(0.5, 0.5); spinText.x = 1024; spinText.y = 1800; self.addChild(spinText); // Continue button (appears after spin) self.continueText = new Text2('TAP TO CONTINUE', { size: 50, fill: 0x4ECDC4 }); self.continueText.anchor.set(0.5, 0.5); self.continueText.x = 1024; self.continueText.y = 2100; self.continueText.alpha = 0; self.addChild(self.continueText); self.hasSpun = false; self.down = function (x, y, obj) { if (!self.hasSpun && !self.wheel.isSpinning) { self.wheel.spin(); self.hasSpun = true; spinText.alpha = 0; // Show continue button after spin completes LK.setTimeout(function () { tween(self.continueText, { alpha: 1 }, { duration: 500 }); }, 3500); } else if (self.hasSpun && !self.wheel.isSpinning) { // Continue to next level self.destroy(); nextLevel(); } }; return self; }); var Shield = Container.expand(function () { var self = Container.call(this); // Shield graphics using circle asset with different tint var shieldGraphics = self.attachAsset('circle', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.4, scaleY: 1.4 }); shieldGraphics.tint = 0x00FFFF; // Cyan shield color shieldGraphics.alpha = 0.7; self.health = 3; // Shield takes 3 hits to destroy self.maxHealth = 3; self.isDestroyed = false; self.takeDamage = function () { if (self.isDestroyed) return false; self.health--; // Visual feedback for damage LK.effects.flashObject(self, 0xFF0000, 500); // Shake effect tween(self, { x: self.x + 10 }, { duration: 100, easing: tween.easeOut, onFinish: function onFinish() { tween(self, { x: self.x - 20 }, { duration: 100, easing: tween.easeOut, onFinish: function onFinish() { tween(self, { x: self.x + 10 }, { duration: 100, easing: tween.easeOut }); } }); } }); // Update shield appearance based on health var healthPercent = self.health / self.maxHealth; shieldGraphics.alpha = 0.3 + healthPercent * 0.4; if (self.health <= 0) { self.destroy(); return true; // Shield destroyed } return false; // Shield still active }; self.update = function () { // Rotate shield slowly self.rotation += 0.01; // Pulsing effect var pulseScale = 1.4 + Math.sin(LK.ticks * 0.1) * 0.1; shieldGraphics.scaleX = pulseScale; shieldGraphics.scaleY = pulseScale; }; return self; }); var Shop = Container.expand(function () { var self = Container.call(this); // Semi-transparent background var bg = LK.getAsset('background', { width: 2048, height: 2732, color: 0x4A90E2, shape: 'box', alpha: 0.9 }); self.addChild(bg); // Shop title var titleText = new Text2('KNIFE SHOP', { size: 120, fill: 0xFFD700 }); titleText.anchor.set(0.5, 0.5); titleText.x = 1024; titleText.y = 200; self.addChild(titleText); // Close button var closeText = new Text2('X', { size: 80, fill: 0xFF4757 }); closeText.anchor.set(0.5, 0.5); closeText.x = 1800; closeText.y = 200; self.addChild(closeText); // Shop items container self.itemsContainer = new Container(); self.itemsContainer.x = 1024; self.itemsContainer.y = 600; self.addChild(self.itemsContainer); self.items = []; // Define shop items with very distinct and prominent pricing tiers self.shopData = [{ id: 'default', name: 'Classic', color: 0xC0C0C0, price: 0 }, { id: 'golden', name: 'Golden', color: 0xFFD700, price: 2500 }, { id: 'ruby', name: 'Ruby', color: 0xFF0000, price: 7500 }, { id: 'emerald', name: 'Emerald', color: 0x00FF00, price: 15000 }, { id: 'sapphire', name: 'Sapphire', color: 0x0000FF, price: 25000 }, { id: 'fire', name: 'Fire', color: 0xFF4500, price: 50000 }, { id: 'ice', name: 'Ice', color: 0x00FFFF, price: 75000 }, { id: 'rainbow', name: 'Rainbow', color: 0xFF69B4, price: 100000 }, { id: 'katana', name: 'Katana', color: 0x8B0000, price: 120000 }]; self.createItems = function () { // Clear existing items for (var i = 0; i < self.items.length; i++) { self.items[i].destroy(); } self.items = []; // Create shop items in grid layout for (var i = 0; i < self.shopData.length; i++) { var item = new ShopItem(self.shopData[i]); var col = i % 3; var row = Math.floor(i / 3); item.x = (col - 1) * 350; item.y = row * 450; self.itemsContainer.addChild(item); self.items.push(item); } }; self.refreshItems = function () { self.createItems(); }; self.createItems(); self.down = function (x, y, obj) { if (x > 1700 && y < 300) { // Close shop self.destroy(); shopScene = null; shop = null; } }; return self; }); var ShopItem = Container.expand(function (itemData) { var self = Container.call(this); self.itemData = itemData; self.isOwned = storage.ownedItems && storage.ownedItems[itemData.id] || false; self.isEquipped = storage.equippedKnife === itemData.id; // Item background var bg = self.attachAsset('background', { width: 300, height: 400, color: self.isOwned ? 0x4ECDC4 : 0x34495E, shape: 'box', anchorX: 0.5, anchorY: 0.5 }); // Knife preview var knifePreview = self.attachAsset('knife', { anchorX: 0.5, anchorY: 0.5, y: -50, scaleX: 0.8, scaleY: 0.8, rotation: Math.PI / 2 }); knifePreview.tint = itemData.color; // Item name var nameText = new Text2(itemData.name, { size: 40, fill: 0xFFFFFF }); nameText.anchor.set(0.5, 0.5); nameText.y = 80; self.addChild(nameText); // Price or status text with very prominent and distinct styling var statusText = new Text2(self.isOwned ? self.isEquipped ? 'EQUIPPED' : 'OWNED' : itemData.price + ' COINS', { size: self.isOwned ? 40 : 50, fill: self.isOwned ? 0x00FF00 : itemData.price >= 75000 ? 0xFF1493 : itemData.price >= 50000 ? 0x9932CC : itemData.price >= 25000 ? 0x1E90FF : itemData.price >= 15000 ? 0x00CED1 : itemData.price >= 7500 ? 0x32CD32 : itemData.price >= 2500 ? 0xFFD700 : 0xFFFFFF }); statusText.anchor.set(0.5, 0.5); statusText.y = 130; self.addChild(statusText); self.down = function (x, y, obj) { if (self.isOwned) { // Equip item storage.equippedKnife = itemData.id; shop.refreshItems(); } else { // Try to buy item var currentCoins = storage.coins || 0; if (currentCoins >= itemData.price) { storage.coins = currentCoins - itemData.price; if (!storage.ownedItems) storage.ownedItems = {}; storage.ownedItems[itemData.id] = true; storage.equippedKnife = itemData.id; coins = storage.coins; coinsText.setText('Coins: ' + coins); shop.refreshItems(); } } }; return self; }); var WheelReward = Container.expand(function () { var self = Container.call(this); // Create wheel outer ring for better definition var outerRing = self.attachAsset('wheel', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.6, scaleY: 1.6 }); outerRing.tint = 0x2C3E50; // Create wheel background var wheelBg = self.attachAsset('wheel', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.4, scaleY: 1.4 }); wheelBg.tint = 0x34495E; // Create inner circle for depth var innerCircle = self.attachAsset('wheel', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.3, scaleY: 0.3 }); innerCircle.tint = 0x1A252F; // Create wheel sections self.sections = []; self.rewards = [500, 100, 1000, 200, 750, 50, 1500, 25]; var sectionColors = [0xFF6B6B, 0x4ECDC4, 0x45B7D1, 0x96CEB4, 0xFECA57, 0xFF9FF3, 0x54A0FF, 0x5F27CD]; for (var i = 0; i < 8; i++) { var section = self.attachAsset('wheelSection', { anchorX: 0, anchorY: 0.5, x: 0, y: 0, scaleX: 2.0, scaleY: 4, rotation: i * Math.PI * 2 / 8 }); section.tint = sectionColors[i]; self.sections.push(section); // Add coin icon for each section var coinIcon = self.attachAsset('coin', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.8, scaleY: 0.8 }); coinIcon.x = Math.cos(i * Math.PI * 2 / 8) * 150; coinIcon.y = Math.sin(i * Math.PI * 2 / 8) * 150; self.addChild(coinIcon); // Add reward text with better styling var rewardText = new Text2(self.rewards[i].toString(), { size: 50, fill: 0xFFFFFF }); rewardText.anchor.set(0.5, 0.5); rewardText.x = Math.cos(i * Math.PI * 2 / 8) * 220; rewardText.y = Math.sin(i * Math.PI * 2 / 8) * 220; self.addChild(rewardText); } // Create decorative border lines for (var j = 0; j < 8; j++) { var borderLine = self.attachAsset('wheelSection', { anchorX: 0, anchorY: 0.5, x: 0, y: 0, scaleX: 2.2, scaleY: 0.1, rotation: j * Math.PI * 2 / 8 }); borderLine.tint = 0x2C3E50; } // Create pointer with enhanced design var pointer = self.attachAsset('pointer', { anchorX: 0.5, anchorY: 1, y: -450, scaleX: 2.0, scaleY: 2.0 }); pointer.tint = 0xFF4757; // Add pointer shadow for depth var pointerShadow = self.attachAsset('pointer', { anchorX: 0.5, anchorY: 1, y: -445, x: 5, scaleX: 2.0, scaleY: 2.0 }); pointerShadow.tint = 0x000000; pointerShadow.alpha = 0.3; self.isSpinning = false; self.spinSpeed = 0; self.finalAngle = 0; self.spin = function () { if (self.isSpinning) return; self.isSpinning = true; self.spinSpeed = 0.3; self.finalAngle = Math.random() * Math.PI * 2 + Math.PI * 12; // More rotations for excitement var currentRotation = self.rotation; // Add anticipation animation before spinning tween(self, { scaleX: 1.1, scaleY: 1.1 }, { duration: 200, easing: tween.easeOut, onFinish: function onFinish() { // Scale back and start main spin tween(self, { scaleX: 1.0, scaleY: 1.0 }, { duration: 100 }); // Main spinning animation with enhanced easing tween(self, { rotation: currentRotation + self.finalAngle }, { duration: 4000, easing: tween.easeOut, onFinish: function onFinish() { self.isSpinning = false; // Add small bounce effect when stopping tween(self, { scaleX: 1.05, scaleY: 1.05 }, { duration: 150, easing: tween.easeOut, onFinish: function onFinish() { tween(self, { scaleX: 1.0, scaleY: 1.0 }, { duration: 150, easing: tween.easeOut, onFinish: function onFinish() { self.giveReward(); } }); } }); } }); } }); }; self.giveReward = function () { var normalizedAngle = (self.rotation % (Math.PI * 2) + Math.PI * 2) % (Math.PI * 2); var sectionIndex = Math.floor(normalizedAngle / (Math.PI * 2 / 8)); var reward = self.rewards[sectionIndex]; coins += reward; storage.coins = coins; coinsText.setText('Coins: ' + coins); // Flash the won amount var winText = new Text2('+' + reward, { size: 80, fill: 0xFFD700 }); winText.anchor.set(0.5, 0.5); winText.x = 1024; winText.y = 1366; game.addChild(winText); tween(winText, { y: 1200, alpha: 0 }, { duration: 2000, onFinish: function onFinish() { winText.destroy(); } }); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x2C3E50 }); /**** * Game Code ****/ var circle = game.addChild(new Circle()); circle.x = 1024; circle.y = 1000; // Initialize boss level tracking var isBossLevel = false; var knives = []; var knivesStuck = 0; var canThrow = true; var coins = storage.coins || 0; var currentLevel = 1; var levelCompleteScene = null; var shopScene = null; var shop = null; // Initialize default knife if none equipped if (!storage.equippedKnife) { storage.equippedKnife = 'default'; if (!storage.ownedItems) storage.ownedItems = {}; storage.ownedItems['default'] = true; } // Coins display var coinsText = new Text2('Coins: ' + coins, { size: 60, fill: 0xFFD700 }); coinsText.anchor.set(1, 0); LK.gui.topRight.addChild(coinsText); coinsText.x = -20; coinsText.y = 20; // Shop button var shopButton = new Text2('SHOP', { size: 50, fill: 0x4ECDC4 }); shopButton.anchor.set(1, 0); LK.gui.topRight.addChild(shopButton); shopButton.x = -20; shopButton.y = 100; // Level display var levelText = new Text2('Level: 1', { size: 60, fill: 0xFFFFFF }); levelText.anchor.set(0, 0); LK.gui.topLeft.addChild(levelText); levelText.x = 120; levelText.y = 20; // Score display var scoreText = new Text2('Knives: 0/7', { size: 80, fill: 0xFFFFFF }); scoreText.anchor.set(0.5, 0); LK.gui.top.addChild(scoreText); // Instructions var instructionText = new Text2('Tap to throw knives!\nAvoid hitting existing knives!', { size: 60, fill: 0xFFFFFF }); instructionText.anchor.set(0.5, 0.5); instructionText.x = 1024; instructionText.y = 400; game.addChild(instructionText); function showLevelComplete() { if (!levelCompleteScene) { levelCompleteScene = new LevelComplete(); game.addChild(levelCompleteScene); } } function nextLevel() { // Advance to next level currentLevel++; // Reset game state for new level knivesStuck = 0; canThrow = true; // Clear existing knives for (var i = 0; i < knives.length; i++) { knives[i].destroy(); } knives = []; // Reset score display scoreText.setText('Knives: 0/7'); // Show instructions again instructionText.alpha = 1; // Remove level complete scene if (levelCompleteScene) { levelCompleteScene.destroy(); levelCompleteScene = null; } // Increase difficulty by making circle spin faster each level circle.rotationSpeed = 0.02 + (currentLevel - 1) * 0.015; // Reset level 10 special cycle flag circle.level10CycleStarted = false; // Reset shield state if (circle.shield) { circle.shield.destroy(); circle.shield = null; } circle.hasShield = false; // Check if this is a boss level (every 5th level) var isBossLevel = currentLevel % 5 === 0; if (isBossLevel) { // Boss level - slightly faster rotation but easier than before circle.rotationSpeed = 0.03 + (currentLevel - 1) * 0.008; circle.children[0].tint = 0xFF4757; // Red tint for boss circle.scaleX = 1.2; circle.scaleY = 1.2; // Special handling for level 10 if (currentLevel === 10) { // Level 10 gets special alternating speed mechanics but slower circle.children[0].tint = 0xFF0000; // Darker red for level 10 circle.scaleX = 1.3; circle.scaleY = 1.3; } else { // Reduced pulsing animation for other boss levels tween(circle, { scaleX: 1.3, scaleY: 1.3 }, { duration: 1500, easing: tween.easeInOut, onFinish: function onFinish() { tween(circle, { scaleX: 1.2, scaleY: 1.2 }, { duration: 1500, easing: tween.easeInOut }); } }); } } else { // Normal level - reset boss modifications circle.children[0].tint = 0xFFFFFF; circle.scaleX = 1.0; circle.scaleY = 1.0; tween.stop(circle); } // Update level display levelText.setText('Level: ' + currentLevel + (isBossLevel ? ' (BOSS)' : '')); } ; function checkKnifeCollisions(newKnife) { var _loop = function _loop() { existingKnife = knives[i]; if (existingKnife.isStuck && existingKnife !== newKnife) { var _showLevelComplete = function _showLevelComplete() { if (!levelCompleteScene) { levelCompleteScene = new LevelComplete(); game.addChild(levelCompleteScene); } }; var _restartGame = function _restartGame() { // Reset game state knivesStuck = 0; canThrow = true; // Clear existing knives for (var i = 0; i < knives.length; i++) { knives[i].destroy(); } knives = []; // Reset score display scoreText.setText('Knives: 0/7'); // Show instructions again instructionText.alpha = 1; // Remove level complete scene if (levelCompleteScene) { levelCompleteScene.destroy(); levelCompleteScene = null; } }; distance = Math.sqrt(Math.pow(newKnife.x - existingKnife.x, 2) + Math.pow(newKnife.y - existingKnife.y, 2)); if (distance < 60) { return { v: true }; } ; } }, existingKnife, distance, _ret; for (var i = 0; i < knives.length; i++) { _ret = _loop(); if (_ret) return _ret.v; } return false; } game.down = function (x, y, obj) { // Check if shop button was tapped var shopButtonGlobal = LK.gui.topRight.toGlobal(shopButton.position); var gameLocal = game.toLocal(shopButtonGlobal); if (x > gameLocal.x - 100 && x < gameLocal.x + 100 && y > gameLocal.y - 50 && y < gameLocal.y + 50) { if (!shopScene) { shopScene = new Shop(); shop = shopScene; game.addChild(shopScene); } return; } if (canThrow && knivesStuck < 7) { var newKnife = new Knife(); newKnife.x = 1024; newKnife.y = 2400; newKnife.isThrown = true; // Apply equipped cosmetic var equippedKnife = storage.equippedKnife || 'default'; var knifeColors = { 'default': 0xC0C0C0, 'golden': 0xFFD700, 'ruby': 0xFF0000, 'emerald': 0x00FF00, 'sapphire': 0x0000FF, 'rainbow': 0xFF69B4, 'fire': 0xFF4500, 'ice': 0x00FFFF, 'katana': 0x8B0000 }; if (knifeColors[equippedKnife]) { newKnife.children[0].tint = knifeColors[equippedKnife]; // Store original tint for rainbow knife color cycling newKnife.children[0].originalTint = knifeColors[equippedKnife]; } knives.push(newKnife); game.addChild(newKnife); canThrow = false; LK.getSound('throw').play(); // Allow next throw after delay LK.setTimeout(function () { canThrow = true; }, 300); } }; game.update = function () { // Check for knife collisions for (var i = 0; i < knives.length; i++) { var knife = knives[i]; if (knife.isThrown && !knife.isStuck) { // Check collision with all stuck knives for (var j = 0; j < knives.length; j++) { var otherKnife = knives[j]; if (otherKnife.isStuck && otherKnife !== knife) { var distance = Math.sqrt(Math.pow(knife.x - otherKnife.x, 2) + Math.pow(knife.y - otherKnife.y, 2)); if (distance < 80) { LK.effects.flashScreen(0xff0000, 1000); LK.showGameOver(); return; } } } } // Remove knives that went off screen if (knife.y < -100 && !knife.isStuck) { knife.destroy(); knives.splice(i, 1); i--; } } // Hide instructions after first throw if (knives.length > 0 && instructionText.alpha > 0) { tween(instructionText, { alpha: 0 }, { duration: 1000 }); } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var BossRewardWheel = Container.expand(function () {
var self = Container.call(this);
// Create wheel outer ring for better definition
var outerRing = self.attachAsset('wheel', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.6,
scaleY: 1.6
});
outerRing.tint = 0x8E44AD;
// Create wheel background
var wheelBg = self.attachAsset('wheel', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.4,
scaleY: 1.4
});
wheelBg.tint = 0x9B59B6;
// Create inner circle for depth
var innerCircle = self.attachAsset('wheel', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.3,
scaleY: 0.3
});
innerCircle.tint = 0x6C3483;
// Create wheel sections
self.sections = [];
self.rewards = [{
type: 'coins',
amount: 1000
}, {
type: 'knife',
id: 'golden'
}, {
type: 'coins',
amount: 2000
}, {
type: 'knife',
id: 'ruby'
}, {
type: 'coins',
amount: 1500
}, {
type: 'knife',
id: 'emerald'
}, {
type: 'coins',
amount: 3000
}, {
type: 'knife',
id: 'katana'
}];
var sectionColors = [0xFF6B6B, 0x4ECDC4, 0x45B7D1, 0x96CEB4, 0xFECA57, 0xFF9FF3, 0x54A0FF, 0x5F27CD];
for (var i = 0; i < 8; i++) {
var section = self.attachAsset('wheelSection', {
anchorX: 0,
anchorY: 0.5,
x: 0,
y: 0,
scaleX: 2.0,
scaleY: 4,
rotation: i * Math.PI * 2 / 8
});
section.tint = sectionColors[i];
self.sections.push(section);
// Add different icons based on reward type
if (self.rewards[i].type === 'knife') {
var knifeIcon = self.attachAsset('knife', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.6,
scaleY: 0.6,
rotation: Math.PI / 2
});
knifeIcon.x = Math.cos(i * Math.PI * 2 / 8) * 150;
knifeIcon.y = Math.sin(i * Math.PI * 2 / 8) * 150;
// Color the knife icon based on type
var knifeColors = {
'golden': 0xFFD700,
'ruby': 0xFF0000,
'emerald': 0x00FF00,
'sapphire': 0x0000FF,
'katana': 0x8B0000
};
knifeIcon.tint = knifeColors[self.rewards[i].id];
self.addChild(knifeIcon);
} else {
var coinIcon = self.attachAsset('coin', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8
});
coinIcon.x = Math.cos(i * Math.PI * 2 / 8) * 150;
coinIcon.y = Math.sin(i * Math.PI * 2 / 8) * 150;
self.addChild(coinIcon);
}
// Add reward text with better styling
var rewardText = new Text2(self.rewards[i].type === 'knife' ? self.rewards[i].id.toUpperCase() : self.rewards[i].amount.toString(), {
size: 40,
fill: 0xFFFFFF
});
rewardText.anchor.set(0.5, 0.5);
rewardText.x = Math.cos(i * Math.PI * 2 / 8) * 220;
rewardText.y = Math.sin(i * Math.PI * 2 / 8) * 220;
self.addChild(rewardText);
}
// Create decorative border lines
for (var j = 0; j < 8; j++) {
var borderLine = self.attachAsset('wheelSection', {
anchorX: 0,
anchorY: 0.5,
x: 0,
y: 0,
scaleX: 2.2,
scaleY: 0.1,
rotation: j * Math.PI * 2 / 8
});
borderLine.tint = 0x6C3483;
}
// Create pointer with enhanced design
var pointer = self.attachAsset('pointer', {
anchorX: 0.5,
anchorY: 1,
y: -450,
scaleX: 2.0,
scaleY: 2.0
});
pointer.tint = 0x8E44AD;
// Add pointer shadow for depth
var pointerShadow = self.attachAsset('pointer', {
anchorX: 0.5,
anchorY: 1,
y: -445,
x: 5,
scaleX: 2.0,
scaleY: 2.0
});
pointerShadow.tint = 0x000000;
pointerShadow.alpha = 0.3;
self.isSpinning = false;
self.spinSpeed = 0;
self.finalAngle = 0;
self.spin = function () {
if (self.isSpinning) return;
self.isSpinning = true;
self.spinSpeed = 0.3;
self.finalAngle = Math.random() * Math.PI * 2 + Math.PI * 12;
var currentRotation = self.rotation;
// Add anticipation animation before spinning
tween(self, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
// Scale back and start main spin
tween(self, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 100
});
// Main spinning animation with enhanced easing
tween(self, {
rotation: currentRotation + self.finalAngle
}, {
duration: 4000,
easing: tween.easeOut,
onFinish: function onFinish() {
self.isSpinning = false;
// Add small bounce effect when stopping
tween(self, {
scaleX: 1.05,
scaleY: 1.05
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
self.giveReward();
}
});
}
});
}
});
}
});
};
self.giveReward = function () {
var normalizedAngle = (self.rotation % (Math.PI * 2) + Math.PI * 2) % (Math.PI * 2);
var sectionIndex = Math.floor(normalizedAngle / (Math.PI * 2 / 8));
var reward = self.rewards[sectionIndex];
if (reward.type === 'knife') {
// Give knife reward
if (!storage.ownedItems) storage.ownedItems = {};
storage.ownedItems[reward.id] = true;
storage.equippedKnife = reward.id;
// Flash the won knife name
var winText = new Text2('NEW KNIFE: ' + reward.id.toUpperCase(), {
size: 80,
fill: 0xFF69B4
});
winText.anchor.set(0.5, 0.5);
winText.x = 1024;
winText.y = 1366;
game.addChild(winText);
tween(winText, {
y: 1200,
alpha: 0
}, {
duration: 2000,
onFinish: function onFinish() {
winText.destroy();
}
});
} else {
// Give coin reward
coins += reward.amount;
storage.coins = coins;
coinsText.setText('Coins: ' + coins);
// Flash the won amount
var winText = new Text2('+' + reward.amount, {
size: 80,
fill: 0xFFD700
});
winText.anchor.set(0.5, 0.5);
winText.x = 1024;
winText.y = 1366;
game.addChild(winText);
tween(winText, {
y: 1200,
alpha: 0
}, {
duration: 2000,
onFinish: function onFinish() {
winText.destroy();
}
});
}
};
return self;
});
var Circle = Container.expand(function () {
var self = Container.call(this);
var circleGraphics = self.attachAsset('circle', {
anchorX: 0.5,
anchorY: 0.5
});
self.rotationSpeed = 0.02;
self.shield = null;
self.hasShield = false;
self.update = function () {
self.rotation += self.rotationSpeed;
// Level 5 boss mechanics - add shield
if (currentLevel % 5 === 0 && currentLevel !== 10 && !self.hasShield) {
self.hasShield = true;
self.shield = new Shield();
self.shield.x = self.x;
self.shield.y = self.y;
self.parent.addChild(self.shield);
}
// Update shield position if it exists
if (self.shield && !self.shield.isDestroyed) {
self.shield.x = self.x;
self.shield.y = self.y;
}
// Level 10 special boss mechanics - alternating fast/slow speed
if (currentLevel === 10) {
if (!self.level10CycleStarted) {
self.level10CycleStarted = true;
self.startLevel10Cycle();
}
}
// Boss level special effects - random direction changes (less frequent)
if (currentLevel % 5 === 0 && currentLevel !== 10 && LK.ticks % 300 === 0) {
// Reverse rotation direction randomly for boss levels (reduced chance)
if (Math.random() < 0.2) {
self.rotationSpeed *= -1;
// Visual feedback for direction change
tween(self, {
scaleX: 1.4,
scaleY: 1.4
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 300,
easing: tween.easeOut
});
}
});
}
}
};
self.startLevel10Cycle = function () {
var baseSpeed = Math.abs(self.rotationSpeed);
var fastSpeed = baseSpeed * 2;
var slowSpeed = baseSpeed * 0.5;
// Start with fast speed
tween(self, {
rotationSpeed: self.rotationSpeed > 0 ? fastSpeed : -fastSpeed
}, {
duration: 2000,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Slow down
tween(self, {
rotationSpeed: self.rotationSpeed > 0 ? slowSpeed : -slowSpeed
}, {
duration: 2000,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Speed up again and repeat cycle
if (currentLevel === 10) {
self.startLevel10Cycle();
}
}
});
}
});
};
return self;
});
var Knife = Container.expand(function () {
var self = Container.call(this);
// Create knife blade
var blade = self.attachAsset('knife', {
anchorX: 0.5,
anchorY: 0.5,
rotation: Math.PI / 2
});
// Create knife handle
var handle = self.attachAsset('handle', {
anchorX: 0.5,
anchorY: 0.5,
y: 50,
rotation: Math.PI / 2
});
self.isThrown = false;
self.isStuck = false;
self.speed = 200;
self.targetDistance = 0;
self.stuckAngle = 0;
self.update = function () {
if (self.isThrown && !self.isStuck) {
self.y -= self.speed;
// Create trailing effect particles for all knives while moving
if (LK.ticks % 8 === 0) {
var particle = LK.getAsset('coin', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.2,
scaleY: 0.2
});
particle.tint = self.children[0].tint || 0xC0C0C0;
particle.alpha = 0.6;
particle.x = self.x + (Math.random() - 0.5) * 15;
particle.y = self.y + 30 + (Math.random() - 0.5) * 15;
game.addChild(particle);
// Animate particles with fade and scale effect
tween(particle, {
y: particle.y + 100,
alpha: 0,
scaleX: 0.05,
scaleY: 0.05
}, {
duration: 600,
easing: tween.easeOut,
onFinish: function onFinish() {
particle.destroy();
}
});
}
// Special fire effects for fire knife
if (self.children[0].tint === 0xFF4500 && LK.ticks % 4 === 0) {
var fireParticle = LK.getAsset('coin', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.15,
scaleY: 0.15
});
fireParticle.tint = Math.random() > 0.5 ? 0xFF4500 : 0xFFFF00;
fireParticle.alpha = 0.8;
fireParticle.x = self.x + (Math.random() - 0.5) * 25;
fireParticle.y = self.y + 35 + (Math.random() - 0.5) * 25;
game.addChild(fireParticle);
// Animate fire particles with flickering effect
tween(fireParticle, {
y: fireParticle.y + 80,
alpha: 0,
scaleX: 0.05,
scaleY: 0.05,
tint: 0xFF0000
}, {
duration: 400,
easing: tween.easeOut,
onFinish: function onFinish() {
fireParticle.destroy();
}
});
}
// Special ice effects for ice knife
if (self.children[0].tint === 0x00FFFF && LK.ticks % 5 === 0) {
var iceParticle = LK.getAsset('coin', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.12,
scaleY: 0.12
});
iceParticle.tint = Math.random() > 0.5 ? 0x00FFFF : 0xFFFFFF;
iceParticle.alpha = 0.9;
iceParticle.x = self.x + (Math.random() - 0.5) * 20;
iceParticle.y = self.y + 35 + (Math.random() - 0.5) * 20;
game.addChild(iceParticle);
// Animate ice particles with crystalline effect
tween(iceParticle, {
y: iceParticle.y + 60,
alpha: 0,
scaleX: 0.03,
scaleY: 0.03,
rotation: Math.PI * 2
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
iceParticle.destroy();
}
});
}
// Special rainbow effects for rainbow knife with color cycling
if (self.children[0].originalTint === 0xFF69B4) {
// Cycle through rainbow colors continuously
var rainbowColors = [0xFF0000, 0xFF8000, 0xFFFF00, 0x80FF00, 0x00FF00, 0x00FF80, 0x00FFFF, 0x0080FF, 0x0000FF, 0x8000FF, 0xFF00FF, 0xFF0080];
var colorIndex = Math.floor(LK.ticks / 10) % rainbowColors.length;
self.children[0].tint = rainbowColors[colorIndex];
// Rainbow particle effects
if (LK.ticks % 6 === 0) {
var rainbowParticle = LK.getAsset('coin', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.18,
scaleY: 0.18
});
rainbowParticle.tint = rainbowColors[Math.floor(Math.random() * rainbowColors.length)];
rainbowParticle.alpha = 0.8;
rainbowParticle.x = self.x + (Math.random() - 0.5) * 30;
rainbowParticle.y = self.y + 35 + (Math.random() - 0.5) * 30;
game.addChild(rainbowParticle);
// Animate rainbow particles with sparkle effect
tween(rainbowParticle, {
y: rainbowParticle.y + 90,
alpha: 0,
scaleX: 0.08,
scaleY: 0.08,
rotation: Math.PI * 3
}, {
duration: 700,
easing: tween.easeOut,
onFinish: function onFinish() {
rainbowParticle.destroy();
}
});
}
}
// Check collision with all stuck knives immediately
for (var i = 0; i < knives.length; i++) {
var otherKnife = knives[i];
if (otherKnife.isStuck && otherKnife !== self) {
var distance = Math.sqrt(Math.pow(self.x - otherKnife.x, 2) + Math.pow(self.y - otherKnife.y, 2));
if (distance < 80) {
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
return;
}
}
}
// Check if knife reached the circle
var distanceToCenter = Math.sqrt(Math.pow(self.x - circle.x, 2) + Math.pow(self.y - circle.y, 2));
if (distanceToCenter <= 200) {
self.stickToCircle();
}
} else if (self.isStuck) {
// Rotate with the circle
var angle = self.stuckAngle + circle.rotation;
self.x = circle.x + Math.cos(angle) * self.targetDistance;
self.y = circle.y + Math.sin(angle) * self.targetDistance;
self.rotation = angle + Math.PI / 2;
}
};
self.stickToCircle = function () {
// Check if circle has a shield first
if (circle.shield && !circle.shield.isDestroyed) {
// Hit the shield instead
var shieldDestroyed = circle.shield.takeDamage();
if (shieldDestroyed) {
circle.shield = null;
}
// Destroy the knife that hit the shield
self.destroy();
// Remove from knives array
for (var i = 0; i < knives.length; i++) {
if (knives[i] === self) {
knives.splice(i, 1);
break;
}
}
LK.getSound('hit').play();
return;
}
self.isStuck = true;
var angle = Math.atan2(self.y - circle.y, self.x - circle.x);
self.stuckAngle = angle - circle.rotation;
self.targetDistance = Math.sqrt(Math.pow(self.x - circle.x, 2) + Math.pow(self.y - circle.y, 2));
self.rotation = angle + Math.PI / 2;
knivesStuck++;
LK.setScore(knivesStuck);
scoreText.setText('Knives: ' + knivesStuck + '/7');
if (knivesStuck >= 7) {
showLevelComplete();
}
LK.getSound('hit').play();
};
return self;
});
var LevelComplete = Container.expand(function () {
var self = Container.call(this);
// Semi-transparent background
var bg = LK.getAsset('background', {
width: 2048,
height: 2732,
color: 0x000000,
shape: 'box',
alpha: 0.8
});
self.addChild(bg);
// Check if this is a boss level
var isBossLevel = currentLevel % 5 === 0;
// Level complete text
var titleText = new Text2('LEVEL ' + currentLevel + ' COMPLETE!' + (isBossLevel ? ' BOSS DEFEATED!' : ''), {
size: isBossLevel ? 80 : 100,
fill: isBossLevel ? 0xFF4757 : 0xFFD700
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 600;
self.addChild(titleText);
// Create different wheels based on level type
if (isBossLevel) {
// Create special boss reward wheel
self.wheel = new BossRewardWheel();
} else {
// Create normal wheel
self.wheel = new WheelReward();
}
self.wheel.x = 1024;
self.wheel.y = 1366;
self.wheel.alpha = 0;
self.wheel.scaleX = 0.3;
self.wheel.scaleY = 0.3;
self.addChild(self.wheel);
// Animate wheel entrance
tween(self.wheel, {
alpha: 1,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 800,
easing: tween.easeOut
});
// Spin button
var spinText = new Text2(isBossLevel ? 'TAP FOR BOSS REWARD!' : 'TAP TO SPIN!', {
size: isBossLevel ? 50 : 60,
fill: isBossLevel ? 0xFF69B4 : 0xFFFFFF
});
spinText.anchor.set(0.5, 0.5);
spinText.x = 1024;
spinText.y = 1800;
self.addChild(spinText);
// Continue button (appears after spin)
self.continueText = new Text2('TAP TO CONTINUE', {
size: 50,
fill: 0x4ECDC4
});
self.continueText.anchor.set(0.5, 0.5);
self.continueText.x = 1024;
self.continueText.y = 2100;
self.continueText.alpha = 0;
self.addChild(self.continueText);
self.hasSpun = false;
self.down = function (x, y, obj) {
if (!self.hasSpun && !self.wheel.isSpinning) {
self.wheel.spin();
self.hasSpun = true;
spinText.alpha = 0;
// Show continue button after spin completes
LK.setTimeout(function () {
tween(self.continueText, {
alpha: 1
}, {
duration: 500
});
}, 3500);
} else if (self.hasSpun && !self.wheel.isSpinning) {
// Continue to next level
self.destroy();
nextLevel();
}
};
return self;
});
var Shield = Container.expand(function () {
var self = Container.call(this);
// Shield graphics using circle asset with different tint
var shieldGraphics = self.attachAsset('circle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.4,
scaleY: 1.4
});
shieldGraphics.tint = 0x00FFFF; // Cyan shield color
shieldGraphics.alpha = 0.7;
self.health = 3; // Shield takes 3 hits to destroy
self.maxHealth = 3;
self.isDestroyed = false;
self.takeDamage = function () {
if (self.isDestroyed) return false;
self.health--;
// Visual feedback for damage
LK.effects.flashObject(self, 0xFF0000, 500);
// Shake effect
tween(self, {
x: self.x + 10
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
x: self.x - 20
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
x: self.x + 10
}, {
duration: 100,
easing: tween.easeOut
});
}
});
}
});
// Update shield appearance based on health
var healthPercent = self.health / self.maxHealth;
shieldGraphics.alpha = 0.3 + healthPercent * 0.4;
if (self.health <= 0) {
self.destroy();
return true; // Shield destroyed
}
return false; // Shield still active
};
self.update = function () {
// Rotate shield slowly
self.rotation += 0.01;
// Pulsing effect
var pulseScale = 1.4 + Math.sin(LK.ticks * 0.1) * 0.1;
shieldGraphics.scaleX = pulseScale;
shieldGraphics.scaleY = pulseScale;
};
return self;
});
var Shop = Container.expand(function () {
var self = Container.call(this);
// Semi-transparent background
var bg = LK.getAsset('background', {
width: 2048,
height: 2732,
color: 0x4A90E2,
shape: 'box',
alpha: 0.9
});
self.addChild(bg);
// Shop title
var titleText = new Text2('KNIFE SHOP', {
size: 120,
fill: 0xFFD700
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 200;
self.addChild(titleText);
// Close button
var closeText = new Text2('X', {
size: 80,
fill: 0xFF4757
});
closeText.anchor.set(0.5, 0.5);
closeText.x = 1800;
closeText.y = 200;
self.addChild(closeText);
// Shop items container
self.itemsContainer = new Container();
self.itemsContainer.x = 1024;
self.itemsContainer.y = 600;
self.addChild(self.itemsContainer);
self.items = [];
// Define shop items with very distinct and prominent pricing tiers
self.shopData = [{
id: 'default',
name: 'Classic',
color: 0xC0C0C0,
price: 0
}, {
id: 'golden',
name: 'Golden',
color: 0xFFD700,
price: 2500
}, {
id: 'ruby',
name: 'Ruby',
color: 0xFF0000,
price: 7500
}, {
id: 'emerald',
name: 'Emerald',
color: 0x00FF00,
price: 15000
}, {
id: 'sapphire',
name: 'Sapphire',
color: 0x0000FF,
price: 25000
}, {
id: 'fire',
name: 'Fire',
color: 0xFF4500,
price: 50000
}, {
id: 'ice',
name: 'Ice',
color: 0x00FFFF,
price: 75000
}, {
id: 'rainbow',
name: 'Rainbow',
color: 0xFF69B4,
price: 100000
}, {
id: 'katana',
name: 'Katana',
color: 0x8B0000,
price: 120000
}];
self.createItems = function () {
// Clear existing items
for (var i = 0; i < self.items.length; i++) {
self.items[i].destroy();
}
self.items = [];
// Create shop items in grid layout
for (var i = 0; i < self.shopData.length; i++) {
var item = new ShopItem(self.shopData[i]);
var col = i % 3;
var row = Math.floor(i / 3);
item.x = (col - 1) * 350;
item.y = row * 450;
self.itemsContainer.addChild(item);
self.items.push(item);
}
};
self.refreshItems = function () {
self.createItems();
};
self.createItems();
self.down = function (x, y, obj) {
if (x > 1700 && y < 300) {
// Close shop
self.destroy();
shopScene = null;
shop = null;
}
};
return self;
});
var ShopItem = Container.expand(function (itemData) {
var self = Container.call(this);
self.itemData = itemData;
self.isOwned = storage.ownedItems && storage.ownedItems[itemData.id] || false;
self.isEquipped = storage.equippedKnife === itemData.id;
// Item background
var bg = self.attachAsset('background', {
width: 300,
height: 400,
color: self.isOwned ? 0x4ECDC4 : 0x34495E,
shape: 'box',
anchorX: 0.5,
anchorY: 0.5
});
// Knife preview
var knifePreview = self.attachAsset('knife', {
anchorX: 0.5,
anchorY: 0.5,
y: -50,
scaleX: 0.8,
scaleY: 0.8,
rotation: Math.PI / 2
});
knifePreview.tint = itemData.color;
// Item name
var nameText = new Text2(itemData.name, {
size: 40,
fill: 0xFFFFFF
});
nameText.anchor.set(0.5, 0.5);
nameText.y = 80;
self.addChild(nameText);
// Price or status text with very prominent and distinct styling
var statusText = new Text2(self.isOwned ? self.isEquipped ? 'EQUIPPED' : 'OWNED' : itemData.price + ' COINS', {
size: self.isOwned ? 40 : 50,
fill: self.isOwned ? 0x00FF00 : itemData.price >= 75000 ? 0xFF1493 : itemData.price >= 50000 ? 0x9932CC : itemData.price >= 25000 ? 0x1E90FF : itemData.price >= 15000 ? 0x00CED1 : itemData.price >= 7500 ? 0x32CD32 : itemData.price >= 2500 ? 0xFFD700 : 0xFFFFFF
});
statusText.anchor.set(0.5, 0.5);
statusText.y = 130;
self.addChild(statusText);
self.down = function (x, y, obj) {
if (self.isOwned) {
// Equip item
storage.equippedKnife = itemData.id;
shop.refreshItems();
} else {
// Try to buy item
var currentCoins = storage.coins || 0;
if (currentCoins >= itemData.price) {
storage.coins = currentCoins - itemData.price;
if (!storage.ownedItems) storage.ownedItems = {};
storage.ownedItems[itemData.id] = true;
storage.equippedKnife = itemData.id;
coins = storage.coins;
coinsText.setText('Coins: ' + coins);
shop.refreshItems();
}
}
};
return self;
});
var WheelReward = Container.expand(function () {
var self = Container.call(this);
// Create wheel outer ring for better definition
var outerRing = self.attachAsset('wheel', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.6,
scaleY: 1.6
});
outerRing.tint = 0x2C3E50;
// Create wheel background
var wheelBg = self.attachAsset('wheel', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.4,
scaleY: 1.4
});
wheelBg.tint = 0x34495E;
// Create inner circle for depth
var innerCircle = self.attachAsset('wheel', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.3,
scaleY: 0.3
});
innerCircle.tint = 0x1A252F;
// Create wheel sections
self.sections = [];
self.rewards = [500, 100, 1000, 200, 750, 50, 1500, 25];
var sectionColors = [0xFF6B6B, 0x4ECDC4, 0x45B7D1, 0x96CEB4, 0xFECA57, 0xFF9FF3, 0x54A0FF, 0x5F27CD];
for (var i = 0; i < 8; i++) {
var section = self.attachAsset('wheelSection', {
anchorX: 0,
anchorY: 0.5,
x: 0,
y: 0,
scaleX: 2.0,
scaleY: 4,
rotation: i * Math.PI * 2 / 8
});
section.tint = sectionColors[i];
self.sections.push(section);
// Add coin icon for each section
var coinIcon = self.attachAsset('coin', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8
});
coinIcon.x = Math.cos(i * Math.PI * 2 / 8) * 150;
coinIcon.y = Math.sin(i * Math.PI * 2 / 8) * 150;
self.addChild(coinIcon);
// Add reward text with better styling
var rewardText = new Text2(self.rewards[i].toString(), {
size: 50,
fill: 0xFFFFFF
});
rewardText.anchor.set(0.5, 0.5);
rewardText.x = Math.cos(i * Math.PI * 2 / 8) * 220;
rewardText.y = Math.sin(i * Math.PI * 2 / 8) * 220;
self.addChild(rewardText);
}
// Create decorative border lines
for (var j = 0; j < 8; j++) {
var borderLine = self.attachAsset('wheelSection', {
anchorX: 0,
anchorY: 0.5,
x: 0,
y: 0,
scaleX: 2.2,
scaleY: 0.1,
rotation: j * Math.PI * 2 / 8
});
borderLine.tint = 0x2C3E50;
}
// Create pointer with enhanced design
var pointer = self.attachAsset('pointer', {
anchorX: 0.5,
anchorY: 1,
y: -450,
scaleX: 2.0,
scaleY: 2.0
});
pointer.tint = 0xFF4757;
// Add pointer shadow for depth
var pointerShadow = self.attachAsset('pointer', {
anchorX: 0.5,
anchorY: 1,
y: -445,
x: 5,
scaleX: 2.0,
scaleY: 2.0
});
pointerShadow.tint = 0x000000;
pointerShadow.alpha = 0.3;
self.isSpinning = false;
self.spinSpeed = 0;
self.finalAngle = 0;
self.spin = function () {
if (self.isSpinning) return;
self.isSpinning = true;
self.spinSpeed = 0.3;
self.finalAngle = Math.random() * Math.PI * 2 + Math.PI * 12; // More rotations for excitement
var currentRotation = self.rotation;
// Add anticipation animation before spinning
tween(self, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
// Scale back and start main spin
tween(self, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 100
});
// Main spinning animation with enhanced easing
tween(self, {
rotation: currentRotation + self.finalAngle
}, {
duration: 4000,
easing: tween.easeOut,
onFinish: function onFinish() {
self.isSpinning = false;
// Add small bounce effect when stopping
tween(self, {
scaleX: 1.05,
scaleY: 1.05
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
self.giveReward();
}
});
}
});
}
});
}
});
};
self.giveReward = function () {
var normalizedAngle = (self.rotation % (Math.PI * 2) + Math.PI * 2) % (Math.PI * 2);
var sectionIndex = Math.floor(normalizedAngle / (Math.PI * 2 / 8));
var reward = self.rewards[sectionIndex];
coins += reward;
storage.coins = coins;
coinsText.setText('Coins: ' + coins);
// Flash the won amount
var winText = new Text2('+' + reward, {
size: 80,
fill: 0xFFD700
});
winText.anchor.set(0.5, 0.5);
winText.x = 1024;
winText.y = 1366;
game.addChild(winText);
tween(winText, {
y: 1200,
alpha: 0
}, {
duration: 2000,
onFinish: function onFinish() {
winText.destroy();
}
});
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2C3E50
});
/****
* Game Code
****/
var circle = game.addChild(new Circle());
circle.x = 1024;
circle.y = 1000;
// Initialize boss level tracking
var isBossLevel = false;
var knives = [];
var knivesStuck = 0;
var canThrow = true;
var coins = storage.coins || 0;
var currentLevel = 1;
var levelCompleteScene = null;
var shopScene = null;
var shop = null;
// Initialize default knife if none equipped
if (!storage.equippedKnife) {
storage.equippedKnife = 'default';
if (!storage.ownedItems) storage.ownedItems = {};
storage.ownedItems['default'] = true;
}
// Coins display
var coinsText = new Text2('Coins: ' + coins, {
size: 60,
fill: 0xFFD700
});
coinsText.anchor.set(1, 0);
LK.gui.topRight.addChild(coinsText);
coinsText.x = -20;
coinsText.y = 20;
// Shop button
var shopButton = new Text2('SHOP', {
size: 50,
fill: 0x4ECDC4
});
shopButton.anchor.set(1, 0);
LK.gui.topRight.addChild(shopButton);
shopButton.x = -20;
shopButton.y = 100;
// Level display
var levelText = new Text2('Level: 1', {
size: 60,
fill: 0xFFFFFF
});
levelText.anchor.set(0, 0);
LK.gui.topLeft.addChild(levelText);
levelText.x = 120;
levelText.y = 20;
// Score display
var scoreText = new Text2('Knives: 0/7', {
size: 80,
fill: 0xFFFFFF
});
scoreText.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreText);
// Instructions
var instructionText = new Text2('Tap to throw knives!\nAvoid hitting existing knives!', {
size: 60,
fill: 0xFFFFFF
});
instructionText.anchor.set(0.5, 0.5);
instructionText.x = 1024;
instructionText.y = 400;
game.addChild(instructionText);
function showLevelComplete() {
if (!levelCompleteScene) {
levelCompleteScene = new LevelComplete();
game.addChild(levelCompleteScene);
}
}
function nextLevel() {
// Advance to next level
currentLevel++;
// Reset game state for new level
knivesStuck = 0;
canThrow = true;
// Clear existing knives
for (var i = 0; i < knives.length; i++) {
knives[i].destroy();
}
knives = [];
// Reset score display
scoreText.setText('Knives: 0/7');
// Show instructions again
instructionText.alpha = 1;
// Remove level complete scene
if (levelCompleteScene) {
levelCompleteScene.destroy();
levelCompleteScene = null;
}
// Increase difficulty by making circle spin faster each level
circle.rotationSpeed = 0.02 + (currentLevel - 1) * 0.015;
// Reset level 10 special cycle flag
circle.level10CycleStarted = false;
// Reset shield state
if (circle.shield) {
circle.shield.destroy();
circle.shield = null;
}
circle.hasShield = false;
// Check if this is a boss level (every 5th level)
var isBossLevel = currentLevel % 5 === 0;
if (isBossLevel) {
// Boss level - slightly faster rotation but easier than before
circle.rotationSpeed = 0.03 + (currentLevel - 1) * 0.008;
circle.children[0].tint = 0xFF4757; // Red tint for boss
circle.scaleX = 1.2;
circle.scaleY = 1.2;
// Special handling for level 10
if (currentLevel === 10) {
// Level 10 gets special alternating speed mechanics but slower
circle.children[0].tint = 0xFF0000; // Darker red for level 10
circle.scaleX = 1.3;
circle.scaleY = 1.3;
} else {
// Reduced pulsing animation for other boss levels
tween(circle, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 1500,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(circle, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 1500,
easing: tween.easeInOut
});
}
});
}
} else {
// Normal level - reset boss modifications
circle.children[0].tint = 0xFFFFFF;
circle.scaleX = 1.0;
circle.scaleY = 1.0;
tween.stop(circle);
}
// Update level display
levelText.setText('Level: ' + currentLevel + (isBossLevel ? ' (BOSS)' : ''));
}
;
function checkKnifeCollisions(newKnife) {
var _loop = function _loop() {
existingKnife = knives[i];
if (existingKnife.isStuck && existingKnife !== newKnife) {
var _showLevelComplete = function _showLevelComplete() {
if (!levelCompleteScene) {
levelCompleteScene = new LevelComplete();
game.addChild(levelCompleteScene);
}
};
var _restartGame = function _restartGame() {
// Reset game state
knivesStuck = 0;
canThrow = true;
// Clear existing knives
for (var i = 0; i < knives.length; i++) {
knives[i].destroy();
}
knives = [];
// Reset score display
scoreText.setText('Knives: 0/7');
// Show instructions again
instructionText.alpha = 1;
// Remove level complete scene
if (levelCompleteScene) {
levelCompleteScene.destroy();
levelCompleteScene = null;
}
};
distance = Math.sqrt(Math.pow(newKnife.x - existingKnife.x, 2) + Math.pow(newKnife.y - existingKnife.y, 2));
if (distance < 60) {
return {
v: true
};
}
;
}
},
existingKnife,
distance,
_ret;
for (var i = 0; i < knives.length; i++) {
_ret = _loop();
if (_ret) return _ret.v;
}
return false;
}
game.down = function (x, y, obj) {
// Check if shop button was tapped
var shopButtonGlobal = LK.gui.topRight.toGlobal(shopButton.position);
var gameLocal = game.toLocal(shopButtonGlobal);
if (x > gameLocal.x - 100 && x < gameLocal.x + 100 && y > gameLocal.y - 50 && y < gameLocal.y + 50) {
if (!shopScene) {
shopScene = new Shop();
shop = shopScene;
game.addChild(shopScene);
}
return;
}
if (canThrow && knivesStuck < 7) {
var newKnife = new Knife();
newKnife.x = 1024;
newKnife.y = 2400;
newKnife.isThrown = true;
// Apply equipped cosmetic
var equippedKnife = storage.equippedKnife || 'default';
var knifeColors = {
'default': 0xC0C0C0,
'golden': 0xFFD700,
'ruby': 0xFF0000,
'emerald': 0x00FF00,
'sapphire': 0x0000FF,
'rainbow': 0xFF69B4,
'fire': 0xFF4500,
'ice': 0x00FFFF,
'katana': 0x8B0000
};
if (knifeColors[equippedKnife]) {
newKnife.children[0].tint = knifeColors[equippedKnife];
// Store original tint for rainbow knife color cycling
newKnife.children[0].originalTint = knifeColors[equippedKnife];
}
knives.push(newKnife);
game.addChild(newKnife);
canThrow = false;
LK.getSound('throw').play();
// Allow next throw after delay
LK.setTimeout(function () {
canThrow = true;
}, 300);
}
};
game.update = function () {
// Check for knife collisions
for (var i = 0; i < knives.length; i++) {
var knife = knives[i];
if (knife.isThrown && !knife.isStuck) {
// Check collision with all stuck knives
for (var j = 0; j < knives.length; j++) {
var otherKnife = knives[j];
if (otherKnife.isStuck && otherKnife !== knife) {
var distance = Math.sqrt(Math.pow(knife.x - otherKnife.x, 2) + Math.pow(knife.y - otherKnife.y, 2));
if (distance < 80) {
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
return;
}
}
}
}
// Remove knives that went off screen
if (knife.y < -100 && !knife.isStuck) {
knife.destroy();
knives.splice(i, 1);
i--;
}
}
// Hide instructions after first throw
if (knives.length > 0 && instructionText.alpha > 0) {
tween(instructionText, {
alpha: 0
}, {
duration: 1000
});
}
};