User prompt
Please fix the bug: 'TypeError: Cannot use 'in' operator to search for 'scaleX' in null' in or related to this line: 'tween(hiori.flowText, {' Line Number: 931 ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Kaldır Flow dışı Monster Trans ı
User prompt
Monster Trans Flow formu olacak Bachira nın topu aldığı gibi Monster Trans a geçmesin sadece Roullet ve Monster Dribbling y apsın ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Monster Trans a toplam 2 tarafta mesela Player 1 - Oppenent 2 ise Bachira diyerleri gibi rastgele bir şansla Flow açar garanti Hiori her zaman Flow açmasın Bachira nın Flow u Monster Trans ve Dribbling ile geçtiği herkez Stun yesin ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Roullet sonrası topu kenara atıp birden topa hızlanıp Topu bizim gibi kaleye atabilsin ! ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Meguru Bachira ekle ! Roullet, Moster Dribbling kullana bilsin Flow dayken Monster Trans a geçsin hızı Dribbling yeteneklerinin Cooldown ı olmasın ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Nagi başlangıçta Flow da olmasın ve Nagi ye Fake atma ekle Nagi nin bazı vuruşları Fake olsun ve Rakibi Stun lasın 5 ila 10 saniye rastgele Cooldown gelsin buna göre ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Sae bizim kalenin altında duruyor sürekli düzelt ve Dribbling leri daha az mesafe kat etsin Nerf getir Sae ye kısaca ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Nagi ye Flow açtırt oyun başında
User prompt
Nagi 5 Revolver Fake Volley yapabilsin Flow a geçtiğinde takımdaki rastgele bir oyuncuya Flow gelsen 2 gol sonra bide ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Sae de 2 Gol atınca Flow a girsin ve Hilal şeklinde Dribble atsın sürekli ve en sonunda kaleye şut çeksin bir forvet gibi ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
6 Zig zag atabilsin ve Dash 10 saniyede bir atsın Chop un menzilini kısalt ve Sae sürekli aktif olsun ve uzaktan Falsolu şut çekmeye ayarla ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Sae Zig zag ve Chop Dribbling de yapabilsin ve Devoured olsun her dribbling ile geçtiği kişi hızları falan düşsün stun lansınlar veya %30 şansla ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Sae ekle karşı tarafa Perfect Pas ı olsun yarım daire çizerek Dribbling atabilsin oyun stun yesin Dribbling bitene kadar Dash atabilsin ufak çaplı ve Falsolu vuruş yapabilsin ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Hiori ye Flow yap Hiori Flow dayken ekstra 4 tane daha dribbling yapsın bide Winter Zone çok daha fazla yavaşlatsın ekstra pas atacaksa direk top bize gelsin ve Winter Zone çok daha büyük olsun Flow gereksinimi 2 Gol yememiz ve rastgele bir oyuncu flow a girecek yani burada o kişi Hiori oluyor
User prompt
Nagi rakip kaleye gitsin o pozisyonda ve Reo da çok daha aktif olsun ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Nagi topu Rakibin ayağındanda çalabilsin Ball Control ile Hiori nin Winter Zone undan biraz daha gküçük bir alana etki edecek ve Nagi den 3 saniye boyunca top çalamayacaklar ve Nagi sadece Gol atmaya odaklanacak ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Chigiri nin Staminası bitince baya bi yavaşlasın
User prompt
Top otomatik Nagi nin ayağına gelsin Ball Control yazzsın üstünde ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Nagi ekle ! Fake Vole 1 kere Fake vuruş yapıp Rakibi şaşırtıp Stun layıp yani Gerçek vuruşu yapsın 2. vuruşta Topu kendine çekebilsin çekeceği zaman etrafındaki menzili yani alanı göster ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Reo Npc lerin Winter Zone gibi yeteneklerinide kopyalayıp kullanabilsin ↪💡 Consider importing and using the following plugins: @upit/tween.v1
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var ChigiriPlayer = Container.expand(function (colorOverride) { var self = Container.call(this); var opponentGraphics = self.attachAsset('opponent', { anchorX: 0.5, anchorY: 0.5 }); if (typeof colorOverride === "number" && opponentGraphics) { opponentGraphics.tint = colorOverride; } self.speed = 5; self.role = 'chigiri'; self.homeX = 800; self.homeY = 2000; self.maxDistance = 600; self.hasBall = false; self.isSpeedBursting = false; self.speedBurstTarget = null; self.speedBurstCooldown = 0; self.speedBurstCooldownTime = 8000; // 8 seconds self.normalSpeed = 5; self.burstSpeed = 12; self.stamina = 100; self.maxStamina = 100; self.staminaDrainRate = 0.8; self.staminaRegenRate = 0.3; self.lowStaminaSpeed = 1.5; // Very slow when stamina is low self.update = function () { // Update speed burst cooldown if (self.speedBurstCooldown > 0) { self.speedBurstCooldown -= 16; if (self.speedBurstCooldown < 0) self.speedBurstCooldown = 0; } // Steal ball if opponent is inside area var nearestOpponent = null; var nearestDistance = Infinity; for (var i = 0; i < opponents.length; i++) { var opponentDist = Math.sqrt((opponents[i].x - self.x) * (opponents[i].x - self.x) + (opponents[i].y - self.y) * (opponents[i].y - self.y)); if (opponentDist < nearestDistance) { nearestDistance = opponentDist; nearestOpponent = opponents[i]; } } if (nearestOpponent && nearestDistance < 80 && nearestOpponent.hasBall) { // Steal the ball nearestOpponent.hasBall = false; ball.active = true; // Ball moves toward Chigiri var stealDx = self.x - nearestOpponent.x; var stealDy = self.y - nearestOpponent.y; var stealDist = Math.sqrt(stealDx * stealDx + stealDy * stealDy); if (stealDist > 0) { ball.velocityX = stealDx / stealDist * 8; ball.velocityY = stealDy / stealDist * 8; } ballDetachCooldown = ballDetachCooldownTime; } var dx = ball.x - self.x; var dy = ball.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); // Enhanced ball pursuit for hybrid player if (distance < 500 && !self.isSpeedBursting) { // Chase ball with hybrid intelligence var chaseSpeed = distance < 150 ? self.normalSpeed * 1.4 : self.normalSpeed * 1.1; self.x += dx / distance * chaseSpeed; self.y += dy / distance * chaseSpeed; } // Speed burst mechanic if (!self.isSpeedBursting && self.speedBurstCooldown <= 0 && distance < 100) { // Throw ball forward and start speed burst var throwX = opponentGoal.x + (Math.random() - 0.5) * 200; var throwY = opponentGoal.y + 200; var throwDx = throwX - ball.x; var throwDy = throwY - ball.y; var throwDist = Math.sqrt(throwDx * throwDx + throwDy * throwDy); if (throwDist > 0) { ball.velocityX = throwDx / throwDist * 14; ball.velocityY = throwDy / throwDist * 14; } // Set speed burst target and activate self.speedBurstTarget = { x: throwX, y: throwY }; self.isSpeedBursting = true; self.speedBurstCooldown = self.speedBurstCooldownTime; // Start cooldown // Visual effect for speed burst tween(self, { scaleX: 1.2, scaleY: 1.2 }, { duration: 100, onFinish: function onFinish() { tween(self, { scaleX: 1, scaleY: 1 }, { duration: 100 }); } }); } if (self.isSpeedBursting && self.speedBurstTarget) { // Move at burst speed toward target var burstDx = self.speedBurstTarget.x - self.x; var burstDy = self.speedBurstTarget.y - self.y; var burstDist = Math.sqrt(burstDx * burstDx + burstDy * burstDy); if (burstDist > 30) { self.x += burstDx / burstDist * self.burstSpeed; self.y += burstDy / burstDist * self.burstSpeed; // Drain stamina during speed burst self.stamina -= self.staminaDrainRate * 2; // Double drain during burst if (self.stamina < 0) self.stamina = 0; } else { // Reached target, stop speed burst self.isSpeedBursting = false; self.speedBurstTarget = null; } } else { // Stamina regeneration when not moving much var currentSpeed = Math.sqrt((self.x - (self.lastMoveX || self.x)) * (self.x - (self.lastMoveX || self.x)) + (self.y - (self.lastMoveY || self.y)) * (self.y - (self.lastMoveY || self.y))); if (currentSpeed < 2 && self.stamina < self.maxStamina) { self.stamina += self.staminaRegenRate; if (self.stamina > self.maxStamina) self.stamina = self.maxStamina; } self.lastMoveX = self.x; self.lastMoveY = self.y; // Determine current speed based on stamina var currentMoveSpeed = self.stamina > 20 ? self.normalSpeed : self.lowStaminaSpeed; // Normal hybrid behavior - enhanced ball pursuit if (distance < 500) { // Move toward ball with improved midfielder intelligence but adjust for stamina var pursuitSpeed = distance < 200 ? currentMoveSpeed * 1.3 : currentMoveSpeed * 1.1; self.x += dx / distance * pursuitSpeed; self.y += dy / distance * pursuitSpeed; // Drain stamina during pursuit self.stamina -= self.staminaDrainRate * 0.5; if (self.stamina < 0) self.stamina = 0; // Attack opponent goal if close to ball if (distance < 80) { var goalDx = opponentGoal.x - ball.x; var goalDy = opponentGoal.y - ball.y; var goalDistance = Math.sqrt(goalDx * goalDx + goalDy * goalDy); if (goalDistance > 0) { ball.velocityX = goalDx / goalDistance * 11; ball.velocityY = goalDy / goalDistance * 11; } } } else { // Return to defensive position var homeDx = self.homeX - self.x; var homeDy = self.homeY - self.y; var homeDistance = Math.sqrt(homeDx * homeDx + homeDy * homeDy); if (homeDistance > 50) { // Use stamina-adjusted speed for returning home var currentMoveSpeed = self.stamina > 20 ? self.normalSpeed : self.lowStaminaSpeed; self.x += homeDx / homeDistance * currentMoveSpeed * 0.4; self.y += homeDy / homeDistance * currentMoveSpeed * 0.4; // Light stamina drain when returning to position self.stamina -= self.staminaDrainRate * 0.3; if (self.stamina < 0) self.stamina = 0; } } } }; return self; }); var DefensePlayer = Container.expand(function (colorOverride) { var self = Container.call(this); var opponentGraphics = self.attachAsset('opponent', { anchorX: 0.5, anchorY: 0.5 }); if (typeof colorOverride === "number" && opponentGraphics) { opponentGraphics.tint = colorOverride; } self.speed = 4; self.role = 'defense'; self.homeX = 1024; self.homeY = 600; self.maxDistance = 400; self.hasBall = false; self.update = function () { // Steal ball if player is inside opponent var playerDist = Math.sqrt((player.x - self.x) * (player.x - self.x) + (player.y - self.y) * (player.y - self.y)); if (playerDist < 80 && player.hasBall) { // Steal the ball player.hasBall = false; ball.active = true; // Ball moves away from player, toward defense var stealDx = self.x - player.x; var stealDy = self.y - player.y; var stealDist = Math.sqrt(stealDx * stealDx + stealDy * stealDy); if (stealDist > 0) { ball.velocityX = stealDx / stealDist * 10; ball.velocityY = stealDy / stealDist * 10; } // Prevent immediate re-attachment ballDetachCooldown = ballDetachCooldownTime; } var dx = ball.x - self.x; var dy = ball.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); // Defense priority: desperately try to get the ball if (distance < 400) { // Move aggressively toward ball - increased chase range self.x += dx / distance * (self.speed * 1.2); self.y += dy / distance * (self.speed * 1.2); // Sliding tackle if player is close to defense var playerDistance = Math.sqrt((player.x - self.x) * (player.x - self.x) + (player.y - self.y) * (player.y - self.y)); if (playerDistance < 120 && ball.active && !player.hasBall) { // Slide tackle: dash toward ball and clear it away var slideDx = ball.x - self.x; var slideDy = ball.y - self.y; var slideDist = Math.sqrt(slideDx * slideDx + slideDy * slideDy); if (slideDist > 0) { // Animate slide (quick move) tween(self, { x: self.x + slideDx / slideDist * 60, y: self.y + slideDy / slideDist * 60 }, { duration: 120, easing: tween.cubicOut }); // Clear ball far away from player var clearX = ball.x < 1024 ? ball.x - 400 : ball.x + 400; var clearY = ball.y - 500; var clearDx = clearX - ball.x; var clearDy = clearY - ball.y; var clearDist = Math.sqrt(clearDx * clearDx + clearDy * clearDy); if (clearDist > 0) { ball.velocityX = clearDx / clearDist * 13; ball.velocityY = clearDy / clearDist * 13; } } } // Kick ball away from player goal if close enough if (distance < 80) { // Find nearest forward player var nearestForward = null; var nearestDistance = Infinity; for (var i = 0; i < opponents.length; i++) { if (opponents[i].role === 'forward') { var forwardDx = opponents[i].x - self.x; var forwardDy = opponents[i].y - self.y; var forwardDistance = Math.sqrt(forwardDx * forwardDx + forwardDy * forwardDy); if (forwardDistance < nearestDistance) { nearestDistance = forwardDistance; nearestForward = opponents[i]; } } } // Pass to forward if found, otherwise clear as before if (nearestForward) { var passDx = nearestForward.x - ball.x; var passDy = nearestForward.y - ball.y; var passDistance = Math.sqrt(passDx * passDx + passDy * passDy); if (passDistance > 0) { ball.velocityX = passDx / passDistance * 10; ball.velocityY = passDy / passDistance * 10; } } else { var kickAwayX = ball.x < 1024 ? ball.x - 200 : ball.x + 200; var kickAwayY = ball.y - 300; // Kick upfield var kickDx = kickAwayX - ball.x; var kickDy = kickAwayY - ball.y; var kickDistance = Math.sqrt(kickDx * kickDx + kickDy * kickDy); if (kickDistance > 0) { ball.velocityX = kickDx / kickDistance * 8; ball.velocityY = kickDy / kickDistance * 8; } } } } else { // Return to defensive position var homeDx = self.homeX - self.x; var homeDy = self.homeY - self.y; var homeDistance = Math.sqrt(homeDx * homeDx + homeDy * homeDy); if (homeDistance > 50) { self.x += homeDx / homeDistance * self.speed * 0.5; self.y += homeDy / homeDistance * self.speed * 0.5; } } }; return self; }); var ForwardPlayer = Container.expand(function () { var self = Container.call(this); var opponentGraphics = self.attachAsset('opponent', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 3.5; self.role = 'forward'; self.homeX = 1024; self.homeY = 1400; self.hasBall = false; self.directShotCooldown = self.directShotCooldown || 0; self.update = function () { // Steal ball if player is inside opponent var playerDist = Math.sqrt((player.x - self.x) * (player.x - self.x) + (player.y - self.y) * (player.y - self.y)); if (playerDist < 80 && player.hasBall) { // Steal the ball player.hasBall = false; ball.active = true; // Ball moves away from player, toward forward var stealDx = self.x - player.x; var stealDy = self.y - player.y; var stealDist = Math.sqrt(stealDx * stealDx + stealDy * stealDy); if (stealDist > 0) { ball.velocityX = stealDx / stealDist * 10; ball.velocityY = stealDy / stealDist * 10; } // Prevent immediate re-attachment ballDetachCooldown = ballDetachCooldownTime; } // Handle direct shot cooldown if (self.directShotCooldown > 0) { self.directShotCooldown -= 16; if (self.directShotCooldown < 0) self.directShotCooldown = 0; } var dx = ball.x - self.x; var dy = ball.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); // Forward: attack and try to score if (distance < 400) { // Move toward ball with aggressive pursuit var pursuitSpeed = distance < 200 ? self.speed * 1.8 : self.speed * 1.3; self.x += dx / distance * pursuitSpeed; self.y += dy / distance * pursuitSpeed; // If close to ball, shoot at goal if (distance < 80) { // Direct Shot every 30s if (self.directShotCooldown <= 0) { var goalDx = playerGoal.x - ball.x; var goalDy = playerGoal.y - ball.y; var goalDistance = Math.sqrt(goalDx * goalDx + goalDy * goalDy); if (goalDistance > 0) { // Direct Shot: very fast and straight ball.velocityX = goalDx / goalDistance * 18; ball.velocityY = goalDy / goalDistance * 18; } self.directShotCooldown = 30000; // 30 seconds } else { // Normal shot var goalDx = playerGoal.x - ball.x; var goalDy = playerGoal.y - ball.y; var goalDistance = Math.sqrt(goalDx * goalDx + goalDy * goalDy); if (goalDistance > 0) { ball.velocityX = goalDx / goalDistance * 10; ball.velocityY = goalDy / goalDistance * 10; } } } } else { // Move toward attacking position var homeDx = self.homeX - self.x; var homeDy = self.homeY - self.y; var homeDistance = Math.sqrt(homeDx * homeDx + homeDy * homeDy); if (homeDistance > 50) { self.x += homeDx / homeDistance * self.speed * 0.4; self.y += homeDy / homeDistance * self.speed * 0.4; } } }; return self; }); var Goal = Container.expand(function () { var self = Container.call(this); // Goal area var goalGraphics = self.attachAsset('goal', { anchorX: 0.5, anchorY: 0.5 }); goalGraphics.alpha = 0.3; // Left goalpost var leftPost = self.addChild(LK.getAsset('goalpost', { anchorX: 0.5, anchorY: 0.5 })); leftPost.x = -210; leftPost.y = 0; // Right goalpost var rightPost = self.addChild(LK.getAsset('goalpost', { anchorX: 0.5, anchorY: 0.5 })); rightPost.x = 210; rightPost.y = 0; return self; }); var Goalkeeper = Container.expand(function (isPlayer) { var self = Container.call(this); var keeperGraphics = self.attachAsset(isPlayer ? 'player' : 'opponent', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 2; self.isPlayer = isPlayer; self.rushCooldown = 0; self.rushCooldownTime = 20000; // 20 seconds self.isRushing = false; self.originalX = 0; self.originalY = 0; self.rushSpeed = 8; self.update = function () { // Update rush cooldown if (self.rushCooldown > 0) { self.rushCooldown -= 16; // Approximately 60 FPS if (self.rushCooldown < 0) self.rushCooldown = 0; } // Check if should rush for ball var ballDistance = Math.sqrt((ball.x - self.x) * (ball.x - self.x) + (ball.y - self.y) * (ball.y - self.y)); if (!self.isRushing && self.rushCooldown <= 0 && ballDistance < 400) { // Start rushing self.isRushing = true; self.rushCooldown = self.rushCooldownTime; } if (self.isRushing) { // Rush toward ball var dx = ball.x - self.x; var dy = ball.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 0 && distance > 50) { self.x += dx / distance * self.rushSpeed; self.y += dy / distance * self.rushSpeed; } else if (distance <= 50) { // Catch ball if close enough ball.velocityX = 0; ball.velocityY = 0; ball.x = self.x; ball.y = self.y; ball.active = false; player.hasBall = false; // Return to original position first self.isRushing = false; tween(self, { x: self.originalX, y: self.originalY }, { duration: 1000, onFinish: function onFinish() { // After returning to position, throw ball to center field ball.active = true; var centerX = 1024; var centerY = 1366; var throwPower = 15; var throwDx = centerX - ball.x; var throwDy = centerY - ball.y; var throwDistance = Math.sqrt(throwDx * throwDx + throwDy * throwDy); if (throwDistance > 0) { ball.velocityX = throwDx / throwDistance * throwPower; ball.velocityY = throwDy / throwDistance * throwPower; } } }); } } else { // Normal goalkeeper movement - stay near goal line var goalCenterX = 1024; var dx = goalCenterX - self.x; if (Math.abs(dx) > 5) { self.x += dx > 0 ? self.speed : -self.speed; } } }; return self; }); var HioriPlayer = Container.expand(function (colorOverride) { var self = Container.call(this); var playerGraphics = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5 }); if (typeof colorOverride === "number" && playerGraphics) { playerGraphics.tint = colorOverride; } self.speed = 4; self.role = 'hiori'; self.homeX = 1200; self.homeY = 2000; self.hasBall = false; // FLOW SYSTEM self.flowActive = false; self.flowDribbleCount = 0; self.flowDribbleMax = 4; // 4 extra dribbles in Flow self.flowText = null; self.flowTriggerChecked = false; // To avoid retriggering // Zig-zag dribbling variables self.isDribbling = false; self.dribbleStartTime = 0; self.dribbleDuration = 2000; // 2 seconds - slower duration self.dribbleSpeed = 6; self.dribbleDirection = 1; // 1 for right, -1 for left self.dribblePhase = 0; // 0-1 progress through dribble self.dribbleStartX = 0; self.dribbleStartY = 0; self.dribbleTargetX = 0; self.dribbleTargetY = 0; // Zigzag pause variables self.zigzagCount = 0; self.zigzagPaused = false; self.zigzagPauseStart = 0; self.zigzagPauseDuration = 10000; // 10 seconds // Winter Zone variables self.winterZoneActive = false; self.winterZoneRadius = 200; self.winterZoneCooldown = 0; self.winterZoneCooldownTime = 12000; // 12 seconds self.winterZoneDuration = 0; self.winterZoneMaxDuration = 10000; // 10 seconds - increased duration self.slowedOpponents = []; // Winter Zone visual self.winterZoneVisual = null; // Perfect pass variables self.passChargingTime = 0; self.perfectPassCooldown = 0; self.perfectPassCooldownTime = 6000; // 6 seconds self.update = function () { // FLOW TRIGGER: If 2 goals conceded, activate Flow for Hiori (only once) if (!self.flowActive && !self.flowTriggerChecked && typeof opponentScore !== "undefined" && opponentScore >= 2) { self.flowActive = true; self.flowDribbleCount = 0; self.flowTriggerChecked = true; // Show Flow text above Hiori if (!self.flowText) { self.flowText = self.addChild(new Text2('FLOW', { size: 48, fill: 0x00FFFF })); self.flowText.anchor.set(0.5, 0.5); self.flowText.x = 0; self.flowText.y = -100; self.flowText.alpha = 1; tween(self.flowText, { scaleX: 1.5, scaleY: 1.5, alpha: 1 }, { duration: 300, onFinish: function onFinish() { tween(self.flowText, { scaleX: 1, scaleY: 1, alpha: 1 }, { duration: 300 }); } }); } } // Remove Flow text if not in Flow if (!self.flowActive && self.flowText) { self.flowText.destroy(); self.flowText = null; } // Update cooldowns if (self.winterZoneCooldown > 0) { self.winterZoneCooldown -= 16; if (self.winterZoneCooldown < 0) self.winterZoneCooldown = 0; } if (self.perfectPassCooldown > 0) { self.perfectPassCooldown -= 16; if (self.perfectPassCooldown < 0) self.perfectPassCooldown = 0; } // FLOW: If in Flow, boost Winter Zone and dribbling var flowWinterZoneRadius = self.flowActive ? 420 : 200; var flowWinterZoneSlow = self.flowActive ? 0.12 : 0.3; // 12% speed in Flow var flowWinterZoneDuration = self.flowActive ? 18000 : self.winterZoneMaxDuration; // 18s in Flow var flowWinterZoneCooldown = self.flowActive ? 6000 : self.winterZoneCooldownTime; // 6s in Flow // Winter Zone duration and effect if (self.winterZoneActive) { self.winterZoneDuration -= 16; if (self.winterZoneDuration <= 0) { self.winterZoneActive = false; // Remove Winter Zone visual if (self.winterZoneVisual) { self.winterZoneVisual.destroy(); self.winterZoneVisual = null; } // Restore opponent speeds for (var i = 0; i < self.slowedOpponents.length; i++) { var opponent = self.slowedOpponents[i]; opponent.speed = opponent.originalSpeed || opponent.speed * 2; } self.slowedOpponents = []; } else { // Apply Winter Zone effect to nearby opponents for (var i = 0; i < opponents.length; i++) { var opponent = opponents[i]; var dist = Math.sqrt((opponent.x - self.x) * (opponent.x - self.x) + (opponent.y - self.y) * (opponent.y - self.y)); if (dist <= (self.winterZoneActive ? flowWinterZoneRadius : self.winterZoneRadius)) { if (self.slowedOpponents.indexOf(opponent) === -1) { opponent.originalSpeed = opponent.speed; opponent.speed = opponent.speed * (self.winterZoneActive ? flowWinterZoneSlow : 0.3); // Much slower in Flow self.slowedOpponents.push(opponent); } } } } } var dx = ball.x - self.x; var dy = ball.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); // FLOW: Dribbling logic if (self.isDribbling) { var elapsed = Date.now() - self.dribbleStartTime; var progress = Math.min(elapsed / self.dribbleDuration, 1); // Create zig-zag pattern - slower frequency for better visibility var zigzagAmplitude = 80; var zigzagFrequency = 4; var zigzagOffset = Math.sin(progress * Math.PI * zigzagFrequency) * zigzagAmplitude; // Move toward target with zig-zag motion - slower speed var targetDx = self.dribbleTargetX - self.dribbleStartX; var targetDy = self.dribbleTargetY - self.dribbleStartY; var targetDist = Math.sqrt(targetDx * targetDx + targetDy * targetDy); if (targetDist > 0) { // Calculate perpendicular vector for zig-zag var perpX = -targetDy / targetDist; var perpY = targetDx / targetDist; // Apply zig-zag movement with slower speed var slowSpeed = 0.6; // Reduced from 1.0 to make it slower self.x = self.dribbleStartX + targetDx * progress * slowSpeed + perpX * zigzagOffset; self.y = self.dribbleStartY + targetDy * progress * slowSpeed + perpY * zigzagOffset; // Ball follows during dribble if (distance < 100) { ball.x = self.x; ball.y = self.y; ball.velocityX = 0; ball.velocityY = 0; } } // End dribbling if (progress >= 1) { self.isDribbling = false; self.zigzagCount = (self.zigzagCount || 0) + 1; // FLOW: If in Flow, allow up to 4 extra dribbles in a row if (self.flowActive && self.flowDribbleCount < self.flowDribbleMax) { self.flowDribbleCount++; // Start another dribble immediately self.isDribbling = true; self.dribbleStartTime = Date.now(); self.dribbleStartX = self.x; self.dribbleStartY = self.y; // Dribble toward opponent goal, randomize a bit self.dribbleTargetX = opponentGoal.x + (Math.random() - 0.5) * 300; self.dribbleTargetY = opponentGoal.y + 200 + Math.random() * 100; } else { // After 4 zigzags, pause for 10 seconds if (self.zigzagCount >= 4) { self.zigzagPaused = true; self.zigzagPauseStart = Date.now(); self.zigzagCount = 0; } // Reset Flow dribble count after sequence if (self.flowActive) self.flowDribbleCount = 0; } } } else { // Normal ball pursuit if (distance < 400) { var chaseSpeed = distance < 150 ? self.speed * 1.3 : self.speed * 1.1; self.x += dx / distance * chaseSpeed; self.y += dy / distance * chaseSpeed; // Handle zigzag pause if (self.zigzagPaused) { var pauseElapsed = Date.now() - self.zigzagPauseStart; if (pauseElapsed >= self.zigzagPauseDuration) { self.zigzagPaused = false; } } // Start zig-zag dribbling when close to ball (only if not paused) if (distance < 80 && !self.isDribbling && !self.zigzagPaused) { self.isDribbling = true; self.dribbleStartTime = Date.now(); self.dribbleStartX = self.x; self.dribbleStartY = self.y; // Dribble toward opponent goal self.dribbleTargetX = opponentGoal.x + (Math.random() - 0.5) * 300; self.dribbleTargetY = opponentGoal.y + 200; // FLOW: If in Flow, reset dribble count for new sequence if (self.flowActive) self.flowDribbleCount = 0; } } } // FLOW: Winter Zone is much bigger, lasts longer, slows more, and triggers more often if (!self.winterZoneActive && self.winterZoneCooldown <= 0) { var nearbyOpponents = 0; for (var i = 0; i < opponents.length; i++) { var opponent = opponents[i]; var dist = Math.sqrt((opponent.x - self.x) * (opponent.x - self.x) + (opponent.y - self.y) * (opponent.y - self.y)); if (dist <= flowWinterZoneRadius + 50) { nearbyOpponents++; } } if (nearbyOpponents >= 2) { // Activate Winter Zone self.winterZoneActive = true; self.winterZoneDuration = flowWinterZoneDuration; self.winterZoneCooldown = flowWinterZoneCooldown; // Create Winter Zone visual area if (self.winterZoneVisual) { self.winterZoneVisual.destroy(); self.winterZoneVisual = null; } self.winterZoneVisual = self.addChild(LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, scaleX: self.flowActive ? 8 : 4, scaleY: self.flowActive ? 8 : 4, tint: 0x87CEEB })); self.winterZoneVisual.alpha = 0.3; // Visual effect tween(self, { scaleX: 1.5, scaleY: 1.5, tint: 0x87CEEB }, { duration: 200, onFinish: function onFinish() { tween(self, { scaleX: 1, scaleY: 1, tint: 0xFFFFFF }, { duration: 200 }); } }); } } // FLOW: If in Flow, perfect pass always goes directly to player, no curve, and is instant if (distance < 80 && self.perfectPassCooldown <= 0) { // Look for player to pass to var playerDist = Math.sqrt((player.x - self.x) * (player.x - self.x) + (player.y - self.y) * (player.y - self.y)); if (playerDist < 600 && playerDist > 100) { // Execute perfect pass var passDx = player.x - ball.x; var passDy = player.y - ball.y; var passDist = Math.sqrt(passDx * passDx + passDy * passDy); if (passDist > 0) { if (self.flowActive) { // FLOW: Pass is instant and direct ball.x = player.x; ball.y = player.y - 50; ball.velocityX = 0; ball.velocityY = 0; ball.active = false; player.hasBall = true; } else { // Normal perfect pass with slight curve to avoid interception var curveAmount = 3; ball.velocityX = passDx / passDist * 12 + curveAmount; ball.velocityY = passDy / passDist * 12; ball.active = true; } self.perfectPassCooldown = self.perfectPassCooldownTime; // Visual effect for perfect pass tween(ball, { scaleX: 1.3, scaleY: 1.3 }, { duration: 150, onFinish: function onFinish() { tween(ball, { scaleX: 1, scaleY: 1 }, { duration: 150 }); } }); } } } // Return to home position when not actively playing if (distance > 500) { var homeDx = self.homeX - self.x; var homeDy = self.homeY - self.y; var homeDistance = Math.sqrt(homeDx * homeDx + homeDy * homeDy); if (homeDistance > 50) { self.x += homeDx / homeDistance * self.speed * 0.4; self.y += homeDy / homeDistance * self.speed * 0.4; } } }; return self; }); var MeguruBachiraPlayer = Container.expand(function (colorOverride) { var self = Container.call(this); var playerGraphics = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5 }); if (typeof colorOverride === "number" && playerGraphics) { playerGraphics.tint = colorOverride; } self.speed = 4.5; self.role = 'bachira'; self.homeX = 1000; self.homeY = 1900; self.hasBall = false; // FLOW SYSTEM for Bachira self.flowActive = false; self.flowTriggerChecked = false; self.flowText = null; // Monster Trans variables (Flow mode transformation) self.monsterTransActive = false; self.monsterTransVisual = null; // Roulette dribbling variables self.rouletteActive = false; self.rouletteStartTime = 0; self.rouletteDuration = 1500; // 1.5 seconds self.rouletteRotations = 3; // 3 full rotations self.rouletteRadius = 80; self.rouletteCooldown = 0; self.rouletteCooldownTime = 4000; // 4 seconds self.rouletteOriginX = 0; self.rouletteOriginY = 0; self.rouletteStunRadius = 120; self.rouletteStunnedOpponents = []; self.rouletteStunEnd = 0; // Monster Dribbling variables self.monsterDribblingActive = false; self.monsterDribblingStartTime = 0; self.monsterDribblingDuration = 2000; // 2 seconds self.monsterDribblingSpeed = 8; self.monsterDribblingCooldown = 0; self.monsterDribblingCooldownTime = 6000; // 6 seconds self.monsterDribblingStartX = 0; self.monsterDribblingStartY = 0; self.monsterDribblingTargetX = 0; self.monsterDribblingTargetY = 0; self.monsterDribblingStunRadius = 150; self.monsterDribblingStunnedOpponents = []; self.monsterDribblingStunEnd = 0; // Rush to ball variables (after Roulette) self.rushingToBall = false; self.rushTargetX = 0; self.rushTargetY = 0; self.rushSpeed = 7; self.readyToShoot = false; self.update = function () { // FLOW TRIGGER: Monster Trans for Bachira, random chance for Hiori, only one Flow at a time if (!self.flowActive && !self.flowTriggerChecked) { // Count Bachira and Hiori on field var bachiraCount = typeof bachira !== "undefined" ? 1 : 0; var hioriCount = typeof hiori !== "undefined" ? 1 : 0; var totalFlowCandidates = bachiraCount + hioriCount; var shouldFlow = false; // If both Bachira and Hiori are present, randomly pick one for Flow if (totalFlowCandidates > 1) { // 50% chance for Bachira, 50% for Hiori var pick = Math.random(); if (pick < 0.5) { shouldFlow = true; // Bachira gets Flow if (typeof hiori !== "undefined") { hiori.flowActive = false; hiori.flowTriggerChecked = true; if (hiori.flowText) { hiori.flowText.destroy(); hiori.flowText = null; } } } else { shouldFlow = false; if (typeof hiori !== "undefined" && !hiori.flowActive && !hiori.flowTriggerChecked) { hiori.flowActive = true; hiori.flowTriggerChecked = true; hiori.flowDribbleCount = 0; // Show Flow text above Hiori if (!hiori.flowText) { hiori.flowText = hiori.addChild(new Text2('FLOW', { size: 48, fill: 0x00FFFF })); hiori.flowText.anchor.set(0.5, 0.5); hiori.flowText.x = 0; hiori.flowText.y = -100; hiori.flowText.alpha = 1; if (hiori.flowText) { // Defensive: only tween if flowText exists tween(hiori.flowText, { scaleX: 1.5, scaleY: 1.5, alpha: 1 }, { duration: 300, onFinish: function onFinish() { if (hiori.flowText) { // Defensive: only tween if flowText still exists tween(hiori.flowText, { scaleX: 1, scaleY: 1, alpha: 1 }, { duration: 300 }); } } }); } } } } } else { // Only Bachira or only Hiori present shouldFlow = true; } if (shouldFlow) { // Only set flowTriggerChecked, but do NOT activate Monster Trans/Flow yet self.flowTriggerChecked = true; // self.flowActive and self.monsterTransActive will be set when using Roulette or Monster Dribbling } } // Remove Flow text and effects if not in Flow if (!self.flowActive && self.flowText) { self.flowText.destroy(); self.flowText = null; } if (!self.flowActive && self.monsterTransVisual) { self.monsterTransVisual.destroy(); self.monsterTransVisual = null; self.monsterTransActive = false; // Reset player appearance tween(playerGraphics, { tint: colorOverride || 0xFFFFFF, scaleX: 1, scaleY: 1 }, { duration: 500 }); } if (!self.flowActive) { self.monsterTransActive = false; } // Update cooldowns if (self.rouletteCooldown > 0) { self.rouletteCooldown -= 16; if (self.rouletteCooldown < 0) self.rouletteCooldown = 0; } if (self.monsterDribblingCooldown > 0) { // In Flow mode, no cooldowns if (!self.flowActive) { self.monsterDribblingCooldown -= 16; if (self.monsterDribblingCooldown < 0) self.monsterDribblingCooldown = 0; } else { self.monsterDribblingCooldown = 0; // No cooldown in Flow } } // Handle Roulette stun end if (self.rouletteStunEnd > 0 && Date.now() > self.rouletteStunEnd) { // Restore stunned opponents from Roulette for (var i = 0; i < self.rouletteStunnedOpponents.length; i++) { var opponent = self.rouletteStunnedOpponents[i]; opponent.stunned = false; opponent.originalSpeed = opponent.originalSpeed || opponent.speed; opponent.speed = opponent.originalSpeed; tween(opponent, { tint: 0xFFFFFF, scaleX: 1, scaleY: 1 }, { duration: 300 }); } self.rouletteStunnedOpponents = []; self.rouletteStunEnd = 0; } // Handle Monster Dribbling stun end if (self.monsterDribblingStunEnd > 0 && Date.now() > self.monsterDribblingStunEnd) { // Restore stunned opponents from Monster Dribbling for (var i = 0; i < self.monsterDribblingStunnedOpponents.length; i++) { var opponent = self.monsterDribblingStunnedOpponents[i]; opponent.stunned = false; opponent.originalSpeed = opponent.originalSpeed || opponent.speed; opponent.speed = opponent.originalSpeed; tween(opponent, { tint: 0xFFFFFF, scaleX: 1, scaleY: 1 }, { duration: 300 }); } self.monsterDribblingStunnedOpponents = []; self.monsterDribblingStunEnd = 0; } var dx = ball.x - self.x; var dy = ball.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); // Roulette dribbling logic if (self.rouletteActive) { var elapsed = Date.now() - self.rouletteStartTime; var t = Math.min(elapsed / self.rouletteDuration, 1); // Create spinning motion around origin point var angle = t * self.rouletteRotations * 2 * Math.PI; self.x = self.rouletteOriginX + Math.cos(angle) * self.rouletteRadius; self.y = self.rouletteOriginY + Math.sin(angle) * self.rouletteRadius; // Ball follows during roulette if (distance < 100) { ball.x = self.x; ball.y = self.y; ball.velocityX = 0; ball.velocityY = 0; } // End roulette and apply stun effect if (t >= 1) { self.rouletteActive = false; self.applyRouletteStun(); } } // Monster Dribbling logic if (self.monsterDribblingActive) { var elapsed = Date.now() - self.monsterDribblingStartTime; var t = Math.min(elapsed / self.monsterDribblingDuration, 1); // Fast, erratic movement toward target var chaosAmplitude = 40; var chaosFrequency = 8; var chaosOffsetX = Math.sin(t * Math.PI * chaosFrequency) * chaosAmplitude; var chaosOffsetY = Math.cos(t * Math.PI * chaosFrequency * 1.3) * chaosAmplitude; // Move toward target with chaos var targetDx = self.monsterDribblingTargetX - self.monsterDribblingStartX; var targetDy = self.monsterDribblingTargetY - self.monsterDribblingStartY; self.x = self.monsterDribblingStartX + targetDx * t + chaosOffsetX; self.y = self.monsterDribblingStartY + targetDy * t + chaosOffsetY; // Ball follows during monster dribbling if (distance < 120) { ball.x = self.x; ball.y = self.y; ball.velocityX = 0; ball.velocityY = 0; } // Stun all opponents passed by during Monster Dribbling (only in Flow/Monster Trans) if (self.flowActive) { for (var i = 0; i < opponents.length; i++) { var opp = opponents[i]; var oppDist = Math.sqrt((opp.x - self.x) * (opp.x - self.x) + (opp.y - self.y) * (opp.y - self.y)); if (oppDist <= self.monsterDribblingStunRadius && !opp.stunned) { opp.stunned = true; opp.originalSpeed = opp.speed; opp.speed = 0; self.monsterDribblingStunnedOpponents.push(opp); tween(opp, { tint: 0xFF0000, scaleX: 1.2, scaleY: 1.2 }, { duration: 250 }); } } if (self.monsterDribblingStunnedOpponents.length > 0) { self.monsterDribblingStunEnd = Date.now() + 4000; } } // End monster dribbling and apply stun effect if (t >= 1) { self.monsterDribblingActive = false; self.applyMonsterDribblingStun(); } } // Rush to ball after Roulette throw if (self.rushingToBall) { var rushDx = self.rushTargetX - self.x; var rushDy = self.rushTargetY - self.y; var rushDist = Math.sqrt(rushDx * rushDx + rushDy * rushDy); if (rushDist > 30) { // Rush toward the thrown ball location self.x += rushDx / rushDist * self.rushSpeed; self.y += rushDy / rushDist * self.rushSpeed; // Stun all opponents passed by during Monster Trans rush (only in Flow) if (self.flowActive) { for (var i = 0; i < opponents.length; i++) { var opp = opponents[i]; var oppDist = Math.sqrt((opp.x - self.x) * (opp.x - self.x) + (opp.y - self.y) * (opp.y - self.y)); if (oppDist <= self.monsterDribblingStunRadius && !opp.stunned) { opp.stunned = true; opp.originalSpeed = opp.speed; opp.speed = 0; self.monsterDribblingStunnedOpponents.push(opp); tween(opp, { tint: 0xFF0000, scaleX: 1.2, scaleY: 1.2 }, { duration: 250 }); } } if (self.monsterDribblingStunnedOpponents.length > 0) { self.monsterDribblingStunEnd = Date.now() + 4000; } } } else { // Reached the target area, check if ball is nearby var ballDist = Math.sqrt((ball.x - self.x) * (ball.x - self.x) + (ball.y - self.y) * (ball.y - self.y)); if (ballDist < 100) { // Ball is close, prepare to shoot self.readyToShoot = true; self.rushingToBall = false; // Control the ball briefly ball.x = self.x; ball.y = self.y; ball.velocityX = 0; ball.velocityY = 0; // Immediately shoot toward opponent goal var goalDx = opponentGoal.x - self.x; var goalDy = opponentGoal.y - self.y; var goalDist = Math.sqrt(goalDx * goalDx + goalDy * goalDy); if (goalDist > 0) { ball.velocityX = goalDx / goalDist * 18; // Powerful shot ball.velocityY = goalDy / goalDist * 18; ball.active = true; // Visual effect for powerful shot tween(self, { scaleX: 1.4, scaleY: 1.4, tint: 0xFF4500 }, { duration: 300, onFinish: function onFinish() { tween(self, { scaleX: self.flowActive ? 1.2 : 1, scaleY: self.flowActive ? 1.2 : 1, tint: self.flowActive ? 0xFF4500 : colorOverride || 0xFFFFFF }, { duration: 300 }); } }); } // Reset after shot self.readyToShoot = false; } else { // Ball not found at target, stop rushing self.rushingToBall = false; } } } else if (!self.rouletteActive && !self.monsterDribblingActive && distance < 400) { // Normal ball pursuit var chaseSpeed = distance < 150 ? self.speed * 1.3 : self.speed * 1.1; self.x += dx / distance * chaseSpeed; self.y += dy / distance * chaseSpeed; // Start abilities when close to ball if (distance < 80) { // Roulette (normal cooldown applies) if (!self.rouletteActive && self.rouletteCooldown <= 0) { var shouldUseRoulette = Math.random() < 0.4; // 40% chance if (shouldUseRoulette) { self.rouletteActive = true; self.rouletteStartTime = Date.now(); self.rouletteOriginX = self.x; self.rouletteOriginY = self.y; // If Flow was triggered for Bachira, activate Monster Trans/Flow now if (self.flowTriggerChecked && !self.flowActive) { self.flowActive = true; self.monsterTransActive = true; // Show Flow text above Bachira if (!self.flowText) { self.flowText = self.addChild(new Text2('MONSTER TRANS', { size: 48, fill: 0xFF0000 })); self.flowText.anchor.set(0.5, 0.5); self.flowText.x = 0; self.flowText.y = -100; self.flowText.alpha = 1; tween(self.flowText, { scaleX: 1.5, scaleY: 1.5, alpha: 1 }, { duration: 300, onFinish: function onFinish() { tween(self.flowText, { scaleX: 1, scaleY: 1, alpha: 1 }, { duration: 300 }); } }); } // Create Monster Trans visual effect if (!self.monsterTransVisual) { self.monsterTransVisual = self.addChild(LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, scaleX: 2, scaleY: 2, tint: 0xFF0000 })); self.monsterTransVisual.alpha = 0.3; } // Transform player appearance tween(playerGraphics, { tint: 0xFF4500, scaleX: 1.2, scaleY: 1.2 }, { duration: 500 }); } if (!self.flowActive) { self.rouletteCooldown = self.rouletteCooldownTime; } // Visual effect for roulette start tween(self, { tint: 0x00FFFF }, { duration: 100, onFinish: function onFinish() { tween(self, { tint: self.flowActive ? 0xFF4500 : colorOverride || 0xFFFFFF }, { duration: 100 }); } }); } } // Monster Dribbling (no cooldown in Flow) if (!self.monsterDribblingActive && (self.flowActive || self.monsterDribblingCooldown <= 0)) { var shouldUseMonsterDribbling = Math.random() < 0.6; // 60% chance if (shouldUseMonsterDribbling) { self.monsterDribblingActive = true; self.monsterDribblingStartTime = Date.now(); self.monsterDribblingStartX = self.x; self.monsterDribblingStartY = self.y; // Target toward opponent goal self.monsterDribblingTargetX = opponentGoal.x + (Math.random() - 0.5) * 200; self.monsterDribblingTargetY = opponentGoal.y + 300; // If Flow was triggered for Bachira, activate Monster Trans/Flow now if (self.flowTriggerChecked && !self.flowActive) { self.flowActive = true; self.monsterTransActive = true; // Show Flow text above Bachira if (!self.flowText) { self.flowText = self.addChild(new Text2('MONSTER TRANS', { size: 48, fill: 0xFF0000 })); self.flowText.anchor.set(0.5, 0.5); self.flowText.x = 0; self.flowText.y = -100; self.flowText.alpha = 1; tween(self.flowText, { scaleX: 1.5, scaleY: 1.5, alpha: 1 }, { duration: 300, onFinish: function onFinish() { tween(self.flowText, { scaleX: 1, scaleY: 1, alpha: 1 }, { duration: 300 }); } }); } // Create Monster Trans visual effect if (!self.monsterTransVisual) { self.monsterTransVisual = self.addChild(LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, scaleX: 2, scaleY: 2, tint: 0xFF0000 })); self.monsterTransVisual.alpha = 0.3; } // Transform player appearance tween(playerGraphics, { tint: 0xFF4500, scaleX: 1.2, scaleY: 1.2 }, { duration: 500 }); } if (!self.flowActive) { self.monsterDribblingCooldown = self.monsterDribblingCooldownTime; } // Visual effect for monster dribbling start tween(self, { tint: 0xFF0000, scaleX: 1.3, scaleY: 1.3 }, { duration: 200, onFinish: function onFinish() { tween(self, { tint: self.flowActive ? 0xFF4500 : colorOverride || 0xFFFFFF, scaleX: self.flowActive ? 1.2 : 1, scaleY: self.flowActive ? 1.2 : 1 }, { duration: 200 }); } }); } } } } else if (!self.rouletteActive && !self.monsterDribblingActive && distance > 500) { // Return to home position when not actively playing var homeDx = self.homeX - self.x; var homeDy = self.homeY - self.y; var homeDistance = Math.sqrt(homeDx * homeDx + homeDy * homeDy); if (homeDistance > 50) { self.x += homeDx / homeDistance * self.speed * 0.4; self.y += homeDy / homeDistance * self.speed * 0.4; } } }; self.applyRouletteStun = function () { var opponentsInRange = []; for (var i = 0; i < opponents.length; i++) { var opponent = opponents[i]; var opponentDist = Math.sqrt((opponent.x - self.x) * (opponent.x - self.x) + (opponent.y - self.y) * (opponent.y - self.y)); if (opponentDist <= self.rouletteStunRadius) { opponentsInRange.push(opponent); } } // Stun opponents in range for (var i = 0; i < opponentsInRange.length; i++) { var opponent = opponentsInRange[i]; opponent.stunned = true; opponent.originalSpeed = opponent.speed; opponent.speed = 0; // Completely stop them self.rouletteStunnedOpponents.push(opponent); // Visual effect for stunned opponent tween(opponent, { tint: 0x00FFFF, scaleX: 1.1, scaleY: 1.1 }, { duration: 200 }); } if (opponentsInRange.length > 0) { self.rouletteStunEnd = Date.now() + 3000; // 3 seconds stun } // After Roulette, throw ball to edge and rush to it self.throwBallToEdgeAndRush(); }; self.applyMonsterDribblingStun = function () { var opponentsInRange = []; for (var i = 0; i < opponents.length; i++) { var opponent = opponents[i]; var opponentDist = Math.sqrt((opponent.x - self.x) * (opponent.x - self.x) + (opponent.y - self.y) * (opponent.y - self.y)); if (opponentDist <= self.monsterDribblingStunRadius) { opponentsInRange.push(opponent); } } // Stun opponents in range for (var i = 0; i < opponentsInRange.length; i++) { var opponent = opponentsInRange[i]; opponent.stunned = true; opponent.originalSpeed = opponent.speed; opponent.speed = 0; // Completely stop them self.monsterDribblingStunnedOpponents.push(opponent); // Visual effect for stunned opponent tween(opponent, { tint: 0xFF0000, scaleX: 1.2, scaleY: 1.2 }, { duration: 250 }); } if (opponentsInRange.length > 0) { self.monsterDribblingStunEnd = Date.now() + 4000; // 4 seconds stun } }; self.throwBallToEdgeAndRush = function () { // Determine which edge to throw to (left or right side of field) var throwToLeft = self.x < 1024; // If Bachira is on left side, throw left; otherwise right var edgeX = throwToLeft ? 200 : 1848; // Near left or right edge var edgeY = self.y + (Math.random() - 0.5) * 200; // Slightly randomize Y position // Ensure edge Y is within field bounds if (edgeY < 300) edgeY = 300; if (edgeY > 2400) edgeY = 2400; // Throw ball to edge with moderate power var throwDx = edgeX - ball.x; var throwDy = edgeY - ball.y; var throwDist = Math.sqrt(throwDx * throwDx + throwDy * throwDy); if (throwDist > 0) { ball.velocityX = throwDx / throwDist * 10; ball.velocityY = throwDy / throwDist * 10; ball.active = true; } // Set rush target and start rushing self.rushTargetX = edgeX; self.rushTargetY = edgeY; self.rushingToBall = true; self.readyToShoot = false; // Visual effect for ball throw tween(ball, { scaleX: 1.3, scaleY: 1.3, tint: 0x00FFFF }, { duration: 200, onFinish: function onFinish() { tween(ball, { scaleX: 1, scaleY: 1, tint: 0xFFFFFF }, { duration: 200 }); } }); }; return self; }); var MidfieldPlayer = Container.expand(function () { var self = Container.call(this); var opponentGraphics = self.attachAsset('opponent', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 3; self.role = 'midfield'; self.homeX = 1024; self.homeY = 1000; self.hasBall = false; // Dribbling state self.isDribbling = false; self.dribbleStartTime = 0; self.dribbleDuration = 1000; self.dribbleRadius = 120; self.dribbleStartAngle = 0; self.dribbleEndAngle = 0; self.dribbleOriginX = 0; self.dribbleOriginY = 0; self.hasDribbled = false; self.update = function () { // Steal ball if player is inside opponent var playerDist = Math.sqrt((player.x - self.x) * (player.x - self.x) + (player.y - self.y) * (player.y - self.y)); if (playerDist < 80 && player.hasBall) { // Steal the ball player.hasBall = false; ball.active = true; // Ball moves away from player, toward midfield var stealDx = self.x - player.x; var stealDy = self.y - player.y; var stealDist = Math.sqrt(stealDx * stealDx + stealDy * stealDy); if (stealDist > 0) { ball.velocityX = stealDx / stealDist * 10; ball.velocityY = stealDy / stealDist * 10; } // Prevent immediate re-attachment ballDetachCooldown = ballDetachCooldownTime; } var dx = ball.x - self.x; var dy = ball.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); // Midfield: get ball and pass to forward if (distance < 350) { // Move toward ball with increased speed when chasing var chaseSpeed = distance < 150 ? self.speed * 1.5 : self.speed * 1.2; self.x += dx / distance * chaseSpeed; self.y += dy / distance * chaseSpeed; // If close to ball, run away from player and pass to forward if (distance < 80) { // Move away from player for a moment var awayDx = self.x - player.x; var awayDy = self.y - player.y; var awayDist = Math.sqrt(awayDx * awayDx + awayDy * awayDy); if (awayDist > 0) { tween(self, { x: self.x + awayDx / awayDist * 120, y: self.y + awayDy / awayDist * 120 }, { duration: 200, easing: tween.cubicOut }); } // Find nearest forward player var nearestForward = null; var nearestDistance = Infinity; for (var i = 0; i < opponents.length; i++) { if (opponents[i].role === 'forward') { var forwardDx = opponents[i].x - self.x; var forwardDy = opponents[i].y - self.y; var forwardDistance = Math.sqrt(forwardDx * forwardDx + forwardDy * forwardDy); if (forwardDistance < nearestDistance) { nearestDistance = forwardDistance; nearestForward = opponents[i]; } } } // Pass to forward if found if (nearestForward) { // Perfect pass: ball goes directly to forward with good speed var passDx = nearestForward.x - ball.x; var passDy = nearestForward.y - ball.y; var passDistance = Math.sqrt(passDx * passDx + passDy * passDy); if (passDistance > 0) { ball.velocityX = passDx / passDistance * 10; ball.velocityY = passDy / passDistance * 10; } } else { // No forward to pass to: perform dribbling and curved shot if (!self.isDribbling) { // Start dribbling: move in a half-circle around the player self.isDribbling = true; self.dribbleStartTime = Date.now(); self.dribbleDuration = 1000; // 1 second self.dribbleRadius = 120; // Calculate angle from midfield to player var angleToPlayer = Math.atan2(player.y - self.y, player.x - self.x); self.dribbleStartAngle = angleToPlayer - Math.PI / 2; self.dribbleEndAngle = angleToPlayer + Math.PI / 2; self.dribbleOriginX = self.x; self.dribbleOriginY = self.y; self.hasDribbled = false; } if (self.isDribbling) { var elapsed = Date.now() - self.dribbleStartTime; var t = Math.min(elapsed / self.dribbleDuration, 1); // Interpolate angle for half-circle var angle = self.dribbleStartAngle + (self.dribbleEndAngle - self.dribbleStartAngle) * t; self.x = self.dribbleOriginX + Math.cos(angle) * self.dribbleRadius; self.y = self.dribbleOriginY + Math.sin(angle) * self.dribbleRadius; // Ball follows midfield during dribble if (distance < 80) { ball.x = self.x; ball.y = self.y; ball.velocityX = 0; ball.velocityY = 0; } // When dribble completes, shoot with curve if (t >= 1 && !self.hasDribbled) { self.hasDribbled = true; self.isDribbling = false; // Falsolu şut: apply curve by adding to X velocity var goalDx = opponentGoal.x - ball.x; var goalDy = opponentGoal.y - ball.y; var goalDistance = Math.sqrt(goalDx * goalDx + goalDy * goalDy); if (goalDistance > 0) { // Add curve: right-footed, so curve to the right (positive X) var curveAmount = 7; ball.velocityX = goalDx / goalDistance * 12 + curveAmount; ball.velocityY = goalDy / goalDistance * 12; ball.active = true; } } } } } } else { // Return to midfield position var homeDx = self.homeX - self.x; var homeDy = self.homeY - self.y; var homeDistance = Math.sqrt(homeDx * homeDx + homeDy * homeDy); if (homeDistance > 50) { self.x += homeDx / homeDistance * self.speed * 0.3; self.y += homeDy / homeDistance * self.speed * 0.3; } } }; return self; }); var NagiPlayer = Container.expand(function (colorOverride) { var self = Container.call(this); var playerGraphics = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5 }); if (typeof colorOverride === "number" && playerGraphics) { playerGraphics.tint = colorOverride; } self.speed = 4; self.role = 'nagi'; self.homeX = 1400; self.homeY = 2000; self.hasBall = false; // --- FLOW SYSTEM for Nagi --- self.flowActive = false; self.flowTriggerChecked = false; self.flowVolleyCount = 0; self.flowVolleyMax = 5; // 5 Revolver Fake Volleys in Flow self.flowText = null; // Fake Volley variables self.fakeVolleyState = 0; // 0: ready, 1: fake shot done, 2: real shot done self.fakeVolleyTarget = null; self.fakeVolleyStunRadius = 120; self.fakeVolleyStunDuration = 2000; // 2 seconds self.fakeVolleyStunnedOpponents = []; self.fakeVolleyStunEnd = 0; // Fake Attack variables self.fakeAttackCooldown = 0; self.fakeAttackCooldownTime = 5000; // Base 5 seconds, will be randomized self.fakeAttackStunRadius = 140; self.fakeAttackStunDuration = 0; // Will be randomized 5-10 seconds self.fakeAttackStunnedOpponents = []; self.fakeAttackStunEnd = 0; self.fakeAttackChance = 0.3; // 30% chance for shots to be fake self.fakeVolleyVisual = null; // Ball pull variables self.ballPullRange = 150; self.ballPullActive = false; self.ballPullVisual = null; self.ballPullCooldown = 0; self.ballPullCooldownTime = 5000; // 5 seconds // Ball control text self.ballControlText = null; self.update = function () { // --- FLOW TRIGGER: If 2 goals scored by Nagi's team, activate Flow for random teammate (including Nagi) --- if (!self.flowActive && !self.flowTriggerChecked && typeof playerScore !== "undefined" && playerScore >= 2) { self.flowTriggerChecked = true; // Pick a random teammate (Nagi, Hiori, Chigiri, Reo) to enter Flow var teammates = []; if (typeof nagi !== "undefined") teammates.push(nagi); if (typeof hiori !== "undefined") teammates.push(hiori); if (typeof chigiri !== "undefined") teammates.push(chigiri); if (typeof reo !== "undefined") teammates.push(reo); if (teammates.length > 0) { var idx = Math.floor(Math.random() * teammates.length); var chosen = teammates[idx]; if (chosen && typeof chosen.flowActive !== "undefined") { chosen.flowActive = true; chosen.flowVolleyCount = 0; // Show Flow text above chosen if (!chosen.flowText) { chosen.flowText = chosen.addChild(new Text2('FLOW', { size: 48, fill: 0x00FFFF })); chosen.flowText.anchor.set(0.5, 0.5); chosen.flowText.x = 0; chosen.flowText.y = -100; chosen.flowText.alpha = 1; tween(chosen.flowText, { scaleX: 1.5, scaleY: 1.5, alpha: 1 }, { duration: 300, onFinish: function onFinish() { tween(chosen.flowText, { scaleX: 1, scaleY: 1, alpha: 1 }, { duration: 300 }); } }); } } } } // Remove Flow text if not in Flow if (!self.flowActive && self.flowText) { self.flowText.destroy(); self.flowText = null; } // Update cooldowns if (self.fakeVolleyStunEnd > 0 && Date.now() > self.fakeVolleyStunEnd) { // Restore stunned opponents for (var i = 0; i < self.fakeVolleyStunnedOpponents.length; i++) { var opponent = self.fakeVolleyStunnedOpponents[i]; opponent.stunned = false; opponent.originalSpeed = opponent.originalSpeed || opponent.speed; opponent.speed = opponent.originalSpeed; tween(opponent, { tint: 0xFFFFFF, scaleX: 1, scaleY: 1 }, { duration: 300 }); } self.fakeVolleyStunnedOpponents = []; self.fakeVolleyStunEnd = 0; } if (self.ballPullCooldown > 0) { self.ballPullCooldown -= 16; if (self.ballPullCooldown < 0) self.ballPullCooldown = 0; } // Update Fake Attack cooldown if (self.fakeAttackCooldown > 0) { self.fakeAttackCooldown -= 16; if (self.fakeAttackCooldown < 0) self.fakeAttackCooldown = 0; } // Handle Fake Attack stun end if (self.fakeAttackStunEnd > 0 && Date.now() > self.fakeAttackStunEnd) { // Restore stunned opponents from Fake Attack for (var i = 0; i < self.fakeAttackStunnedOpponents.length; i++) { var opponent = self.fakeAttackStunnedOpponents[i]; opponent.stunned = false; opponent.originalSpeed = opponent.originalSpeed || opponent.speed; opponent.speed = opponent.originalSpeed; tween(opponent, { tint: 0xFFFFFF, scaleX: 1, scaleY: 1 }, { duration: 300 }); } self.fakeAttackStunnedOpponents = []; self.fakeAttackStunEnd = 0; } var dx = ball.x - self.x; var dy = ball.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); // Nagi Ball Control: Steal from opponent if close and not immune if (!self.nagiStealImmunity) self.nagiStealImmunity = 0; var canSteal = true; if (self.nagiStealImmunity > Date.now()) canSteal = false; // Check for opponent with ball in Ball Control range var stoleFromOpponent = false; if (canSteal) { for (var i = 0; i < opponents.length; i++) { var opp = opponents[i]; var oppDist = Math.sqrt((opp.x - self.x) * (opp.x - self.x) + (opp.y - self.y) * (opp.y - self.y)); if (opp.hasBall && oppDist < 120) { // Steal the ball from opponent opp.hasBall = false; ball.active = true; // Move ball to Nagi's feet ball.velocityX = 0; ball.velocityY = 0; tween(ball, { x: self.x, y: self.y + 40 }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { ball.active = false; self.hasBall = true; } }); // Show "Ball Control" text if (!self.ballControlText) { self.ballControlText = self.addChild(new Text2('Ball Control', { size: 40, fill: 0xFFFFFF })); self.ballControlText.anchor.set(0.5, 0.5); self.ballControlText.x = 0; self.ballControlText.y = -80; tween(self.ballControlText, { alpha: 1, scaleX: 1.2, scaleY: 1.2 }, { duration: 200, onFinish: function onFinish() { LK.setTimeout(function () { tween(self.ballControlText, { alpha: 0, scaleX: 0.8, scaleY: 0.8 }, { duration: 300, onFinish: function onFinish() { if (self.ballControlText) { self.ballControlText.destroy(); self.ballControlText = null; } } }); }, 2000); } }); } // Set 3s immunity for Nagi after stealing self.nagiStealImmunity = Date.now() + 3000; stoleFromOpponent = true; break; } } } // If not stealing from opponent, allow normal ball control from loose ball if (!stoleFromOpponent && distance < 120 && ball.active && !self.hasBall && canSteal) { ball.velocityX = 0; ball.velocityY = 0; tween(ball, { x: self.x, y: self.y + 40 }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { ball.active = false; self.hasBall = true; } }); if (!self.ballControlText) { self.ballControlText = self.addChild(new Text2('Ball Control', { size: 40, fill: 0xFFFFFF })); self.ballControlText.anchor.set(0.5, 0.5); self.ballControlText.x = 0; self.ballControlText.y = -80; tween(self.ballControlText, { alpha: 1, scaleX: 1.2, scaleY: 1.2 }, { duration: 200, onFinish: function onFinish() { LK.setTimeout(function () { tween(self.ballControlText, { alpha: 0, scaleX: 0.8, scaleY: 0.8 }, { duration: 300, onFinish: function onFinish() { if (self.ballControlText) { self.ballControlText.destroy(); self.ballControlText = null; } } }); }, 2000); } }); } } // --- FLOW: 5 Revolver Fake Volley logic --- if (self.flowActive) { // If close to ball, perform up to 5 chained fake volleys (fake+real) in a row if (distance < 80 && self.flowVolleyCount < self.flowVolleyMax && self.fakeVolleyState === 0) { self.fakeVolleyState = 1; self.flowVolleyCount++; // Stun nearby opponents var opponentsInRange = []; for (var i = 0; i < opponents.length; i++) { var opponent = opponents[i]; var opponentDist = Math.sqrt((opponent.x - self.x) * (opponent.x - self.x) + (opponent.y - self.y) * (opponent.y - self.y)); if (opponentDist <= self.fakeVolleyStunRadius) { opponentsInRange.push(opponent); } } for (var i = 0; i < opponentsInRange.length; i++) { var opponent = opponentsInRange[i]; opponent.stunned = true; opponent.originalSpeed = opponent.speed; opponent.speed = 0; self.fakeVolleyStunnedOpponents.push(opponent); tween(opponent, { tint: 0xFFFF00, scaleX: 1.1, scaleY: 1.1 }, { duration: 200 }); } self.fakeVolleyStunEnd = Date.now() + self.fakeVolleyStunDuration; // Fake shot - ball barely moves ball.velocityX = (Math.random() - 0.5) * 2; ball.velocityY = (Math.random() - 0.5) * 2; ball.active = true; tween(self, { scaleX: 1.3, scaleY: 1.3, tint: 0xFFFF00 }, { duration: 200, onFinish: function onFinish() { tween(self, { scaleX: 1, scaleY: 1, tint: 0xFFFFFF }, { duration: 200 }); } }); } else if (self.flowActive && self.fakeVolleyState === 1) { // After fake, do real volley self.fakeVolleyState = 2; var goalDx = opponentGoal.x - ball.x; var goalDy = opponentGoal.y - ball.y; var goalDistance = Math.sqrt(goalDx * goalDx + goalDy * goalDy); if (goalDistance > 0) { ball.velocityX = goalDx / goalDistance * 16; ball.velocityY = goalDy / goalDistance * 16; ball.active = true; } tween(self, { scaleX: 1.4, scaleY: 1.4, tint: 0xFF0000 }, { duration: 300, onFinish: function onFinish() { tween(self, { scaleX: 1, scaleY: 1, tint: 0xFFFFFF }, { duration: 300 }); } }); // Reset fake volley state after a short delay, and chain next if not reached max LK.setTimeout(function () { self.fakeVolleyState = 0; // If not reached 5, chain next volley automatically (simulate rapid-fire) if (self.flowActive && self.flowVolleyCount < self.flowVolleyMax) { // Move Nagi slightly forward for next volley self.x += (opponentGoal.x - self.x) * 0.08; self.y += (opponentGoal.y - self.y) * 0.08; } else if (self.flowActive && self.flowVolleyCount >= self.flowVolleyMax) { // End Flow after 5 volleys self.flowActive = false; self.flowVolleyCount = 0; if (self.flowText) { self.flowText.destroy(); self.flowText = null; } } }, 500); } // Prevent normal volley logic during Flow return; } // After stealing, for 3s, Nagi cannot be stolen from and focuses on goal if (self.hasBall && self.nagiStealImmunity > Date.now()) { // Nagi focuses on goal: move toward opponent goal and shoot if close var goalDx = opponentGoal.x - self.x; var goalDy = opponentGoal.y - self.y; var goalDist = Math.sqrt(goalDx * goalDx + goalDy * goalDy); if (goalDist > 0) { self.x += goalDx / goalDist * self.speed * 1.2; self.y += goalDy / goalDist * self.speed * 1.2; // If close to goal, shoot if (goalDist < 200) { ball.active = true; ball.velocityX = goalDx / goalDist * 16; ball.velocityY = goalDy / goalDist * 16; self.hasBall = false; // Remove immunity after shot self.nagiStealImmunity = 0; } } } else { // If Nagi doesn't have ball, always move to a good attacking position near the opponent goal var attackTargetX = opponentGoal.x + 200 * Math.sin(Date.now() / 1200); // oscillate a bit for realism var attackTargetY = opponentGoal.y + 250; var attackDx = attackTargetX - self.x; var attackDy = attackTargetY - self.y; var attackDist = Math.sqrt(attackDx * attackDx + attackDy * attackDy); if (attackDist > 10) { self.x += attackDx / attackDist * self.speed * 0.8; self.y += attackDy / attackDist * self.speed * 0.8; } } // Ball pull ability - show range when ball is within pull range if (distance <= self.ballPullRange && !self.ballPullActive && self.ballPullCooldown <= 0) { if (!self.ballPullVisual) { // Create ball pull range visual self.ballPullVisual = self.addChild(LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, scaleX: 3, scaleY: 3, tint: 0x00FF00 })); self.ballPullVisual.alpha = 0.2; } // Pull ball towards self if (distance > 30) { self.ballPullActive = true; var pullForce = 8; ball.velocityX = -dx / distance * pullForce; ball.velocityY = -dy / distance * pullForce; ball.active = true; self.ballPullCooldown = self.ballPullCooldownTime; // Visual effect for ball pull tween(self, { scaleX: 1.2, scaleY: 1.2, tint: 0x00FF00 }, { duration: 150, onFinish: function onFinish() { tween(self, { scaleX: 1, scaleY: 1, tint: 0xFFFFFF }, { duration: 150 }); } }); } } else { // Remove ball pull visual if ball is out of range if (self.ballPullVisual) { self.ballPullVisual.destroy(); self.ballPullVisual = null; } self.ballPullActive = false; } // Normal ball pursuit if (distance < 400) { var chaseSpeed = distance < 150 ? self.speed * 1.2 : self.speed * 1.0; self.x += dx / distance * chaseSpeed; self.y += dy / distance * chaseSpeed; // Volley ability when close to ball with Fake Attack chance if (distance < 80) { // Check if this should be a Fake Attack var shouldFakeAttack = self.fakeAttackCooldown <= 0 && Math.random() < self.fakeAttackChance; if (shouldFakeAttack) { // FAKE ATTACK - stun opponents and barely move ball // Find opponents within Fake Attack stun radius var opponentsInRange = []; for (var i = 0; i < opponents.length; i++) { var opponent = opponents[i]; var opponentDist = Math.sqrt((opponent.x - self.x) * (opponent.x - self.x) + (opponent.y - self.y) * (opponent.y - self.y)); if (opponentDist <= self.fakeAttackStunRadius) { opponentsInRange.push(opponent); } } // Stun opponents in range for (var i = 0; i < opponentsInRange.length; i++) { var opponent = opponentsInRange[i]; opponent.stunned = true; opponent.originalSpeed = opponent.speed; opponent.speed = 0; // Completely stop them self.fakeAttackStunnedOpponents.push(opponent); // Visual effect for stunned opponent tween(opponent, { tint: 0xFF6600, // Orange tint for Fake Attack scaleX: 1.2, scaleY: 1.2 }, { duration: 250 }); } // Randomize stun duration (5-10 seconds) self.fakeAttackStunDuration = 5000 + Math.random() * 5000; self.fakeAttackStunEnd = Date.now() + self.fakeAttackStunDuration; // Randomize next cooldown (5-10 seconds) self.fakeAttackCooldownTime = 5000 + Math.random() * 5000; self.fakeAttackCooldown = self.fakeAttackCooldownTime; // Fake attack - ball barely moves ball.velocityX = (Math.random() - 0.5) * 3; ball.velocityY = (Math.random() - 0.5) * 3; ball.active = true; // Visual effect for Fake Attack tween(self, { scaleX: 1.4, scaleY: 1.4, tint: 0xFF6600 // Orange for Fake Attack }, { duration: 300, onFinish: function onFinish() { tween(self, { scaleX: 1, scaleY: 1, tint: 0xFFFFFF }, { duration: 300 }); } }); } else if (self.fakeVolleyState === 0) { // First shot - FAKE VOLLEY self.fakeVolleyState = 1; // Find opponents within stun radius var opponentsInRange = []; for (var i = 0; i < opponents.length; i++) { var opponent = opponents[i]; var opponentDist = Math.sqrt((opponent.x - self.x) * (opponent.x - self.x) + (opponent.y - self.y) * (opponent.y - self.y)); if (opponentDist <= self.fakeVolleyStunRadius) { opponentsInRange.push(opponent); } } // Stun opponents in range for (var i = 0; i < opponentsInRange.length; i++) { var opponent = opponentsInRange[i]; opponent.stunned = true; opponent.originalSpeed = opponent.speed; opponent.speed = 0; // Completely stop them self.fakeVolleyStunnedOpponents.push(opponent); // Visual effect for stunned opponent tween(opponent, { tint: 0xFFFF00, scaleX: 1.1, scaleY: 1.1 }, { duration: 200 }); } self.fakeVolleyStunEnd = Date.now() + self.fakeVolleyStunDuration; // Fake shot - ball barely moves to show it's fake ball.velocityX = (Math.random() - 0.5) * 2; ball.velocityY = (Math.random() - 0.5) * 2; ball.active = true; // Visual effect for fake shot tween(self, { scaleX: 1.3, scaleY: 1.3, tint: 0xFFFF00 }, { duration: 200, onFinish: function onFinish() { tween(self, { scaleX: 1, scaleY: 1, tint: 0xFFFFFF }, { duration: 200 }); } }); } else if (self.fakeVolleyState === 1) { // Second shot - REAL VOLLEY self.fakeVolleyState = 2; // Real powerful shot toward opponent goal var goalDx = opponentGoal.x - ball.x; var goalDy = opponentGoal.y - ball.y; var goalDistance = Math.sqrt(goalDx * goalDx + goalDy * goalDy); if (goalDistance > 0) { ball.velocityX = goalDx / goalDistance * 16; ball.velocityY = goalDy / goalDistance * 16; ball.active = true; } // Visual effect for real shot tween(self, { scaleX: 1.4, scaleY: 1.4, tint: 0xFF0000 }, { duration: 300, onFinish: function onFinish() { tween(self, { scaleX: 1, scaleY: 1, tint: 0xFFFFFF }, { duration: 300 }); } }); // Reset fake volley state after a delay LK.setTimeout(function () { self.fakeVolleyState = 0; }, 3000); } } } else { // Return to home position when not actively playing var homeDx = self.homeX - self.x; var homeDy = self.homeY - self.y; var homeDistance = Math.sqrt(homeDx * homeDx + homeDy * homeDy); if (homeDistance > 50) { self.x += homeDx / homeDistance * self.speed * 0.4; self.y += homeDy / homeDistance * self.speed * 0.4; } } }; return self; }); var Player = Container.expand(function () { var self = Container.call(this); var playerGraphics = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 3; self.hasBall = false; return self; }); var ReoPlayer = Container.expand(function (colorOverride) { var self = Container.call(this); var playerGraphics = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5 }); if (typeof colorOverride === "number" && playerGraphics) { playerGraphics.tint = colorOverride; } self.speed = 4; self.role = 'reo'; self.homeX = 600; self.homeY = 1800; self.hasBall = false; // Mode switching variables self.isDefensiveMode = true; self.defensiveColor = 0x000000; // Black self.attackingColor = 0xffa500; // Orange self.modeSwitch = 0; self.modeSwitchInterval = 5000; // 5 seconds // Chameleon ability variables self.chameleonCooldown = 0; self.chameleonInterval = 30000; // 30 seconds self.copiedStats = null; self.originalSpeed = 4; self.originalDribbling = 1; self.originalShot = 1; // Copied ability variables self.copiedWinterZone = false; self.copiedWinterZoneRadius = 200; self.copiedWinterZoneCooldown = 0; self.copiedWinterZoneActive = false; self.copiedWinterZoneDuration = 0; self.copiedWinterZoneMaxDuration = 8000; self.copiedSlowedOpponents = []; self.copiedWinterZoneVisual = null; self.copiedSpeedBurst = false; self.copiedSpeedBurstCooldown = 0; self.copiedSpeedBurstActive = false; self.copiedBurstSpeed = 10; self.copiedNormalSpeed = 4; self.update = function () { // Update mode switching self.modeSwitch += 16; if (self.modeSwitch >= self.modeSwitchInterval) { self.modeSwitch = 0; self.isDefensiveMode = !self.isDefensiveMode; // Change color based on mode if (self.isDefensiveMode) { tween(playerGraphics, { tint: self.defensiveColor }, { duration: 300 }); } else { tween(playerGraphics, { tint: self.attackingColor }, { duration: 300 }); } } // Update Chameleon cooldown self.chameleonCooldown += 16; if (self.chameleonCooldown >= self.chameleonInterval) { self.chameleonCooldown = 0; self.activateChameleon(); } // Update copied abilities if (self.copiedWinterZone) { // Update Winter Zone cooldown if (self.copiedWinterZoneCooldown > 0) { self.copiedWinterZoneCooldown -= 16; if (self.copiedWinterZoneCooldown < 0) self.copiedWinterZoneCooldown = 0; } // Winter Zone duration and effect if (self.copiedWinterZoneActive) { self.copiedWinterZoneDuration -= 16; if (self.copiedWinterZoneDuration <= 0) { self.copiedWinterZoneActive = false; // Remove Winter Zone visual if (self.copiedWinterZoneVisual) { self.copiedWinterZoneVisual.destroy(); self.copiedWinterZoneVisual = null; } // Restore opponent speeds for (var i = 0; i < self.copiedSlowedOpponents.length; i++) { var opponent = self.copiedSlowedOpponents[i]; opponent.speed = opponent.originalSpeed || opponent.speed * 2; } self.copiedSlowedOpponents = []; } else { // Apply Winter Zone effect to nearby opponents for (var i = 0; i < opponents.length; i++) { var opponent = opponents[i]; var dist = Math.sqrt((opponent.x - self.x) * (opponent.x - self.x) + (opponent.y - self.y) * (opponent.y - self.y)); if (dist <= self.copiedWinterZoneRadius) { if (self.copiedSlowedOpponents.indexOf(opponent) === -1) { opponent.originalSpeed = opponent.speed; opponent.speed = opponent.speed * 0.3; // Slow to 30% speed self.copiedSlowedOpponents.push(opponent); } } } } } // Activate Winter Zone when opponents get close if (!self.copiedWinterZoneActive && self.copiedWinterZoneCooldown <= 0) { var nearbyOpponents = 0; for (var i = 0; i < opponents.length; i++) { var opponent = opponents[i]; var dist = Math.sqrt((opponent.x - self.x) * (opponent.x - self.x) + (opponent.y - self.y) * (opponent.y - self.y)); if (dist <= self.copiedWinterZoneRadius + 50) { nearbyOpponents++; } } if (nearbyOpponents >= 2) { // Activate Winter Zone self.copiedWinterZoneActive = true; self.copiedWinterZoneDuration = self.copiedWinterZoneMaxDuration; self.copiedWinterZoneCooldown = 12000; // 12 seconds cooldown // Create Winter Zone visual area self.copiedWinterZoneVisual = self.addChild(LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, scaleX: 4, scaleY: 4, tint: 0x87CEEB })); self.copiedWinterZoneVisual.alpha = 0.3; // Visual effect tween(self, { scaleX: 1.5, scaleY: 1.5, tint: 0x87CEEB }, { duration: 200, onFinish: function onFinish() { tween(self, { scaleX: 1, scaleY: 1, tint: self.isDefensiveMode ? self.defensiveColor : self.attackingColor }, { duration: 200 }); } }); } } } if (self.copiedSpeedBurst) { // Update Speed Burst cooldown if (self.copiedSpeedBurstCooldown > 0) { self.copiedSpeedBurstCooldown -= 16; if (self.copiedSpeedBurstCooldown < 0) self.copiedSpeedBurstCooldown = 0; } // Speed burst when close to ball if (!self.copiedSpeedBurstActive && self.copiedSpeedBurstCooldown <= 0 && distance < 100) { self.copiedSpeedBurstActive = true; self.copiedSpeedBurstCooldown = 8000; // 8 seconds cooldown self.speed = self.copiedBurstSpeed; // Visual effect for speed burst tween(self, { scaleX: 1.2, scaleY: 1.2 }, { duration: 100, onFinish: function onFinish() { tween(self, { scaleX: 1, scaleY: 1 }, { duration: 100 }); } }); // Speed burst lasts for 2 seconds LK.setTimeout(function () { self.copiedSpeedBurstActive = false; self.speed = self.copiedNormalSpeed; }, 2000); } } var dx = ball.x - self.x; var dy = ball.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); // Mode-based behavior if (self.isDefensiveMode) { // Defensive mode: more active interception and ball pursuit if (distance < 500) { var defensiveSpeed = self.speed * 1.1; self.x += dx / distance * defensiveSpeed; self.y += dy / distance * defensiveSpeed; // Defensive tackle if (distance < 80) { var clearX = ball.x < 1024 ? ball.x - 300 : ball.x + 300; var clearY = ball.y - 200; var clearDx = clearX - ball.x; var clearDy = clearY - ball.y; var clearDist = Math.sqrt(clearDx * clearDx + clearDy * clearDy); if (clearDist > 0) { ball.velocityX = clearDx / clearDist * 8; ball.velocityY = clearDy / clearDist * 8; } } } else { // Return to defensive position, but move more actively var homeDx = self.homeX - self.x; var homeDy = self.homeY - self.y; var homeDistance = Math.sqrt(homeDx * homeDx + homeDy * homeDy); if (homeDistance > 50) { self.x += homeDx / homeDistance * self.speed * 0.7; self.y += homeDy / homeDistance * self.speed * 0.7; } } } else { // Attacking mode: chase ball very aggressively and support attack if (distance < 700) { var attackSpeed = self.speed * 1.7; self.x += dx / distance * attackSpeed; self.y += dy / distance * attackSpeed; // Attack shot if (distance < 80) { var goalDx = opponentGoal.x - ball.x; var goalDy = opponentGoal.y - ball.y; var goalDistance = Math.sqrt(goalDx * goalDx + goalDy * goalDy); if (goalDistance > 0) { ball.velocityX = goalDx / goalDistance * 14; ball.velocityY = goalDy / goalDistance * 14; } } } else { // If not near ball, move up to a supporting attacking position var supportX = opponentGoal.x - 200; var supportY = opponentGoal.y + 400; var supportDx = supportX - self.x; var supportDy = supportY - self.y; var supportDist = Math.sqrt(supportDx * supportDx + supportDy * supportDy); if (supportDist > 30) { self.x += supportDx / supportDist * self.speed * 0.7; self.y += supportDy / supportDist * self.speed * 0.7; } } } }; self.activateChameleon = function () { // Find random NPC to copy stats from (including player team members) var availableNPCs = []; for (var i = 0; i < opponents.length; i++) { availableNPCs.push(opponents[i]); } // Also add player team members with special abilities if (typeof hiori !== 'undefined') availableNPCs.push(hiori); if (typeof chigiri !== 'undefined') availableNPCs.push(chigiri); if (typeof nagi !== 'undefined') availableNPCs.push(nagi); if (availableNPCs.length > 0) { var randomNPC = availableNPCs[Math.floor(Math.random() * availableNPCs.length)]; // Copy stats from random NPC self.copiedStats = { speed: randomNPC.speed || self.originalSpeed, dribbling: randomNPC.dribbleSpeed || self.originalDribbling, shot: randomNPC.burstSpeed || self.originalShot, role: randomNPC.role || 'reo' }; // Apply copied stats self.speed = self.copiedStats.speed; // Copy special abilities based on role if (self.copiedStats.role === 'hiori') { // Copy Winter Zone ability self.copiedWinterZone = true; self.copiedWinterZoneRadius = 200; self.copiedWinterZoneCooldown = 0; self.copiedWinterZoneActive = false; self.copiedWinterZoneDuration = 0; self.copiedWinterZoneMaxDuration = 8000; // Slightly shorter than original self.copiedSlowedOpponents = []; self.copiedWinterZoneVisual = null; } else if (self.copiedStats.role === 'chigiri') { // Copy Speed Burst ability self.copiedSpeedBurst = true; self.copiedSpeedBurstCooldown = 0; self.copiedSpeedBurstActive = false; self.copiedBurstSpeed = 10; self.copiedNormalSpeed = self.speed; } else { // Reset copied abilities self.copiedWinterZone = false; self.copiedSpeedBurst = false; } // Visual effect for Chameleon activation tween(self, { scaleX: 1.3, scaleY: 1.3, tint: 0xff00ff }, { duration: 200, onFinish: function onFinish() { tween(self, { scaleX: 1, scaleY: 1, tint: self.isDefensiveMode ? self.defensiveColor : self.attackingColor }, { duration: 200 }); } }); } }; return self; }); var SaePlayer = Container.expand(function (colorOverride) { var self = Container.call(this); var playerGraphics = self.attachAsset('opponent', { anchorX: 0.5, anchorY: 0.5 }); if (typeof colorOverride === "number" && playerGraphics) { playerGraphics.tint = colorOverride; } self.speed = 4.5; self.role = 'sae'; self.homeX = 1024; self.homeY = 800; self.hasBall = false; // Perfect Pass variables self.perfectPassRange = 800; self.perfectPassCooldown = 0; self.perfectPassCooldownTime = 8000; // 8 seconds // Half-circle dribbling variables self.isDribbling = false; self.dribbleStartTime = 0; self.dribbleDuration = 1500; // 1.5 seconds self.dribbleRadius = 100; self.dribbleStartAngle = 0; self.dribbleEndAngle = 0; self.dribbleOriginX = 0; self.dribbleOriginY = 0; self.dribbleStunRadius = 150; self.dribbleStunDuration = 2000; // 2 seconds self.dribbleStunnedOpponents = []; self.dribbleStunEnd = 0; // Zigzag dribbling variables self.isZigzagDribbling = false; self.zigzagStartTime = 0; self.zigzagDuration = 2000; // 2 seconds self.zigzagStartX = 0; self.zigzagStartY = 0; self.zigzagTargetX = 0; self.zigzagTargetY = 0; self.zigzagDevourRadius = 120; // Zigzag chain variables self.zigzagCount = 0; self.zigzagPaused = false; self.zigzagPauseStart = 0; self.zigzagPauseDuration = 10000; // 10 seconds pause after 6 zigzags // Chop dribbling variables self.isChopDribbling = false; self.chopStartTime = 0; self.chopDuration = 1000; // 1 second self.chopStartX = 0; self.chopStartY = 0; self.chopTargetX = 0; self.chopTargetY = 0; self.chopDevourRadius = 100; // Devoured effect variables self.devouredOpponents = []; self.devouredEndTime = 0; self.devouredDuration = 3000; // 3 seconds // Dash ability variables self.dashCooldown = 0; self.dashCooldownTime = 10000; // 10 seconds self.dashSpeed = 10; self.dashDuration = 800; // 0.8 seconds self.dashActive = false; self.dashEndTime = 0; // False shot variables self.falseShotCooldown = 0; self.falseShotCooldownTime = 12000; // 12 seconds self.falseShotActive = false; // FLOW SYSTEM for Sae if (typeof self.flowActive === "undefined") { self.flowActive = false; self.flowTriggerChecked = false; self.flowDribbleCount = 0; self.flowDribbleMax = 999; // Unlimited while in Flow self.flowText = null; self.flowHilalDribbling = false; self.flowHilalStartTime = 0; self.flowHilalDuration = 1200; // ms per crescent self.flowHilalOriginX = 0; self.flowHilalOriginY = 0; self.flowHilalRadius = 180; self.flowHilalStartAngle = 0; self.flowHilalEndAngle = 0; self.flowHilalPhase = 0; self.flowHilalCount = 0; self.flowHilalMax = 4; // Number of crescents before shot self.flowHilalShotDone = false; } // FLOW TRIGGER: If 2 goals scored by Sae, activate Flow (only once) if (!self.flowActive && !self.flowTriggerChecked && typeof opponentScore !== "undefined" && opponentScore >= 2) { self.flowActive = true; self.flowDribbleCount = 0; self.flowTriggerChecked = true; self.flowHilalDribbling = false; self.flowHilalCount = 0; self.flowHilalShotDone = false; // Show Flow text above Sae if (!self.flowText) { self.flowText = self.addChild(new Text2('FLOW', { size: 48, fill: 0xFF6600 })); self.flowText.anchor.set(0.5, 0.5); self.flowText.x = 0; self.flowText.y = -100; self.flowText.alpha = 1; tween(self.flowText, { scaleX: 1.5, scaleY: 1.5, alpha: 1 }, { duration: 300, onFinish: function onFinish() { tween(self.flowText, { scaleX: 1, scaleY: 1, alpha: 1 }, { duration: 300 }); } }); } } // Remove Flow text if not in Flow if (!self.flowActive && self.flowText) { self.flowText.destroy(); self.flowText = null; } self.update = function () { // Update cooldowns if (self.perfectPassCooldown > 0) { self.perfectPassCooldown -= 16; if (self.perfectPassCooldown < 0) self.perfectPassCooldown = 0; } if (self.dashCooldown > 0) { self.dashCooldown -= 16; if (self.dashCooldown < 0) self.dashCooldown = 0; } if (self.falseShotCooldown > 0) { self.falseShotCooldown -= 16; if (self.falseShotCooldown < 0) self.falseShotCooldown = 0; } // Handle dribble stun end if (self.dribbleStunEnd > 0 && Date.now() > self.dribbleStunEnd) { // Restore stunned opponents for (var i = 0; i < self.dribbleStunnedOpponents.length; i++) { var opponent = self.dribbleStunnedOpponents[i]; opponent.stunned = false; opponent.originalSpeed = opponent.originalSpeed || opponent.speed; opponent.speed = opponent.originalSpeed; tween(opponent, { tint: 0xFFFFFF, scaleX: 1, scaleY: 1 }, { duration: 300 }); } self.dribbleStunnedOpponents = []; self.dribbleStunEnd = 0; } // Handle dash duration if (self.dashActive && Date.now() > self.dashEndTime) { self.dashActive = false; self.speed = 4.5; // Return to normal speed } // Steal ball if player is inside opponent var playerDist = Math.sqrt((player.x - self.x) * (player.x - self.x) + (player.y - self.y) * (player.y - self.y)); if (playerDist < 80 && player.hasBall) { // Steal the ball player.hasBall = false; ball.active = true; // Ball moves away from player, toward Sae var stealDx = self.x - player.x; var stealDy = self.y - player.y; var stealDist = Math.sqrt(stealDx * stealDx + stealDy * stealDy); if (stealDist > 0) { ball.velocityX = stealDx / stealDist * 10; ball.velocityY = stealDy / stealDist * 10; } // Prevent immediate re-attachment ballDetachCooldown = ballDetachCooldownTime; } var dx = ball.x - self.x; var dy = ball.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); // Handle devoured opponents restoration if (self.devouredEndTime > 0 && Date.now() > self.devouredEndTime) { // Restore devoured opponents for (var i = 0; i < self.devouredOpponents.length; i++) { var opponent = self.devouredOpponents[i]; opponent.speed = opponent.originalSpeed || opponent.speed * 2; opponent.devoured = false; tween(opponent, { tint: 0xFFFFFF, scaleX: 1, scaleY: 1 }, { duration: 300 }); } self.devouredOpponents = []; self.devouredEndTime = 0; } // Half-circle dribbling logic if (self.isDribbling) { var elapsed = Date.now() - self.dribbleStartTime; var t = Math.min(elapsed / self.dribbleDuration, 1); // Interpolate angle for half-circle var angle = self.dribbleStartAngle + (self.dribbleEndAngle - self.dribbleStartAngle) * t; self.x = self.dribbleOriginX + Math.cos(angle) * self.dribbleRadius; self.y = self.dribbleOriginY + Math.sin(angle) * self.dribbleRadius; // Ball follows during dribble if (distance < 80) { ball.x = self.x; ball.y = self.y; ball.velocityX = 0; ball.velocityY = 0; } // When dribble completes, apply Devoured effect if (t >= 1) { self.isDribbling = false; self.applyDevouredEffect(self.dribbleStunRadius); } } // Zigzag dribbling logic if (self.isZigzagDribbling) { var elapsed = Date.now() - self.zigzagStartTime; var progress = Math.min(elapsed / self.zigzagDuration, 1); // Create zigzag pattern var zigzagAmplitude = 60; var zigzagFrequency = 6; var zigzagOffset = Math.sin(progress * Math.PI * zigzagFrequency) * zigzagAmplitude; // Move toward target with zigzag motion var targetDx = self.zigzagTargetX - self.zigzagStartX; var targetDy = self.zigzagTargetY - self.zigzagStartY; var targetDist = Math.sqrt(targetDx * targetDx + targetDy * targetDy); if (targetDist > 0) { // Calculate perpendicular vector for zigzag var perpX = -targetDy / targetDist; var perpY = targetDx / targetDist; // Apply zigzag movement self.x = self.zigzagStartX + targetDx * progress + perpX * zigzagOffset; self.y = self.zigzagStartY + targetDy * progress + perpY * zigzagOffset; // Ball follows during dribble if (distance < 100) { ball.x = self.x; ball.y = self.y; ball.velocityX = 0; ball.velocityY = 0; } } // End zigzag dribbling and apply Devoured effect if (progress >= 1) { self.isZigzagDribbling = false; self.applyDevouredEffect(self.zigzagDevourRadius); // Chain up to 6 zigzags, then pause self.zigzagCount = (self.zigzagCount || 0) + 1; if (self.zigzagCount < 6) { // Start another zigzag immediately self.isZigzagDribbling = true; self.zigzagStartTime = Date.now(); self.zigzagStartX = self.x; self.zigzagStartY = self.y; // Dribble toward player goal with reduced distance self.zigzagTargetX = self.x + (playerGoal.x - self.x) * 0.3 + (Math.random() - 0.5) * 80; self.zigzagTargetY = self.y + (playerGoal.y - self.y) * 0.3 + 50; } else { // Pause after 6 zigzags self.zigzagPaused = true; self.zigzagPauseStart = Date.now(); self.zigzagCount = 0; } } } // Zigzag pause logic if (self.zigzagPaused) { var pauseElapsed = Date.now() - self.zigzagPauseStart; if (pauseElapsed >= self.zigzagPauseDuration) { self.zigzagPaused = false; } } // Chop dribbling logic if (self.isChopDribbling) { var elapsed = Date.now() - self.chopStartTime; var progress = Math.min(elapsed / self.chopDuration, 1); // Quick chop movement - sharp direction change var chopPhase = progress < 0.5 ? progress * 2 : 1 - (progress - 0.5) * 2; var chopIntensity = Math.sin(chopPhase * Math.PI) * 80; // Move with chop motion var targetDx = self.chopTargetX - self.chopStartX; var targetDy = self.chopTargetY - self.chopStartY; var targetDist = Math.sqrt(targetDx * targetDx + targetDy * targetDy); if (targetDist > 0) { // Calculate perpendicular vector for chop var perpX = -targetDy / targetDist; var perpY = targetDx / targetDist; // Apply chop movement self.x = self.chopStartX + targetDx * progress + perpX * chopIntensity; self.y = self.chopStartY + targetDy * progress + perpY * chopIntensity; // Ball follows during dribble if (distance < 100) { ball.x = self.x; ball.y = self.y; ball.velocityX = 0; ball.velocityY = 0; } } // End chop dribbling and apply Devoured effect if (progress >= 1) { self.isChopDribbling = false; self.applyDevouredEffect(self.chopDevourRadius); } } // FLOW: If Sae is in Flow, perform continuous crescent (hilal) dribble and finish with a striker shot if (self.flowActive) { // Start Hilal dribble if not already started and not shot yet if (!self.flowHilalDribbling && !self.flowHilalShotDone && distance < 120) { self.flowHilalDribbling = true; self.flowHilalStartTime = Date.now(); self.flowHilalOriginX = self.x; self.flowHilalOriginY = self.y; // Each crescent alternates direction for visual effect var angleToGoal = Math.atan2(playerGoal.y - self.y, playerGoal.x - self.x); var dir = self.flowHilalCount % 2 === 0 ? 1 : -1; self.flowHilalStartAngle = angleToGoal - dir * Math.PI / 2; self.flowHilalEndAngle = angleToGoal + dir * Math.PI / 2; self.flowHilalPhase = 0; } // Hilal dribble logic if (self.flowHilalDribbling && !self.flowHilalShotDone) { var elapsed = Date.now() - self.flowHilalStartTime; var t = Math.min(elapsed / self.flowHilalDuration, 1); var angle = self.flowHilalStartAngle + (self.flowHilalEndAngle - self.flowHilalStartAngle) * t; self.x = self.flowHilalOriginX + Math.cos(angle) * self.flowHilalRadius; self.y = self.flowHilalOriginY + Math.sin(angle) * self.flowHilalRadius; // Ball follows during dribble if (distance < 120) { ball.x = self.x; ball.y = self.y; ball.velocityX = 0; ball.velocityY = 0; } // When crescent completes, start next or shoot if (t >= 1) { self.flowHilalDribbling = false; self.flowHilalCount++; // Visual effect for each crescent tween(self, { scaleX: 1.15, scaleY: 1.15, tint: 0xFF6600 }, { duration: 120, onFinish: function onFinish() { tween(self, { scaleX: 1, scaleY: 1, tint: 0xFFFFFF }, { duration: 120 }); } }); // After enough crescents, shoot at goal if (self.flowHilalCount >= self.flowHilalMax) { // Striker shot: powerful, straight, with curve var goalDx = playerGoal.x - self.x; var goalDy = playerGoal.y - self.y; var goalDistance = Math.sqrt(goalDx * goalDx + goalDy * goalDy); if (goalDistance > 0) { var curveAmount = 18 + Math.random() * 8; ball.velocityX = goalDx / goalDistance * 20 + curveAmount; ball.velocityY = goalDy / goalDistance * 20; ball.active = true; // Visual effect for shot tween(self, { scaleX: 1.3, scaleY: 1.3, tint: 0xFF6600 }, { duration: 200, onFinish: function onFinish() { tween(self, { scaleX: 1, scaleY: 1, tint: 0xFFFFFF }, { duration: 200 }); } }); } self.flowHilalShotDone = true; // Reset after a short delay for next Flow LK.setTimeout(function () { self.flowActive = false; self.flowHilalCount = 0; self.flowHilalShotDone = false; }, 1200); } else { // Start next crescent immediately self.flowHilalDribbling = true; self.flowHilalStartTime = Date.now(); self.flowHilalOriginX = self.x; self.flowHilalOriginY = self.y; var angleToGoal = Math.atan2(playerGoal.y - self.y, playerGoal.x - self.x); var dir = self.flowHilalCount % 2 === 0 ? 1 : -1; self.flowHilalStartAngle = angleToGoal - dir * Math.PI / 2; self.flowHilalEndAngle = angleToGoal + dir * Math.PI / 2; self.flowHilalPhase = 0; } } // Prevent other dribbling/shot logic during Flow return; } } // (Original code follows) // Sae behavior: pursue ball aggressively but stay in attacking areas if (distance < 500) { // Use dash if available and close to ball if (!self.dashActive && self.dashCooldown <= 0 && distance < 150) { self.dashActive = true; self.dashCooldown = self.dashCooldownTime; self.dashEndTime = Date.now() + self.dashDuration; self.speed = self.dashSpeed; // Visual effect for dash tween(self, { scaleX: 1.3, scaleY: 1.3, tint: 0x00FFFF }, { duration: 150, onFinish: function onFinish() { tween(self, { scaleX: 1, scaleY: 1, tint: 0xFFFFFF }, { duration: 150 }); } }); } // Move toward ball but avoid going too deep into player's half var pursuitSpeed = distance < 200 ? self.speed * 1.4 : self.speed * 1.2; // Limit Sae's movement to stay in upper half of field (y < 1500) var targetX = self.x + dx / distance * pursuitSpeed; var targetY = self.y + dy / distance * pursuitSpeed; if (targetY > 1500) { // Don't go too deep, stay in attacking position targetY = Math.min(targetY, 1500); } self.x = targetX; self.y = targetY; // Actions when close to ball if (distance < 80) { // Perfect Pass - find forward player to pass to if (self.perfectPassCooldown <= 0) { var nearestForward = null; var nearestDistance = Infinity; for (var i = 0; i < opponents.length; i++) { if (opponents[i].role === 'forward') { var forwardDx = opponents[i].x - self.x; var forwardDy = opponents[i].y - self.y; var forwardDistance = Math.sqrt(forwardDx * forwardDx + forwardDy * forwardDy); if (forwardDistance < nearestDistance && forwardDistance < self.perfectPassRange) { nearestDistance = forwardDistance; nearestForward = opponents[i]; } } } if (nearestForward) { // Execute Perfect Pass var passDx = nearestForward.x - ball.x; var passDy = nearestForward.y - ball.y; var passDist = Math.sqrt(passDx * passDx + passDy * passDy); if (passDist > 0) { ball.velocityX = passDx / passDist * 15; ball.velocityY = passDy / passDist * 15; ball.active = true; } self.perfectPassCooldown = self.perfectPassCooldownTime; // Visual effect for Perfect Pass tween(ball, { scaleX: 1.4, scaleY: 1.4, tint: 0x00FF00 }, { duration: 200, onFinish: function onFinish() { tween(ball, { scaleX: 1, scaleY: 1, tint: 0xFFFFFF }, { duration: 200 }); } }); } } // Choose dribbling type randomly if no pass available if (!self.isDribbling && !self.isZigzagDribbling && !self.isChopDribbling && self.perfectPassCooldown > 0) { var dribbleType = Math.random(); if (dribbleType < 0.33) { // Half-circle dribbling self.isDribbling = true; self.dribbleStartTime = Date.now(); self.dribbleRadius = 100; // Calculate angle from Sae to player goal var angleToGoal = Math.atan2(playerGoal.y - self.y, playerGoal.x - self.x); self.dribbleStartAngle = angleToGoal - Math.PI / 2; self.dribbleEndAngle = angleToGoal + Math.PI / 2; self.dribbleOriginX = self.x; self.dribbleOriginY = self.y; } else if (dribbleType < 0.66) { // Zigzag dribbling self.isZigzagDribbling = true; self.zigzagStartTime = Date.now(); self.zigzagStartX = self.x; self.zigzagStartY = self.y; // Dribble toward player goal with reduced distance self.zigzagTargetX = self.x + (playerGoal.x - self.x) * 0.3 + (Math.random() - 0.5) * 80; self.zigzagTargetY = self.y + (playerGoal.y - self.y) * 0.3 + 50; // Visual effect for zigzag start tween(self, { tint: 0xFF4500 }, { duration: 200, onFinish: function onFinish() { tween(self, { tint: 0xFFFFFF }, { duration: 200 }); } }); } else { // Chop dribbling self.isChopDribbling = true; self.chopStartTime = Date.now(); self.chopStartX = self.x; self.chopStartY = self.y; // Chop toward player goal (even shorter range) self.chopTargetX = self.x + (playerGoal.x - self.x) * 0.2 + (Math.random() - 0.5) * 30; self.chopTargetY = self.y + (playerGoal.y - self.y) * 0.2 + 20; // Visual effect for chop start tween(self, { tint: 0x32CD32 }, { duration: 150, onFinish: function onFinish() { tween(self, { tint: 0xFFFFFF }, { duration: 150 }); } }); } } // False shot ability if (self.falseShotCooldown <= 0 && !self.falseShotActive) { self.falseShotActive = true; self.falseShotCooldown = self.falseShotCooldownTime; // Fake shot motion - ball barely moves ball.velocityX = (Math.random() - 0.5) * 3; ball.velocityY = (Math.random() - 0.5) * 3; ball.active = true; // Visual effect for false shot tween(self, { scaleX: 1.2, scaleY: 1.2, tint: 0xFF6600 }, { duration: 300, onFinish: function onFinish() { // After fake, real shot toward goal var goalDx = playerGoal.x - ball.x; var goalDy = playerGoal.y - ball.y; var goalDistance = Math.sqrt(goalDx * goalDx + goalDy * goalDy); if (goalDistance > 0) { ball.velocityX = goalDx / goalDistance * 14; ball.velocityY = goalDy / goalDistance * 14; ball.active = true; } tween(self, { scaleX: 1, scaleY: 1, tint: 0xFFFFFF }, { duration: 300 }); self.falseShotActive = false; } }); } } } else { // Sae is always active: maintain attacking midfield position var attackingMidfieldX = 1024 + (Math.random() - 0.5) * 300; var attackingMidfieldY = 1000 + Math.random() * 200; // Stay in upper midfield area var shotDx = attackingMidfieldX - self.x; var shotDy = attackingMidfieldY - self.y; var shotDist = Math.sqrt(shotDx * shotDx + shotDy * shotDy); if (shotDist > 50) { self.x += shotDx / shotDist * self.speed * 0.5; self.y += shotDy / shotDist * self.speed * 0.5; } // If far from ball but in shooting range, attempt long-range curved shot if (distance > 200 && distance < 700 && !self.isDribbling && !self.isZigzagDribbling && !self.isChopDribbling && !self.falseShotActive) { // Falsolu şut: apply curve by adding to X velocity var goalDx = playerGoal.x - ball.x; var goalDy = playerGoal.y - ball.y; var goalDistance = Math.sqrt(goalDx * goalDx + goalDy * goalDy); if (goalDistance > 0) { var curveAmount = 12 + Math.random() * 8; // Stronger curve for long shot ball.velocityX = goalDx / goalDistance * 16 + curveAmount; ball.velocityY = goalDy / goalDistance * 16; ball.active = true; // Visual effect for long-range shot tween(self, { scaleX: 1.2, scaleY: 1.2, tint: 0xFF1493 }, { duration: 300, onFinish: function onFinish() { tween(self, { scaleX: 1, scaleY: 1, tint: 0xFFFFFF }, { duration: 300 }); } }); } } } // Apply Devoured effect to nearby opponents self.applyDevouredEffect = function (radius) { var opponentsInRange = []; // Check all player team members if (typeof player !== 'undefined') { var playerDist = Math.sqrt((player.x - self.x) * (player.x - self.x) + (player.y - self.y) * (player.y - self.y)); if (playerDist <= radius) { opponentsInRange.push(player); } } if (typeof chigiri !== 'undefined') { var chigiriDist = Math.sqrt((chigiri.x - self.x) * (chigiri.x - self.x) + (chigiri.y - self.y) * (chigiri.y - self.y)); if (chigiriDist <= radius) { opponentsInRange.push(chigiri); } } if (typeof hiori !== 'undefined') { var hioriDist = Math.sqrt((hiori.x - self.x) * (hiori.x - self.x) + (hiori.y - self.y) * (hiori.y - self.y)); if (hioriDist <= radius) { opponentsInRange.push(hiori); } } if (typeof reo !== 'undefined') { var reoDist = Math.sqrt((reo.x - self.x) * (reo.x - self.x) + (reo.y - self.y) * (reo.y - self.y)); if (reoDist <= radius) { opponentsInRange.push(reo); } } if (typeof nagi !== 'undefined') { var nagiDist = Math.sqrt((nagi.x - self.x) * (nagi.x - self.x) + (nagi.y - self.y) * (nagi.y - self.y)); if (nagiDist <= radius) { opponentsInRange.push(nagi); } } // Apply Devoured effect to found opponents for (var i = 0; i < opponentsInRange.length; i++) { var opponent = opponentsInRange[i]; // 30% chance to apply full effect, otherwise just stun var isFullDevoured = Math.random() < 0.3; if (isFullDevoured) { // Full Devoured effect: severely reduce speed opponent.originalSpeed = opponent.speed; opponent.speed = opponent.speed * 0.2; // 20% speed opponent.devoured = true; self.devouredOpponents.push(opponent); // Visual effect for devoured opponent tween(opponent, { tint: 0x800080, // Purple tint for devoured scaleX: 0.8, scaleY: 0.8 }, { duration: 300 }); } else { // Just stun effect opponent.originalSpeed = opponent.speed; opponent.speed = 0; opponent.stunned = true; self.dribbleStunnedOpponents.push(opponent); // Visual effect for stunned opponent tween(opponent, { tint: 0xFFFF00, scaleX: 1.1, scaleY: 1.1 }, { duration: 200 }); } } if (opponentsInRange.length > 0) { self.devouredEndTime = Date.now() + self.devouredDuration; if (self.dribbleStunnedOpponents.length > 0) { self.dribbleStunEnd = Date.now() + self.dribbleStunDuration; } } }; }; return self; }); var SoccerBall = Container.expand(function () { var self = Container.call(this); var ballGraphics = self.attachAsset('ball', { anchorX: 0.5, anchorY: 0.5 }); self.velocityX = 0; self.velocityY = 0; self.friction = 0.98; self.active = true; self.update = function () { if (self.active) { self.x += self.velocityX; self.y += self.velocityY; self.velocityX *= self.friction; self.velocityY *= self.friction; // Keep ball in bounds with bounce effect if (self.x < 30) { self.x = 30; self.velocityX = Math.abs(self.velocityX) * 0.8; } if (self.x > 2018) { self.x = 2018; self.velocityX = -Math.abs(self.velocityX) * 0.8; } if (self.y < 30) { self.y = 30; self.velocityY = Math.abs(self.velocityY) * 0.8; } if (self.y > 2702) { self.y = 2702; self.velocityY = -Math.abs(self.velocityY) * 0.8; } } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x228B22 }); /**** * Game Code ****/ game.setBackgroundColor(0x228B22); // Game variables var opponents = []; var playerScore = 0; var opponentScore = 0; var dragNode = null; var maxStamina = 100; var currentStamina = 100; var staminaRegenRate = 0.2; var staminaDrainRate = 0.5; var lastPlayerX = 0; var lastPlayerY = 0; var shotChargeStart = 0; var isChargingShot = false; var shotPower = 0; var maxShotPower = 20; var minChargeTime = 2000; // 2 seconds minimum charge time var lastTouchX = 0; var lastTouchY = 0; var ballDetachCooldown = 0; var ballDetachCooldownTime = 1000; // 1 second cooldown // UI Elements var scoreTxt = new Text2('Player: 0 - Opponent: 0', { size: 80, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // Stamina UI var staminaTxt = new Text2('Stamina: 100', { size: 60, fill: 0x00FF00 }); staminaTxt.anchor.set(0, 0); staminaTxt.x = 50; staminaTxt.y = 50; LK.gui.topLeft.addChild(staminaTxt); // Shot Power UI var shotPowerTxt = new Text2('Shot Power: 0%', { size: 60, fill: 0xFFFFFF }); shotPowerTxt.anchor.set(0, 0); shotPowerTxt.x = 50; shotPowerTxt.y = 130; LK.gui.topLeft.addChild(shotPowerTxt); // Game objects var player = game.addChild(new Player()); player.x = 1024; player.y = 2200; var ball = game.addChild(new SoccerBall()); ball.x = 1024; ball.y = 1366; // Player's goal (bottom) var playerGoal = game.addChild(new Goal()); playerGoal.x = 1024; playerGoal.y = 2600; // Opponent's goal (top) var opponentGoal = game.addChild(new Goal()); opponentGoal.x = 1024; opponentGoal.y = 300; // Create opponents with specific roles // Defense player (opponent) var defensePlayer = game.addChild(new DefensePlayer()); defensePlayer.x = 1024; defensePlayer.y = 600; defensePlayer.homeX = 1024; defensePlayer.homeY = 600; opponents.push(defensePlayer); // Chigiri - player team hybrid defender var chigiri = game.addChild(new ChigiriPlayer(0x3399ff)); chigiri.x = 800; chigiri.y = 2000; chigiri.homeX = 800; chigiri.homeY = 2000; // Hiori - player team creative midfielder var hiori = game.addChild(new HioriPlayer(0x6699ff)); hiori.x = 1200; hiori.y = 2000; hiori.homeX = 1200; hiori.homeY = 2000; // Reo - player team adaptive defender/attacker var reo = game.addChild(new ReoPlayer(0x000000)); reo.x = 600; reo.y = 1800; reo.homeX = 600; reo.homeY = 1800; // Nagi - player team striker with Fake Volley ability var nagi = game.addChild(new NagiPlayer(0x9966ff)); nagi.x = 1400; nagi.y = 2000; nagi.homeX = 1400; nagi.homeY = 2000; // Nagi starts without Flow // Meguru Bachira - player team creative winger with Roulette and Monster abilities var bachira = game.addChild(new MeguruBachiraPlayer(0x20B2AA)); bachira.x = 1000; bachira.y = 1900; bachira.homeX = 1000; bachira.homeY = 1900; // Midfield player var midfieldPlayer = game.addChild(new MidfieldPlayer()); midfieldPlayer.x = 1024; midfieldPlayer.y = 1000; midfieldPlayer.homeX = 1024; midfieldPlayer.homeY = 1000; opponents.push(midfieldPlayer); // Forward player var forwardPlayer = game.addChild(new ForwardPlayer()); forwardPlayer.x = 1024; forwardPlayer.y = 1400; forwardPlayer.homeX = 1024; forwardPlayer.homeY = 1400; opponents.push(forwardPlayer); // Sae - opponent team attacking midfielder with Perfect Pass and special abilities var sae = game.addChild(new SaePlayer(0xff6600)); sae.x = 1024; sae.y = 800; sae.homeX = 1024; sae.homeY = 800; opponents.push(sae); // Create goalkeepers var playerGoalkeeper = game.addChild(new Goalkeeper(true)); // Blue goalkeeper for player team playerGoalkeeper.x = 1024; playerGoalkeeper.y = 2500; // In front of player's goal playerGoalkeeper.originalX = 1024; playerGoalkeeper.originalY = 2500; var opponentGoalkeeper = game.addChild(new Goalkeeper(false)); // Red goalkeeper for opponent team opponentGoalkeeper.x = 1024; opponentGoalkeeper.y = 400; // In front of opponent's goal opponentGoalkeeper.originalX = 1024; opponentGoalkeeper.originalY = 400; // Ball kicking mechanics function kickBall(targetX, targetY, power) { var dx = targetX - ball.x; var dy = targetY - ball.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 0) { var finalPower = power || Math.min(distance / 100, 15); // Properly detach ball from player first player.hasBall = false; ball.active = true; // Set cooldown to prevent immediate re-attachment ballDetachCooldown = ballDetachCooldownTime; // Apply velocity after detachment ball.velocityX = dx / distance * finalPower; ball.velocityY = dy / distance * finalPower; LK.getSound('kick').play(); } } // Touch controls for player movement and ball kicking game.down = function (x, y, obj) { // Always update last touch position for shot direction lastTouchX = x; lastTouchY = y; var playerDistance = Math.sqrt((x - player.x) * (x - player.x) + (y - player.y) * (y - player.y)); var ballDistance = Math.sqrt((x - ball.x) * (x - ball.x) + (y - ball.y) * (y - ball.y)); if (playerDistance < ballDistance) { // Move player dragNode = player; } else { // Start charging shot if player has ball if (player.hasBall) { shotChargeStart = Date.now(); isChargingShot = true; shotPower = 0; } } }; game.move = function (x, y, obj) { // Always update last touch position for shot direction lastTouchX = x; lastTouchY = y; if (dragNode && currentStamina > 0) { var dx = x - dragNode.x; var dy = y - dragNode.y; var distance = Math.sqrt(dx * dx + dy * dy); // Slow down movement and consume stamina - even slower when having ball var moveSpeed = player.hasBall ? 0.15 : 0.2; dragNode.x += dx * moveSpeed; dragNode.y += dy * moveSpeed; // Consume stamina based on movement if (distance > 5) { currentStamina -= staminaDrainRate; if (currentStamina < 0) currentStamina = 0; } } }; game.up = function (x, y, obj) { dragNode = null; // Handle shot release if (isChargingShot && player.hasBall) { var chargeTime = Date.now() - shotChargeStart; if (chargeTime >= minChargeTime) { // Release charged shot - use last touch position for direction kickBall(lastTouchX, lastTouchY, shotPower); } else { // Not charged enough, no shot } isChargingShot = false; shotPower = 0; } }; // Goal scoring function function scoreGoal(isPlayer) { if (isPlayer) { playerScore++; } else { opponentScore++; } scoreTxt.setText('Player: ' + playerScore + ' - Opponent: ' + opponentScore); LK.getSound('goal').play(); // Reset ball position ball.x = 1024; ball.y = 1366; ball.velocityX = 0; ball.velocityY = 0; } // Game update loop game.update = function () { // Update ball detach cooldown if (ballDetachCooldown > 0) { ballDetachCooldown -= 16; // Approximately 60 FPS if (ballDetachCooldown < 0) ballDetachCooldown = 0; } // Check if player is close to ball for interaction (only if cooldown expired) var playerToBallDistance = Math.sqrt((player.x - ball.x) * (player.x - ball.x) + (player.y - ball.y) * (player.y - ball.y)); if (playerToBallDistance < 80 && !player.hasBall && ballDetachCooldown <= 0) { player.hasBall = true; ball.active = false; ball.velocityX = 0; ball.velocityY = 0; } // If player has ball, make it stick to player if (player.hasBall && ball.active === false) { ball.x = player.x; ball.y = player.y - 50; } // Stamina regeneration when not moving var playerMoving = Math.abs(player.x - lastPlayerX) > 1 || Math.abs(player.y - lastPlayerY) > 1; if (!playerMoving && currentStamina < maxStamina) { currentStamina += staminaRegenRate; if (currentStamina > maxStamina) currentStamina = maxStamina; } // Update last position lastPlayerX = player.x; lastPlayerY = player.y; // Update stamina UI var staminaPercent = Math.round(currentStamina / maxStamina * 100); staminaTxt.setText('Stamina: ' + staminaPercent); // Change color based on stamina level if (staminaPercent > 50) { staminaTxt.fill = 0x00FF00; } else if (staminaPercent > 25) { staminaTxt.fill = 0xFFFF00; } else { staminaTxt.fill = 0xFF0000; } // Update shot charging if (isChargingShot && player.hasBall) { var chargeTime = Date.now() - shotChargeStart; if (chargeTime >= minChargeTime) { // Calculate shot power based on charge time var chargeProgress = Math.min((chargeTime - minChargeTime) / 1000, 1); // 1 second after minimum for max power shotPower = 5 + chargeProgress * maxShotPower; // Minimum 5, maximum 25 power var powerPercent = Math.round(chargeProgress * 100); shotPowerTxt.setText('Shot Power: ' + powerPercent + '%'); shotPowerTxt.fill = 0x00FF00; // Automatically kick ball forward when shot power reaches 100% if (powerPercent >= 100) { shotPower = 5 + maxShotPower; // Keep at maximum power shotPowerTxt.setText('Shot Power: 100%'); shotPowerTxt.fill = 0x00FF00; // Auto-kick ball forward when power reaches 100% var forwardX = player.x; var forwardY = player.y - 300; // Kick forward (up the field) kickBall(forwardX, forwardY, shotPower); isChargingShot = false; shotPower = 0; } } else { // Not charged enough yet var timeLeft = Math.ceil((minChargeTime - chargeTime) / 1000); shotPowerTxt.setText('Hold for ' + timeLeft + 's'); shotPowerTxt.fill = 0xFFFF00; } } else { shotPowerTxt.setText('Shot Power: 0%'); shotPowerTxt.fill = 0xFFFFFF; } // Check player goal scoring (opponent scores) if (ball.y > playerGoal.y - 50 && ball.x > playerGoal.x - 200 && ball.x < playerGoal.x + 200) { scoreGoal(false); LK.effects.flashObject(playerGoal, 0xFF0000, 500); } // Check opponent goal scoring (player scores) if (ball.y < opponentGoal.y + 50 && ball.x > opponentGoal.x - 200 && ball.x < opponentGoal.x + 200) { scoreGoal(true); LK.effects.flashObject(opponentGoal, 0x00FF00, 500); } // Check win condition if (playerScore >= 5) { LK.showYouWin(); } if (opponentScore >= 5) { LK.showGameOver(); } // Enhanced AI positioning based on ball location for (var i = 0; i < opponents.length; i++) { var opponent = opponents[i]; var ballThreatLevel = Math.sqrt((ball.x - 1024) * (ball.x - 1024) + (ball.y - 1366) * (ball.y - 1366)); // Adjust opponent aggression based on ball threat if (ballThreatLevel < 300) { // Ball is in center - all opponents become more aggressive if (opponent.role === 'defense') { opponent.speed = 4.5; opponent.maxDistance = 500; } else if (opponent.role === 'midfield') { opponent.speed = 3.5; } else if (opponent.role === 'forward') { opponent.speed = 4.2; } } else { // Ball is far - return to normal behavior if (opponent.role === 'defense') { opponent.speed = 4; opponent.maxDistance = 400; } else if (opponent.role === 'midfield') { opponent.speed = 3; } else if (opponent.role === 'forward') { opponent.speed = 3.5; } } } // Role-based AI is now handled in each player's update method // Defense, Midfield, and Forward players have their own specialized behaviors };
===================================================================
--- original.js
+++ change.js
@@ -886,24 +886,30 @@
hiori.flowText.anchor.set(0.5, 0.5);
hiori.flowText.x = 0;
hiori.flowText.y = -100;
hiori.flowText.alpha = 1;
- tween(hiori.flowText, {
- scaleX: 1.5,
- scaleY: 1.5,
- alpha: 1
- }, {
- duration: 300,
- onFinish: function onFinish() {
- tween(hiori.flowText, {
- scaleX: 1,
- scaleY: 1,
- alpha: 1
- }, {
- duration: 300
- });
- }
- });
+ if (hiori.flowText) {
+ // Defensive: only tween if flowText exists
+ tween(hiori.flowText, {
+ scaleX: 1.5,
+ scaleY: 1.5,
+ alpha: 1
+ }, {
+ duration: 300,
+ onFinish: function onFinish() {
+ if (hiori.flowText) {
+ // Defensive: only tween if flowText still exists
+ tween(hiori.flowText, {
+ scaleX: 1,
+ scaleY: 1,
+ alpha: 1
+ }, {
+ duration: 300
+ });
+ }
+ }
+ });
+ }
}
}
}
} else {