/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Bullet class var Bullet = Container.expand(function () { var self = Container.call(this); var bullet = self.attachAsset('bullet', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 0; self.dirX = 0; self.dirY = 0; self.update = function () { self.x += self.dirX * self.speed; self.y += self.dirY * self.speed; }; return self; }); // Enemy class var Enemy = Container.expand(function () { var self = Container.call(this); // Attach enemybottomthing as a child of enemy var enemybottomthing = self.attachAsset('bottomthingenemy', { anchorX: 0.5, anchorY: 0.5, x: 0, y: 80 // moved 10px up from previous (90 -> 80) }); // Legs var lleg = self.attachAsset('enemyLeg', { anchorX: 0.5, anchorY: 0, x: -140 / 4 + 5 - 5, // moved 5px left // use width of enemyBody (140) since body not yet defined y: 180 / 2 - 15 - 3 // use height of enemyBody (180) }); var rleg = self.attachAsset('enemyLeg', { anchorX: 0.5, anchorY: 0, x: 140 / 4 + 5 - 5, // moved 5px left y: 180 / 2 - 15 - 3 }); // Left Arm var larm = self.attachAsset('enemyArm', { anchorX: 0.5, anchorY: 0, x: -140 / 2 + 5 + 10, // use width of enemyBody (140) since body not yet defined // 10px right // 5px closer to body, 10px right y: -80 //{t} // 30px up (10px further down) }); // Body var body = self.attachAsset('enemyBody', { anchorX: 0.5, anchorY: 0.5, x: 10, y: -15 //{h} // 5px daha aşağı, 10px sağa taşındı }); // Head var head = self.attachAsset('enemyHead', { anchorX: 0.5, anchorY: 0.5, x: -4 + 5 - 4, // 4px left from previous // 5px right, 4px left y: -body.height / 2 - 45 - 4 - 5 - 4 // 4px up from previous }); // Right Arm (gun hand) var rarm = self.attachAsset('enemyArm', { anchorX: 0.5, anchorY: 0, x: body.width / 2 - 5, // 5px closer to body y: -80 //{z} // 30px up (10px further down) }); // Legs var lleg = self.attachAsset('enemyLeg', { anchorX: 0.5, anchorY: 0, x: -body.width / 4 + 5 - 5 + 3, // moved 5px left, now 3px right y: body.height / 2 - 15 - 3 //{z} // 3px up }); var rleg = self.attachAsset('enemyLeg', { anchorX: 0.5, anchorY: 0, x: body.width / 4 + 5 - 5 + 3, // moved 5px left, now 3px right y: body.height / 2 - 15 - 3 //{E} // 3px up }); // Gun (in hand) var gun = self.attachAsset('enemyGun', { anchorX: 0.5, // 0.5 yerine 0.5 anchorY: 0.5, x: rarm.x, y: rarm.y + rarm.height, rotation: 0 }); // Holster gun (on hip, always visible unless drawn) var hipGun = self.attachAsset('enemyGun', { anchorX: 0.5, anchorY: 0.5, x: body.width / 2 + 8 - 10 - 5 - 10, // 5px further left // 10px further left, 5px more left, 10px more left y: body.height / 2 - 22 + 15 + 10 + 3, // 3px further down // 10px further down, 3px more down rotation: Math.PI / 2 }); // Start with gun in holster, hand empty gun.visible = false; hipGun.visible = true; // Helper methods to switch gun/holster visibility self.toHolster = function () { hipGun.visible = true; gun.visible = false; }; self.toHand = function () { hipGun.visible = false; gun.visible = true; }; self.bodyParts = [body, head, larm, rarm, lleg, rleg, gun]; self.gun = gun; self.rarm = rarm; self.head = head; self.body = body; self.ragdoll = function (hitX, hitY) { for (var i = 0; i < self.bodyParts.length; i++) { var part = self.bodyParts[i]; tween(part, { rotation: (Math.random() - 0.5) * 2.5, x: part.x + (Math.random() - 0.5) * 200, y: part.y + (Math.random() - 0.5) * 200 }, { duration: 600, delay: i * 30, easing: tween.elasticOut }); } }; self.resetPose = function () { // Body body.x = 10; body.y = -15; body.rotation = 0; // Head (use constant offset, not accumulated) head.x = 0; head.y = -body.height / 2 - 45; // SABİT offset, yukarı kayma engellendi head.rotation = 0; // Left Arm larm.x = -body.width / 2 + 5 + 10; larm.y = -80; larm.rotation = 0; // Right Arm rarm.x = body.width / 2 - 5; rarm.y = -80; rarm.rotation = 0; // Left Leg lleg.x = -body.width / 4 + 5 - 5 + 3; lleg.y = body.height / 2 - 15 - 3; lleg.rotation = 0; // Right Leg rleg.x = body.width / 4 + 5 - 5 + 3; rleg.y = body.height / 2 - 15 - 3; rleg.rotation = 0; // Gun (in hand) gun.x = rarm.x; gun.y = rarm.y + rarm.height; gun.rotation = 0; // Hip gun (holster) if (typeof hipGun !== "undefined") { hipGun.x = body.width / 2 + 8 - 10 - 5 - 10; hipGun.y = body.height / 2 - 22 + 15 + 10 + 3; hipGun.rotation = Math.PI / 2; } self.toHolster(); // always start with gun in holster }; return self; }); // Player class var Player = Container.expand(function () { var self = Container.call(this); // Head var head = self.attachAsset('playerHead', { anchorX: 0.5, anchorY: 0.5, x: 0, y: -160 / 2 - 45 - 20 // use playerBody height (160) since body not yet defined, moved 25px up }); // Body var body = self.attachAsset('playerBody', { anchorX: 0.5, anchorY: 0.5, x: -12, y: 10 //{1U} // moved 15px down, 5px left from previous }); // bottomthingplayer as child of player, 75px down (moved 15px further down) var bottomthingplayer = self.attachAsset('bottomthingplayer', { anchorX: 0.5, anchorY: 0.5, x: -5, //{21} // moved 5px left y: 101 // moved 6px further down (95+6) }); // Left Arm var larm = self.attachAsset('playerArm', { anchorX: 0.5, anchorY: 0, x: -body.width / 2 - 10 - 5 + 5 + 7 + 3, // move 3px right // move 5px right, 7px more right, 3px more right y: -100 + 10 + 10 + 15, // move 15px down // move 10px down, 15px more down zIndex: -1 // ensure arm is behind body (if zIndex is supported) }); // Move left arm behind body in display list if (typeof self.setChildIndex === "function") { self.setChildIndex(larm, 0); } // Right Arm (gun hand) var rarm = self.attachAsset('playerArm', { anchorX: 0.5, anchorY: 0, x: body.width / 2 + 10 - 5 - 20 - 5 - 10, // 10px more left y: -100 + 10 + 15 + 10 //{1Y} // 10px more down, 15px more down, 10px more down }); // Legs var lleg = self.attachAsset('playerLeg', { anchorX: 0.5, anchorY: 0, x: -body.width / 4 - 10 + 3 + 10, // moved 10px right // move 3px right (total 6px closer) // 10px left, 3px right, 10px right y: body.height / 2 - 10 + 10 // 10px down }); var rleg = self.attachAsset('playerLeg', { anchorX: 0.5, anchorY: 0, x: body.width / 4 - 10 - 3, // move 3px left (total 6px closer) // 10px left, 3px left y: body.height / 2 - 10 + 10 // 10px down }); // Gun (in hand) var gun = self.attachAsset('playerGun', { anchorX: 0.5, // 0.5 yerine 0.5 anchorY: 0.5, x: rarm.x - 20, //{2m} // 20px left y: rarm.y + rarm.height + 5, //{2n} // 5px down rotation: 0 }); // Holster gun (on hip, always visible unless drawn) var hipGun = self.attachAsset('playerGun', { anchorX: 0.5, anchorY: 0.5, x: body.width / 2 + -28, y: body.height / 2 - -12, rotation: Math.PI / 2 }); // Start with gun in holster, hand empty gun.visible = false; hipGun.visible = true; // Helper methods to switch gun/holster visibility self.toHolster = function () { hipGun.visible = true; gun.visible = false; }; self.toHand = function () { hipGun.visible = false; gun.visible = true; }; // Used for ragdoll effect self.bodyParts = [body, head, larm, rarm, lleg, rleg, gun]; // Used for aiming self.gun = gun; self.rarm = rarm; // Used for hit detection self.head = head; self.body = body; // Used for ragdoll self.ragdoll = function (hitX, hitY) { // Animate all parts to random positions/rotations for (var i = 0; i < self.bodyParts.length; i++) { var part = self.bodyParts[i]; tween(part, { rotation: (Math.random() - 0.5) * 2.5, x: part.x + (Math.random() - 0.5) * 200, y: part.y + (Math.random() - 0.5) * 200 }, { duration: 600, delay: i * 30, easing: tween.elasticOut }); } }; // Reset pose self.resetPose = function () { // Body body.x = -12; body.y = 10; body.rotation = 0; // Head (use constant offset, not accumulated) head.x = 0; head.y = -body.height / 2 - 45; // SABİT offset, yukarı kayma engellendi head.rotation = 0; // Left Arm larm.x = -body.width / 2 - 10 - 5 + 5 + 7 + 3; larm.y = -100 + 10 + 10 + 15; larm.rotation = 0; // Move left arm behind body in display list if (typeof self.setChildIndex === "function") { self.setChildIndex(larm, 0); } // Right Arm rarm.x = body.width / 2 + 10 - 5 - 20 - 5 - 10; rarm.y = -100 + 10 + 15 + 10; rarm.rotation = 0; // Left Leg lleg.x = -body.width / 4 - 10 + 3 + 10; lleg.y = body.height / 2 - 10 + 10; lleg.rotation = 0; // Right Leg rleg.x = body.width / 4 - 10 - 3; rleg.y = body.height / 2 - 10 + 10; rleg.rotation = 0; // Gun (in hand) gun.x = rarm.x - 20; gun.y = rarm.y + rarm.height + 5; gun.rotation = 0; // Move bottomthingplayer 6px further down and 5px left if (typeof bottomthingplayer !== "undefined") { bottomthingplayer.x = -5; bottomthingplayer.y = 101; } self.toHolster(); // always start with gun in holster }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x2e1a09 }); /**** * Game Code ****/ // Player and enemy bodies (torso, head, arms, legs) as simple shapes // Game state var STATE_WAIT = 0; var STATE_DRAW = 1; var STATE_SHOT = 2; var STATE_RESULT = 3; var duelState = STATE_WAIT; var canShoot = false; var playerShot = false; var enemyShot = false; var playerBullet = null; var enemyBullet = null; var duelTimer = null; var drawTimeout = null; var resultTimeout = null; var duelStartTime = 0; var playerShotTime = 0; var enemyShotTime = 0; var aimX = 0; var aimY = 0; var aimRadius = 180; var aimAngle = 0; var aimSpeed = 0.018; // %30 daha yavaş var aimDir = 1; var aimActive = false; var playerScore = 0; var roundNum = 1; var maxRounds = 5; // === GLOBAL SHOT COUNTERS === var playerShotsFiredCnt = 0; var enemyShotsFiredCnt = 0; // === PLAYER SHOT COOLDOWN === var playerShotCooldown = 0; // ms left until next shot allowed var enemyData = [{ name: "Greenhorn", minReact: 3.0, maxReact: 3.4, coneStart: 42, coneEnd: 0 }, { name: "Billy the Kid", minReact: 2.4, maxReact: 2.7, coneStart: 36, coneEnd: 0 }, { name: "Doc Holliday", minReact: 1.6, maxReact: 1.9, coneStart: 30, coneEnd: 0 }, { name: "Calamity Jane", minReact: 1.0, maxReact: 1.3, coneStart: 24, coneEnd: 0 }, { name: "The Undertaker", minReact: 0.6, maxReact: 0.8, coneStart: 18, coneEnd: 0, scale: 1.5 }]; var currentEnemy = null; // ==== FIX #1 : SAHNENİN BAŞINDA ==== var world = new Container(); game.addChild(world); // Add arkaplan background image centered in the screen var arkaplan = LK.getAsset('arkaplan', { anchorX: 0.5, anchorY: 0.5 }); arkaplan.x = 2048 / 2; arkaplan.y = 2732 / 2; world.addChild(arkaplan); // Player and enemy var player = new Player(); var enemy = new Enemy(); world.addChild(player); world.addChild(enemy); // Center positions var centerX = 2048 / 2; var playerY = 2732 * 0.7; var enemyY = 2732 * 0.3; // 6-bullet UI for player and enemy var playerAmmoUI = []; var enemyAmmoUI = []; function setupAmmoUI() { // Remove old UI if any for (var i = 0; i < playerAmmoUI.length; i++) { if (playerAmmoUI[i].parent) { playerAmmoUI[i].parent.removeChild(playerAmmoUI[i]); } } for (var i = 0; i < enemyAmmoUI.length; i++) { if (enemyAmmoUI[i].parent) { enemyAmmoUI[i].parent.removeChild(enemyAmmoUI[i]); } } playerAmmoUI = []; enemyAmmoUI = []; for (var i = 0; i < 6; i++) { var px = player.x - 120 + i * 40; var ex = enemy.x - 120 + i * 40; var bulletP = LK.getAsset('bullet', { scaleX: 0.6, scaleY: 0.6, anchorX: 0.5, anchorY: 0.5 }); var bulletE = LK.getAsset('bullet', { scaleX: 0.6, scaleY: 0.6, anchorX: 0.5, anchorY: 0.5 }); bulletP.y = player.y + 250 + 60; // Düşman: yalnızca 5. raundda 75 px yukarı var enemyExtraY = roundNum === 5 ? -75 : 0; bulletE.y = enemy.y - 250 + enemyExtraY; bulletP.x = px; bulletE.x = ex; // HUD’u world içine koy ki zoom animasyonuyla birlikte büyüsün world.addChild(bulletP); world.addChild(bulletE); playerAmmoUI.push(bulletP); enemyAmmoUI.push(bulletE); } } // Position player and enemy player.x = centerX - 500; player.y = playerY; enemy.x = centerX + 500; enemy.y = enemyY; // Score text var scoreTxt = new Text2('Score: 0', { size: 90, fill: 0xFFF7D6 }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // Round text var roundTxt = new Text2('', { size: 70, fill: 0xFFE4B5 }); roundTxt.anchor.set(0.5, 0); LK.gui.top.addChild(roundTxt); roundTxt.y = 110; // Duel status text var statusTxt = new Text2('', { size: 110, fill: 0xFFECB3 }); statusTxt.anchor.set(0.5, 0.5); LK.gui.center.addChild(statusTxt); // (Aim reticle removed) // Helper: reset all state for a new round function resetDuel() { duelState = STATE_WAIT; canShoot = false; playerShot = false; enemyShot = false; playerBullet = null; enemyBullet = null; duelStartTime = 0; playerShotTime = 0; enemyShotTime = 0; aimAngle = Math.random() * Math.PI * 2; aimDir = Math.random() > 0.5 ? 1 : -1; aimActive = false; // (aimReticle removed) player.resetPose(); enemy.resetPose(); player.toHolster(); enemy.toHolster(); holsterFull.visible = true; holsterEmpty.visible = false; setupAmmoUI(); // === RESET SHOT COUNTERS === playerShotsFiredCnt = 0; enemyShotsFiredCnt = 0; // === RESET HOLSTER FLAGS === playerReady = false; // yeni ← round’a nötr gir holdingHolster = false; // yeni holsterHoldTime = 0; // güvenlik duelStarted = false; // <-- YENİ: her raunda nötr gir cancelHold(); // 1. raunddan kalma musicTimeout varsa temizle zoomFinished = false; // yeni animasyona hazırlan var roundMusic = roundNum === 1 ? 'duelmusic' : roundNum === 2 ? 'round2music' : roundNum === 3 ? 'round3music' : roundNum === 4 ? 'round4music' : 'round5music'; startZoomIn(roundMusic); statusTxt.setText("Wait for the music..."); statusTxt.visible = true; // Set up enemy for this round currentEnemy = enemyData[roundNum - 1]; roundTxt.setText("Round " + roundNum + ": " + currentEnemy.name); // Boss scale (if any) enemy.scaleX = enemy.scaleY = currentEnemy.scale || 1; // Play duel music // (music now only plays during zoom-in, do not play here) // drawTimeout is now set after zoom-in, not here if (drawTimeout) { LK.clearTimeout(drawTimeout); } } // Start the "DRAW!" phase function startDraw() { if (!playerReady) { earlyLose(); return; } duelState = STATE_DRAW; canShoot = true; aimActive = true; // (aimReticle removed) statusTxt.setText("DRAW!"); statusTxt.visible = true; LK.stopMusic(); LK.getSound('draw').play(); player.toHand(); // draw from holster enemy.toHand(); // enemy draws too aimEnemyGunAt(player.x, player.y - 40); // hemen hizala duelStartTime = Date.now(); // Enemy will shoot after their reaction time var reactTime = 1200; // fallback default if (currentEnemy && typeof currentEnemy.minReact === "number" && typeof currentEnemy.maxReact === "number") { reactTime = 1000 * (currentEnemy.minReact + Math.random() * (currentEnemy.maxReact - currentEnemy.minReact)); reactTime *= 0.425; // %57.5 daha hızlı tepki (eski 0.5 ve yeni 0.35 arası) } if (duelTimer) { LK.clearTimeout(duelTimer); } duelTimer = LK.setTimeout(enemyFire, reactTime); } // Player fires function playerFire(x, y) { // 6 mermi limiti if (playerShotsFiredCnt >= 6) { statusTxt.setText("Out of ammo!"); statusTxt.visible = true; return; } if (!canShoot) { return; } // === COOLDOWN: Block if cooldown active === if (playerShotCooldown > 0) { return; } playerShot = true; playerShotsFiredCnt++; // sayaç ↑ playerShotTime = Date.now(); // === COOLDOWN: Set cooldown after shot === playerShotCooldown = 300; // 0.3 seconds in ms // Animate gun tween(player.gun, { rotation: -0.5 }, { duration: 80, easing: tween.cubicOut }); tween(player.rarm, { rotation: -0.3 }, { duration: 80, easing: tween.cubicOut }); LK.getSound('gunshot').play(); // Create bullet playerBullet = new Bullet(); // Muzzle position helper function muzzlePos() { // Use full gun width/height for muzzle (center anchor) var gunW = player.gun.width || 60; var gunH = player.gun.height || 15; return { x: player.x + player.gun.x + Math.cos(player.gun.rotation) * gunW, y: player.y + player.gun.y + Math.sin(player.gun.rotation) * gunH }; } var muzzle = muzzlePos(); playerBullet.x = muzzle.x; playerBullet.y = muzzle.y; // Ateş anındaki imleç (x, y) fonksiyona zaten parametre olarak geliyor var dx = x - muzzle.x; var dy = y - muzzle.y; var dist = Math.sqrt(dx * dx + dy * dy); playerBullet.dirX = dx / dist; playerBullet.dirY = dy / dist; playerBullet.speed = 60; game.addChild(playerBullet); // Decrement player bullet UI for (var i = 0; i < playerAmmoUI.length; i++) { if (playerAmmoUI[i].visible !== false) { playerAmmoUI[i].visible = false; break; } } // If shot before draw, instant loss if (duelState === STATE_WAIT) { duelState = STATE_RESULT; statusTxt.setText("You shot too early!\nYou Lose!"); statusTxt.visible = true; LK.getSound('fail').play(); player.ragdoll(); enemy.ragdoll(); endRound(false); return; } // bir sonraki mermiye izin ver if (duelState === STATE_DRAW && playerShotsFiredCnt < 6) { canShoot = true; aimActive = true; // (aimReticle removed) } // DRAW fazı açık kalsın ki 6 mermi bitene kadar tekrar tekrar ateş edebilelim } // Enemy fires function enemyFire() { var _currentEnemy; if (enemyShotsFiredCnt >= 6 || duelState === STATE_RESULT) { return; } if (!enemyShot) { enemyShot = true; } // ilk mermi için eski bayrak enemyShotsFiredCnt++; enemyShotTime = Date.now(); // Ateşten önce hedefe çevir aimEnemyGunAt(player.x, player.y - 40); // Animate gun tween(enemy.gun, { rotation: 0.5 }, { duration: 80, easing: tween.cubicOut }); tween(enemy.rarm, { rotation: 0.3 }, { duration: 80, easing: tween.cubicOut }); LK.getSound('gunshot').play(); // Create bullet enemyBullet = new Bullet(); var gunW = enemy.gun.width || 60; var gunH = enemy.gun.height || 18; enemyBullet.x = enemy.x + enemy.gun.x + Math.cos(enemy.gun.rotation) * gunW; enemyBullet.y = enemy.y + enemy.gun.y + Math.sin(enemy.gun.rotation) * gunH; // Decrement enemy bullet UI for (var i = 0; i < enemyAmmoUI.length; i++) { if (enemyAmmoUI[i].visible !== false) { enemyAmmoUI[i].visible = false; break; } } // Konik isabet modeliyle hedef seçimi // 1️⃣ hedef vektörü var baseDX = player.x - enemyBullet.x; var baseDY = player.y - 40 - enemyBullet.y; // gövdenin biraz üstü var baseAng = Math.atan2(baseDY, baseDX); // 2️⃣ saçılma açısı (daralan koni) var sIdx = enemyShotsFiredCnt; // 1-6 var sMax = 6; var cStart = currentEnemy && typeof currentEnemy.coneStart === "number" ? currentEnemy.coneStart : 24; // fallback var cEnd = currentEnemy && typeof currentEnemy.coneEnd === "number" ? currentEnemy.coneEnd : 0; var coneDeg = cStart + (cEnd - cStart) * ((sIdx - 1) / (sMax - 1)); var coneRad = coneDeg * Math.PI / 180; var isLast = sIdx === sMax; // son kurşun var spread = isLast ? 0 : Math.random() * coneRad - coneRad / 2; // 3️⃣ hedef noktasını diagramdaki yayı keserek bul var range = 1500; // ekran dışına yeter var targetX = enemyBullet.x + Math.cos(baseAng + spread) * range; var targetY = enemyBullet.y + Math.sin(baseAng + spread) * range; var dx = targetX - enemyBullet.x; var dy = targetY - enemyBullet.y; var dist = Math.sqrt(dx * dx + dy * dy); enemyBullet.dirX = dx / dist; enemyBullet.dirY = dy / dist; enemyBullet.speed = 60; game.addChild(enemyBullet); // sonraki mermi (tak-tak) 0.6 sn sonra if (enemyShotsFiredCnt < 6) { LK.setTimeout(enemyFire, 600); } // Round oyuncu ateş etmediyse ANCAK bütün 6 mermi atıldıktan sonra if (enemyShotsFiredCnt === 6 && !playerShot) { // Son kurşunun ekrandan çıkması için çok kısa bir gecikme bırak LK.setTimeout(function () { if (duelState !== STATE_RESULT) { duelState = STATE_RESULT; statusTxt.setText("You Survived!"); statusTxt.visible = true; endRound(true); } }, 350); } } // End round, win: true/false function endRound(win) { canShoot = false; aimActive = false; // (aimReticle removed) if (drawTimeout) { LK.clearTimeout(drawTimeout); } if (duelTimer) { LK.clearTimeout(duelTimer); } if (resultTimeout) { LK.clearTimeout(resultTimeout); } drawTimeout = null; duelTimer = null; resultTimeout = null; // Next round or end game resultTimeout = LK.setTimeout(function () { if (win) { playerScore += 1; scoreTxt.setText("Score: " + playerScore); roundNum += 1; if (roundNum > maxRounds) { statusTxt.setText("You Win!\nScore: " + playerScore); statusTxt.visible = true; LK.showYouWin(); } else { resetDuel(); } } else { statusTxt.setText("You Lose!\nScore: " + playerScore); statusTxt.visible = true; LK.showGameOver(); } }, 1600); } // Handle aiming reticle movement (circular motion) function updateAimReticle() { // (aim reticle removed) } // Handle bullet collisions and duel result function checkBullets() { // Player bullet hits enemy if (playerBullet) { // Check if bullet reached enemy var dx = playerBullet.x - enemy.x; var dy = playerBullet.y - enemy.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < 120) { // Hit! LK.getSound('hit').play(); enemy.ragdoll(playerBullet.x, playerBullet.y); game.removeChild(playerBullet); playerBullet = null; duelState = STATE_RESULT; statusTxt.setText("You Win the Duel!"); statusTxt.visible = true; endRound(true); } } // Enemy bullet hits player if (enemyBullet) { var dx = enemyBullet.x - player.x; var dy = enemyBullet.y - player.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < 120) { LK.getSound('hit').play(); player.ragdoll(enemyBullet.x, enemyBullet.y); game.removeChild(enemyBullet); enemyBullet = null; duelState = STATE_RESULT; statusTxt.setText("You were shot!"); statusTxt.visible = true; endRound(false); } } // Both bullets exist (simultaneous fire) if (playerBullet && enemyBullet) { // Check which bullet hits first var pdx = playerBullet.x - enemy.x; var pdy = playerBullet.y - enemy.y; var pdist = Math.sqrt(pdx * pdx + pdy * pdy); var edx = enemyBullet.x - player.x; var edy = enemyBullet.y - player.y; var edist = Math.sqrt(edx * edx + edy * edy); if (pdist < 120 && edist < 120) { // Both hit at same time: draw LK.getSound('hit').play(); player.ragdoll(); enemy.ragdoll(); game.removeChild(playerBullet); game.removeChild(enemyBullet); playerBullet = null; enemyBullet = null; duelState = STATE_RESULT; statusTxt.setText("Draw!\nBoth shot!"); statusTxt.visible = true; endRound(false); } else if (pdist < 120) { LK.getSound('hit').play(); enemy.ragdoll(playerBullet.x, playerBullet.y); game.removeChild(playerBullet); playerBullet = null; duelState = STATE_RESULT; statusTxt.setText("You Win the Duel!"); statusTxt.visible = true; endRound(true); } else if (edist < 120) { LK.getSound('hit').play(); player.ragdoll(enemyBullet.x, enemyBullet.y); game.removeChild(enemyBullet); enemyBullet = null; duelState = STATE_RESULT; statusTxt.setText("You were shot!"); statusTxt.visible = true; endRound(false); } } // Remove bullets if off screen if (playerBullet && (playerBullet.x < 0 || playerBullet.x > 2048 || playerBullet.y < 0 || playerBullet.y > 2732)) { game.removeChild(playerBullet); playerBullet = null; // === COOLDOWN: Only allow new shot if cooldown expired === if (playerShotCooldown <= 0) { canShoot = true; } } if (enemyBullet && (enemyBullet.x < 0 || enemyBullet.x > 2048 || enemyBullet.y < 0 || enemyBullet.y > 2732)) { game.removeChild(enemyBullet); enemyBullet = null; enemyShot = false; // yeni atışa izin ver } } // ==== FIX #2 : holster konumu ==== // Use two holster sprites: full and empty, toggle visibility var holsterFull = LK.getAsset('kilif', { width: 300, height: 300, anchorX: -0.2, anchorY: 0 }); var holsterEmpty = LK.getAsset('kilifbos', { width: 300, height: 300, anchorX: -0.2, anchorY: 0 }); holsterFull.visible = true; holsterEmpty.visible = false; var holsterOffset = 250; holsterFull.x = player.x - 200; holsterFull.y = player.y + player.body.height / 2 + holsterOffset; holsterEmpty.x = holsterFull.x; holsterEmpty.y = holsterFull.y; world.addChild(holsterFull); world.addChild(holsterEmpty); // === Place enemygunpocket in the middle of the screen === var enemygunpocket = LK.getAsset('enemygunpocket', { anchorX: 0.5, anchorY: 0.5 }); enemygunpocket.x = 2048 / 2 + 550 + 50 - 30 - 5 - 5; enemygunpocket.y = 2732 / 2 - 600 + 150 + 10; world.addChild(enemygunpocket); // Helper: check if global point is inside holsterFull's bounds (always use holsterFull for hit area) function holsterContains(globalX, globalY) { // Global (stage) → world-içi (local) koordinata çevir var localX = (globalX - world.x) / world.scaleX; var localY = (globalY - world.y) / world.scaleY; // kilif sprite’ının local kutusu var b = { x: holsterFull.x, y: holsterFull.y, w: holsterFull.width, h: holsterFull.height }; return localX >= b.x && localX <= b.x + b.w && localY >= b.y && localY <= b.y + b.h; } // Holster hold/zoom/duel state var zoomFinished = false, duelStarted = false, holsterHoldTime = 0; var playerReady = false; var holdingHolster = false; // Track if holster is being held var musicTimeout = null; // Timer for music/draw phase function beginHold() { if (musicTimeout) { LK.clearTimeout(musicTimeout); } var extra = 4000 + Math.random() * 6000; // 4-10 s musicTimeout = LK.setTimeout(stopMusicAndDraw, extra); } function cancelHold() { if (musicTimeout) { LK.clearTimeout(musicTimeout); } musicTimeout = null; } function stopMusicAndDraw() { LK.stopMusic(); // müzik sustu if (enemygunpocket && enemygunpocket.visible !== false) { enemygunpocket.visible = false; } duelStarted = true; // <-- ERKEN KAYIP KONTROLÜ ARTIK PASİF holsterHoldTime = 0; // güvenlik: sayaç sıfırla startDraw(); // DRAW fazına geç } // Touch/click to fire or start holster hold game.down = function (x, y, obj) { // No fire until duel actually started if (zoomFinished && !duelStarted && holsterContains(x, y)) { playerReady = true; holdingHolster = true; // holster pressed player.toHand(); // ← kılıftan çek (hemen ele ver) // Play holdsound when gun is drawn to hand LK.getSound('holdsound').play(); // --- holster assetini kilifbos ile değiştir (Çözüm 2: iki sprite, görünürlük) --- holsterFull.visible = false; holsterEmpty.visible = true; pointGunAt(x, y); // artık global ve erişilebilir beginHold(); // HOLD başlatılırken zamanlayıcı kuruluyor return; } if (!duelStarted) { return; } if (duelState === STATE_DRAW && canShoot && aimActive) { playerFire(x, y); } else if (duelState === STATE_WAIT && !playerShot) { playerFire(x, y); } }; // On pointer up, check for early leave from holster // ==== FIX #4c : tetikleyici ===== game.up = function (x, y, obj) { // HOLSTER EARLY RELEASE CHECK holdingHolster = false; // holster released cancelHold(); // el çekildi, zamanlayıcı iptal if (!duelStarted && playerReady && duelState === STATE_WAIT) { earlyLose(); return; } if (duelState === STATE_DRAW && canShoot) { playerFire(x, y); return; } }; // Move reticle with finger (optional: drag to aim) game.move = function (x, y, obj) { // Holster hold/early leave logic if (zoomFinished && !duelStarted) { if (holsterContains(x, y)) { // handled in update for dt-accurate timing } else if (holdingHolster) { cancelHold(); earlyLose(); } } // (aim reticle removed) // Namlu her zaman fareyi izlesin (DRAW’tan önce holster tutulurken de) pointGunAt(x, y); }; /**** GLOBAL YARDIMCI : Silahı imlece çevir ****/ function pointGunAt(globalX, globalY) { // 1) Omuz pivotu – dünya koordinatı var shX = player.x + player.rarm.x; var shY = player.y + player.rarm.y; // 2) Omuz → imleç vektörü ve açı (0 rad = sağ) var dx = globalX - shX; var dy = globalY - shY; var ang = Math.atan2(dy, dx); // 3) Kol sprite’ı AŞAĞI bakıyor → –90° (-π/2) düzelt var armRot = ang - Math.PI / 2; player.rarm.rotation = armRot; // 4) El / silah konumu (player LOCAL) var L = player.rarm.height; // ≈110 px // ❗️ Doğru ofset: (-sin, +cos) player.gun.x = player.rarm.x - Math.sin(armRot) * L; player.gun.y = player.rarm.y + Math.cos(armRot) * L; // 5) Silah namlu yönü if (!duelStarted && holsterContains(globalX, globalY)) { player.gun.rotation = Math.PI / 2; // kılıfta ⇒ namlu yere } else { player.gun.rotation = ang; // hedefe bak } } /**** GLOBAL : Enemy silahını hedefe çevir ****/ function aimEnemyGunAt(globalX, globalY) { // 1) Omuz pivotu (world) var shX = enemy.x + enemy.rarm.x; var shY = enemy.y + enemy.rarm.y; // 2) Omuz→hedef vektörü var dx = globalX - shX; var dy = globalY - shY; var ang = Math.atan2(dy, dx); // 3) Kol sprite’ı AŞAĞI bakıyor → –90° (–π/2) düzeltme var armRot = ang - Math.PI / 2; enemy.rarm.rotation = armRot; // 4) El / silah konumu (enemy LOCAL) **ayna!** var L = enemy.rarm.height; // ≈145 px enemy.gun.x = enemy.rarm.x - Math.sin(armRot) * L; enemy.gun.y = enemy.rarm.y + Math.cos(armRot) * L; // 5) Namluyu hedefe döndür enemy.gun.rotation = ang; } // Helper to update holster box position under player's feet function updateHolsterBox() { holsterFull.x = player.x - 200; holsterFull.y = player.y + player.body.height / 2 + holsterOffset; holsterEmpty.x = holsterFull.x; holsterEmpty.y = holsterFull.y; } // Main update loop game.update = function (dt) { // Move enemygun assets in pocket 5px down and 10px left when music is not stopped if (LK.musicPlaying && enemygunpocket) { enemygunpocket.x = 2048 / 2 + 550 + 50 - 30 - 5 - 5 - 10; // 10px more left enemygunpocket.y = 2732 / 2 - 600 + 150 + 10 + 5; // 5px more down } // Hide status text during zoom-in if (!zoomFinished) { statusTxt.visible = false; return; } // Always update holster position to follow player updateHolsterBox(); // (aim reticle removed) // Rakip silahı eldeyse oyuncuyu takip etsin if (enemy.gun.visible) { aimEnemyGunAt(player.x, player.y - 40); } // Animate bullets if (playerBullet) { playerBullet.update(); } if (enemyBullet) { enemyBullet.update(); } // === PLAYER SHOT COOLDOWN TIMER === if (playerShotCooldown > 0) { var dtMs = typeof dt === "number" ? dt : 16.7; playerShotCooldown -= dtMs; if (playerShotCooldown < 0) { playerShotCooldown = 0; } } // Check for bullet collisions checkBullets(); // ==== FIX #3 : statusTxt ayarı ==== // Holster hold logic after zoom if (zoomFinished && !duelStarted) { // Use pointerX/Y for current pointer var px = typeof game.pointerX === "number" ? game.pointerX : 0; var py = typeof game.pointerY === "number" ? game.pointerY : 0; var dtMs = typeof dt === "number" ? dt : 16.7; if (holsterContains(px, py) && holdingHolster) { holsterHoldTime += dtMs; } else { if (holsterHoldTime > 0 && holdingHolster) { earlyLose(); } holsterHoldTime = 0; } if (!duelStarted) { if (!playerReady) { statusTxt.setText("Hold holster to start duel"); } else { statusTxt.setText("Wait for music to end…\nthen aim & release"); } } // if (holsterHoldTime >= 4000 && !duelStarted) { // duelStarted = true; // holsterHoldTime = 0; // resetDuel(); // } statusTxt.visible = true; } else { if (duelState === STATE_DRAW) { statusTxt.setText("Aim and SHOOT!"); } statusTxt.visible = true; } }; // Early lose function function earlyLose() { if (duelState === STATE_RESULT) { return; } // only trigger once holdingHolster = false; holsterHoldTime = 0; duelStarted = false; LK.stopMusic(); if (drawTimeout) { LK.clearTimeout(drawTimeout); } statusTxt.setText("Too early!\nYou lose!"); statusTxt.visible = true; LK.getSound('gunshot').play(); // yere ateş LK.getSound('fail').play(); // Optionally, also play gunshot sound: // LK.getSound('gunshot').play(); // Show game over after 1 second LK.setTimeout(function () { LK.showGameOver(); }, 1000); } // Camera zoom-in before duel starts function startZoomIn(music) { // ==== FIX #1b : zoom fonksiyonunda ==== var startScale = 0.4; world.scaleX = world.scaleY = startScale; world.x = centerX * (1 - startScale); world.y = 2732 / 2 * (1 - startScale); LK.playMusic(music || 'duelmusic'); tween(world, { scaleX: 1, scaleY: 1, x: 0, y: 0 }, { duration: 4000, easing: tween.quadInOut, onFinish: function onFinish() { zoomFinished = true; } }); } // Start zoom-in and music immediately on boot startZoomIn();
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Bullet class
var Bullet = Container.expand(function () {
var self = Container.call(this);
var bullet = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 0;
self.dirX = 0;
self.dirY = 0;
self.update = function () {
self.x += self.dirX * self.speed;
self.y += self.dirY * self.speed;
};
return self;
});
// Enemy class
var Enemy = Container.expand(function () {
var self = Container.call(this);
// Attach enemybottomthing as a child of enemy
var enemybottomthing = self.attachAsset('bottomthingenemy', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: 80 // moved 10px up from previous (90 -> 80)
});
// Legs
var lleg = self.attachAsset('enemyLeg', {
anchorX: 0.5,
anchorY: 0,
x: -140 / 4 + 5 - 5,
// moved 5px left
// use width of enemyBody (140) since body not yet defined
y: 180 / 2 - 15 - 3 // use height of enemyBody (180)
});
var rleg = self.attachAsset('enemyLeg', {
anchorX: 0.5,
anchorY: 0,
x: 140 / 4 + 5 - 5,
// moved 5px left
y: 180 / 2 - 15 - 3
});
// Left Arm
var larm = self.attachAsset('enemyArm', {
anchorX: 0.5,
anchorY: 0,
x: -140 / 2 + 5 + 10,
// use width of enemyBody (140) since body not yet defined
// 10px right
// 5px closer to body, 10px right
y: -80 //{t} // 30px up (10px further down)
});
// Body
var body = self.attachAsset('enemyBody', {
anchorX: 0.5,
anchorY: 0.5,
x: 10,
y: -15 //{h} // 5px daha aşağı, 10px sağa taşındı
});
// Head
var head = self.attachAsset('enemyHead', {
anchorX: 0.5,
anchorY: 0.5,
x: -4 + 5 - 4,
// 4px left from previous
// 5px right, 4px left
y: -body.height / 2 - 45 - 4 - 5 - 4 // 4px up from previous
});
// Right Arm (gun hand)
var rarm = self.attachAsset('enemyArm', {
anchorX: 0.5,
anchorY: 0,
x: body.width / 2 - 5,
// 5px closer to body
y: -80 //{z} // 30px up (10px further down)
});
// Legs
var lleg = self.attachAsset('enemyLeg', {
anchorX: 0.5,
anchorY: 0,
x: -body.width / 4 + 5 - 5 + 3,
// moved 5px left, now 3px right
y: body.height / 2 - 15 - 3 //{z} // 3px up
});
var rleg = self.attachAsset('enemyLeg', {
anchorX: 0.5,
anchorY: 0,
x: body.width / 4 + 5 - 5 + 3,
// moved 5px left, now 3px right
y: body.height / 2 - 15 - 3 //{E} // 3px up
});
// Gun (in hand)
var gun = self.attachAsset('enemyGun', {
anchorX: 0.5,
// 0.5 yerine 0.5
anchorY: 0.5,
x: rarm.x,
y: rarm.y + rarm.height,
rotation: 0
});
// Holster gun (on hip, always visible unless drawn)
var hipGun = self.attachAsset('enemyGun', {
anchorX: 0.5,
anchorY: 0.5,
x: body.width / 2 + 8 - 10 - 5 - 10,
// 5px further left
// 10px further left, 5px more left, 10px more left
y: body.height / 2 - 22 + 15 + 10 + 3,
// 3px further down
// 10px further down, 3px more down
rotation: Math.PI / 2
});
// Start with gun in holster, hand empty
gun.visible = false;
hipGun.visible = true;
// Helper methods to switch gun/holster visibility
self.toHolster = function () {
hipGun.visible = true;
gun.visible = false;
};
self.toHand = function () {
hipGun.visible = false;
gun.visible = true;
};
self.bodyParts = [body, head, larm, rarm, lleg, rleg, gun];
self.gun = gun;
self.rarm = rarm;
self.head = head;
self.body = body;
self.ragdoll = function (hitX, hitY) {
for (var i = 0; i < self.bodyParts.length; i++) {
var part = self.bodyParts[i];
tween(part, {
rotation: (Math.random() - 0.5) * 2.5,
x: part.x + (Math.random() - 0.5) * 200,
y: part.y + (Math.random() - 0.5) * 200
}, {
duration: 600,
delay: i * 30,
easing: tween.elasticOut
});
}
};
self.resetPose = function () {
// Body
body.x = 10;
body.y = -15;
body.rotation = 0;
// Head (use constant offset, not accumulated)
head.x = 0;
head.y = -body.height / 2 - 45; // SABİT offset, yukarı kayma engellendi
head.rotation = 0;
// Left Arm
larm.x = -body.width / 2 + 5 + 10;
larm.y = -80;
larm.rotation = 0;
// Right Arm
rarm.x = body.width / 2 - 5;
rarm.y = -80;
rarm.rotation = 0;
// Left Leg
lleg.x = -body.width / 4 + 5 - 5 + 3;
lleg.y = body.height / 2 - 15 - 3;
lleg.rotation = 0;
// Right Leg
rleg.x = body.width / 4 + 5 - 5 + 3;
rleg.y = body.height / 2 - 15 - 3;
rleg.rotation = 0;
// Gun (in hand)
gun.x = rarm.x;
gun.y = rarm.y + rarm.height;
gun.rotation = 0;
// Hip gun (holster)
if (typeof hipGun !== "undefined") {
hipGun.x = body.width / 2 + 8 - 10 - 5 - 10;
hipGun.y = body.height / 2 - 22 + 15 + 10 + 3;
hipGun.rotation = Math.PI / 2;
}
self.toHolster(); // always start with gun in holster
};
return self;
});
// Player class
var Player = Container.expand(function () {
var self = Container.call(this);
// Head
var head = self.attachAsset('playerHead', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: -160 / 2 - 45 - 20 // use playerBody height (160) since body not yet defined, moved 25px up
});
// Body
var body = self.attachAsset('playerBody', {
anchorX: 0.5,
anchorY: 0.5,
x: -12,
y: 10 //{1U} // moved 15px down, 5px left from previous
});
// bottomthingplayer as child of player, 75px down (moved 15px further down)
var bottomthingplayer = self.attachAsset('bottomthingplayer', {
anchorX: 0.5,
anchorY: 0.5,
x: -5,
//{21} // moved 5px left
y: 101 // moved 6px further down (95+6)
});
// Left Arm
var larm = self.attachAsset('playerArm', {
anchorX: 0.5,
anchorY: 0,
x: -body.width / 2 - 10 - 5 + 5 + 7 + 3,
// move 3px right
// move 5px right, 7px more right, 3px more right
y: -100 + 10 + 10 + 15,
// move 15px down
// move 10px down, 15px more down
zIndex: -1 // ensure arm is behind body (if zIndex is supported)
});
// Move left arm behind body in display list
if (typeof self.setChildIndex === "function") {
self.setChildIndex(larm, 0);
}
// Right Arm (gun hand)
var rarm = self.attachAsset('playerArm', {
anchorX: 0.5,
anchorY: 0,
x: body.width / 2 + 10 - 5 - 20 - 5 - 10,
// 10px more left
y: -100 + 10 + 15 + 10 //{1Y} // 10px more down, 15px more down, 10px more down
});
// Legs
var lleg = self.attachAsset('playerLeg', {
anchorX: 0.5,
anchorY: 0,
x: -body.width / 4 - 10 + 3 + 10,
// moved 10px right
// move 3px right (total 6px closer)
// 10px left, 3px right, 10px right
y: body.height / 2 - 10 + 10 // 10px down
});
var rleg = self.attachAsset('playerLeg', {
anchorX: 0.5,
anchorY: 0,
x: body.width / 4 - 10 - 3,
// move 3px left (total 6px closer)
// 10px left, 3px left
y: body.height / 2 - 10 + 10 // 10px down
});
// Gun (in hand)
var gun = self.attachAsset('playerGun', {
anchorX: 0.5,
// 0.5 yerine 0.5
anchorY: 0.5,
x: rarm.x - 20,
//{2m} // 20px left
y: rarm.y + rarm.height + 5,
//{2n} // 5px down
rotation: 0
});
// Holster gun (on hip, always visible unless drawn)
var hipGun = self.attachAsset('playerGun', {
anchorX: 0.5,
anchorY: 0.5,
x: body.width / 2 + -28,
y: body.height / 2 - -12,
rotation: Math.PI / 2
});
// Start with gun in holster, hand empty
gun.visible = false;
hipGun.visible = true;
// Helper methods to switch gun/holster visibility
self.toHolster = function () {
hipGun.visible = true;
gun.visible = false;
};
self.toHand = function () {
hipGun.visible = false;
gun.visible = true;
};
// Used for ragdoll effect
self.bodyParts = [body, head, larm, rarm, lleg, rleg, gun];
// Used for aiming
self.gun = gun;
self.rarm = rarm;
// Used for hit detection
self.head = head;
self.body = body;
// Used for ragdoll
self.ragdoll = function (hitX, hitY) {
// Animate all parts to random positions/rotations
for (var i = 0; i < self.bodyParts.length; i++) {
var part = self.bodyParts[i];
tween(part, {
rotation: (Math.random() - 0.5) * 2.5,
x: part.x + (Math.random() - 0.5) * 200,
y: part.y + (Math.random() - 0.5) * 200
}, {
duration: 600,
delay: i * 30,
easing: tween.elasticOut
});
}
};
// Reset pose
self.resetPose = function () {
// Body
body.x = -12;
body.y = 10;
body.rotation = 0;
// Head (use constant offset, not accumulated)
head.x = 0;
head.y = -body.height / 2 - 45; // SABİT offset, yukarı kayma engellendi
head.rotation = 0;
// Left Arm
larm.x = -body.width / 2 - 10 - 5 + 5 + 7 + 3;
larm.y = -100 + 10 + 10 + 15;
larm.rotation = 0;
// Move left arm behind body in display list
if (typeof self.setChildIndex === "function") {
self.setChildIndex(larm, 0);
}
// Right Arm
rarm.x = body.width / 2 + 10 - 5 - 20 - 5 - 10;
rarm.y = -100 + 10 + 15 + 10;
rarm.rotation = 0;
// Left Leg
lleg.x = -body.width / 4 - 10 + 3 + 10;
lleg.y = body.height / 2 - 10 + 10;
lleg.rotation = 0;
// Right Leg
rleg.x = body.width / 4 - 10 - 3;
rleg.y = body.height / 2 - 10 + 10;
rleg.rotation = 0;
// Gun (in hand)
gun.x = rarm.x - 20;
gun.y = rarm.y + rarm.height + 5;
gun.rotation = 0;
// Move bottomthingplayer 6px further down and 5px left
if (typeof bottomthingplayer !== "undefined") {
bottomthingplayer.x = -5;
bottomthingplayer.y = 101;
}
self.toHolster(); // always start with gun in holster
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2e1a09
});
/****
* Game Code
****/
// Player and enemy bodies (torso, head, arms, legs) as simple shapes
// Game state
var STATE_WAIT = 0;
var STATE_DRAW = 1;
var STATE_SHOT = 2;
var STATE_RESULT = 3;
var duelState = STATE_WAIT;
var canShoot = false;
var playerShot = false;
var enemyShot = false;
var playerBullet = null;
var enemyBullet = null;
var duelTimer = null;
var drawTimeout = null;
var resultTimeout = null;
var duelStartTime = 0;
var playerShotTime = 0;
var enemyShotTime = 0;
var aimX = 0;
var aimY = 0;
var aimRadius = 180;
var aimAngle = 0;
var aimSpeed = 0.018; // %30 daha yavaş
var aimDir = 1;
var aimActive = false;
var playerScore = 0;
var roundNum = 1;
var maxRounds = 5;
// === GLOBAL SHOT COUNTERS ===
var playerShotsFiredCnt = 0;
var enemyShotsFiredCnt = 0;
// === PLAYER SHOT COOLDOWN ===
var playerShotCooldown = 0; // ms left until next shot allowed
var enemyData = [{
name: "Greenhorn",
minReact: 3.0,
maxReact: 3.4,
coneStart: 42,
coneEnd: 0
}, {
name: "Billy the Kid",
minReact: 2.4,
maxReact: 2.7,
coneStart: 36,
coneEnd: 0
}, {
name: "Doc Holliday",
minReact: 1.6,
maxReact: 1.9,
coneStart: 30,
coneEnd: 0
}, {
name: "Calamity Jane",
minReact: 1.0,
maxReact: 1.3,
coneStart: 24,
coneEnd: 0
}, {
name: "The Undertaker",
minReact: 0.6,
maxReact: 0.8,
coneStart: 18,
coneEnd: 0,
scale: 1.5
}];
var currentEnemy = null;
// ==== FIX #1 : SAHNENİN BAŞINDA ====
var world = new Container();
game.addChild(world);
// Add arkaplan background image centered in the screen
var arkaplan = LK.getAsset('arkaplan', {
anchorX: 0.5,
anchorY: 0.5
});
arkaplan.x = 2048 / 2;
arkaplan.y = 2732 / 2;
world.addChild(arkaplan);
// Player and enemy
var player = new Player();
var enemy = new Enemy();
world.addChild(player);
world.addChild(enemy);
// Center positions
var centerX = 2048 / 2;
var playerY = 2732 * 0.7;
var enemyY = 2732 * 0.3;
// 6-bullet UI for player and enemy
var playerAmmoUI = [];
var enemyAmmoUI = [];
function setupAmmoUI() {
// Remove old UI if any
for (var i = 0; i < playerAmmoUI.length; i++) {
if (playerAmmoUI[i].parent) {
playerAmmoUI[i].parent.removeChild(playerAmmoUI[i]);
}
}
for (var i = 0; i < enemyAmmoUI.length; i++) {
if (enemyAmmoUI[i].parent) {
enemyAmmoUI[i].parent.removeChild(enemyAmmoUI[i]);
}
}
playerAmmoUI = [];
enemyAmmoUI = [];
for (var i = 0; i < 6; i++) {
var px = player.x - 120 + i * 40;
var ex = enemy.x - 120 + i * 40;
var bulletP = LK.getAsset('bullet', {
scaleX: 0.6,
scaleY: 0.6,
anchorX: 0.5,
anchorY: 0.5
});
var bulletE = LK.getAsset('bullet', {
scaleX: 0.6,
scaleY: 0.6,
anchorX: 0.5,
anchorY: 0.5
});
bulletP.y = player.y + 250 + 60;
// Düşman: yalnızca 5. raundda 75 px yukarı
var enemyExtraY = roundNum === 5 ? -75 : 0;
bulletE.y = enemy.y - 250 + enemyExtraY;
bulletP.x = px;
bulletE.x = ex;
// HUD’u world içine koy ki zoom animasyonuyla birlikte büyüsün
world.addChild(bulletP);
world.addChild(bulletE);
playerAmmoUI.push(bulletP);
enemyAmmoUI.push(bulletE);
}
}
// Position player and enemy
player.x = centerX - 500;
player.y = playerY;
enemy.x = centerX + 500;
enemy.y = enemyY;
// Score text
var scoreTxt = new Text2('Score: 0', {
size: 90,
fill: 0xFFF7D6
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Round text
var roundTxt = new Text2('', {
size: 70,
fill: 0xFFE4B5
});
roundTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(roundTxt);
roundTxt.y = 110;
// Duel status text
var statusTxt = new Text2('', {
size: 110,
fill: 0xFFECB3
});
statusTxt.anchor.set(0.5, 0.5);
LK.gui.center.addChild(statusTxt);
// (Aim reticle removed)
// Helper: reset all state for a new round
function resetDuel() {
duelState = STATE_WAIT;
canShoot = false;
playerShot = false;
enemyShot = false;
playerBullet = null;
enemyBullet = null;
duelStartTime = 0;
playerShotTime = 0;
enemyShotTime = 0;
aimAngle = Math.random() * Math.PI * 2;
aimDir = Math.random() > 0.5 ? 1 : -1;
aimActive = false;
// (aimReticle removed)
player.resetPose();
enemy.resetPose();
player.toHolster();
enemy.toHolster();
holsterFull.visible = true;
holsterEmpty.visible = false;
setupAmmoUI();
// === RESET SHOT COUNTERS ===
playerShotsFiredCnt = 0;
enemyShotsFiredCnt = 0;
// === RESET HOLSTER FLAGS ===
playerReady = false; // yeni ← round’a nötr gir
holdingHolster = false; // yeni
holsterHoldTime = 0; // güvenlik
duelStarted = false; // <-- YENİ: her raunda nötr gir
cancelHold(); // 1. raunddan kalma musicTimeout varsa temizle
zoomFinished = false; // yeni animasyona hazırlan
var roundMusic = roundNum === 1 ? 'duelmusic' : roundNum === 2 ? 'round2music' : roundNum === 3 ? 'round3music' : roundNum === 4 ? 'round4music' : 'round5music';
startZoomIn(roundMusic);
statusTxt.setText("Wait for the music...");
statusTxt.visible = true;
// Set up enemy for this round
currentEnemy = enemyData[roundNum - 1];
roundTxt.setText("Round " + roundNum + ": " + currentEnemy.name);
// Boss scale (if any)
enemy.scaleX = enemy.scaleY = currentEnemy.scale || 1;
// Play duel music
// (music now only plays during zoom-in, do not play here)
// drawTimeout is now set after zoom-in, not here
if (drawTimeout) {
LK.clearTimeout(drawTimeout);
}
}
// Start the "DRAW!" phase
function startDraw() {
if (!playerReady) {
earlyLose();
return;
}
duelState = STATE_DRAW;
canShoot = true;
aimActive = true;
// (aimReticle removed)
statusTxt.setText("DRAW!");
statusTxt.visible = true;
LK.stopMusic();
LK.getSound('draw').play();
player.toHand(); // draw from holster
enemy.toHand(); // enemy draws too
aimEnemyGunAt(player.x, player.y - 40); // hemen hizala
duelStartTime = Date.now();
// Enemy will shoot after their reaction time
var reactTime = 1200; // fallback default
if (currentEnemy && typeof currentEnemy.minReact === "number" && typeof currentEnemy.maxReact === "number") {
reactTime = 1000 * (currentEnemy.minReact + Math.random() * (currentEnemy.maxReact - currentEnemy.minReact));
reactTime *= 0.425; // %57.5 daha hızlı tepki (eski 0.5 ve yeni 0.35 arası)
}
if (duelTimer) {
LK.clearTimeout(duelTimer);
}
duelTimer = LK.setTimeout(enemyFire, reactTime);
}
// Player fires
function playerFire(x, y) {
// 6 mermi limiti
if (playerShotsFiredCnt >= 6) {
statusTxt.setText("Out of ammo!");
statusTxt.visible = true;
return;
}
if (!canShoot) {
return;
}
// === COOLDOWN: Block if cooldown active ===
if (playerShotCooldown > 0) {
return;
}
playerShot = true;
playerShotsFiredCnt++; // sayaç ↑
playerShotTime = Date.now();
// === COOLDOWN: Set cooldown after shot ===
playerShotCooldown = 300; // 0.3 seconds in ms
// Animate gun
tween(player.gun, {
rotation: -0.5
}, {
duration: 80,
easing: tween.cubicOut
});
tween(player.rarm, {
rotation: -0.3
}, {
duration: 80,
easing: tween.cubicOut
});
LK.getSound('gunshot').play();
// Create bullet
playerBullet = new Bullet();
// Muzzle position helper
function muzzlePos() {
// Use full gun width/height for muzzle (center anchor)
var gunW = player.gun.width || 60;
var gunH = player.gun.height || 15;
return {
x: player.x + player.gun.x + Math.cos(player.gun.rotation) * gunW,
y: player.y + player.gun.y + Math.sin(player.gun.rotation) * gunH
};
}
var muzzle = muzzlePos();
playerBullet.x = muzzle.x;
playerBullet.y = muzzle.y;
// Ateş anındaki imleç (x, y) fonksiyona zaten parametre olarak geliyor
var dx = x - muzzle.x;
var dy = y - muzzle.y;
var dist = Math.sqrt(dx * dx + dy * dy);
playerBullet.dirX = dx / dist;
playerBullet.dirY = dy / dist;
playerBullet.speed = 60;
game.addChild(playerBullet);
// Decrement player bullet UI
for (var i = 0; i < playerAmmoUI.length; i++) {
if (playerAmmoUI[i].visible !== false) {
playerAmmoUI[i].visible = false;
break;
}
}
// If shot before draw, instant loss
if (duelState === STATE_WAIT) {
duelState = STATE_RESULT;
statusTxt.setText("You shot too early!\nYou Lose!");
statusTxt.visible = true;
LK.getSound('fail').play();
player.ragdoll();
enemy.ragdoll();
endRound(false);
return;
}
// bir sonraki mermiye izin ver
if (duelState === STATE_DRAW && playerShotsFiredCnt < 6) {
canShoot = true;
aimActive = true;
// (aimReticle removed)
}
// DRAW fazı açık kalsın ki 6 mermi bitene kadar tekrar tekrar ateş edebilelim
}
// Enemy fires
function enemyFire() {
var _currentEnemy;
if (enemyShotsFiredCnt >= 6 || duelState === STATE_RESULT) {
return;
}
if (!enemyShot) {
enemyShot = true;
} // ilk mermi için eski bayrak
enemyShotsFiredCnt++;
enemyShotTime = Date.now();
// Ateşten önce hedefe çevir
aimEnemyGunAt(player.x, player.y - 40);
// Animate gun
tween(enemy.gun, {
rotation: 0.5
}, {
duration: 80,
easing: tween.cubicOut
});
tween(enemy.rarm, {
rotation: 0.3
}, {
duration: 80,
easing: tween.cubicOut
});
LK.getSound('gunshot').play();
// Create bullet
enemyBullet = new Bullet();
var gunW = enemy.gun.width || 60;
var gunH = enemy.gun.height || 18;
enemyBullet.x = enemy.x + enemy.gun.x + Math.cos(enemy.gun.rotation) * gunW;
enemyBullet.y = enemy.y + enemy.gun.y + Math.sin(enemy.gun.rotation) * gunH;
// Decrement enemy bullet UI
for (var i = 0; i < enemyAmmoUI.length; i++) {
if (enemyAmmoUI[i].visible !== false) {
enemyAmmoUI[i].visible = false;
break;
}
}
// Konik isabet modeliyle hedef seçimi
// 1️⃣ hedef vektörü
var baseDX = player.x - enemyBullet.x;
var baseDY = player.y - 40 - enemyBullet.y; // gövdenin biraz üstü
var baseAng = Math.atan2(baseDY, baseDX);
// 2️⃣ saçılma açısı (daralan koni)
var sIdx = enemyShotsFiredCnt; // 1-6
var sMax = 6;
var cStart = currentEnemy && typeof currentEnemy.coneStart === "number" ? currentEnemy.coneStart : 24; // fallback
var cEnd = currentEnemy && typeof currentEnemy.coneEnd === "number" ? currentEnemy.coneEnd : 0;
var coneDeg = cStart + (cEnd - cStart) * ((sIdx - 1) / (sMax - 1));
var coneRad = coneDeg * Math.PI / 180;
var isLast = sIdx === sMax; // son kurşun
var spread = isLast ? 0 : Math.random() * coneRad - coneRad / 2;
// 3️⃣ hedef noktasını diagramdaki yayı keserek bul
var range = 1500; // ekran dışına yeter
var targetX = enemyBullet.x + Math.cos(baseAng + spread) * range;
var targetY = enemyBullet.y + Math.sin(baseAng + spread) * range;
var dx = targetX - enemyBullet.x;
var dy = targetY - enemyBullet.y;
var dist = Math.sqrt(dx * dx + dy * dy);
enemyBullet.dirX = dx / dist;
enemyBullet.dirY = dy / dist;
enemyBullet.speed = 60;
game.addChild(enemyBullet);
// sonraki mermi (tak-tak) 0.6 sn sonra
if (enemyShotsFiredCnt < 6) {
LK.setTimeout(enemyFire, 600);
}
// Round oyuncu ateş etmediyse ANCAK bütün 6 mermi atıldıktan sonra
if (enemyShotsFiredCnt === 6 && !playerShot) {
// Son kurşunun ekrandan çıkması için çok kısa bir gecikme bırak
LK.setTimeout(function () {
if (duelState !== STATE_RESULT) {
duelState = STATE_RESULT;
statusTxt.setText("You Survived!");
statusTxt.visible = true;
endRound(true);
}
}, 350);
}
}
// End round, win: true/false
function endRound(win) {
canShoot = false;
aimActive = false;
// (aimReticle removed)
if (drawTimeout) {
LK.clearTimeout(drawTimeout);
}
if (duelTimer) {
LK.clearTimeout(duelTimer);
}
if (resultTimeout) {
LK.clearTimeout(resultTimeout);
}
drawTimeout = null;
duelTimer = null;
resultTimeout = null;
// Next round or end game
resultTimeout = LK.setTimeout(function () {
if (win) {
playerScore += 1;
scoreTxt.setText("Score: " + playerScore);
roundNum += 1;
if (roundNum > maxRounds) {
statusTxt.setText("You Win!\nScore: " + playerScore);
statusTxt.visible = true;
LK.showYouWin();
} else {
resetDuel();
}
} else {
statusTxt.setText("You Lose!\nScore: " + playerScore);
statusTxt.visible = true;
LK.showGameOver();
}
}, 1600);
}
// Handle aiming reticle movement (circular motion)
function updateAimReticle() {
// (aim reticle removed)
}
// Handle bullet collisions and duel result
function checkBullets() {
// Player bullet hits enemy
if (playerBullet) {
// Check if bullet reached enemy
var dx = playerBullet.x - enemy.x;
var dy = playerBullet.y - enemy.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < 120) {
// Hit!
LK.getSound('hit').play();
enemy.ragdoll(playerBullet.x, playerBullet.y);
game.removeChild(playerBullet);
playerBullet = null;
duelState = STATE_RESULT;
statusTxt.setText("You Win the Duel!");
statusTxt.visible = true;
endRound(true);
}
}
// Enemy bullet hits player
if (enemyBullet) {
var dx = enemyBullet.x - player.x;
var dy = enemyBullet.y - player.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < 120) {
LK.getSound('hit').play();
player.ragdoll(enemyBullet.x, enemyBullet.y);
game.removeChild(enemyBullet);
enemyBullet = null;
duelState = STATE_RESULT;
statusTxt.setText("You were shot!");
statusTxt.visible = true;
endRound(false);
}
}
// Both bullets exist (simultaneous fire)
if (playerBullet && enemyBullet) {
// Check which bullet hits first
var pdx = playerBullet.x - enemy.x;
var pdy = playerBullet.y - enemy.y;
var pdist = Math.sqrt(pdx * pdx + pdy * pdy);
var edx = enemyBullet.x - player.x;
var edy = enemyBullet.y - player.y;
var edist = Math.sqrt(edx * edx + edy * edy);
if (pdist < 120 && edist < 120) {
// Both hit at same time: draw
LK.getSound('hit').play();
player.ragdoll();
enemy.ragdoll();
game.removeChild(playerBullet);
game.removeChild(enemyBullet);
playerBullet = null;
enemyBullet = null;
duelState = STATE_RESULT;
statusTxt.setText("Draw!\nBoth shot!");
statusTxt.visible = true;
endRound(false);
} else if (pdist < 120) {
LK.getSound('hit').play();
enemy.ragdoll(playerBullet.x, playerBullet.y);
game.removeChild(playerBullet);
playerBullet = null;
duelState = STATE_RESULT;
statusTxt.setText("You Win the Duel!");
statusTxt.visible = true;
endRound(true);
} else if (edist < 120) {
LK.getSound('hit').play();
player.ragdoll(enemyBullet.x, enemyBullet.y);
game.removeChild(enemyBullet);
enemyBullet = null;
duelState = STATE_RESULT;
statusTxt.setText("You were shot!");
statusTxt.visible = true;
endRound(false);
}
}
// Remove bullets if off screen
if (playerBullet && (playerBullet.x < 0 || playerBullet.x > 2048 || playerBullet.y < 0 || playerBullet.y > 2732)) {
game.removeChild(playerBullet);
playerBullet = null;
// === COOLDOWN: Only allow new shot if cooldown expired ===
if (playerShotCooldown <= 0) {
canShoot = true;
}
}
if (enemyBullet && (enemyBullet.x < 0 || enemyBullet.x > 2048 || enemyBullet.y < 0 || enemyBullet.y > 2732)) {
game.removeChild(enemyBullet);
enemyBullet = null;
enemyShot = false; // yeni atışa izin ver
}
}
// ==== FIX #2 : holster konumu ====
// Use two holster sprites: full and empty, toggle visibility
var holsterFull = LK.getAsset('kilif', {
width: 300,
height: 300,
anchorX: -0.2,
anchorY: 0
});
var holsterEmpty = LK.getAsset('kilifbos', {
width: 300,
height: 300,
anchorX: -0.2,
anchorY: 0
});
holsterFull.visible = true;
holsterEmpty.visible = false;
var holsterOffset = 250;
holsterFull.x = player.x - 200;
holsterFull.y = player.y + player.body.height / 2 + holsterOffset;
holsterEmpty.x = holsterFull.x;
holsterEmpty.y = holsterFull.y;
world.addChild(holsterFull);
world.addChild(holsterEmpty);
// === Place enemygunpocket in the middle of the screen ===
var enemygunpocket = LK.getAsset('enemygunpocket', {
anchorX: 0.5,
anchorY: 0.5
});
enemygunpocket.x = 2048 / 2 + 550 + 50 - 30 - 5 - 5;
enemygunpocket.y = 2732 / 2 - 600 + 150 + 10;
world.addChild(enemygunpocket);
// Helper: check if global point is inside holsterFull's bounds (always use holsterFull for hit area)
function holsterContains(globalX, globalY) {
// Global (stage) → world-içi (local) koordinata çevir
var localX = (globalX - world.x) / world.scaleX;
var localY = (globalY - world.y) / world.scaleY;
// kilif sprite’ının local kutusu
var b = {
x: holsterFull.x,
y: holsterFull.y,
w: holsterFull.width,
h: holsterFull.height
};
return localX >= b.x && localX <= b.x + b.w && localY >= b.y && localY <= b.y + b.h;
}
// Holster hold/zoom/duel state
var zoomFinished = false,
duelStarted = false,
holsterHoldTime = 0;
var playerReady = false;
var holdingHolster = false; // Track if holster is being held
var musicTimeout = null; // Timer for music/draw phase
function beginHold() {
if (musicTimeout) {
LK.clearTimeout(musicTimeout);
}
var extra = 4000 + Math.random() * 6000; // 4-10 s
musicTimeout = LK.setTimeout(stopMusicAndDraw, extra);
}
function cancelHold() {
if (musicTimeout) {
LK.clearTimeout(musicTimeout);
}
musicTimeout = null;
}
function stopMusicAndDraw() {
LK.stopMusic(); // müzik sustu
if (enemygunpocket && enemygunpocket.visible !== false) {
enemygunpocket.visible = false;
}
duelStarted = true; // <-- ERKEN KAYIP KONTROLÜ ARTIK PASİF
holsterHoldTime = 0; // güvenlik: sayaç sıfırla
startDraw(); // DRAW fazına geç
}
// Touch/click to fire or start holster hold
game.down = function (x, y, obj) {
// No fire until duel actually started
if (zoomFinished && !duelStarted && holsterContains(x, y)) {
playerReady = true;
holdingHolster = true; // holster pressed
player.toHand(); // ← kılıftan çek (hemen ele ver)
// Play holdsound when gun is drawn to hand
LK.getSound('holdsound').play();
// --- holster assetini kilifbos ile değiştir (Çözüm 2: iki sprite, görünürlük) ---
holsterFull.visible = false;
holsterEmpty.visible = true;
pointGunAt(x, y); // artık global ve erişilebilir
beginHold(); // HOLD başlatılırken zamanlayıcı kuruluyor
return;
}
if (!duelStarted) {
return;
}
if (duelState === STATE_DRAW && canShoot && aimActive) {
playerFire(x, y);
} else if (duelState === STATE_WAIT && !playerShot) {
playerFire(x, y);
}
};
// On pointer up, check for early leave from holster
// ==== FIX #4c : tetikleyici =====
game.up = function (x, y, obj) {
// HOLSTER EARLY RELEASE CHECK
holdingHolster = false; // holster released
cancelHold(); // el çekildi, zamanlayıcı iptal
if (!duelStarted && playerReady && duelState === STATE_WAIT) {
earlyLose();
return;
}
if (duelState === STATE_DRAW && canShoot) {
playerFire(x, y);
return;
}
};
// Move reticle with finger (optional: drag to aim)
game.move = function (x, y, obj) {
// Holster hold/early leave logic
if (zoomFinished && !duelStarted) {
if (holsterContains(x, y)) {
// handled in update for dt-accurate timing
} else if (holdingHolster) {
cancelHold();
earlyLose();
}
}
// (aim reticle removed)
// Namlu her zaman fareyi izlesin (DRAW’tan önce holster tutulurken de)
pointGunAt(x, y);
};
/**** GLOBAL YARDIMCI : Silahı imlece çevir ****/
function pointGunAt(globalX, globalY) {
// 1) Omuz pivotu – dünya koordinatı
var shX = player.x + player.rarm.x;
var shY = player.y + player.rarm.y;
// 2) Omuz → imleç vektörü ve açı (0 rad = sağ)
var dx = globalX - shX;
var dy = globalY - shY;
var ang = Math.atan2(dy, dx);
// 3) Kol sprite’ı AŞAĞI bakıyor → –90° (-π/2) düzelt
var armRot = ang - Math.PI / 2;
player.rarm.rotation = armRot;
// 4) El / silah konumu (player LOCAL)
var L = player.rarm.height; // ≈110 px
// ❗️ Doğru ofset: (-sin, +cos)
player.gun.x = player.rarm.x - Math.sin(armRot) * L;
player.gun.y = player.rarm.y + Math.cos(armRot) * L;
// 5) Silah namlu yönü
if (!duelStarted && holsterContains(globalX, globalY)) {
player.gun.rotation = Math.PI / 2; // kılıfta ⇒ namlu yere
} else {
player.gun.rotation = ang; // hedefe bak
}
}
/**** GLOBAL : Enemy silahını hedefe çevir ****/
function aimEnemyGunAt(globalX, globalY) {
// 1) Omuz pivotu (world)
var shX = enemy.x + enemy.rarm.x;
var shY = enemy.y + enemy.rarm.y;
// 2) Omuz→hedef vektörü
var dx = globalX - shX;
var dy = globalY - shY;
var ang = Math.atan2(dy, dx);
// 3) Kol sprite’ı AŞAĞI bakıyor → –90° (–π/2) düzeltme
var armRot = ang - Math.PI / 2;
enemy.rarm.rotation = armRot;
// 4) El / silah konumu (enemy LOCAL) **ayna!**
var L = enemy.rarm.height; // ≈145 px
enemy.gun.x = enemy.rarm.x - Math.sin(armRot) * L;
enemy.gun.y = enemy.rarm.y + Math.cos(armRot) * L;
// 5) Namluyu hedefe döndür
enemy.gun.rotation = ang;
}
// Helper to update holster box position under player's feet
function updateHolsterBox() {
holsterFull.x = player.x - 200;
holsterFull.y = player.y + player.body.height / 2 + holsterOffset;
holsterEmpty.x = holsterFull.x;
holsterEmpty.y = holsterFull.y;
}
// Main update loop
game.update = function (dt) {
// Move enemygun assets in pocket 5px down and 10px left when music is not stopped
if (LK.musicPlaying && enemygunpocket) {
enemygunpocket.x = 2048 / 2 + 550 + 50 - 30 - 5 - 5 - 10; // 10px more left
enemygunpocket.y = 2732 / 2 - 600 + 150 + 10 + 5; // 5px more down
}
// Hide status text during zoom-in
if (!zoomFinished) {
statusTxt.visible = false;
return;
}
// Always update holster position to follow player
updateHolsterBox();
// (aim reticle removed)
// Rakip silahı eldeyse oyuncuyu takip etsin
if (enemy.gun.visible) {
aimEnemyGunAt(player.x, player.y - 40);
}
// Animate bullets
if (playerBullet) {
playerBullet.update();
}
if (enemyBullet) {
enemyBullet.update();
}
// === PLAYER SHOT COOLDOWN TIMER ===
if (playerShotCooldown > 0) {
var dtMs = typeof dt === "number" ? dt : 16.7;
playerShotCooldown -= dtMs;
if (playerShotCooldown < 0) {
playerShotCooldown = 0;
}
}
// Check for bullet collisions
checkBullets();
// ==== FIX #3 : statusTxt ayarı ====
// Holster hold logic after zoom
if (zoomFinished && !duelStarted) {
// Use pointerX/Y for current pointer
var px = typeof game.pointerX === "number" ? game.pointerX : 0;
var py = typeof game.pointerY === "number" ? game.pointerY : 0;
var dtMs = typeof dt === "number" ? dt : 16.7;
if (holsterContains(px, py) && holdingHolster) {
holsterHoldTime += dtMs;
} else {
if (holsterHoldTime > 0 && holdingHolster) {
earlyLose();
}
holsterHoldTime = 0;
}
if (!duelStarted) {
if (!playerReady) {
statusTxt.setText("Hold holster to start duel");
} else {
statusTxt.setText("Wait for music to end…\nthen aim & release");
}
}
// if (holsterHoldTime >= 4000 && !duelStarted) {
// duelStarted = true;
// holsterHoldTime = 0;
// resetDuel();
// }
statusTxt.visible = true;
} else {
if (duelState === STATE_DRAW) {
statusTxt.setText("Aim and SHOOT!");
}
statusTxt.visible = true;
}
};
// Early lose function
function earlyLose() {
if (duelState === STATE_RESULT) {
return;
} // only trigger once
holdingHolster = false;
holsterHoldTime = 0;
duelStarted = false;
LK.stopMusic();
if (drawTimeout) {
LK.clearTimeout(drawTimeout);
}
statusTxt.setText("Too early!\nYou lose!");
statusTxt.visible = true;
LK.getSound('gunshot').play(); // yere ateş
LK.getSound('fail').play();
// Optionally, also play gunshot sound:
// LK.getSound('gunshot').play();
// Show game over after 1 second
LK.setTimeout(function () {
LK.showGameOver();
}, 1000);
}
// Camera zoom-in before duel starts
function startZoomIn(music) {
// ==== FIX #1b : zoom fonksiyonunda ====
var startScale = 0.4;
world.scaleX = world.scaleY = startScale;
world.x = centerX * (1 - startScale);
world.y = 2732 / 2 * (1 - startScale);
LK.playMusic(music || 'duelmusic');
tween(world, {
scaleX: 1,
scaleY: 1,
x: 0,
y: 0
}, {
duration: 4000,
easing: tween.quadInOut,
onFinish: function onFinish() {
zoomFinished = true;
}
});
}
// Start zoom-in and music immediately on boot
startZoomIn();