/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var AntiTankGrenade = Container.expand(function () { var self = Container.call(this); // Create grenade body (dark grey) var grenadeBody = self.attachAsset('antiTankGrenade', { anchorX: 0.5, anchorY: 0.5 }); grenadeBody.tint = 0x4A4A4A; // Dark grey // Add pin indicator (small red circle) var pin = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.15, scaleY: 0.15, x: 15, y: -25 }); pin.tint = 0xFF0000; // Red pin self.addChild(pin); // Add explosive marking (yellow stripe) var marking = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.8, scaleY: 0.2, y: 5 }); marking.tint = 0xFFFF00; // Yellow marking self.addChild(marking); self.isCollected = false; self.timeLeft = 480; // 8 seconds at 60fps // Grenade collection self.collect = function () { if (!self.isCollected) { self.isCollected = true; // Collection animation tween(self, { alpha: 0, scaleX: 0.1, scaleY: 0.1 }, { duration: 300, onFinish: function onFinish() { self.visible = false; } }); return true; } return false; }; // Update function to handle grenade lifetime self.update = function () { self.timeLeft--; // Pulse when about to disappear if (self.timeLeft < 120) { self.alpha = 0.5 + Math.sin(self.timeLeft * 0.1) * 0.5; } if (self.timeLeft <= 0 && !self.isCollected) { self.collect(); } }; return self; }); var AtomicBomb = Container.expand(function () { var self = Container.call(this); // Create bomb body (blue sphere with electric glow) var bombBody = self.attachAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.8, scaleY: 0.8 }); bombBody.tint = 0x0066ff; // Electric blue color // Add energy core (bright white) var energyCore = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.4, scaleY: 0.4 }); energyCore.tint = 0xffffff; self.addChild(energyCore); // Add outer energy ring (cyan) var outerRing = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.2, scaleY: 1.2 }); outerRing.tint = 0x00ffff; outerRing.alpha = 0.5; self.addChild(outerRing); self.explosionRadius = 500; self.isExploding = false; self.isCollected = false; self.freezeOnUse = true; // New property - bomb freezes enemies rather than pushing them // Bomb collection self.collect = function () { if (!self.isCollected) { self.isCollected = true; return true; } return false; }; // Explosion effect self.explode = function () { if (!self.isExploding) { self.isExploding = true; // Create explosion animation - now a freezing blast tween(self, { scaleX: 10, scaleY: 10, alpha: 0.8 }, { duration: 700, easing: tween.easeOut, onFinish: function onFinish() { tween(self, { alpha: 0 }, { duration: 500, onFinish: function onFinish() { self.visible = false; } }); } }); return true; } return false; }; // Electric pulse animation for idle bomb function startElectricAnimation() { // Outer ring pulsing function pulseOuterRing() { tween(outerRing, { alpha: 0.2, scaleX: 1.4, scaleY: 1.4 }, { duration: 700, easing: tween.easeInOut, onFinish: function onFinish() { tween(outerRing, { alpha: 0.5, scaleX: 1.2, scaleY: 1.2 }, { duration: 700, easing: tween.easeInOut, onFinish: pulseOuterRing }); } }); } // Core pulsing tween(energyCore, { scaleX: 0.5, scaleY: 0.5, alpha: 0.9 }, { duration: 600, easing: tween.easeInOut, onFinish: function onFinish() { tween(energyCore, { scaleX: 0.4, scaleY: 0.4, alpha: 1 }, { duration: 600, easing: tween.easeInOut, onFinish: startElectricAnimation }); } }); // Start the outer ring animation too pulseOuterRing(); } // Start electric pulsing startElectricAnimation(); return self; }); var Bread = Container.expand(function () { var self = Container.call(this); // Create bread visual var breadBody = self.attachAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.5, scaleY: 0.3 }); breadBody.tint = 0xE8B96F; // Brown bread color // Create crust detail var crust = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.52, scaleY: 0.32 }); crust.tint = 0xC68642; // Darker crust color self.addChild(crust); self.isConsumed = false; self.timeLeft = 360; // 6 seconds at 60fps self.sinkingSpeed = 0.5; self.inWater = false; // Bread consumption self.consume = function () { if (!self.isConsumed) { self.isConsumed = true; // Consumption animation tween(self, { alpha: 0, scaleX: 0.1, scaleY: 0.1 }, { duration: 300, onFinish: function onFinish() { self.visible = false; } }); return true; } return false; }; // Start sinking animation when bread hits water self.startSinking = function () { if (!self.inWater) { self.inWater = true; // Make bread rotate slowly while sinking tween(self, { rotation: Math.PI * 0.5 * (Math.random() > 0.5 ? 1 : -1) }, { duration: 3000, easing: tween.easeInOut }); } }; // Update function self.update = function () { self.timeLeft--; // Sink when in water if (self.inWater) { self.y += self.sinkingSpeed; // Fade out as it sinks if (self.timeLeft < 180) { self.alpha = Math.max(0, self.timeLeft / 180); } } // Pulse when about to disappear if (self.timeLeft < 60 && !self.inWater) { self.alpha = 0.5 + Math.sin(self.timeLeft * 0.2) * 0.5; } // Despawn when time runs out if (self.timeLeft <= 0 && !self.isConsumed) { self.consume(); } }; return self; }); var Chip = Container.expand(function () { var self = Container.call(this); var chipGraphic = self.attachAsset('chip', { anchorX: 0.5, anchorY: 0.5 }); self.isCollected = false; self.collect = function () { if (!self.isCollected) { self.isCollected = true; LK.getSound('eat').play(); tween(self, { alpha: 0, scaleX: 0.1, scaleY: 0.1 }, { duration: 300, onFinish: function onFinish() { self.visible = false; } }); return true; } return false; }; return self; }); var Chocolate = Container.expand(function () { var self = Container.call(this); // Create chocolate graphic (brown rectangle) var chocolateBody = self.attachAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.7, scaleY: 0.5 }); // Set chocolate color to brown chocolateBody.tint = 0x4B2E20; // Add inner layer for chocolate texture var innerLayer = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.5, scaleY: 0.3 }); innerLayer.tint = 0x663C28; self.addChild(innerLayer); self.isConsumed = false; self.timeLeft = 300; // 5 seconds at 60fps // Swan consumes chocolate self.consume = function () { if (!self.isConsumed) { self.isConsumed = true; // Consumption animation tween(self, { alpha: 0, scaleX: 0.1, scaleY: 0.1 }, { duration: 300, onFinish: function onFinish() { self.visible = false; } }); return true; } return false; }; self.update = function () { self.timeLeft--; // Pulse when about to disappear if (self.timeLeft < 60) { self.alpha = 0.5 + Math.sin(self.timeLeft * 0.2) * 0.5; } if (self.timeLeft <= 0 && !self.isConsumed) { self.consume(); } }; return self; }); var Cookie = Container.expand(function () { var self = Container.call(this); this.init = function () { var cookieBody = self.attachAsset('cookieShape', { anchorX: 0.5, anchorY: 0.5 }); // Add some chocolate chips for decoration for (var i = 0; i < 5; i++) { var chip = LK.getAsset('cookieChipShape', { anchorX: 0.5, anchorY: 0.5, x: (Math.random() - 0.5) * (cookieBody.width * 0.4), // position chips within cookie y: (Math.random() - 0.5) * (cookieBody.height * 0.4) }); self.addChild(chip); } self.isCollected = false; self.timeLeft = 480; // 8 seconds at 60fps to despawn if not collected }; self.collect = function () { if (!self.isCollected) { self.isCollected = true; tween(self, { alpha: 0, scaleX: 0.1, scaleY: 0.1 }, { duration: 300, onFinish: function onFinish() { self.visible = false; } }); return true; } return false; }; self.update = function () { if (self.isCollected || !self.visible) return; self.timeLeft--; if (self.timeLeft < 60 && self.timeLeft > 0) { // Pulsate before disappearing self.alpha = 0.5 + Math.sin(self.timeLeft * 0.2) * 0.5; } else if (self.timeLeft <= 0) { self.visible = false; // Mark for removal if (self.parent) { self.parent.removeChild(self); } } }; this.init(); return self; }); var Country = Container.expand(function () { var self = Container.call(this); // Create country portal visual (rainbow-colored circle) var portalBody = self.attachAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.2, scaleY: 1.2 }); portalBody.tint = 0x00AAFF; // Blue base color // Add interior of portal var portalInterior = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.9, scaleY: 0.9 }); portalInterior.tint = 0xFFFFFF; self.addChild(portalInterior); // Country name label self.nameText = new Text2('', { size: 40, fill: 0xFFFFFF }); self.nameText.anchor.set(0.5, 0.5); self.nameText.y = -80; self.addChild(self.nameText); // Properties self.countryName = ""; self.countryColor = 0x00AAFF; self.isActive = false; self.isVisited = false; self.travelCooldown = 0; self.visitBonus = 10; // Score bonus for first visit // Set country information self.setCountry = function (name, color) { self.countryName = name; self.countryColor = color; self.nameText.setText(name); portalBody.tint = color; // Return for method chaining return self; }; // Activate the portal self.activate = function () { if (!self.isActive) { self.isActive = true; // Start portal animation startPortalAnimation(); // Make visible with fade-in self.alpha = 0; tween(self, { alpha: 1 }, { duration: 800, easing: tween.easeOut }); } }; // Travel effect when goose enters the portal self.travel = function () { if (self.travelCooldown <= 0) { self.travelCooldown = 180; // 3 second cooldown // Create travel animation - portal expands tween(self, { scaleX: 3, scaleY: 3, alpha: 0.8 }, { duration: 800, easing: tween.easeOut, onFinish: function onFinish() { tween(self, { scaleX: 1, scaleY: 1, alpha: 1 }, { duration: 500, easing: tween.easeOut }); } }); // First time visit bonus var scoreBonus = self.isVisited ? 5 : self.visitBonus; self.isVisited = true; return { success: true, countryName: self.countryName, scoreBonus: scoreBonus }; } return { success: false }; }; // Portal animation function startPortalAnimation() { // Rotating animation function spin() { tween(portalInterior, { rotation: portalInterior.rotation + Math.PI * 2 }, { duration: 5000, onFinish: spin }); } // Pulsing animation function pulse() { tween(portalBody, { scaleX: 1.3, scaleY: 1.3 }, { duration: 1500, easing: tween.easeInOut, onFinish: function onFinish() { tween(portalBody, { scaleX: 1.2, scaleY: 1.2 }, { duration: 1500, easing: tween.easeInOut, onFinish: pulse }); } }); } // Start both animations spin(); pulse(); } self.update = function () { if (self.travelCooldown > 0) { self.travelCooldown--; } }; return self; }); var Dachshund = Container.expand(function () { var self = Container.call(this); // Create dachshund body (long brown sausage dog) var body = self.attachAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.2, scaleY: 0.5 }); body.tint = 0x8B4513; // Brown color // Create head var head = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.4, scaleY: 0.4, x: 50, y: 0 }); head.tint = 0x654321; // Darker brown self.addChild(head); // Create snout var snout = LK.getAsset('centerCircle', { anchorX: 0, anchorY: 0.5, scaleX: 0.3, scaleY: 0.2, x: 65, y: 0 }); snout.tint = 0x4B2E20; // Even darker brown self.addChild(snout); // Create tail var tail = LK.getAsset('centerCircle', { anchorX: 1, anchorY: 0.5, scaleX: 0.4, scaleY: 0.15, x: -55, y: -5, rotation: -0.3 }); tail.tint = 0x8B4513; self.addChild(tail); // Create legs (4 stubby legs) for (var i = 0; i < 4; i++) { var leg = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0, scaleX: 0.1, scaleY: 0.3, x: -30 + i * 25, y: 25 }); leg.tint = 0x654321; self.addChild(leg); self['leg' + i] = leg; // Store reference for animation } // Properties self.speed = 2.5; self.targetX = 0; self.targetY = 0; self.state = 'hunting'; // Always hunting self.target = null; // Current chase target self.barkCooldown = 0; self.biteCooldown = 0; // Set target position self.setTarget = function (x, y) { self.targetX = x; self.targetY = y; }; // Bark at target self.bark = function () { if (self.barkCooldown <= 0) { self.barkCooldown = 90; // 1.5 second cooldown // Bark animation tween(head, { scaleX: 0.5, scaleY: 0.5 }, { duration: 150, easing: tween.easeOut, onFinish: function onFinish() { tween(head, { scaleX: 0.4, scaleY: 0.4 }, { duration: 150, easing: tween.easeInOut }); } }); // Play sound (use existing honk sound) LK.getSound('honk').play(); return true; } return false; }; // Bite attack self.bite = function () { if (self.biteCooldown <= 0) { self.biteCooldown = 60; // 1 second cooldown // Bite animation tween(snout, { x: 75, scaleX: 0.4 }, { duration: 100, easing: tween.easeOut, onFinish: function onFinish() { tween(snout, { x: 65, scaleX: 0.3 }, { duration: 200, easing: tween.easeInOut }); } }); return true; } return false; }; // Tail wagging animation function wagTail() { tween(tail, { rotation: 0.3 }, { duration: 300, easing: tween.easeInOut, onFinish: function onFinish() { tween(tail, { rotation: -0.3 }, { duration: 300, easing: tween.easeInOut, onFinish: wagTail }); } }); } wagTail(); self.update = function () { // Update cooldowns if (self.barkCooldown > 0) { self.barkCooldown--; } if (self.biteCooldown > 0) { self.biteCooldown--; } // Move toward target var dx = self.targetX - self.x; var dy = self.targetY - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 10) { self.x += dx / dist * self.speed; self.y += dy / dist * self.speed; // Face movement direction if (dx < 0) { self.scale.x = -1; } else { self.scale.x = 1; } // Running animation (stubby legs moving) for (var i = 0; i < 4; i++) { self['leg' + i].y = 25 + Math.sin(LK.ticks * 0.3 + i * Math.PI * 0.5) * 3; } } }; return self; }); var Drowning = Container.expand(function () { var self = Container.call(this); // Create water bubbles effect var bubbles = []; var bubbleCount = 8; for (var i = 0; i < bubbleCount; i++) { var bubble = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.2 + Math.random() * 0.2, scaleY: 0.2 + Math.random() * 0.2, x: (Math.random() - 0.5) * 100, y: (Math.random() - 0.5) * 100 }); bubble.tint = 0x88CCFF; // Light blue for water bubbles bubble.alpha = 0.7; bubble.speedY = -1 - Math.random() * 2; bubble.speedX = (Math.random() - 0.5) * 1; self.addChild(bubble); bubbles.push(bubble); } self.isActive = false; self.duration = 180; // 3 seconds at 60fps self.timer = 0; self.warningLevel = 0; self.activate = function () { if (!self.isActive) { self.isActive = true; self.timer = 0; self.warningLevel = 0; self.alpha = 1; // Start bubble animation for (var i = 0; i < bubbles.length; i++) { animateBubble(bubbles[i]); } } }; self.deactivate = function () { if (self.isActive) { self.isActive = false; self.timer = 0; self.warningLevel = 0; // Fade out tween(self, { alpha: 0 }, { duration: 300, easing: tween.easeOut }); } }; function animateBubble(bubble) { // Random position around character bubble.x = (Math.random() - 0.5) * 100; bubble.y = (Math.random() - 0.5) * 100 + 50; bubble.alpha = 0; bubble.scale.x = bubble.scale.y = 0.1 + Math.random() * 0.2; // Animate bubble rising tween(bubble, { y: bubble.y - 100 - Math.random() * 50, alpha: 0.7, scaleX: bubble.scale.x * 1.5, scaleY: bubble.scale.y * 1.5 }, { duration: 1000 + Math.random() * 500, easing: tween.easeOut, onFinish: function onFinish() { tween(bubble, { alpha: 0 }, { duration: 300, onFinish: function onFinish() { if (self.isActive) { animateBubble(bubble); } } }); } }); } self.update = function () { if (!self.isActive) return; self.timer++; // Update warning level var newWarningLevel = Math.min(3, Math.floor(self.timer / 60)); // Warning level changed - trigger visual feedback if (newWarningLevel > self.warningLevel) { self.warningLevel = newWarningLevel; // Pulse effect based on warning level tween(self, { alpha: 0.4 }, { duration: 200, onFinish: function onFinish() { tween(self, { alpha: 1 }, { duration: 200 }); } }); } // Check if drowning is complete if (self.timer >= self.duration) { return true; // Return true to signal drowning is complete } return false; // Not yet drowned }; return self; }); var EurovisionFlashbang = Container.expand(function () { var self = Container.call(this); // Create flashbang body (silver/white circle) var flashbangBody = self.attachAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.8, scaleY: 0.8 }); flashbangBody.tint = 0xE5E4E2; // Silver color // Add eurovision star symbol var starSymbol = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.5, scaleY: 0.5 }); starSymbol.tint = 0xFFD700; // Gold color self.addChild(starSymbol); self.isCollected = false; self.isExploding = false; // Rainbow effect colors self.rainbowColors = [0xFF0000, // Red 0xFF7F00, // Orange 0xFFFF00, // Yellow 0x00FF00, // Green 0x0000FF, // Blue 0x4B0082, // Indigo 0x9400D3 // Violet ]; // Flashbang collection self.collect = function () { if (!self.isCollected) { self.isCollected = true; return true; } return false; }; // Explosion effect self.explode = function () { if (!self.isExploding) { self.isExploding = true; // Create explosion animation tween(self, { scaleX: 15, scaleY: 15, alpha: 0.9 }, { duration: 700, easing: tween.easeOut, onFinish: function onFinish() { tween(self, { alpha: 0 }, { duration: 500, onFinish: function onFinish() { self.visible = false; } }); } }); return true; } return false; }; // Rainbow pulse animation function startRainbowAnimation() { var colorIndex = 0; function cycleColors() { flashbangBody.tint = self.rainbowColors[colorIndex]; colorIndex = (colorIndex + 1) % self.rainbowColors.length; tween(self, { scaleX: 1.1, scaleY: 1.1 }, { duration: 400, easing: tween.easeInOut, onFinish: function onFinish() { tween(self, { scaleX: 1.0, scaleY: 1.0 }, { duration: 400, easing: tween.easeInOut, onFinish: cycleColors }); } }); } cycleColors(); } // Start pulsing startRainbowAnimation(); return self; }); var Goose = Container.expand(function () { var self = Container.call(this); // Body var body = self.attachAsset('goose', { anchorX: 0.5, anchorY: 0.5 }); self.lastIsSwimming = false; // Wings var leftWing = LK.getAsset('gooseWing', { anchorX: 0, anchorY: 0.5, x: -80, y: 0, rotation: -0.3 }); var rightWing = LK.getAsset('gooseWing', { anchorX: 1, anchorY: 0.5, x: 80, y: 0, rotation: 0.3 }); // Beak var beak = LK.getAsset('gooseBeak', { anchorX: 0, anchorY: 0.5, x: 80, y: 0 }); self.addChild(leftWing); self.addChild(rightWing); self.addChild(beak); self.speed = 7; self.attackCooldown = 0; self.isAttacking = false; self.stunned = 0; self.attack = function () { if (self.attackCooldown <= 0 && !self.isAttacking && self.stunned <= 0) { self.isAttacking = true; LK.getSound('honk').play(); // Wing attack animation tween(leftWing, { rotation: -0.8, x: -100 }, { duration: 200, easing: tween.easeOut }); tween(rightWing, { rotation: 0.8, x: 100 }, { duration: 200, easing: tween.easeOut, onFinish: function onFinish() { // Return wings to normal tween(leftWing, { rotation: -0.3, x: -80 }, { duration: 300, easing: tween.easeInOut }); tween(rightWing, { rotation: 0.3, x: 80 }, { duration: 300, easing: tween.easeInOut, onFinish: function onFinish() { self.isAttacking = false; } }); self.attackCooldown = 60; // 1 second cooldown (60 frames) } }); return true; } return false; }; self.stun = function (duration) { self.stunned = duration; // Stun animation tween(self, { alpha: 0.6 }, { duration: 100, onFinish: function onFinish() { tween(self, { alpha: 1 }, { duration: 100 }); } }); }; self.update = function () { if (self.attackCooldown > 0) { self.attackCooldown--; } if (self.stunned > 0) { self.stunned--; } }; return self; }); var Human = Container.expand(function () { var self = Container.call(this); // Create human body var body = self.attachAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.9, scaleY: 1.5 }); body.tint = 0xFFD2B7; // Skin tone // Add clothes var clothes = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.0, scaleY: 1.0, y: 20 }); clothes.tint = Math.random() > 0.5 ? 0x3498DB : 0xE74C3C; // Random blue or red self.addChild(clothes); // Add head var head = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.6, scaleY: 0.6, y: -50 }); head.tint = 0xFFD2B7; // Same skin tone as body self.addChild(head); // Properties self.speed = 1 + Math.random() * 1.5; self.targetX = 0; self.targetY = 0; self.breadCount = 0; self.maxBread = 3; self.lastBreadThrow = 0; self.breadCooldown = 120 + Math.floor(Math.random() * 240); // 2-6 second cooldown self.isAngry = false; // Set target position self.setTarget = function (x, y) { self.targetX = x; self.targetY = y; }; // Make human throw bread self.throwBread = function (pondX, pondY) { if (self.breadCount > 0 && self.lastBreadThrow <= 0) { self.breadCount--; self.lastBreadThrow = self.breadCooldown; // Calculate throw position (toward pond center) var dx = pondX - self.x; var dy = pondY - self.y; var dist = Math.sqrt(dx * dx + dy * dy); var throwDist = Math.min(dist * 0.7, 300); return { x: self.x + dx / dist * throwDist, y: self.y + dy / dist * throwDist }; } return null; }; // Make human angry at goose self.becomeAngry = function () { if (!self.isAngry) { self.isAngry = true; body.tint = 0xFFB2B7; // Slightly redder skin tone when angry // Angry animation tween(self, { scaleX: 1.2, scaleY: 1.2 }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { tween(self, { scaleX: 1.0, scaleY: 1.0 }, { duration: 300, easing: tween.easeOut }); } }); return true; } return false; }; // Make human happy (feed birds) self.refillBread = function () { self.breadCount = self.maxBread; // Happy animation tween(head, { y: -60 }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { tween(head, { y: -50 }, { duration: 300, easing: tween.easeInOut }); } }); }; // Update function self.update = function () { if (self.lastBreadThrow > 0) { self.lastBreadThrow--; } // Move toward target var dx = self.targetX - self.x; var dy = self.targetY - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 10) { self.x += dx / dist * self.speed; self.y += dy / dist * self.speed; // Flip based on movement direction if (dx < 0) { self.scale.x = -1; } else { self.scale.x = 1; } } // Calm down after some time if (self.isAngry && Math.random() < 0.001) { self.isAngry = false; body.tint = 0xFFD2B7; // Normal skin tone } }; return self; }); var Painkiller = Container.expand(function () { var self = Container.call(this); // Create painkiller item (white pill with red cross) var pillBody = self.attachAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.7, scaleY: 0.4 }); pillBody.tint = 0xFFFFFF; // White pill // Add red cross to indicate healing var redCross = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.4, scaleY: 0.1 }); redCross.tint = 0xFF0000; // Red self.addChild(redCross); // Add vertical line of cross var redCrossVert = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.1, scaleY: 0.4 }); redCrossVert.tint = 0xFF0000; // Red self.addChild(redCrossVert); self.isCollected = false; self.timeLeft = 360; // 6 seconds at 60fps // Painkiller collection self.collect = function () { if (!self.isCollected) { self.isCollected = true; // Collection animation tween(self, { alpha: 0, scaleX: 0.1, scaleY: 0.1 }, { duration: 300, onFinish: function onFinish() { self.visible = false; } }); return true; } return false; }; // Update function to handle pill lifetime self.update = function () { self.timeLeft--; // Pulse when about to disappear if (self.timeLeft < 60) { self.alpha = 0.5 + Math.sin(self.timeLeft * 0.2) * 0.5; } if (self.timeLeft <= 0 && !self.isCollected) { self.collect(); } }; return self; }); var PanzerBoss = Container.expand(function () { var self = Container.call(this); // Create tank body (main hull) var tankBody = self.attachAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, scaleX: 2.0, scaleY: 1.2 }); tankBody.tint = 0x2F4F2F; // Dark olive green // Create tank turret var turret = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.2, scaleY: 1.2 }); turret.tint = 0x556B2F; // Olive drab self.addChild(turret); // Create tank barrel (cannon) var barrel = LK.getAsset('centerCircle', { anchorX: 0, anchorY: 0.5, scaleX: 1.5, scaleY: 0.3, x: 60 }); barrel.tint = 0x2F4F2F; // Dark olive green turret.addChild(barrel); // Add German cross marking var cross1 = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.6, scaleY: 0.1 }); cross1.tint = 0x000000; // Black cross turret.addChild(cross1); var cross2 = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.1, scaleY: 0.6 }); cross2.tint = 0x000000; // Black cross turret.addChild(cross2); self.health = 2; // Takes 2 hits to destroy self.shootCooldown = 0; self.shootInterval = 120; // Shoot every 2 seconds self.isDestroyed = false; self.targetX = 0; self.targetY = 0; self.speed = 1.5; // Set target for movement self.setTarget = function (x, y) { self.targetX = x; self.targetY = y; }; // Shoot shell at target self.shoot = function (targetX, targetY) { if (self.shootCooldown <= 0 && !self.isDestroyed) { self.shootCooldown = self.shootInterval; // Create shell var shell = new PanzerShell(); shell.x = self.x + Math.cos(turret.rotation) * 80; shell.y = self.y + Math.sin(turret.rotation) * 80; shell.setTarget(targetX, targetY); panzerShells.push(shell); game.addChild(shell); // Play shoot sound LK.getSound('tankShoot').play(); // Barrel recoil animation tween(barrel, { x: 40 }, { duration: 100, easing: tween.easeOut, onFinish: function onFinish() { tween(barrel, { x: 60 }, { duration: 200, easing: tween.easeInOut }); } }); return true; } return false; }; // Take damage from special weapons self.takeDamage = function () { if (!self.isDestroyed) { self.health--; // Play tank damage sound LK.getSound('tankDestroy').play(); // Damage effect tween(self, { alpha: 0.5 }, { duration: 100, onFinish: function onFinish() { tween(self, { alpha: 1 }, { duration: 100 }); } }); if (self.health <= 0) { self.destroy(); } return true; } return false; }; // Destroy tank self.destroy = function () { if (!self.isDestroyed) { self.isDestroyed = true; // Play destroy sound LK.getSound('tankDestroy').play(); // Destruction animation tween(self, { alpha: 0, scaleX: 2.5, scaleY: 2.5, rotation: Math.PI * 0.5 }, { duration: 1000, easing: tween.easeOut, onFinish: function onFinish() { self.visible = false; } }); // Award points for destroying tank LK.setScore(LK.getScore() + 15); scoreTxt.setText("Punkte: " + LK.getScore()); // Show bonus points var bonusTxt = new Text2("+15 Panzer Zerstört!", { size: 70, fill: 0xFFD700 }); bonusTxt.anchor.set(0.5, 0.5); bonusTxt.x = self.x; bonusTxt.y = self.y - 100; game.addChild(bonusTxt); // Animate bonus text tween(bonusTxt, { y: bonusTxt.y - 100, alpha: 0 }, { duration: 1500, easing: tween.easeOut, onFinish: function onFinish() { game.removeChild(bonusTxt); } }); return true; } return false; }; self.update = function () { if (self.isDestroyed) return; // Check if panzer is near any offensive collectibles and flee immediately var fleeRadius = 300; // Distance to detect and flee from threats var shouldFlee = false; var fleeAngle = 0; // Check Eurovision flashbang threat (both when it's on the ground and when goose has it) if (eurovisionFlashbang && !hasFlashbang) { var dx = self.x - eurovisionFlashbang.x; var dy = self.y - eurovisionFlashbang.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < fleeRadius) { shouldFlee = true; fleeAngle = Math.atan2(dy, dx); // Flee away from flashbang } } // Check if goose has flashbang and flee from goose if (hasFlashbang) { var dx = self.x - goose.x; var dy = self.y - goose.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < fleeRadius) { shouldFlee = true; fleeAngle = Math.atan2(dy, dx); // Flee away from goose with flashbang } } // Check atomic bomb threat (both when it's on the ground and when goose has it) if (atomicBomb && !hasBomb) { var dx = self.x - atomicBomb.x; var dy = self.y - atomicBomb.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < fleeRadius) { shouldFlee = true; fleeAngle = Math.atan2(dy, dx); // Flee away from bomb } } // Check if goose has atomic bomb and flee from goose if (hasBomb) { var dx = self.x - goose.x; var dy = self.y - goose.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < fleeRadius) { shouldFlee = true; fleeAngle = Math.atan2(dy, dx); // Flee away from goose with bomb } } // If should flee, move away from threat at high speed if (shouldFlee) { var fleeSpeed = self.speed * 3; // Triple speed when fleeing var fleeDistance = 800; // Flee far away self.setTarget(self.x + Math.cos(fleeAngle) * fleeDistance, self.y + Math.sin(fleeAngle) * fleeDistance); // Move immediately toward flee target var dx = self.targetX - self.x; var dy = self.targetY - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 0) { self.x += dx / dist * fleeSpeed; self.y += dy / dist * fleeSpeed; } return; // Skip normal behavior when fleeing } // Update cooldowns if (self.shootCooldown > 0) { self.shootCooldown--; } // Move toward target var dx = self.targetX - self.x; var dy = self.targetY - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 50) { self.x += dx / dist * self.speed; self.y += dy / dist * self.speed; } // Rotate turret to face goose var angleToGoose = Math.atan2(goose.y - self.y, goose.x - self.x); turret.rotation = angleToGoose; // Shoot at goose periodically if (self.shootCooldown <= 0 && Math.random() < 0.02) { // Predict goose position slightly for better accuracy var predictedX = goose.x + (goose.x - goose.lastX || 0) * 5; var predictedY = goose.y + (goose.y - goose.lastY || 0) * 5; self.shoot(predictedX, predictedY); } }; return self; }); var PanzerShell = Container.expand(function () { var self = Container.call(this); // Create shell body (dark metallic projectile) var shellBody = self.attachAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.4, scaleY: 0.6 }); shellBody.tint = 0x444444; // Dark grey metallic // Add explosive tip (orange) var tip = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.2, scaleY: 0.3, y: -15 }); tip.tint = 0xFF4500; // Orange explosive tip self.addChild(tip); self.speed = 8; self.targetX = 0; self.targetY = 0; self.isExploded = false; // Set target for shell trajectory self.setTarget = function (x, y) { self.targetX = x; self.targetY = y; // Calculate direction var dx = x - self.x; var dy = y - self.y; var angle = Math.atan2(dy, dx); self.rotation = angle; }; // Explode shell on impact self.explode = function () { if (!self.isExploded) { self.isExploded = true; // Create explosion effect var explosion = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, x: self.x, y: self.y, scaleX: 0.1, scaleY: 0.1 }); explosion.tint = 0xFF4500; // Orange explosion game.addChild(explosion); // Explosion animation tween(explosion, { scaleX: 4, scaleY: 4, alpha: 0 }, { duration: 600, easing: tween.easeOut, onFinish: function onFinish() { game.removeChild(explosion); } }); // Hide shell self.visible = false; return true; } return false; }; self.update = function () { if (self.isExploded) return; // Move toward target var dx = self.targetX - self.x; var dy = self.targetY - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 10) { self.x += dx / dist * self.speed; self.y += dy / dist * self.speed; } else { // Reached target, explode self.explode(); } // Check if shell went off screen if (self.x < -100 || self.x > 2148 || self.y < -100 || self.y > 2832) { self.explode(); } }; return self; }); var Pond = Container.expand(function () { var self = Container.call(this); var pondGraphic = self.attachAsset('pond', { anchorX: 0.5, anchorY: 0.5 }); return self; }); var Pretzel = Container.expand(function () { var self = Container.call(this); // Create main pretzel body (brown) var pretzelBody = self.attachAsset('pretzelShape', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.9, scaleY: 0.9 }); pretzelBody.tint = 0x8B4513; // Saddle brown // Add salt crystals (white spots) for (var i = 0; i < 8; i++) { var salt = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.08, scaleY: 0.08, x: (Math.random() - 0.5) * 60, y: (Math.random() - 0.5) * 60 }); salt.tint = 0xFFFFFF; // White salt self.addChild(salt); } self.isCollected = false; self.timeLeft = 600; // 10 seconds at 60fps self.scoreValue = 5; // Higher value than regular chips // Pretzel collection self.collect = function () { if (!self.isCollected) { self.isCollected = true; // Collection animation tween(self, { alpha: 0, scaleX: 0.1, scaleY: 0.1, rotation: Math.PI * 2 }, { duration: 400, easing: tween.easeOut, onFinish: function onFinish() { self.visible = false; } }); return true; } return false; }; // Update function to handle pretzel lifetime self.update = function () { self.timeLeft--; // Gentle rotation animation self.rotation += 0.02; // Pulse when about to disappear if (self.timeLeft < 120) { self.alpha = 0.5 + Math.sin(self.timeLeft * 0.15) * 0.5; } if (self.timeLeft <= 0 && !self.isCollected) { self.collect(); } }; return self; }); var Storch = Container.expand(function () { var self = Container.call(this); // Create stork body (white) var body = self.attachAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.8, scaleY: 1.2 }); body.tint = 0xFFFFFF; // White body // Create stork neck var neck = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 1, scaleX: 0.3, scaleY: 0.8, y: -60 }); neck.tint = 0xFFFFFF; self.addChild(neck); // Create stork head var head = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.4, scaleY: 0.4, y: -100 }); head.tint = 0xFFFFFF; self.addChild(head); // Create orange beak var beak = LK.getAsset('centerCircle', { anchorX: 0, anchorY: 0.5, scaleX: 0.6, scaleY: 0.15, x: 20, y: -100 }); beak.tint = 0xFF6600; // Orange beak self.addChild(beak); // Create red legs var leftLeg = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0, scaleX: 0.1, scaleY: 0.8, x: -15, y: 60 }); leftLeg.tint = 0xFF0000; // Red legs self.addChild(leftLeg); var rightLeg = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0, scaleX: 0.1, scaleY: 0.8, x: 15, y: 60 }); rightLeg.tint = 0xFF0000; self.addChild(rightLeg); // Properties self.speed = 1.5; self.targetX = 0; self.targetY = 0; self.state = 'wandering'; // 'wandering', 'hunting', 'fleeing' self.huntTimer = 0; self.peckCooldown = 0; self.fleeTimer = 0; // Set target position self.setTarget = function (x, y) { self.targetX = x; self.targetY = y; }; // Peck attack self.peck = function () { if (self.peckCooldown <= 0) { self.peckCooldown = 60; // 1 second cooldown // Peck animation tween(neck, { scaleY: 1.2, y: -40 }, { duration: 150, easing: tween.easeOut, onFinish: function onFinish() { tween(neck, { scaleY: 0.8, y: -60 }, { duration: 200, easing: tween.easeInOut }); } }); // Move beak forward tween(beak, { x: 40 }, { duration: 150, easing: tween.easeOut, onFinish: function onFinish() { tween(beak, { x: 20 }, { duration: 200, easing: tween.easeInOut }); } }); return true; } return false; }; // Make stork flee self.flee = function (fromX, fromY) { self.state = 'fleeing'; self.fleeTimer = 180; // Flee for 3 seconds // Calculate flee direction var angle = Math.atan2(self.y - fromY, self.x - fromX); var fleeDistance = 400; self.setTarget(self.x + Math.cos(angle) * fleeDistance, self.y + Math.sin(angle) * fleeDistance); // Speed up when fleeing self.speed = 3; }; self.update = function () { // Update cooldowns if (self.peckCooldown > 0) { self.peckCooldown--; } if (self.fleeTimer > 0) { self.fleeTimer--; if (self.fleeTimer === 0) { self.state = 'wandering'; self.speed = 1.5; } } // Move toward target var dx = self.targetX - self.x; var dy = self.targetY - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 10) { self.x += dx / dist * self.speed; self.y += dy / dist * self.speed; // Face movement direction if (dx < 0) { self.scale.x = -1; } else { self.scale.x = 1; } } // Walking animation if (dist > 10) { leftLeg.rotation = Math.sin(LK.ticks * 0.1) * 0.2; rightLeg.rotation = -Math.sin(LK.ticks * 0.1) * 0.2; } }; return self; }); var WaterMine = Container.expand(function () { var self = Container.call(this); // Create mine visual var mineBody = self.attachAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.6, scaleY: 0.6 }); mineBody.tint = 0x333333; // Dark grey // Add spikes/details var spike1 = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.1, scaleY: 0.8, rotation: 0 }); spike1.tint = 0x555555; self.addChild(spike1); var spike2 = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.1, scaleY: 0.8, rotation: Math.PI / 2 }); spike2.tint = 0x555555; self.addChild(spike2); self.isExploded = false; self.damage = 1; // Damage dealt to goose on explosion // Explode the mine self.explode = function () { if (!self.isExploded) { self.isExploded = true; // Explosion animation (expanding reddish circle) var explosionEffect = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, x: self.x, y: self.y, scaleX: 0.1, scaleY: 0.1, alpha: 1 }); explosionEffect.tint = 0xFF4500; // OrangeRed for explosion game.addChild(explosionEffect); tween(explosionEffect, { scaleX: 5, scaleY: 5, alpha: 0 }, { duration: 500, easing: tween.easeOut, onFinish: function onFinish() { game.removeChild(explosionEffect); } }); // Fade out and remove the mine tween(self, { alpha: 0 }, { duration: 200, onFinish: function onFinish() { self.visible = false; } }); return true; } return false; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x87CEEB // Sky blue background }); /**** * Game Code ****/ // Game variables var goose; var pond; var chips = []; var chipCount = 15; var dragNode = null; var lastIntersecting = false; var gameActive = true; var highScore = storage.highScore || 0; var atomicBomb = null; var bombTimer = 0; var hasBomb = false; var chocolate = null; var chocolateTimer = 0; var eurovisionFlashbang = null; var flashbangTimer = 0; var hasFlashbang = false; var drowning = null; var isInShallowWater = false; var lastPondDistance = 0; var painkiller = null; var painkillerTimer = 0; var gooseHealth = 3; // Initial health var maxGooseHealth = 5; // Maximum health possible // Human-related variables var humans = []; var maxHumans = 3; var humanSpawnTimer = 180; var breadPieces = []; var gooseChasingHuman = null; var chasingTimeout = 0; // Country variables var countries = []; var availableCountries = [{ name: "Bayern", color: 0x0066CC }, { name: "Berlin", color: 0x000000 }, { name: "Hamburg", color: 0xFF0000 }, { name: "Sachsen", color: 0x00FF00 }, { name: "Rheinland", color: 0x800080 }, { name: "Hessen", color: 0xFF6600 }, { name: "Thüringen", color: 0x0000FF }, { name: "Baden", color: 0xFFD700 }]; var visitedCountries = {}; // Track visited countries var countryPortalTimer = 0; var maxActiveCountries = 2; // Maximum number of active portals at once var currentBackground = "default"; // Current background theme var travelEffectActive = false; // Cookie variables var currentCookie = null; var cookieSpawnTimer = 0; var gooseHasCookie = false; var cookieEffectDuration = 300; // 5 seconds at 60fps var cookieEffectTimer = 0; var gooseCookieIndicator = null; var waterMines = []; var maxWaterMines = 3; var waterMineSpawnTimer = 600; // 10 seconds var panzerBoss = null; var panzerShells = []; var panzerSpawned = false; var pretzels = []; var pretzelSpawnTimer = 0; var maxPretzels = 2; var storchs = []; var maxStorchs = 2; var storchSpawnTimer = 0; var dachshunds = []; var maxDachshunds = 2; var dachshundSpawnTimer = 0; var antiTankGrenade = null; var grenadeSpawnTimer = 0; var hasGrenade = false; // Initialize the game UI var scoreTxt = new Text2('0', { size: 80, fill: 0xFFFFFF }); scoreTxt.setText("Punkte: " + LK.getScore()); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); var highScoreTxt = new Text2('0', { size: 50, fill: 0xFFFFFF }); highScoreTxt.setText("Rekord: " + highScore); highScoreTxt.anchor.set(0.5, 0); highScoreTxt.y = 90; LK.gui.top.addChild(highScoreTxt); // Create visited countries display var countriesVisitedTxt = new Text2('0', { size: 45, fill: 0xFFFFFF }); countriesVisitedTxt.setText("Länder: 0"); countriesVisitedTxt.anchor.set(0.5, 0); countriesVisitedTxt.y = 150; LK.gui.top.addChild(countriesVisitedTxt); // Update countries visited text function updateCountriesVisited() { var count = Object.keys(visitedCountries).length; countriesVisitedTxt.setText("Länder: " + count); // Change text color based on countries visited if (count >= 5) { countriesVisitedTxt.style = { fill: 0xFFD700 }; // Gold } else if (count >= 3) { countriesVisitedTxt.style = { fill: 0xC0C0C0 }; // Silver } else if (count >= 1) { countriesVisitedTxt.style = { fill: 0xCD7F32 }; // Bronze } } // Settings variables var settingsButton; var settingsPanel; var isSettingsOpen = false; // Create settings button settingsButton = LK.getAsset('settingsBackground', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.04, scaleY: 0.04 }); settingsButton.tint = 0x444444; // Darker grey for rectangular button settingsButton.x = -60; // Position relative to topRight settingsButton.y = 60; LK.gui.topRight.addChild(settingsButton); // Add gear symbol to settings button var gearSymbol = new Text2('⚙', { size: 40, fill: 0xFFFFFF }); gearSymbol.anchor.set(0.5, 0.5); settingsButton.addChild(gearSymbol); // Create settings panel (initially hidden) settingsPanel = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, scaleX: 4, scaleY: 3 }); settingsPanel.tint = 0x333333; // Dark background settingsPanel.alpha = 0.9; settingsPanel.x = -150; settingsPanel.y = 200; settingsPanel.visible = false; LK.gui.topRight.addChild(settingsPanel); // Add settings title var settingsTitle = new Text2('Einstellungen', { size: 50, fill: 0xFFFFFF }); settingsTitle.anchor.set(0.5, 0.5); settingsTitle.y = -80; settingsPanel.addChild(settingsTitle); // Add music toggle button var musicToggle = new Text2('Musik: AN', { size: 35, fill: 0x00FF00 }); musicToggle.anchor.set(0.5, 0.5); musicToggle.y = -20; settingsPanel.addChild(musicToggle); // Add close button var closeButton = new Text2('✕', { size: 40, fill: 0xFF5555 }); closeButton.anchor.set(0.5, 0.5); closeButton.y = 60; settingsPanel.addChild(closeButton); // Settings button functionality settingsButton.down = function (x, y, obj) { if (!isSettingsOpen) { settingsPanel.visible = true; isSettingsOpen = true; // Pause game when settings open gameActive = false; } else { settingsPanel.visible = false; isSettingsOpen = false; // Resume game when settings close gameActive = true; } }; // Music toggle functionality musicToggle.down = function (x, y, obj) { if (musicToggle.text === 'Musik: AN') { LK.stopMusic(); musicToggle.setText('Musik: AUS'); musicToggle.style = { fill: 0xFF5555 }; // Red for OFF } else { LK.playMusic('bgMusic', { loop: true }); musicToggle.setText('Musik: AN'); musicToggle.style = { fill: 0x00FF00 }; // Green for ON } }; // Close button functionality closeButton.down = function (x, y, obj) { settingsPanel.visible = false; isSettingsOpen = false; // Resume game when settings close gameActive = true; }; // Health display var healthTxt = new Text2('Leben: ♥♥♥', { size: 45, fill: 0xFF5555 }); healthTxt.anchor.set(0, 0); healthTxt.x = 20; healthTxt.y = 20; LK.gui.topLeft.addChild(healthTxt); // Update health display function updateHealthDisplay() { var hearts = ''; for (var i = 0; i < gooseHealth; i++) { hearts += '♥'; } healthTxt.setText('Leben: ' + hearts); } // Create the pond (play area) pond = game.addChild(new Pond()); pond.x = 2048 / 2; pond.y = 2732 / 2; pond.innerRadius = 400; // Safe swimming area pond.outerRadius = 850; // Pond edge // Create the goose (player character) goose = game.addChild(new Goose()); goose.x = 2048 / 2; goose.y = 2732 / 2 + 600; // Create drowning effect drowning = game.addChild(new Drowning()); drowning.visible = false; drowning.alpha = 0; // Spawn chips around the pond function spawnChips() { for (var i = 0; i < chipCount; i++) { var chip = new Chip(); var angle = Math.random() * Math.PI * 2; var distance = Math.random() * 700 + 200; chip.x = pond.x + Math.cos(angle) * distance; chip.y = pond.y + Math.sin(angle) * distance; // Make sure chips are within pond boundaries var dx = chip.x - pond.x; var dy = chip.y - pond.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 850) { // Adjust to keep within pond chip.x = pond.x + dx / dist * 850; chip.y = pond.y + dy / dist * 850; } chips.push(chip); game.addChild(chip); } } // Spawn initial chips spawnChips(); // Spawn initial humans function spawnHuman() { if (humans.length < maxHumans) { var human = new Human(); // Position human around the pond edges var angle = Math.random() * Math.PI * 2; var distance = pond.outerRadius + 100 + Math.random() * 200; human.x = pond.x + Math.cos(angle) * distance; human.y = pond.y + Math.sin(angle) * distance; // Set initial target to another spot around the pond var targetAngle = angle + (Math.random() * Math.PI * 0.5 - Math.PI * 0.25); human.setTarget(pond.x + Math.cos(targetAngle) * distance, pond.y + Math.sin(targetAngle) * distance); // Fill bread supply human.refillBread(); humans.push(human); game.addChild(human); return human; } return null; } // Spawn initial humans for (var i = 0; i < 2; i++) { spawnHuman(); } // Spawn initial storchs function spawnStorch() { if (storchs.length < maxStorchs) { var storch = new Storch(); // Position storch around pond edges var angle = Math.random() * Math.PI * 2; var distance = pond.outerRadius - 100 - Math.random() * 200; storch.x = pond.x + Math.cos(angle) * distance; storch.y = pond.y + Math.sin(angle) * distance; // Set initial wandering target var targetAngle = Math.random() * Math.PI * 2; var targetDistance = pond.outerRadius - 100 - Math.random() * 300; storch.setTarget(pond.x + Math.cos(targetAngle) * targetDistance, pond.y + Math.sin(targetAngle) * targetDistance); storchs.push(storch); game.addChild(storch); return storch; } return null; } // Spawn initial storch spawnStorch(); // Spawn dachshunds function spawnDachshund() { if (dachshunds.length < maxDachshunds) { var dachshund = new Dachshund(); // Position dachshund around pond edges var angle = Math.random() * Math.PI * 2; var distance = pond.outerRadius + 50 + Math.random() * 150; dachshund.x = pond.x + Math.cos(angle) * distance; dachshund.y = pond.y + Math.sin(angle) * distance; dachshunds.push(dachshund); game.addChild(dachshund); return dachshund; } return null; } // Spawn initial dachshund spawnDachshund(); // Play background music LK.playMusic('bgMusic', { loop: true }); // Handle movement function handleMove(x, y, obj) { if (dragNode && gameActive) { // Limit goose movement to within the pond boundaries var dx = x - pond.x; var dy = y - pond.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 850) { // Keep goose within the pond boundaries dragNode.x = pond.x + dx / dist * 850; dragNode.y = pond.y + dy / dist * 850; } else { dragNode.x = x; dragNode.y = y; } // Rotate toward movement direction var moveAngle = Math.atan2(y - dragNode.y, x - dragNode.x); dragNode.rotation = moveAngle; } } // Mouse/touch events game.move = handleMove; game.down = function (x, y, obj) { if (gameActive) { dragNode = goose; handleMove(x, y, obj); // Deactivate drowning when goose starts moving if (drowning.isActive) { drowning.deactivate(); } // Attack on tap/click goose.attack(); // Special effect when having atomic bomb if (hasBomb) { LK.effects.flashScreen(0xff0000, 500); } } }; game.up = function (x, y, obj) { dragNode = null; }; // Main game update loop game.update = function () { if (!gameActive) return; // Update game entities goose.update(); if (chocolate) { chocolate.update(); } if (painkiller) { painkiller.update(); } if (antiTankGrenade) { antiTankGrenade.update(); } // Drowning mechanics - check how far goose is from pond center var dx = goose.x - pond.x; var dy = goose.y - pond.y; var distFromCenter = Math.sqrt(dx * dx + dy * dy); lastPondDistance = distFromCenter; // Different water zones if (distFromCenter > pond.outerRadius) { // Outside the pond - no drowning drowning.deactivate(); drowning.visible = false; isInShallowWater = false; } else if (distFromCenter > pond.innerRadius) { // In the shallow area - safe swimming isInShallowWater = true; drowning.deactivate(); drowning.visible = false; } else { // In the deep area - risk of drowning isInShallowWater = false; // Only start drowning if goose isn't moving if (dragNode !== goose) { if (!drowning.isActive) { drowning.activate(); drowning.visible = true; drowning.x = goose.x; drowning.y = goose.y; } else { // Update drowning position to follow goose drowning.x = goose.x; drowning.y = goose.y; // Check if drowning is complete if (drowning.update()) { // Goose drowned - game over LK.getSound('hit').play(); LK.effects.flashScreen(0x0066ff, 1000); // Update high score if needed if (LK.getScore() > highScore) { highScore = LK.getScore(); storage.highScore = highScore; highScoreTxt.setText("Rekord: " + highScore); } // End the game gameActive = false; LK.showGameOver(); } } } else { // Goose is moving, deactivate drowning drowning.deactivate(); } } // Chocolate spawn logic chocolateTimer++; if (!chocolate && chocolateTimer > 480 && Math.random() < 0.008) { chocolate = new Chocolate(); var angle = Math.random() * Math.PI * 2; var distance = Math.random() * 600 + 150; chocolate.x = pond.x + Math.cos(angle) * distance; chocolate.y = pond.y + Math.sin(angle) * distance; game.addChild(chocolate); chocolateTimer = 0; } // Atomic bomb spawn logic bombTimer++; if (!atomicBomb && !hasBomb && bombTimer > 600 && Math.random() < 0.005) { atomicBomb = new AtomicBomb(); var angle = Math.random() * Math.PI * 2; var distance = Math.random() * 600 + 150; atomicBomb.x = pond.x + Math.cos(angle) * distance; atomicBomb.y = pond.y + Math.sin(angle) * distance; game.addChild(atomicBomb); bombTimer = 0; } // Check for goose collecting chips for (var i = chips.length - 1; i >= 0; i--) { if (!chips[i].isCollected && goose.intersects(chips[i])) { if (chips[i].collect()) { // Increase score LK.setScore(LK.getScore() + 1); scoreTxt.setText("Punkte: " + LK.getScore()); // Remove the chip from the array chips.splice(i, 1); // Spawn a new chip if needed if (chips.length < 5) { var chip = new Chip(); var angle = Math.random() * Math.PI * 2; var distance = Math.random() * 700 + 200; chip.x = pond.x + Math.cos(angle) * distance; chip.y = pond.y + Math.sin(angle) * distance; chips.push(chip); game.addChild(chip); } } } } // Painkiller spawn logic painkillerTimer++; if (!painkiller && painkillerTimer > 420 && gooseHealth < maxGooseHealth && Math.random() < 0.006) { painkiller = new Painkiller(); var angle = Math.random() * Math.PI * 2; var distance = Math.random() * 600 + 200; painkiller.x = pond.x + Math.cos(angle) * distance; painkiller.y = pond.y + Math.sin(angle) * distance; game.addChild(painkiller); painkillerTimer = 0; } // Check for painkiller collection if (painkiller && !painkiller.isCollected && goose.intersects(painkiller)) { if (painkiller.collect()) { // Increase health gooseHealth = Math.min(maxGooseHealth, gooseHealth + 1); updateHealthDisplay(); // Health up animation var healthUpTxt = new Text2("+1 ♥ Gesundheit", { size: 60, fill: 0xFF5555 }); healthUpTxt.anchor.set(0.5, 0.5); healthUpTxt.x = goose.x; healthUpTxt.y = goose.y - 80; game.addChild(healthUpTxt); // Animate health text tween(healthUpTxt, { y: healthUpTxt.y - 100, alpha: 0 }, { duration: 1000, easing: tween.easeOut, onFinish: function onFinish() { game.removeChild(healthUpTxt); } }); // Play sound LK.getSound('eat').play(); // Reset painkiller painkiller = null; painkillerTimer = 0; } } // Check for anti-tank grenade collection if (antiTankGrenade && !hasGrenade && goose.intersects(antiTankGrenade) && antiTankGrenade.collect()) { hasGrenade = true; antiTankGrenade.visible = false; // Create grenade indicator on goose var grenadeIndicator = LK.getAsset('antiTankGrenade', { anchorX: 0.5, anchorY: 0.5, x: 0, y: -80, scaleX: 0.3, scaleY: 0.3 }); grenadeIndicator.tint = 0x4A4A4A; // Dark grey goose.addChild(grenadeIndicator); LK.getSound('eat').play(); } // Check for atomic bomb collection if (atomicBomb && !hasBomb && goose.intersects(atomicBomb) && atomicBomb.collect()) { // Pulse animation for the indicator var _pulseIndicator = function pulseIndicator() { tween(indicatorGlow, { alpha: 0.3, scaleX: 0.5, scaleY: 0.5 }, { duration: 600, easing: tween.easeInOut, onFinish: function onFinish() { tween(indicatorGlow, { alpha: 0.6, scaleX: 0.4, scaleY: 0.4 }, { duration: 600, easing: tween.easeInOut, onFinish: _pulseIndicator }); } }); }; hasBomb = true; atomicBomb.visible = false; // Create bomb indicator on goose with new blue design var bombIndicator = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, x: 0, y: -80, scaleX: 0.3, scaleY: 0.3 }); bombIndicator.tint = 0x0066ff; // Electric blue to match new bomb design // Add glow effect to indicator var indicatorGlow = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, x: 0, y: 0, scaleX: 0.4, scaleY: 0.4, alpha: 0.6 }); indicatorGlow.tint = 0x00ffff; // Cyan glow bombIndicator.addChild(indicatorGlow); _pulseIndicator(); goose.addChild(bombIndicator); LK.getSound('eat').play(); } // Use atomic bomb when attacking with bomb collected if (hasBomb && goose.isAttacking) { hasBomb = false; // Remove bomb indicator goose.removeChild(goose.children[goose.children.length - 1]); // Create explosion at goose position var explosion = new AtomicBomb(); explosion.x = goose.x; explosion.y = goose.y; game.addChild(explosion); explosion.explode(); // Flash screen blue for freezing effect LK.effects.flashScreen(0x0066ff, 800); // Reset bomb variables atomicBomb = null; bombTimer = 0; } // Country portal spawn logic countryPortalTimer++; if (countryPortalTimer > 600 && Math.random() < 0.008 && countries.length < maxActiveCountries) { // Only spawn countries if we have unvisited countries or rarely for visited ones var availableForSpawn = availableCountries.filter(function (country) { return !visitedCountries[country.name] || Math.random() < 0.2; }); if (availableForSpawn.length > 0) { // Select random country var countryData = availableForSpawn[Math.floor(Math.random() * availableForSpawn.length)]; // Create country portal var portal = new Country(); portal.setCountry(countryData.name, countryData.color); // Position in a random location, biased toward pond edges var angle = Math.random() * Math.PI * 2; var distance = Math.random() * 300 + 500; // Between 500-800 units from center portal.x = pond.x + Math.cos(angle) * distance; portal.y = pond.y + Math.sin(angle) * distance; // Ensure within pond var dx = portal.x - pond.x; var dy = portal.y - pond.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 800) { portal.x = pond.x + dx / dist * 800; portal.y = pond.y + dy / dist * 800; } portal.activate(); countries.push(portal); game.addChild(portal); countryPortalTimer = 0; } } // Update countries for (var i = countries.length - 1; i >= 0; i--) { countries[i].update(); // Check if goose enters portal if (!travelEffectActive && goose.intersects(countries[i])) { var travelResult = countries[i].travel(); if (travelResult.success) { travelEffectActive = true; // Add score bonus LK.setScore(LK.getScore() + travelResult.scoreBonus); scoreTxt.setText("Punkte: " + LK.getScore()); // Mark country as visited visitedCountries[travelResult.countryName] = true; updateCountriesVisited(); // Travel effect var countryName = travelResult.countryName; var countryColor = countries[i].countryColor; // Flash screen with country color LK.effects.flashScreen(countryColor, 800); // Display travel message var travelText = new Text2("Reise nach " + countryName + "!", { size: 100, fill: countryColor }); travelText.anchor.set(0.5, 0.5); travelText.x = 2048 / 2; travelText.y = 2732 / 2; travelText.alpha = 0; game.addChild(travelText); // Animate travel text tween(travelText, { alpha: 1, scaleX: 1.2, scaleY: 1.2 }, { duration: 500, easing: tween.easeOut, onFinish: function onFinish() { tween(travelText, { alpha: 0, y: travelText.y - 100 }, { duration: 800, delay: 1000, easing: tween.easeIn, onFinish: function onFinish() { game.removeChild(travelText); } }); } }); // Change background tint temporarily to represent country var originalTint = pond.children[0].tint; tween(pond.children[0], { tint: countryColor }, { duration: 1000, onFinish: function onFinish() { LK.setTimeout(function () { tween(pond.children[0], { tint: originalTint }, { duration: 1000, onFinish: function onFinish() { travelEffectActive = false; } }); }, 3000); } }); } } // Remove expired portals if (countries[i].travelCooldown <= 0 && Math.random() < 0.002) { // Fade out and remove tween(countries[i], { alpha: 0, scaleX: 0.1, scaleY: 0.1 }, { duration: 500, onFinish: function (index) { return function () { game.removeChild(countries[index]); countries.splice(index, 1); }; }(i) }); } } // Eurovision flashbang spawn logic flashbangTimer++; if (!eurovisionFlashbang && !hasFlashbang && flashbangTimer > 900 && Math.random() < 0.003) { eurovisionFlashbang = new EurovisionFlashbang(); var angle = Math.random() * Math.PI * 2; var distance = Math.random() * 650 + 100; eurovisionFlashbang.x = pond.x + Math.cos(angle) * distance; eurovisionFlashbang.y = pond.y + Math.sin(angle) * distance; game.addChild(eurovisionFlashbang); flashbangTimer = 0; } // Check for eurovision flashbang collection if (eurovisionFlashbang && !hasFlashbang && goose.intersects(eurovisionFlashbang) && eurovisionFlashbang.collect()) { hasFlashbang = true; eurovisionFlashbang.visible = false; // Create flashbang indicator on goose (sparkling effect) var flashbangIndicator = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, x: 0, y: -80, scaleX: 0.3, scaleY: 0.3 }); flashbangIndicator.tint = 0xFFD700; // Gold color goose.addChild(flashbangIndicator); LK.getSound('eat').play(); } // Use eurovision flashbang when attacking with flashbang collected if (hasFlashbang && goose.isAttacking) { var _flashNextColor = function flashNextColor() { if (flashCount < colors.length) { LK.effects.flashScreen(colors[flashCount], 300); flashCount++; LK.setTimeout(_flashNextColor, 300); } }; hasFlashbang = false; // Remove flashbang indicator goose.removeChild(goose.children[goose.children.length - 1]); // Create explosion at goose position var explosion = new EurovisionFlashbang(); explosion.x = goose.x; explosion.y = goose.y; game.addChild(explosion); explosion.explode(); // Apply Eurovision flashbang effect // Create rainbow flashing effect that stuns all characters var colors = [0xFF0000, 0xFF7F00, 0xFFFF00, 0x00FF00, 0x0000FF, 0x4B0082, 0x9400D3]; var flashCount = 0; _flashNextColor(); // Reset flashbang variables eurovisionFlashbang = null; flashbangTimer = 0; } // Cookie Spawn Logic cookieSpawnTimer++; if (!currentCookie && cookieSpawnTimer > 12 * 60 && Math.random() < 0.01) { // Approx. every 12-13 seconds currentCookie = new Cookie(); var angle = Math.random() * Math.PI * 2; var distance = Math.random() * (pond.outerRadius * 0.8) + pond.innerRadius * 0.2; // Spawn within pond, not too close to center currentCookie.x = pond.x + Math.cos(angle) * distance; currentCookie.y = pond.y + Math.sin(angle) * distance; game.addChild(currentCookie); cookieSpawnTimer = 0; } // Update current cookie if it exists and handle its self-despawn if (currentCookie) { currentCookie.update(); // Cookie handles its own visibility and removal from parent if timed out if (!currentCookie.visible) { currentCookie = null; } } // Cookie Collection Logic if (currentCookie && currentCookie.visible && !currentCookie.isCollected && !gooseHasCookie && goose.intersects(currentCookie)) { if (currentCookie.collect()) { // collect() handles animation and sets isCollected LK.getSound('eat').play(); gooseHasCookie = true; cookieEffectTimer = cookieEffectDuration; if (gooseCookieIndicator && gooseCookieIndicator.parent) { // Remove old one if somehow it exists gooseCookieIndicator.parent.removeChild(gooseCookieIndicator); } gooseCookieIndicator = LK.getAsset('cookieShape', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.25, scaleY: 0.25, x: 0, y: -85 // Position above goose's head }); goose.addChild(gooseCookieIndicator); // The currentCookie will become invisible due to its collect animation. // The check above `if (!currentCookie.visible)` will handle setting `currentCookie = null;` } } // Cookie Effect Update (manages gooseHasCookie timer and indicator) if (gooseHasCookie) { cookieEffectTimer--; if (cookieEffectTimer <= 0) { gooseHasCookie = false; if (gooseCookieIndicator && gooseCookieIndicator.parent) { goose.removeChild(gooseCookieIndicator); gooseCookieIndicator = null; } } } // Human spawn logic humanSpawnTimer--; if (humanSpawnTimer <= 0 && humans.length < maxHumans) { spawnHuman(); humanSpawnTimer = 300 + Math.floor(Math.random() * 300); } // Update humans and bread for (var i = humans.length - 1; i >= 0; i--) { var human = humans[i]; human.update(); // Humans throw bread randomly if (Math.random() < 0.005 && human.breadCount > 0) { var breadPosition = human.throwBread(pond.x, pond.y); if (breadPosition) { var bread = new Bread(); bread.x = breadPosition.x; bread.y = breadPosition.y; // Check if bread landed in water var dx = bread.x - pond.x; var dy = bread.y - pond.y; var distFromCenter = Math.sqrt(dx * dx + dy * dy); if (distFromCenter < pond.outerRadius) { bread.startSinking(); } breadPieces.push(bread); game.addChild(bread); } } // Human movement around pond if (Math.random() < 0.01 && gooseChasingHuman !== human) { var newAngle = Math.random() * Math.PI * 2; var newDistance = pond.outerRadius + 100 + Math.random() * 200; human.setTarget(pond.x + Math.cos(newAngle) * newDistance, pond.y + Math.sin(newAngle) * newDistance); } // Goose scares human if (goose.intersects(human) && !human.isAngry && !gooseHasCookie) { // Human doesn't flee if goose has a cookie! // Human reacts to goose if (human.becomeAngry()) { // Human runs away from goose var runAngle = Math.atan2(human.y - goose.y, human.x - goose.x); var runDistance = pond.outerRadius + 300; human.setTarget(pond.x + Math.cos(runAngle) * runDistance, pond.y + Math.sin(runAngle) * runDistance); // Running animation human.speed = 4; // Chance to drop bread in panic if (human.breadCount > 0 && Math.random() < 0.5) { var breadPosition = human.throwBread(human.x + Math.random() * 100 - 50, human.y + Math.random() * 100 - 50); if (breadPosition) { var bread = new Bread(); bread.x = breadPosition.x; bread.y = breadPosition.y; breadPieces.push(bread); game.addChild(bread); } } // Add score for scaring human LK.setScore(LK.getScore() + 2); scoreTxt.setText("Punkte: " + LK.getScore()); // Show point popup var pointsTxt = new Text2("+2", { size: 60, fill: 0xFFFFFF }); pointsTxt.anchor.set(0.5, 0.5); pointsTxt.x = human.x; pointsTxt.y = human.y - 80; game.addChild(pointsTxt); // Animate points popup tween(pointsTxt, { y: pointsTxt.y - 80, alpha: 0 }, { duration: 800, easing: tween.easeOut, onFinish: function onFinish() { game.removeChild(pointsTxt); } }); // Set human as target for goose chase effect gooseChasingHuman = human; chasingTimeout = 180; // 3 seconds timeout } } // Remove humans that have run too far var distanceFromPond = Math.sqrt(Math.pow(human.x - pond.x, 2) + Math.pow(human.y - pond.y, 2)); if (distanceFromPond > pond.outerRadius + 800) { // Human left the scene, remove them tween(human, { alpha: 0 }, { duration: 500, onFinish: function (index) { return function () { game.removeChild(humans[index]); humans.splice(index, 1); }; }(i) }); } } // Update chasing timeout if (gooseChasingHuman !== null) { chasingTimeout--; if (chasingTimeout <= 0) { gooseChasingHuman = null; } } // Update bread pieces for (var i = breadPieces.length - 1; i >= 0; i--) { var bread = breadPieces[i]; bread.update(); // Check for bread collection by birds if (!bread.isConsumed) { // Goose can collect bread for points if (goose.intersects(bread)) { if (bread.consume()) { // Add score LK.setScore(LK.getScore() + 1); scoreTxt.setText("Punkte: " + LK.getScore()); // Remove from array breadPieces.splice(i, 1); // Play eat sound LK.getSound('eat').play(); } } // Remove bread that's no longer visible else if (bread.alpha <= 0) { breadPieces.splice(i, 1); game.removeChild(bread); } } } // Storch spawn logic (early game enemy) storchSpawnTimer++; if (storchSpawnTimer > 300 && storchs.length < maxStorchs && LK.getScore() < 40) { // Only spawn storchs in early game (before score 40) if (Math.random() < 0.01) { spawnStorch(); storchSpawnTimer = 0; } } // Update storchs for (var i = storchs.length - 1; i >= 0; i--) { var storch = storchs[i]; storch.update(); // Storch AI behavior if (storch.state === 'wandering') { // Check distance to goose var distToGoose = Math.sqrt(Math.pow(goose.x - storch.x, 2) + Math.pow(goose.y - storch.y, 2)); // Start hunting if goose is close if (distToGoose < 200 && storch.fleeTimer === 0) { storch.state = 'hunting'; storch.huntTimer = 180; // Hunt for 3 seconds storch.speed = 2.5; } // Wander to new position occasionally if (Math.random() < 0.005) { var angle = Math.random() * Math.PI * 2; var distance = pond.outerRadius - 100 - Math.random() * 300; storch.setTarget(pond.x + Math.cos(angle) * distance, pond.y + Math.sin(angle) * distance); } } else if (storch.state === 'hunting') { // Chase the goose storch.setTarget(goose.x, goose.y); storch.huntTimer--; // Stop hunting after timer expires if (storch.huntTimer <= 0) { storch.state = 'wandering'; storch.speed = 1.5; } // Try to peck if close enough var distToGoose = Math.sqrt(Math.pow(goose.x - storch.x, 2) + Math.pow(goose.y - storch.y, 2)); if (distToGoose < 80 && storch.peck()) { // Check if actually hit the goose if (goose.intersects(storch)) { // Damage goose LK.getSound('hit').play(); gooseHealth--; updateHealthDisplay(); // Knockback effect on goose var knockbackAngle = Math.atan2(goose.y - storch.y, goose.x - storch.x); goose.x += Math.cos(knockbackAngle) * 50; goose.y += Math.sin(knockbackAngle) * 50; // Show damage effect LK.effects.flashObject(goose, 0xFF0000, 500); // Check game over if (gooseHealth <= 0) { if (LK.getScore() > highScore) { highScore = LK.getScore(); storage.highScore = highScore; highScoreTxt.setText("Rekord: " + highScore); } LK.effects.flashScreen(0xff0000, 1000); gameActive = false; LK.showGameOver(); } } } } // Storch flees from goose attacks if (goose.isAttacking && !storch.state === 'fleeing') { var distToGoose = Math.sqrt(Math.pow(goose.x - storch.x, 2) + Math.pow(goose.y - storch.y, 2)); if (distToGoose < 150) { storch.flee(goose.x, goose.y); // Award points for scaring storch LK.setScore(LK.getScore() + 1); scoreTxt.setText("Punkte: " + LK.getScore()); // Show point popup var pointsTxt = new Text2("+1", { size: 50, fill: 0xFFFFFF }); pointsTxt.anchor.set(0.5, 0.5); pointsTxt.x = storch.x; pointsTxt.y = storch.y - 60; game.addChild(pointsTxt); tween(pointsTxt, { y: pointsTxt.y - 60, alpha: 0 }, { duration: 800, easing: tween.easeOut, onFinish: function onFinish() { game.removeChild(pointsTxt); } }); } } // Remove storchs that wander too far var distFromPond = Math.sqrt(Math.pow(storch.x - pond.x, 2) + Math.pow(storch.y - pond.y, 2)); if (distFromPond > pond.outerRadius + 400) { // Storch left the area tween(storch, { alpha: 0 }, { duration: 500, onFinish: function (index) { return function () { game.removeChild(storchs[index]); storchs.splice(index, 1); }; }(i) }); } } // Dachshund spawn logic dachshundSpawnTimer++; if (dachshundSpawnTimer > 400 && dachshunds.length < maxDachshunds && Math.random() < 0.008) { spawnDachshund(); dachshundSpawnTimer = 0; } // Update dachshunds for (var i = dachshunds.length - 1; i >= 0; i--) { var dachshund = dachshunds[i]; dachshund.update(); // Find nearest target (goose or storch) var nearestTarget = null; var nearestDistance = Infinity; // Check distance to goose var distToGoose = Math.sqrt(Math.pow(goose.x - dachshund.x, 2) + Math.pow(goose.y - dachshund.y, 2)); if (distToGoose < nearestDistance) { nearestDistance = distToGoose; nearestTarget = goose; } // Check distances to all storchs for (var j = 0; j < storchs.length; j++) { var distToStorch = Math.sqrt(Math.pow(storchs[j].x - dachshund.x, 2) + Math.pow(storchs[j].y - dachshund.y, 2)); if (distToStorch < nearestDistance) { nearestDistance = distToStorch; nearestTarget = storchs[j]; } } // Chase nearest target if (nearestTarget) { dachshund.target = nearestTarget; dachshund.setTarget(nearestTarget.x, nearestTarget.y); // Bark when getting close if (nearestDistance < 200 && nearestDistance > 80) { dachshund.bark(); } // Try to bite when very close if (nearestDistance < 60 && dachshund.bite()) { // Check if actually hit the target if (dachshund.intersects(nearestTarget)) { if (nearestTarget === goose) { // Damage goose LK.getSound('hit').play(); gooseHealth--; updateHealthDisplay(); // Knockback effect on goose var knockbackAngle = Math.atan2(goose.y - dachshund.y, goose.x - dachshund.x); goose.x += Math.cos(knockbackAngle) * 40; goose.y += Math.sin(knockbackAngle) * 40; // Show damage effect LK.effects.flashObject(goose, 0xFF0000, 500); // Check game over if (gooseHealth <= 0) { if (LK.getScore() > highScore) { highScore = LK.getScore(); storage.highScore = highScore; highScoreTxt.setText("Rekord: " + highScore); } LK.effects.flashScreen(0xff0000, 1000); gameActive = false; LK.showGameOver(); } } else { // Hit a storch - make it flee nearestTarget.flee(dachshund.x, dachshund.y); // Award small points for helping chase storch LK.setScore(LK.getScore() + 1); scoreTxt.setText("Punkte: " + LK.getScore()); } } } } // Dachshunds flee from goose attacks too if (goose.isAttacking && dachshund.intersects(goose)) { // Dachshund gets scared and runs away temporarily var fleeAngle = Math.atan2(dachshund.y - goose.y, dachshund.x - goose.x); dachshund.setTarget(dachshund.x + Math.cos(fleeAngle) * 300, dachshund.y + Math.sin(fleeAngle) * 300); dachshund.speed = 4; // Run faster when scared // Award points for scaring dachshund LK.setScore(LK.getScore() + 2); scoreTxt.setText("Punkte: " + LK.getScore()); // Show point popup var pointsTxt = new Text2("+2 Dackel!", { size: 60, fill: 0xFFD700 }); pointsTxt.anchor.set(0.5, 0.5); pointsTxt.x = dachshund.x; pointsTxt.y = dachshund.y - 60; game.addChild(pointsTxt); tween(pointsTxt, { y: pointsTxt.y - 80, alpha: 0 }, { duration: 800, easing: tween.easeOut, onFinish: function onFinish() { game.removeChild(pointsTxt); } }); // Reset speed after some time LK.setTimeout(function () { dachshund.speed = 2.5; }, 2000); } // Remove dachshunds that wander too far var distFromPond = Math.sqrt(Math.pow(dachshund.x - pond.x, 2) + Math.pow(dachshund.y - pond.y, 2)); if (distFromPond > pond.outerRadius + 600) { // Dachshund left the area tween(dachshund, { alpha: 0 }, { duration: 500, onFinish: function (index) { return function () { game.removeChild(dachshunds[index]); dachshunds.splice(index, 1); }; }(i) }); } } // Water mine spawn logic waterMineSpawnTimer--; if (waterMineSpawnTimer <= 0 && waterMines.length < maxWaterMines) { var mine = new WaterMine(); // Position mine randomly within the deep pond area var angle = Math.random() * Math.PI * 2; var distance = Math.random() * (pond.innerRadius - 100) + 50; // Between 50 and innerRadius-100 from center mine.x = pond.x + Math.cos(angle) * distance; mine.y = pond.y + Math.sin(angle) * distance; waterMines.push(mine); game.addChild(mine); waterMineSpawnTimer = 600 + Math.floor(Math.random() * 300); // Next spawn in 10-15 seconds } // Update water mines and check for goose collision for (var i = waterMines.length - 1; i >= 0; i--) { var mine = waterMines[i]; // Mines don't have an update function, but we check collision here // Check for goose collision with mine if (!mine.isExploded && goose.intersects(mine)) { if (mine.explode()) { // Goose hit a mine - take damage LK.getSound('hit').play(); gooseHealth -= mine.damage; updateHealthDisplay(); // Damage animation var damageEffect = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, x: goose.x, y: goose.y, scaleX: 2, scaleY: 2, alpha: 0.5 }); damageEffect.tint = 0xFF0000; game.addChild(damageEffect); // Animate damage effect tween(damageEffect, { alpha: 0, scaleX: 3, scaleY: 3 }, { duration: 500, easing: tween.easeOut, onFinish: function onFinish() { game.removeChild(damageEffect); } }); // Game over if health reaches zero if (gooseHealth <= 0) { // Update high score if needed if (LK.getScore() > highScore) { highScore = LK.getScore(); storage.highScore = highScore; highScoreTxt.setText("Rekord: " + highScore); } // Flash screen red LK.effects.flashScreen(0xff0000, 1000); // End the game gameActive = false; LK.showGameOver(); } // Remove the mine from the array waterMines.splice(i, 1); } } else if (!mine.visible && mine.isExploded) { // Remove mines that have finished exploding and are no longer visible waterMines.splice(i, 1); game.removeChild(mine); } } // Anti-tank grenade spawn logic (spawns when panzer boss appears) grenadeSpawnTimer++; if (!antiTankGrenade && !hasGrenade && panzerSpawned && grenadeSpawnTimer > 300 && Math.random() < 0.01) { antiTankGrenade = new AntiTankGrenade(); var angle = Math.random() * Math.PI * 2; var distance = Math.random() * 500 + 200; antiTankGrenade.x = pond.x + Math.cos(angle) * distance; antiTankGrenade.y = pond.y + Math.sin(angle) * distance; game.addChild(antiTankGrenade); grenadeSpawnTimer = 0; } // Panzer Boss spawn logic at score 60 if (!panzerSpawned && LK.getScore() >= 60) { panzerSpawned = true; panzerBoss = new PanzerBoss(); // Position tank at edge of pond area var spawnAngle = Math.random() * Math.PI * 2; var spawnDistance = pond.outerRadius + 200; panzerBoss.x = pond.x + Math.cos(spawnAngle) * spawnDistance; panzerBoss.y = pond.y + Math.sin(spawnAngle) * spawnDistance; // Set initial target near pond edge var targetAngle = spawnAngle + Math.PI; panzerBoss.setTarget(pond.x + Math.cos(targetAngle) * (pond.outerRadius + 50), pond.y + Math.sin(targetAngle) * (pond.outerRadius + 50)); game.addChild(panzerBoss); // Show boss warning var bossWarning = new Text2("ACHTUNG! PANZER BOSS!", { size: 100, fill: 0xFF0000 }); bossWarning.anchor.set(0.5, 0.5); bossWarning.x = 2048 / 2; bossWarning.y = 2732 / 2; game.addChild(bossWarning); // Flash screen red LK.effects.flashScreen(0xFF0000, 1000); // Animate warning text tween(bossWarning, { alpha: 0, scaleX: 1.5, scaleY: 1.5 }, { duration: 2000, easing: tween.easeOut, onFinish: function onFinish() { game.removeChild(bossWarning); } }); } // Use anti-tank grenade when attacking with grenade collected if (hasGrenade && goose.isAttacking && panzerBoss && !panzerBoss.isDestroyed && goose.intersects(panzerBoss)) { hasGrenade = false; // Remove grenade indicator if (goose.children.length > 0) { goose.removeChild(goose.children[goose.children.length - 1]); } // Damage panzer boss with grenade (2 damage) panzerBoss.takeDamage(); panzerBoss.takeDamage(); // Create explosion effect at panzer var explosion = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, x: panzerBoss.x, y: panzerBoss.y, scaleX: 0.1, scaleY: 0.1 }); explosion.tint = 0xFF4500; // Orange explosion game.addChild(explosion); // Explosion animation tween(explosion, { scaleX: 6, scaleY: 6, alpha: 0 }, { duration: 600, easing: tween.easeOut, onFinish: function onFinish() { game.removeChild(explosion); } }); // Flash screen orange LK.effects.flashScreen(0xFF4500, 800); // Reset grenade variables antiTankGrenade = null; grenadeSpawnTimer = 0; } // Update panzer boss if (panzerBoss && !panzerBoss.isDestroyed) { panzerBoss.update(); // Check for special weapon hits on panzer boss if (hasFlashbang && goose.isAttacking && goose.intersects(panzerBoss)) { hasFlashbang = false; // Remove flashbang indicator if (goose.children.length > 0) { goose.removeChild(goose.children[goose.children.length - 1]); } // Create explosion at panzer var explosion = new EurovisionFlashbang(); explosion.x = panzerBoss.x; explosion.y = panzerBoss.y; game.addChild(explosion); explosion.explode(); // Damage panzer boss panzerBoss.takeDamage(); // Flash screen with eurovision colors LK.effects.flashScreen(0xFFD700, 800); } if (hasBomb && goose.isAttacking && goose.intersects(panzerBoss)) { hasBomb = false; // Remove bomb indicator if (goose.children.length > 0) { goose.removeChild(goose.children[goose.children.length - 1]); } // Create explosion at panzer var explosion = new AtomicBomb(); explosion.x = panzerBoss.x; explosion.y = panzerBoss.y; game.addChild(explosion); explosion.explode(); // Damage panzer boss panzerBoss.takeDamage(); // Flash screen blue LK.effects.flashScreen(0x0066ff, 800); } } // Update panzer shells for (var i = panzerShells.length - 1; i >= 0; i--) { var shell = panzerShells[i]; shell.update(); // Check shell collision with goose if (!shell.isExploded && goose.intersects(shell)) { shell.explode(); // Damage goose LK.getSound('hit').play(); gooseHealth--; updateHealthDisplay(); // Damage animation var damageEffect = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, x: goose.x, y: goose.y, scaleX: 2, scaleY: 2, alpha: 0.5 }); damageEffect.tint = 0xFF0000; game.addChild(damageEffect); tween(damageEffect, { alpha: 0, scaleX: 3, scaleY: 3 }, { duration: 500, easing: tween.easeOut, onFinish: function onFinish() { game.removeChild(damageEffect); } }); // Game over if health reaches zero if (gooseHealth <= 0) { if (LK.getScore() > highScore) { highScore = LK.getScore(); storage.highScore = highScore; highScoreTxt.setText("Rekord: " + highScore); } LK.effects.flashScreen(0xff0000, 1000); gameActive = false; LK.showGameOver(); } // Remove shell from array panzerShells.splice(i, 1); } else if (shell.isExploded && !shell.visible) { // Remove exploded shells panzerShells.splice(i, 1); game.removeChild(shell); } } // Pretzel spawn logic pretzelSpawnTimer++; if (pretzelSpawnTimer > 450 && pretzels.length < maxPretzels && Math.random() < 0.01) { var pretzel = new Pretzel(); // Position pretzel around pond edges (German food should be accessible) var angle = Math.random() * Math.PI * 2; var distance = Math.random() * 400 + 300; // Between inner and outer pond pretzel.x = pond.x + Math.cos(angle) * distance; pretzel.y = pond.y + Math.sin(angle) * distance; // Ensure within pond boundaries var dx = pretzel.x - pond.x; var dy = pretzel.y - pond.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 800) { pretzel.x = pond.x + dx / dist * 800; pretzel.y = pond.y + dy / dist * 800; } pretzels.push(pretzel); game.addChild(pretzel); pretzelSpawnTimer = 0; } // Update pretzels and check for collection for (var i = pretzels.length - 1; i >= 0; i--) { var pretzel = pretzels[i]; pretzel.update(); // Check for goose collecting pretzel if (!pretzel.isCollected && goose.intersects(pretzel)) { if (pretzel.collect()) { // Add score bonus LK.setScore(LK.getScore() + pretzel.scoreValue); scoreTxt.setText("Punkte: " + LK.getScore()); // Show bonus points popup var bonusTxt = new Text2("+" + pretzel.scoreValue + " Brezel!", { size: 70, fill: 0xFFD700 }); bonusTxt.anchor.set(0.5, 0.5); bonusTxt.x = pretzel.x; bonusTxt.y = pretzel.y - 100; game.addChild(bonusTxt); // Animate bonus text tween(bonusTxt, { y: bonusTxt.y - 100, alpha: 0 }, { duration: 1500, easing: tween.easeOut, onFinish: function onFinish() { game.removeChild(bonusTxt); } }); // Play eat sound LK.getSound('eat').play(); // Remove from array pretzels.splice(i, 1); } } // Remove pretzels that are no longer visible else if (!pretzel.visible) { pretzels.splice(i, 1); game.removeChild(pretzel); } } // Check for win condition: collect 75 chips if (LK.getScore() >= 75) { // Update high score if (LK.getScore() > highScore) { highScore = LK.getScore(); storage.highScore = highScore; highScoreTxt.setText("Rekord: " + highScore); } // End the game with a win gameActive = false; LK.showYouWin(); } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var AntiTankGrenade = Container.expand(function () {
var self = Container.call(this);
// Create grenade body (dark grey)
var grenadeBody = self.attachAsset('antiTankGrenade', {
anchorX: 0.5,
anchorY: 0.5
});
grenadeBody.tint = 0x4A4A4A; // Dark grey
// Add pin indicator (small red circle)
var pin = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.15,
scaleY: 0.15,
x: 15,
y: -25
});
pin.tint = 0xFF0000; // Red pin
self.addChild(pin);
// Add explosive marking (yellow stripe)
var marking = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.2,
y: 5
});
marking.tint = 0xFFFF00; // Yellow marking
self.addChild(marking);
self.isCollected = false;
self.timeLeft = 480; // 8 seconds at 60fps
// Grenade collection
self.collect = function () {
if (!self.isCollected) {
self.isCollected = true;
// Collection animation
tween(self, {
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
}, {
duration: 300,
onFinish: function onFinish() {
self.visible = false;
}
});
return true;
}
return false;
};
// Update function to handle grenade lifetime
self.update = function () {
self.timeLeft--;
// Pulse when about to disappear
if (self.timeLeft < 120) {
self.alpha = 0.5 + Math.sin(self.timeLeft * 0.1) * 0.5;
}
if (self.timeLeft <= 0 && !self.isCollected) {
self.collect();
}
};
return self;
});
var AtomicBomb = Container.expand(function () {
var self = Container.call(this);
// Create bomb body (blue sphere with electric glow)
var bombBody = self.attachAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8
});
bombBody.tint = 0x0066ff; // Electric blue color
// Add energy core (bright white)
var energyCore = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.4,
scaleY: 0.4
});
energyCore.tint = 0xffffff;
self.addChild(energyCore);
// Add outer energy ring (cyan)
var outerRing = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2
});
outerRing.tint = 0x00ffff;
outerRing.alpha = 0.5;
self.addChild(outerRing);
self.explosionRadius = 500;
self.isExploding = false;
self.isCollected = false;
self.freezeOnUse = true; // New property - bomb freezes enemies rather than pushing them
// Bomb collection
self.collect = function () {
if (!self.isCollected) {
self.isCollected = true;
return true;
}
return false;
};
// Explosion effect
self.explode = function () {
if (!self.isExploding) {
self.isExploding = true;
// Create explosion animation - now a freezing blast
tween(self, {
scaleX: 10,
scaleY: 10,
alpha: 0.8
}, {
duration: 700,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
alpha: 0
}, {
duration: 500,
onFinish: function onFinish() {
self.visible = false;
}
});
}
});
return true;
}
return false;
};
// Electric pulse animation for idle bomb
function startElectricAnimation() {
// Outer ring pulsing
function pulseOuterRing() {
tween(outerRing, {
alpha: 0.2,
scaleX: 1.4,
scaleY: 1.4
}, {
duration: 700,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(outerRing, {
alpha: 0.5,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 700,
easing: tween.easeInOut,
onFinish: pulseOuterRing
});
}
});
}
// Core pulsing
tween(energyCore, {
scaleX: 0.5,
scaleY: 0.5,
alpha: 0.9
}, {
duration: 600,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(energyCore, {
scaleX: 0.4,
scaleY: 0.4,
alpha: 1
}, {
duration: 600,
easing: tween.easeInOut,
onFinish: startElectricAnimation
});
}
});
// Start the outer ring animation too
pulseOuterRing();
}
// Start electric pulsing
startElectricAnimation();
return self;
});
var Bread = Container.expand(function () {
var self = Container.call(this);
// Create bread visual
var breadBody = self.attachAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.5,
scaleY: 0.3
});
breadBody.tint = 0xE8B96F; // Brown bread color
// Create crust detail
var crust = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.52,
scaleY: 0.32
});
crust.tint = 0xC68642; // Darker crust color
self.addChild(crust);
self.isConsumed = false;
self.timeLeft = 360; // 6 seconds at 60fps
self.sinkingSpeed = 0.5;
self.inWater = false;
// Bread consumption
self.consume = function () {
if (!self.isConsumed) {
self.isConsumed = true;
// Consumption animation
tween(self, {
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
}, {
duration: 300,
onFinish: function onFinish() {
self.visible = false;
}
});
return true;
}
return false;
};
// Start sinking animation when bread hits water
self.startSinking = function () {
if (!self.inWater) {
self.inWater = true;
// Make bread rotate slowly while sinking
tween(self, {
rotation: Math.PI * 0.5 * (Math.random() > 0.5 ? 1 : -1)
}, {
duration: 3000,
easing: tween.easeInOut
});
}
};
// Update function
self.update = function () {
self.timeLeft--;
// Sink when in water
if (self.inWater) {
self.y += self.sinkingSpeed;
// Fade out as it sinks
if (self.timeLeft < 180) {
self.alpha = Math.max(0, self.timeLeft / 180);
}
}
// Pulse when about to disappear
if (self.timeLeft < 60 && !self.inWater) {
self.alpha = 0.5 + Math.sin(self.timeLeft * 0.2) * 0.5;
}
// Despawn when time runs out
if (self.timeLeft <= 0 && !self.isConsumed) {
self.consume();
}
};
return self;
});
var Chip = Container.expand(function () {
var self = Container.call(this);
var chipGraphic = self.attachAsset('chip', {
anchorX: 0.5,
anchorY: 0.5
});
self.isCollected = false;
self.collect = function () {
if (!self.isCollected) {
self.isCollected = true;
LK.getSound('eat').play();
tween(self, {
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
}, {
duration: 300,
onFinish: function onFinish() {
self.visible = false;
}
});
return true;
}
return false;
};
return self;
});
var Chocolate = Container.expand(function () {
var self = Container.call(this);
// Create chocolate graphic (brown rectangle)
var chocolateBody = self.attachAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.7,
scaleY: 0.5
});
// Set chocolate color to brown
chocolateBody.tint = 0x4B2E20;
// Add inner layer for chocolate texture
var innerLayer = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.5,
scaleY: 0.3
});
innerLayer.tint = 0x663C28;
self.addChild(innerLayer);
self.isConsumed = false;
self.timeLeft = 300; // 5 seconds at 60fps
// Swan consumes chocolate
self.consume = function () {
if (!self.isConsumed) {
self.isConsumed = true;
// Consumption animation
tween(self, {
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
}, {
duration: 300,
onFinish: function onFinish() {
self.visible = false;
}
});
return true;
}
return false;
};
self.update = function () {
self.timeLeft--;
// Pulse when about to disappear
if (self.timeLeft < 60) {
self.alpha = 0.5 + Math.sin(self.timeLeft * 0.2) * 0.5;
}
if (self.timeLeft <= 0 && !self.isConsumed) {
self.consume();
}
};
return self;
});
var Cookie = Container.expand(function () {
var self = Container.call(this);
this.init = function () {
var cookieBody = self.attachAsset('cookieShape', {
anchorX: 0.5,
anchorY: 0.5
});
// Add some chocolate chips for decoration
for (var i = 0; i < 5; i++) {
var chip = LK.getAsset('cookieChipShape', {
anchorX: 0.5,
anchorY: 0.5,
x: (Math.random() - 0.5) * (cookieBody.width * 0.4),
// position chips within cookie
y: (Math.random() - 0.5) * (cookieBody.height * 0.4)
});
self.addChild(chip);
}
self.isCollected = false;
self.timeLeft = 480; // 8 seconds at 60fps to despawn if not collected
};
self.collect = function () {
if (!self.isCollected) {
self.isCollected = true;
tween(self, {
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
}, {
duration: 300,
onFinish: function onFinish() {
self.visible = false;
}
});
return true;
}
return false;
};
self.update = function () {
if (self.isCollected || !self.visible) return;
self.timeLeft--;
if (self.timeLeft < 60 && self.timeLeft > 0) {
// Pulsate before disappearing
self.alpha = 0.5 + Math.sin(self.timeLeft * 0.2) * 0.5;
} else if (self.timeLeft <= 0) {
self.visible = false; // Mark for removal
if (self.parent) {
self.parent.removeChild(self);
}
}
};
this.init();
return self;
});
var Country = Container.expand(function () {
var self = Container.call(this);
// Create country portal visual (rainbow-colored circle)
var portalBody = self.attachAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2
});
portalBody.tint = 0x00AAFF; // Blue base color
// Add interior of portal
var portalInterior = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.9,
scaleY: 0.9
});
portalInterior.tint = 0xFFFFFF;
self.addChild(portalInterior);
// Country name label
self.nameText = new Text2('', {
size: 40,
fill: 0xFFFFFF
});
self.nameText.anchor.set(0.5, 0.5);
self.nameText.y = -80;
self.addChild(self.nameText);
// Properties
self.countryName = "";
self.countryColor = 0x00AAFF;
self.isActive = false;
self.isVisited = false;
self.travelCooldown = 0;
self.visitBonus = 10; // Score bonus for first visit
// Set country information
self.setCountry = function (name, color) {
self.countryName = name;
self.countryColor = color;
self.nameText.setText(name);
portalBody.tint = color;
// Return for method chaining
return self;
};
// Activate the portal
self.activate = function () {
if (!self.isActive) {
self.isActive = true;
// Start portal animation
startPortalAnimation();
// Make visible with fade-in
self.alpha = 0;
tween(self, {
alpha: 1
}, {
duration: 800,
easing: tween.easeOut
});
}
};
// Travel effect when goose enters the portal
self.travel = function () {
if (self.travelCooldown <= 0) {
self.travelCooldown = 180; // 3 second cooldown
// Create travel animation - portal expands
tween(self, {
scaleX: 3,
scaleY: 3,
alpha: 0.8
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 1,
scaleY: 1,
alpha: 1
}, {
duration: 500,
easing: tween.easeOut
});
}
});
// First time visit bonus
var scoreBonus = self.isVisited ? 5 : self.visitBonus;
self.isVisited = true;
return {
success: true,
countryName: self.countryName,
scoreBonus: scoreBonus
};
}
return {
success: false
};
};
// Portal animation
function startPortalAnimation() {
// Rotating animation
function spin() {
tween(portalInterior, {
rotation: portalInterior.rotation + Math.PI * 2
}, {
duration: 5000,
onFinish: spin
});
}
// Pulsing animation
function pulse() {
tween(portalBody, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 1500,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(portalBody, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 1500,
easing: tween.easeInOut,
onFinish: pulse
});
}
});
}
// Start both animations
spin();
pulse();
}
self.update = function () {
if (self.travelCooldown > 0) {
self.travelCooldown--;
}
};
return self;
});
var Dachshund = Container.expand(function () {
var self = Container.call(this);
// Create dachshund body (long brown sausage dog)
var body = self.attachAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 0.5
});
body.tint = 0x8B4513; // Brown color
// Create head
var head = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.4,
scaleY: 0.4,
x: 50,
y: 0
});
head.tint = 0x654321; // Darker brown
self.addChild(head);
// Create snout
var snout = LK.getAsset('centerCircle', {
anchorX: 0,
anchorY: 0.5,
scaleX: 0.3,
scaleY: 0.2,
x: 65,
y: 0
});
snout.tint = 0x4B2E20; // Even darker brown
self.addChild(snout);
// Create tail
var tail = LK.getAsset('centerCircle', {
anchorX: 1,
anchorY: 0.5,
scaleX: 0.4,
scaleY: 0.15,
x: -55,
y: -5,
rotation: -0.3
});
tail.tint = 0x8B4513;
self.addChild(tail);
// Create legs (4 stubby legs)
for (var i = 0; i < 4; i++) {
var leg = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0,
scaleX: 0.1,
scaleY: 0.3,
x: -30 + i * 25,
y: 25
});
leg.tint = 0x654321;
self.addChild(leg);
self['leg' + i] = leg; // Store reference for animation
}
// Properties
self.speed = 2.5;
self.targetX = 0;
self.targetY = 0;
self.state = 'hunting'; // Always hunting
self.target = null; // Current chase target
self.barkCooldown = 0;
self.biteCooldown = 0;
// Set target position
self.setTarget = function (x, y) {
self.targetX = x;
self.targetY = y;
};
// Bark at target
self.bark = function () {
if (self.barkCooldown <= 0) {
self.barkCooldown = 90; // 1.5 second cooldown
// Bark animation
tween(head, {
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(head, {
scaleX: 0.4,
scaleY: 0.4
}, {
duration: 150,
easing: tween.easeInOut
});
}
});
// Play sound (use existing honk sound)
LK.getSound('honk').play();
return true;
}
return false;
};
// Bite attack
self.bite = function () {
if (self.biteCooldown <= 0) {
self.biteCooldown = 60; // 1 second cooldown
// Bite animation
tween(snout, {
x: 75,
scaleX: 0.4
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(snout, {
x: 65,
scaleX: 0.3
}, {
duration: 200,
easing: tween.easeInOut
});
}
});
return true;
}
return false;
};
// Tail wagging animation
function wagTail() {
tween(tail, {
rotation: 0.3
}, {
duration: 300,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(tail, {
rotation: -0.3
}, {
duration: 300,
easing: tween.easeInOut,
onFinish: wagTail
});
}
});
}
wagTail();
self.update = function () {
// Update cooldowns
if (self.barkCooldown > 0) {
self.barkCooldown--;
}
if (self.biteCooldown > 0) {
self.biteCooldown--;
}
// Move toward target
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 10) {
self.x += dx / dist * self.speed;
self.y += dy / dist * self.speed;
// Face movement direction
if (dx < 0) {
self.scale.x = -1;
} else {
self.scale.x = 1;
}
// Running animation (stubby legs moving)
for (var i = 0; i < 4; i++) {
self['leg' + i].y = 25 + Math.sin(LK.ticks * 0.3 + i * Math.PI * 0.5) * 3;
}
}
};
return self;
});
var Drowning = Container.expand(function () {
var self = Container.call(this);
// Create water bubbles effect
var bubbles = [];
var bubbleCount = 8;
for (var i = 0; i < bubbleCount; i++) {
var bubble = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.2 + Math.random() * 0.2,
scaleY: 0.2 + Math.random() * 0.2,
x: (Math.random() - 0.5) * 100,
y: (Math.random() - 0.5) * 100
});
bubble.tint = 0x88CCFF; // Light blue for water bubbles
bubble.alpha = 0.7;
bubble.speedY = -1 - Math.random() * 2;
bubble.speedX = (Math.random() - 0.5) * 1;
self.addChild(bubble);
bubbles.push(bubble);
}
self.isActive = false;
self.duration = 180; // 3 seconds at 60fps
self.timer = 0;
self.warningLevel = 0;
self.activate = function () {
if (!self.isActive) {
self.isActive = true;
self.timer = 0;
self.warningLevel = 0;
self.alpha = 1;
// Start bubble animation
for (var i = 0; i < bubbles.length; i++) {
animateBubble(bubbles[i]);
}
}
};
self.deactivate = function () {
if (self.isActive) {
self.isActive = false;
self.timer = 0;
self.warningLevel = 0;
// Fade out
tween(self, {
alpha: 0
}, {
duration: 300,
easing: tween.easeOut
});
}
};
function animateBubble(bubble) {
// Random position around character
bubble.x = (Math.random() - 0.5) * 100;
bubble.y = (Math.random() - 0.5) * 100 + 50;
bubble.alpha = 0;
bubble.scale.x = bubble.scale.y = 0.1 + Math.random() * 0.2;
// Animate bubble rising
tween(bubble, {
y: bubble.y - 100 - Math.random() * 50,
alpha: 0.7,
scaleX: bubble.scale.x * 1.5,
scaleY: bubble.scale.y * 1.5
}, {
duration: 1000 + Math.random() * 500,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(bubble, {
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
if (self.isActive) {
animateBubble(bubble);
}
}
});
}
});
}
self.update = function () {
if (!self.isActive) return;
self.timer++;
// Update warning level
var newWarningLevel = Math.min(3, Math.floor(self.timer / 60));
// Warning level changed - trigger visual feedback
if (newWarningLevel > self.warningLevel) {
self.warningLevel = newWarningLevel;
// Pulse effect based on warning level
tween(self, {
alpha: 0.4
}, {
duration: 200,
onFinish: function onFinish() {
tween(self, {
alpha: 1
}, {
duration: 200
});
}
});
}
// Check if drowning is complete
if (self.timer >= self.duration) {
return true; // Return true to signal drowning is complete
}
return false; // Not yet drowned
};
return self;
});
var EurovisionFlashbang = Container.expand(function () {
var self = Container.call(this);
// Create flashbang body (silver/white circle)
var flashbangBody = self.attachAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8
});
flashbangBody.tint = 0xE5E4E2; // Silver color
// Add eurovision star symbol
var starSymbol = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.5,
scaleY: 0.5
});
starSymbol.tint = 0xFFD700; // Gold color
self.addChild(starSymbol);
self.isCollected = false;
self.isExploding = false;
// Rainbow effect colors
self.rainbowColors = [0xFF0000,
// Red
0xFF7F00,
// Orange
0xFFFF00,
// Yellow
0x00FF00,
// Green
0x0000FF,
// Blue
0x4B0082,
// Indigo
0x9400D3 // Violet
];
// Flashbang collection
self.collect = function () {
if (!self.isCollected) {
self.isCollected = true;
return true;
}
return false;
};
// Explosion effect
self.explode = function () {
if (!self.isExploding) {
self.isExploding = true;
// Create explosion animation
tween(self, {
scaleX: 15,
scaleY: 15,
alpha: 0.9
}, {
duration: 700,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
alpha: 0
}, {
duration: 500,
onFinish: function onFinish() {
self.visible = false;
}
});
}
});
return true;
}
return false;
};
// Rainbow pulse animation
function startRainbowAnimation() {
var colorIndex = 0;
function cycleColors() {
flashbangBody.tint = self.rainbowColors[colorIndex];
colorIndex = (colorIndex + 1) % self.rainbowColors.length;
tween(self, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 400,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 400,
easing: tween.easeInOut,
onFinish: cycleColors
});
}
});
}
cycleColors();
}
// Start pulsing
startRainbowAnimation();
return self;
});
var Goose = Container.expand(function () {
var self = Container.call(this);
// Body
var body = self.attachAsset('goose', {
anchorX: 0.5,
anchorY: 0.5
});
self.lastIsSwimming = false;
// Wings
var leftWing = LK.getAsset('gooseWing', {
anchorX: 0,
anchorY: 0.5,
x: -80,
y: 0,
rotation: -0.3
});
var rightWing = LK.getAsset('gooseWing', {
anchorX: 1,
anchorY: 0.5,
x: 80,
y: 0,
rotation: 0.3
});
// Beak
var beak = LK.getAsset('gooseBeak', {
anchorX: 0,
anchorY: 0.5,
x: 80,
y: 0
});
self.addChild(leftWing);
self.addChild(rightWing);
self.addChild(beak);
self.speed = 7;
self.attackCooldown = 0;
self.isAttacking = false;
self.stunned = 0;
self.attack = function () {
if (self.attackCooldown <= 0 && !self.isAttacking && self.stunned <= 0) {
self.isAttacking = true;
LK.getSound('honk').play();
// Wing attack animation
tween(leftWing, {
rotation: -0.8,
x: -100
}, {
duration: 200,
easing: tween.easeOut
});
tween(rightWing, {
rotation: 0.8,
x: 100
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
// Return wings to normal
tween(leftWing, {
rotation: -0.3,
x: -80
}, {
duration: 300,
easing: tween.easeInOut
});
tween(rightWing, {
rotation: 0.3,
x: 80
}, {
duration: 300,
easing: tween.easeInOut,
onFinish: function onFinish() {
self.isAttacking = false;
}
});
self.attackCooldown = 60; // 1 second cooldown (60 frames)
}
});
return true;
}
return false;
};
self.stun = function (duration) {
self.stunned = duration;
// Stun animation
tween(self, {
alpha: 0.6
}, {
duration: 100,
onFinish: function onFinish() {
tween(self, {
alpha: 1
}, {
duration: 100
});
}
});
};
self.update = function () {
if (self.attackCooldown > 0) {
self.attackCooldown--;
}
if (self.stunned > 0) {
self.stunned--;
}
};
return self;
});
var Human = Container.expand(function () {
var self = Container.call(this);
// Create human body
var body = self.attachAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.9,
scaleY: 1.5
});
body.tint = 0xFFD2B7; // Skin tone
// Add clothes
var clothes = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.0,
scaleY: 1.0,
y: 20
});
clothes.tint = Math.random() > 0.5 ? 0x3498DB : 0xE74C3C; // Random blue or red
self.addChild(clothes);
// Add head
var head = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.6,
scaleY: 0.6,
y: -50
});
head.tint = 0xFFD2B7; // Same skin tone as body
self.addChild(head);
// Properties
self.speed = 1 + Math.random() * 1.5;
self.targetX = 0;
self.targetY = 0;
self.breadCount = 0;
self.maxBread = 3;
self.lastBreadThrow = 0;
self.breadCooldown = 120 + Math.floor(Math.random() * 240); // 2-6 second cooldown
self.isAngry = false;
// Set target position
self.setTarget = function (x, y) {
self.targetX = x;
self.targetY = y;
};
// Make human throw bread
self.throwBread = function (pondX, pondY) {
if (self.breadCount > 0 && self.lastBreadThrow <= 0) {
self.breadCount--;
self.lastBreadThrow = self.breadCooldown;
// Calculate throw position (toward pond center)
var dx = pondX - self.x;
var dy = pondY - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
var throwDist = Math.min(dist * 0.7, 300);
return {
x: self.x + dx / dist * throwDist,
y: self.y + dy / dist * throwDist
};
}
return null;
};
// Make human angry at goose
self.becomeAngry = function () {
if (!self.isAngry) {
self.isAngry = true;
body.tint = 0xFFB2B7; // Slightly redder skin tone when angry
// Angry animation
tween(self, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 300,
easing: tween.easeOut
});
}
});
return true;
}
return false;
};
// Make human happy (feed birds)
self.refillBread = function () {
self.breadCount = self.maxBread;
// Happy animation
tween(head, {
y: -60
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(head, {
y: -50
}, {
duration: 300,
easing: tween.easeInOut
});
}
});
};
// Update function
self.update = function () {
if (self.lastBreadThrow > 0) {
self.lastBreadThrow--;
}
// Move toward target
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 10) {
self.x += dx / dist * self.speed;
self.y += dy / dist * self.speed;
// Flip based on movement direction
if (dx < 0) {
self.scale.x = -1;
} else {
self.scale.x = 1;
}
}
// Calm down after some time
if (self.isAngry && Math.random() < 0.001) {
self.isAngry = false;
body.tint = 0xFFD2B7; // Normal skin tone
}
};
return self;
});
var Painkiller = Container.expand(function () {
var self = Container.call(this);
// Create painkiller item (white pill with red cross)
var pillBody = self.attachAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.7,
scaleY: 0.4
});
pillBody.tint = 0xFFFFFF; // White pill
// Add red cross to indicate healing
var redCross = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.4,
scaleY: 0.1
});
redCross.tint = 0xFF0000; // Red
self.addChild(redCross);
// Add vertical line of cross
var redCrossVert = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.1,
scaleY: 0.4
});
redCrossVert.tint = 0xFF0000; // Red
self.addChild(redCrossVert);
self.isCollected = false;
self.timeLeft = 360; // 6 seconds at 60fps
// Painkiller collection
self.collect = function () {
if (!self.isCollected) {
self.isCollected = true;
// Collection animation
tween(self, {
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
}, {
duration: 300,
onFinish: function onFinish() {
self.visible = false;
}
});
return true;
}
return false;
};
// Update function to handle pill lifetime
self.update = function () {
self.timeLeft--;
// Pulse when about to disappear
if (self.timeLeft < 60) {
self.alpha = 0.5 + Math.sin(self.timeLeft * 0.2) * 0.5;
}
if (self.timeLeft <= 0 && !self.isCollected) {
self.collect();
}
};
return self;
});
var PanzerBoss = Container.expand(function () {
var self = Container.call(this);
// Create tank body (main hull)
var tankBody = self.attachAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.0,
scaleY: 1.2
});
tankBody.tint = 0x2F4F2F; // Dark olive green
// Create tank turret
var turret = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2
});
turret.tint = 0x556B2F; // Olive drab
self.addChild(turret);
// Create tank barrel (cannon)
var barrel = LK.getAsset('centerCircle', {
anchorX: 0,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 0.3,
x: 60
});
barrel.tint = 0x2F4F2F; // Dark olive green
turret.addChild(barrel);
// Add German cross marking
var cross1 = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.6,
scaleY: 0.1
});
cross1.tint = 0x000000; // Black cross
turret.addChild(cross1);
var cross2 = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.1,
scaleY: 0.6
});
cross2.tint = 0x000000; // Black cross
turret.addChild(cross2);
self.health = 2; // Takes 2 hits to destroy
self.shootCooldown = 0;
self.shootInterval = 120; // Shoot every 2 seconds
self.isDestroyed = false;
self.targetX = 0;
self.targetY = 0;
self.speed = 1.5;
// Set target for movement
self.setTarget = function (x, y) {
self.targetX = x;
self.targetY = y;
};
// Shoot shell at target
self.shoot = function (targetX, targetY) {
if (self.shootCooldown <= 0 && !self.isDestroyed) {
self.shootCooldown = self.shootInterval;
// Create shell
var shell = new PanzerShell();
shell.x = self.x + Math.cos(turret.rotation) * 80;
shell.y = self.y + Math.sin(turret.rotation) * 80;
shell.setTarget(targetX, targetY);
panzerShells.push(shell);
game.addChild(shell);
// Play shoot sound
LK.getSound('tankShoot').play();
// Barrel recoil animation
tween(barrel, {
x: 40
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(barrel, {
x: 60
}, {
duration: 200,
easing: tween.easeInOut
});
}
});
return true;
}
return false;
};
// Take damage from special weapons
self.takeDamage = function () {
if (!self.isDestroyed) {
self.health--;
// Play tank damage sound
LK.getSound('tankDestroy').play();
// Damage effect
tween(self, {
alpha: 0.5
}, {
duration: 100,
onFinish: function onFinish() {
tween(self, {
alpha: 1
}, {
duration: 100
});
}
});
if (self.health <= 0) {
self.destroy();
}
return true;
}
return false;
};
// Destroy tank
self.destroy = function () {
if (!self.isDestroyed) {
self.isDestroyed = true;
// Play destroy sound
LK.getSound('tankDestroy').play();
// Destruction animation
tween(self, {
alpha: 0,
scaleX: 2.5,
scaleY: 2.5,
rotation: Math.PI * 0.5
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
self.visible = false;
}
});
// Award points for destroying tank
LK.setScore(LK.getScore() + 15);
scoreTxt.setText("Punkte: " + LK.getScore());
// Show bonus points
var bonusTxt = new Text2("+15 Panzer Zerstört!", {
size: 70,
fill: 0xFFD700
});
bonusTxt.anchor.set(0.5, 0.5);
bonusTxt.x = self.x;
bonusTxt.y = self.y - 100;
game.addChild(bonusTxt);
// Animate bonus text
tween(bonusTxt, {
y: bonusTxt.y - 100,
alpha: 0
}, {
duration: 1500,
easing: tween.easeOut,
onFinish: function onFinish() {
game.removeChild(bonusTxt);
}
});
return true;
}
return false;
};
self.update = function () {
if (self.isDestroyed) return;
// Check if panzer is near any offensive collectibles and flee immediately
var fleeRadius = 300; // Distance to detect and flee from threats
var shouldFlee = false;
var fleeAngle = 0;
// Check Eurovision flashbang threat (both when it's on the ground and when goose has it)
if (eurovisionFlashbang && !hasFlashbang) {
var dx = self.x - eurovisionFlashbang.x;
var dy = self.y - eurovisionFlashbang.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < fleeRadius) {
shouldFlee = true;
fleeAngle = Math.atan2(dy, dx); // Flee away from flashbang
}
}
// Check if goose has flashbang and flee from goose
if (hasFlashbang) {
var dx = self.x - goose.x;
var dy = self.y - goose.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < fleeRadius) {
shouldFlee = true;
fleeAngle = Math.atan2(dy, dx); // Flee away from goose with flashbang
}
}
// Check atomic bomb threat (both when it's on the ground and when goose has it)
if (atomicBomb && !hasBomb) {
var dx = self.x - atomicBomb.x;
var dy = self.y - atomicBomb.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < fleeRadius) {
shouldFlee = true;
fleeAngle = Math.atan2(dy, dx); // Flee away from bomb
}
}
// Check if goose has atomic bomb and flee from goose
if (hasBomb) {
var dx = self.x - goose.x;
var dy = self.y - goose.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < fleeRadius) {
shouldFlee = true;
fleeAngle = Math.atan2(dy, dx); // Flee away from goose with bomb
}
}
// If should flee, move away from threat at high speed
if (shouldFlee) {
var fleeSpeed = self.speed * 3; // Triple speed when fleeing
var fleeDistance = 800; // Flee far away
self.setTarget(self.x + Math.cos(fleeAngle) * fleeDistance, self.y + Math.sin(fleeAngle) * fleeDistance);
// Move immediately toward flee target
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 0) {
self.x += dx / dist * fleeSpeed;
self.y += dy / dist * fleeSpeed;
}
return; // Skip normal behavior when fleeing
}
// Update cooldowns
if (self.shootCooldown > 0) {
self.shootCooldown--;
}
// Move toward target
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 50) {
self.x += dx / dist * self.speed;
self.y += dy / dist * self.speed;
}
// Rotate turret to face goose
var angleToGoose = Math.atan2(goose.y - self.y, goose.x - self.x);
turret.rotation = angleToGoose;
// Shoot at goose periodically
if (self.shootCooldown <= 0 && Math.random() < 0.02) {
// Predict goose position slightly for better accuracy
var predictedX = goose.x + (goose.x - goose.lastX || 0) * 5;
var predictedY = goose.y + (goose.y - goose.lastY || 0) * 5;
self.shoot(predictedX, predictedY);
}
};
return self;
});
var PanzerShell = Container.expand(function () {
var self = Container.call(this);
// Create shell body (dark metallic projectile)
var shellBody = self.attachAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.4,
scaleY: 0.6
});
shellBody.tint = 0x444444; // Dark grey metallic
// Add explosive tip (orange)
var tip = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.2,
scaleY: 0.3,
y: -15
});
tip.tint = 0xFF4500; // Orange explosive tip
self.addChild(tip);
self.speed = 8;
self.targetX = 0;
self.targetY = 0;
self.isExploded = false;
// Set target for shell trajectory
self.setTarget = function (x, y) {
self.targetX = x;
self.targetY = y;
// Calculate direction
var dx = x - self.x;
var dy = y - self.y;
var angle = Math.atan2(dy, dx);
self.rotation = angle;
};
// Explode shell on impact
self.explode = function () {
if (!self.isExploded) {
self.isExploded = true;
// Create explosion effect
var explosion = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
x: self.x,
y: self.y,
scaleX: 0.1,
scaleY: 0.1
});
explosion.tint = 0xFF4500; // Orange explosion
game.addChild(explosion);
// Explosion animation
tween(explosion, {
scaleX: 4,
scaleY: 4,
alpha: 0
}, {
duration: 600,
easing: tween.easeOut,
onFinish: function onFinish() {
game.removeChild(explosion);
}
});
// Hide shell
self.visible = false;
return true;
}
return false;
};
self.update = function () {
if (self.isExploded) return;
// Move toward target
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 10) {
self.x += dx / dist * self.speed;
self.y += dy / dist * self.speed;
} else {
// Reached target, explode
self.explode();
}
// Check if shell went off screen
if (self.x < -100 || self.x > 2148 || self.y < -100 || self.y > 2832) {
self.explode();
}
};
return self;
});
var Pond = Container.expand(function () {
var self = Container.call(this);
var pondGraphic = self.attachAsset('pond', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
var Pretzel = Container.expand(function () {
var self = Container.call(this);
// Create main pretzel body (brown)
var pretzelBody = self.attachAsset('pretzelShape', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.9,
scaleY: 0.9
});
pretzelBody.tint = 0x8B4513; // Saddle brown
// Add salt crystals (white spots)
for (var i = 0; i < 8; i++) {
var salt = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.08,
scaleY: 0.08,
x: (Math.random() - 0.5) * 60,
y: (Math.random() - 0.5) * 60
});
salt.tint = 0xFFFFFF; // White salt
self.addChild(salt);
}
self.isCollected = false;
self.timeLeft = 600; // 10 seconds at 60fps
self.scoreValue = 5; // Higher value than regular chips
// Pretzel collection
self.collect = function () {
if (!self.isCollected) {
self.isCollected = true;
// Collection animation
tween(self, {
alpha: 0,
scaleX: 0.1,
scaleY: 0.1,
rotation: Math.PI * 2
}, {
duration: 400,
easing: tween.easeOut,
onFinish: function onFinish() {
self.visible = false;
}
});
return true;
}
return false;
};
// Update function to handle pretzel lifetime
self.update = function () {
self.timeLeft--;
// Gentle rotation animation
self.rotation += 0.02;
// Pulse when about to disappear
if (self.timeLeft < 120) {
self.alpha = 0.5 + Math.sin(self.timeLeft * 0.15) * 0.5;
}
if (self.timeLeft <= 0 && !self.isCollected) {
self.collect();
}
};
return self;
});
var Storch = Container.expand(function () {
var self = Container.call(this);
// Create stork body (white)
var body = self.attachAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 1.2
});
body.tint = 0xFFFFFF; // White body
// Create stork neck
var neck = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 1,
scaleX: 0.3,
scaleY: 0.8,
y: -60
});
neck.tint = 0xFFFFFF;
self.addChild(neck);
// Create stork head
var head = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.4,
scaleY: 0.4,
y: -100
});
head.tint = 0xFFFFFF;
self.addChild(head);
// Create orange beak
var beak = LK.getAsset('centerCircle', {
anchorX: 0,
anchorY: 0.5,
scaleX: 0.6,
scaleY: 0.15,
x: 20,
y: -100
});
beak.tint = 0xFF6600; // Orange beak
self.addChild(beak);
// Create red legs
var leftLeg = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0,
scaleX: 0.1,
scaleY: 0.8,
x: -15,
y: 60
});
leftLeg.tint = 0xFF0000; // Red legs
self.addChild(leftLeg);
var rightLeg = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0,
scaleX: 0.1,
scaleY: 0.8,
x: 15,
y: 60
});
rightLeg.tint = 0xFF0000;
self.addChild(rightLeg);
// Properties
self.speed = 1.5;
self.targetX = 0;
self.targetY = 0;
self.state = 'wandering'; // 'wandering', 'hunting', 'fleeing'
self.huntTimer = 0;
self.peckCooldown = 0;
self.fleeTimer = 0;
// Set target position
self.setTarget = function (x, y) {
self.targetX = x;
self.targetY = y;
};
// Peck attack
self.peck = function () {
if (self.peckCooldown <= 0) {
self.peckCooldown = 60; // 1 second cooldown
// Peck animation
tween(neck, {
scaleY: 1.2,
y: -40
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(neck, {
scaleY: 0.8,
y: -60
}, {
duration: 200,
easing: tween.easeInOut
});
}
});
// Move beak forward
tween(beak, {
x: 40
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(beak, {
x: 20
}, {
duration: 200,
easing: tween.easeInOut
});
}
});
return true;
}
return false;
};
// Make stork flee
self.flee = function (fromX, fromY) {
self.state = 'fleeing';
self.fleeTimer = 180; // Flee for 3 seconds
// Calculate flee direction
var angle = Math.atan2(self.y - fromY, self.x - fromX);
var fleeDistance = 400;
self.setTarget(self.x + Math.cos(angle) * fleeDistance, self.y + Math.sin(angle) * fleeDistance);
// Speed up when fleeing
self.speed = 3;
};
self.update = function () {
// Update cooldowns
if (self.peckCooldown > 0) {
self.peckCooldown--;
}
if (self.fleeTimer > 0) {
self.fleeTimer--;
if (self.fleeTimer === 0) {
self.state = 'wandering';
self.speed = 1.5;
}
}
// Move toward target
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 10) {
self.x += dx / dist * self.speed;
self.y += dy / dist * self.speed;
// Face movement direction
if (dx < 0) {
self.scale.x = -1;
} else {
self.scale.x = 1;
}
}
// Walking animation
if (dist > 10) {
leftLeg.rotation = Math.sin(LK.ticks * 0.1) * 0.2;
rightLeg.rotation = -Math.sin(LK.ticks * 0.1) * 0.2;
}
};
return self;
});
var WaterMine = Container.expand(function () {
var self = Container.call(this);
// Create mine visual
var mineBody = self.attachAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.6,
scaleY: 0.6
});
mineBody.tint = 0x333333; // Dark grey
// Add spikes/details
var spike1 = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.1,
scaleY: 0.8,
rotation: 0
});
spike1.tint = 0x555555;
self.addChild(spike1);
var spike2 = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.1,
scaleY: 0.8,
rotation: Math.PI / 2
});
spike2.tint = 0x555555;
self.addChild(spike2);
self.isExploded = false;
self.damage = 1; // Damage dealt to goose on explosion
// Explode the mine
self.explode = function () {
if (!self.isExploded) {
self.isExploded = true;
// Explosion animation (expanding reddish circle)
var explosionEffect = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
x: self.x,
y: self.y,
scaleX: 0.1,
scaleY: 0.1,
alpha: 1
});
explosionEffect.tint = 0xFF4500; // OrangeRed for explosion
game.addChild(explosionEffect);
tween(explosionEffect, {
scaleX: 5,
scaleY: 5,
alpha: 0
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
game.removeChild(explosionEffect);
}
});
// Fade out and remove the mine
tween(self, {
alpha: 0
}, {
duration: 200,
onFinish: function onFinish() {
self.visible = false;
}
});
return true;
}
return false;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB // Sky blue background
});
/****
* Game Code
****/
// Game variables
var goose;
var pond;
var chips = [];
var chipCount = 15;
var dragNode = null;
var lastIntersecting = false;
var gameActive = true;
var highScore = storage.highScore || 0;
var atomicBomb = null;
var bombTimer = 0;
var hasBomb = false;
var chocolate = null;
var chocolateTimer = 0;
var eurovisionFlashbang = null;
var flashbangTimer = 0;
var hasFlashbang = false;
var drowning = null;
var isInShallowWater = false;
var lastPondDistance = 0;
var painkiller = null;
var painkillerTimer = 0;
var gooseHealth = 3; // Initial health
var maxGooseHealth = 5; // Maximum health possible
// Human-related variables
var humans = [];
var maxHumans = 3;
var humanSpawnTimer = 180;
var breadPieces = [];
var gooseChasingHuman = null;
var chasingTimeout = 0;
// Country variables
var countries = [];
var availableCountries = [{
name: "Bayern",
color: 0x0066CC
}, {
name: "Berlin",
color: 0x000000
}, {
name: "Hamburg",
color: 0xFF0000
}, {
name: "Sachsen",
color: 0x00FF00
}, {
name: "Rheinland",
color: 0x800080
}, {
name: "Hessen",
color: 0xFF6600
}, {
name: "Thüringen",
color: 0x0000FF
}, {
name: "Baden",
color: 0xFFD700
}];
var visitedCountries = {}; // Track visited countries
var countryPortalTimer = 0;
var maxActiveCountries = 2; // Maximum number of active portals at once
var currentBackground = "default"; // Current background theme
var travelEffectActive = false;
// Cookie variables
var currentCookie = null;
var cookieSpawnTimer = 0;
var gooseHasCookie = false;
var cookieEffectDuration = 300; // 5 seconds at 60fps
var cookieEffectTimer = 0;
var gooseCookieIndicator = null;
var waterMines = [];
var maxWaterMines = 3;
var waterMineSpawnTimer = 600; // 10 seconds
var panzerBoss = null;
var panzerShells = [];
var panzerSpawned = false;
var pretzels = [];
var pretzelSpawnTimer = 0;
var maxPretzels = 2;
var storchs = [];
var maxStorchs = 2;
var storchSpawnTimer = 0;
var dachshunds = [];
var maxDachshunds = 2;
var dachshundSpawnTimer = 0;
var antiTankGrenade = null;
var grenadeSpawnTimer = 0;
var hasGrenade = false;
// Initialize the game UI
var scoreTxt = new Text2('0', {
size: 80,
fill: 0xFFFFFF
});
scoreTxt.setText("Punkte: " + LK.getScore());
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
var highScoreTxt = new Text2('0', {
size: 50,
fill: 0xFFFFFF
});
highScoreTxt.setText("Rekord: " + highScore);
highScoreTxt.anchor.set(0.5, 0);
highScoreTxt.y = 90;
LK.gui.top.addChild(highScoreTxt);
// Create visited countries display
var countriesVisitedTxt = new Text2('0', {
size: 45,
fill: 0xFFFFFF
});
countriesVisitedTxt.setText("Länder: 0");
countriesVisitedTxt.anchor.set(0.5, 0);
countriesVisitedTxt.y = 150;
LK.gui.top.addChild(countriesVisitedTxt);
// Update countries visited text
function updateCountriesVisited() {
var count = Object.keys(visitedCountries).length;
countriesVisitedTxt.setText("Länder: " + count);
// Change text color based on countries visited
if (count >= 5) {
countriesVisitedTxt.style = {
fill: 0xFFD700
}; // Gold
} else if (count >= 3) {
countriesVisitedTxt.style = {
fill: 0xC0C0C0
}; // Silver
} else if (count >= 1) {
countriesVisitedTxt.style = {
fill: 0xCD7F32
}; // Bronze
}
}
// Settings variables
var settingsButton;
var settingsPanel;
var isSettingsOpen = false;
// Create settings button
settingsButton = LK.getAsset('settingsBackground', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.04,
scaleY: 0.04
});
settingsButton.tint = 0x444444; // Darker grey for rectangular button
settingsButton.x = -60; // Position relative to topRight
settingsButton.y = 60;
LK.gui.topRight.addChild(settingsButton);
// Add gear symbol to settings button
var gearSymbol = new Text2('⚙', {
size: 40,
fill: 0xFFFFFF
});
gearSymbol.anchor.set(0.5, 0.5);
settingsButton.addChild(gearSymbol);
// Create settings panel (initially hidden)
settingsPanel = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 4,
scaleY: 3
});
settingsPanel.tint = 0x333333; // Dark background
settingsPanel.alpha = 0.9;
settingsPanel.x = -150;
settingsPanel.y = 200;
settingsPanel.visible = false;
LK.gui.topRight.addChild(settingsPanel);
// Add settings title
var settingsTitle = new Text2('Einstellungen', {
size: 50,
fill: 0xFFFFFF
});
settingsTitle.anchor.set(0.5, 0.5);
settingsTitle.y = -80;
settingsPanel.addChild(settingsTitle);
// Add music toggle button
var musicToggle = new Text2('Musik: AN', {
size: 35,
fill: 0x00FF00
});
musicToggle.anchor.set(0.5, 0.5);
musicToggle.y = -20;
settingsPanel.addChild(musicToggle);
// Add close button
var closeButton = new Text2('✕', {
size: 40,
fill: 0xFF5555
});
closeButton.anchor.set(0.5, 0.5);
closeButton.y = 60;
settingsPanel.addChild(closeButton);
// Settings button functionality
settingsButton.down = function (x, y, obj) {
if (!isSettingsOpen) {
settingsPanel.visible = true;
isSettingsOpen = true;
// Pause game when settings open
gameActive = false;
} else {
settingsPanel.visible = false;
isSettingsOpen = false;
// Resume game when settings close
gameActive = true;
}
};
// Music toggle functionality
musicToggle.down = function (x, y, obj) {
if (musicToggle.text === 'Musik: AN') {
LK.stopMusic();
musicToggle.setText('Musik: AUS');
musicToggle.style = {
fill: 0xFF5555
}; // Red for OFF
} else {
LK.playMusic('bgMusic', {
loop: true
});
musicToggle.setText('Musik: AN');
musicToggle.style = {
fill: 0x00FF00
}; // Green for ON
}
};
// Close button functionality
closeButton.down = function (x, y, obj) {
settingsPanel.visible = false;
isSettingsOpen = false;
// Resume game when settings close
gameActive = true;
};
// Health display
var healthTxt = new Text2('Leben: ♥♥♥', {
size: 45,
fill: 0xFF5555
});
healthTxt.anchor.set(0, 0);
healthTxt.x = 20;
healthTxt.y = 20;
LK.gui.topLeft.addChild(healthTxt);
// Update health display
function updateHealthDisplay() {
var hearts = '';
for (var i = 0; i < gooseHealth; i++) {
hearts += '♥';
}
healthTxt.setText('Leben: ' + hearts);
}
// Create the pond (play area)
pond = game.addChild(new Pond());
pond.x = 2048 / 2;
pond.y = 2732 / 2;
pond.innerRadius = 400; // Safe swimming area
pond.outerRadius = 850; // Pond edge
// Create the goose (player character)
goose = game.addChild(new Goose());
goose.x = 2048 / 2;
goose.y = 2732 / 2 + 600;
// Create drowning effect
drowning = game.addChild(new Drowning());
drowning.visible = false;
drowning.alpha = 0;
// Spawn chips around the pond
function spawnChips() {
for (var i = 0; i < chipCount; i++) {
var chip = new Chip();
var angle = Math.random() * Math.PI * 2;
var distance = Math.random() * 700 + 200;
chip.x = pond.x + Math.cos(angle) * distance;
chip.y = pond.y + Math.sin(angle) * distance;
// Make sure chips are within pond boundaries
var dx = chip.x - pond.x;
var dy = chip.y - pond.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 850) {
// Adjust to keep within pond
chip.x = pond.x + dx / dist * 850;
chip.y = pond.y + dy / dist * 850;
}
chips.push(chip);
game.addChild(chip);
}
}
// Spawn initial chips
spawnChips();
// Spawn initial humans
function spawnHuman() {
if (humans.length < maxHumans) {
var human = new Human();
// Position human around the pond edges
var angle = Math.random() * Math.PI * 2;
var distance = pond.outerRadius + 100 + Math.random() * 200;
human.x = pond.x + Math.cos(angle) * distance;
human.y = pond.y + Math.sin(angle) * distance;
// Set initial target to another spot around the pond
var targetAngle = angle + (Math.random() * Math.PI * 0.5 - Math.PI * 0.25);
human.setTarget(pond.x + Math.cos(targetAngle) * distance, pond.y + Math.sin(targetAngle) * distance);
// Fill bread supply
human.refillBread();
humans.push(human);
game.addChild(human);
return human;
}
return null;
}
// Spawn initial humans
for (var i = 0; i < 2; i++) {
spawnHuman();
}
// Spawn initial storchs
function spawnStorch() {
if (storchs.length < maxStorchs) {
var storch = new Storch();
// Position storch around pond edges
var angle = Math.random() * Math.PI * 2;
var distance = pond.outerRadius - 100 - Math.random() * 200;
storch.x = pond.x + Math.cos(angle) * distance;
storch.y = pond.y + Math.sin(angle) * distance;
// Set initial wandering target
var targetAngle = Math.random() * Math.PI * 2;
var targetDistance = pond.outerRadius - 100 - Math.random() * 300;
storch.setTarget(pond.x + Math.cos(targetAngle) * targetDistance, pond.y + Math.sin(targetAngle) * targetDistance);
storchs.push(storch);
game.addChild(storch);
return storch;
}
return null;
}
// Spawn initial storch
spawnStorch();
// Spawn dachshunds
function spawnDachshund() {
if (dachshunds.length < maxDachshunds) {
var dachshund = new Dachshund();
// Position dachshund around pond edges
var angle = Math.random() * Math.PI * 2;
var distance = pond.outerRadius + 50 + Math.random() * 150;
dachshund.x = pond.x + Math.cos(angle) * distance;
dachshund.y = pond.y + Math.sin(angle) * distance;
dachshunds.push(dachshund);
game.addChild(dachshund);
return dachshund;
}
return null;
}
// Spawn initial dachshund
spawnDachshund();
// Play background music
LK.playMusic('bgMusic', {
loop: true
});
// Handle movement
function handleMove(x, y, obj) {
if (dragNode && gameActive) {
// Limit goose movement to within the pond boundaries
var dx = x - pond.x;
var dy = y - pond.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 850) {
// Keep goose within the pond boundaries
dragNode.x = pond.x + dx / dist * 850;
dragNode.y = pond.y + dy / dist * 850;
} else {
dragNode.x = x;
dragNode.y = y;
}
// Rotate toward movement direction
var moveAngle = Math.atan2(y - dragNode.y, x - dragNode.x);
dragNode.rotation = moveAngle;
}
}
// Mouse/touch events
game.move = handleMove;
game.down = function (x, y, obj) {
if (gameActive) {
dragNode = goose;
handleMove(x, y, obj);
// Deactivate drowning when goose starts moving
if (drowning.isActive) {
drowning.deactivate();
}
// Attack on tap/click
goose.attack();
// Special effect when having atomic bomb
if (hasBomb) {
LK.effects.flashScreen(0xff0000, 500);
}
}
};
game.up = function (x, y, obj) {
dragNode = null;
};
// Main game update loop
game.update = function () {
if (!gameActive) return;
// Update game entities
goose.update();
if (chocolate) {
chocolate.update();
}
if (painkiller) {
painkiller.update();
}
if (antiTankGrenade) {
antiTankGrenade.update();
}
// Drowning mechanics - check how far goose is from pond center
var dx = goose.x - pond.x;
var dy = goose.y - pond.y;
var distFromCenter = Math.sqrt(dx * dx + dy * dy);
lastPondDistance = distFromCenter;
// Different water zones
if (distFromCenter > pond.outerRadius) {
// Outside the pond - no drowning
drowning.deactivate();
drowning.visible = false;
isInShallowWater = false;
} else if (distFromCenter > pond.innerRadius) {
// In the shallow area - safe swimming
isInShallowWater = true;
drowning.deactivate();
drowning.visible = false;
} else {
// In the deep area - risk of drowning
isInShallowWater = false;
// Only start drowning if goose isn't moving
if (dragNode !== goose) {
if (!drowning.isActive) {
drowning.activate();
drowning.visible = true;
drowning.x = goose.x;
drowning.y = goose.y;
} else {
// Update drowning position to follow goose
drowning.x = goose.x;
drowning.y = goose.y;
// Check if drowning is complete
if (drowning.update()) {
// Goose drowned - game over
LK.getSound('hit').play();
LK.effects.flashScreen(0x0066ff, 1000);
// Update high score if needed
if (LK.getScore() > highScore) {
highScore = LK.getScore();
storage.highScore = highScore;
highScoreTxt.setText("Rekord: " + highScore);
}
// End the game
gameActive = false;
LK.showGameOver();
}
}
} else {
// Goose is moving, deactivate drowning
drowning.deactivate();
}
}
// Chocolate spawn logic
chocolateTimer++;
if (!chocolate && chocolateTimer > 480 && Math.random() < 0.008) {
chocolate = new Chocolate();
var angle = Math.random() * Math.PI * 2;
var distance = Math.random() * 600 + 150;
chocolate.x = pond.x + Math.cos(angle) * distance;
chocolate.y = pond.y + Math.sin(angle) * distance;
game.addChild(chocolate);
chocolateTimer = 0;
}
// Atomic bomb spawn logic
bombTimer++;
if (!atomicBomb && !hasBomb && bombTimer > 600 && Math.random() < 0.005) {
atomicBomb = new AtomicBomb();
var angle = Math.random() * Math.PI * 2;
var distance = Math.random() * 600 + 150;
atomicBomb.x = pond.x + Math.cos(angle) * distance;
atomicBomb.y = pond.y + Math.sin(angle) * distance;
game.addChild(atomicBomb);
bombTimer = 0;
}
// Check for goose collecting chips
for (var i = chips.length - 1; i >= 0; i--) {
if (!chips[i].isCollected && goose.intersects(chips[i])) {
if (chips[i].collect()) {
// Increase score
LK.setScore(LK.getScore() + 1);
scoreTxt.setText("Punkte: " + LK.getScore());
// Remove the chip from the array
chips.splice(i, 1);
// Spawn a new chip if needed
if (chips.length < 5) {
var chip = new Chip();
var angle = Math.random() * Math.PI * 2;
var distance = Math.random() * 700 + 200;
chip.x = pond.x + Math.cos(angle) * distance;
chip.y = pond.y + Math.sin(angle) * distance;
chips.push(chip);
game.addChild(chip);
}
}
}
}
// Painkiller spawn logic
painkillerTimer++;
if (!painkiller && painkillerTimer > 420 && gooseHealth < maxGooseHealth && Math.random() < 0.006) {
painkiller = new Painkiller();
var angle = Math.random() * Math.PI * 2;
var distance = Math.random() * 600 + 200;
painkiller.x = pond.x + Math.cos(angle) * distance;
painkiller.y = pond.y + Math.sin(angle) * distance;
game.addChild(painkiller);
painkillerTimer = 0;
}
// Check for painkiller collection
if (painkiller && !painkiller.isCollected && goose.intersects(painkiller)) {
if (painkiller.collect()) {
// Increase health
gooseHealth = Math.min(maxGooseHealth, gooseHealth + 1);
updateHealthDisplay();
// Health up animation
var healthUpTxt = new Text2("+1 ♥ Gesundheit", {
size: 60,
fill: 0xFF5555
});
healthUpTxt.anchor.set(0.5, 0.5);
healthUpTxt.x = goose.x;
healthUpTxt.y = goose.y - 80;
game.addChild(healthUpTxt);
// Animate health text
tween(healthUpTxt, {
y: healthUpTxt.y - 100,
alpha: 0
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
game.removeChild(healthUpTxt);
}
});
// Play sound
LK.getSound('eat').play();
// Reset painkiller
painkiller = null;
painkillerTimer = 0;
}
}
// Check for anti-tank grenade collection
if (antiTankGrenade && !hasGrenade && goose.intersects(antiTankGrenade) && antiTankGrenade.collect()) {
hasGrenade = true;
antiTankGrenade.visible = false;
// Create grenade indicator on goose
var grenadeIndicator = LK.getAsset('antiTankGrenade', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: -80,
scaleX: 0.3,
scaleY: 0.3
});
grenadeIndicator.tint = 0x4A4A4A; // Dark grey
goose.addChild(grenadeIndicator);
LK.getSound('eat').play();
}
// Check for atomic bomb collection
if (atomicBomb && !hasBomb && goose.intersects(atomicBomb) && atomicBomb.collect()) {
// Pulse animation for the indicator
var _pulseIndicator = function pulseIndicator() {
tween(indicatorGlow, {
alpha: 0.3,
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 600,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(indicatorGlow, {
alpha: 0.6,
scaleX: 0.4,
scaleY: 0.4
}, {
duration: 600,
easing: tween.easeInOut,
onFinish: _pulseIndicator
});
}
});
};
hasBomb = true;
atomicBomb.visible = false;
// Create bomb indicator on goose with new blue design
var bombIndicator = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: -80,
scaleX: 0.3,
scaleY: 0.3
});
bombIndicator.tint = 0x0066ff; // Electric blue to match new bomb design
// Add glow effect to indicator
var indicatorGlow = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: 0,
scaleX: 0.4,
scaleY: 0.4,
alpha: 0.6
});
indicatorGlow.tint = 0x00ffff; // Cyan glow
bombIndicator.addChild(indicatorGlow);
_pulseIndicator();
goose.addChild(bombIndicator);
LK.getSound('eat').play();
}
// Use atomic bomb when attacking with bomb collected
if (hasBomb && goose.isAttacking) {
hasBomb = false;
// Remove bomb indicator
goose.removeChild(goose.children[goose.children.length - 1]);
// Create explosion at goose position
var explosion = new AtomicBomb();
explosion.x = goose.x;
explosion.y = goose.y;
game.addChild(explosion);
explosion.explode();
// Flash screen blue for freezing effect
LK.effects.flashScreen(0x0066ff, 800);
// Reset bomb variables
atomicBomb = null;
bombTimer = 0;
}
// Country portal spawn logic
countryPortalTimer++;
if (countryPortalTimer > 600 && Math.random() < 0.008 && countries.length < maxActiveCountries) {
// Only spawn countries if we have unvisited countries or rarely for visited ones
var availableForSpawn = availableCountries.filter(function (country) {
return !visitedCountries[country.name] || Math.random() < 0.2;
});
if (availableForSpawn.length > 0) {
// Select random country
var countryData = availableForSpawn[Math.floor(Math.random() * availableForSpawn.length)];
// Create country portal
var portal = new Country();
portal.setCountry(countryData.name, countryData.color);
// Position in a random location, biased toward pond edges
var angle = Math.random() * Math.PI * 2;
var distance = Math.random() * 300 + 500; // Between 500-800 units from center
portal.x = pond.x + Math.cos(angle) * distance;
portal.y = pond.y + Math.sin(angle) * distance;
// Ensure within pond
var dx = portal.x - pond.x;
var dy = portal.y - pond.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 800) {
portal.x = pond.x + dx / dist * 800;
portal.y = pond.y + dy / dist * 800;
}
portal.activate();
countries.push(portal);
game.addChild(portal);
countryPortalTimer = 0;
}
}
// Update countries
for (var i = countries.length - 1; i >= 0; i--) {
countries[i].update();
// Check if goose enters portal
if (!travelEffectActive && goose.intersects(countries[i])) {
var travelResult = countries[i].travel();
if (travelResult.success) {
travelEffectActive = true;
// Add score bonus
LK.setScore(LK.getScore() + travelResult.scoreBonus);
scoreTxt.setText("Punkte: " + LK.getScore());
// Mark country as visited
visitedCountries[travelResult.countryName] = true;
updateCountriesVisited();
// Travel effect
var countryName = travelResult.countryName;
var countryColor = countries[i].countryColor;
// Flash screen with country color
LK.effects.flashScreen(countryColor, 800);
// Display travel message
var travelText = new Text2("Reise nach " + countryName + "!", {
size: 100,
fill: countryColor
});
travelText.anchor.set(0.5, 0.5);
travelText.x = 2048 / 2;
travelText.y = 2732 / 2;
travelText.alpha = 0;
game.addChild(travelText);
// Animate travel text
tween(travelText, {
alpha: 1,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(travelText, {
alpha: 0,
y: travelText.y - 100
}, {
duration: 800,
delay: 1000,
easing: tween.easeIn,
onFinish: function onFinish() {
game.removeChild(travelText);
}
});
}
});
// Change background tint temporarily to represent country
var originalTint = pond.children[0].tint;
tween(pond.children[0], {
tint: countryColor
}, {
duration: 1000,
onFinish: function onFinish() {
LK.setTimeout(function () {
tween(pond.children[0], {
tint: originalTint
}, {
duration: 1000,
onFinish: function onFinish() {
travelEffectActive = false;
}
});
}, 3000);
}
});
}
}
// Remove expired portals
if (countries[i].travelCooldown <= 0 && Math.random() < 0.002) {
// Fade out and remove
tween(countries[i], {
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
}, {
duration: 500,
onFinish: function (index) {
return function () {
game.removeChild(countries[index]);
countries.splice(index, 1);
};
}(i)
});
}
}
// Eurovision flashbang spawn logic
flashbangTimer++;
if (!eurovisionFlashbang && !hasFlashbang && flashbangTimer > 900 && Math.random() < 0.003) {
eurovisionFlashbang = new EurovisionFlashbang();
var angle = Math.random() * Math.PI * 2;
var distance = Math.random() * 650 + 100;
eurovisionFlashbang.x = pond.x + Math.cos(angle) * distance;
eurovisionFlashbang.y = pond.y + Math.sin(angle) * distance;
game.addChild(eurovisionFlashbang);
flashbangTimer = 0;
}
// Check for eurovision flashbang collection
if (eurovisionFlashbang && !hasFlashbang && goose.intersects(eurovisionFlashbang) && eurovisionFlashbang.collect()) {
hasFlashbang = true;
eurovisionFlashbang.visible = false;
// Create flashbang indicator on goose (sparkling effect)
var flashbangIndicator = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: -80,
scaleX: 0.3,
scaleY: 0.3
});
flashbangIndicator.tint = 0xFFD700; // Gold color
goose.addChild(flashbangIndicator);
LK.getSound('eat').play();
}
// Use eurovision flashbang when attacking with flashbang collected
if (hasFlashbang && goose.isAttacking) {
var _flashNextColor = function flashNextColor() {
if (flashCount < colors.length) {
LK.effects.flashScreen(colors[flashCount], 300);
flashCount++;
LK.setTimeout(_flashNextColor, 300);
}
};
hasFlashbang = false;
// Remove flashbang indicator
goose.removeChild(goose.children[goose.children.length - 1]);
// Create explosion at goose position
var explosion = new EurovisionFlashbang();
explosion.x = goose.x;
explosion.y = goose.y;
game.addChild(explosion);
explosion.explode();
// Apply Eurovision flashbang effect
// Create rainbow flashing effect that stuns all characters
var colors = [0xFF0000, 0xFF7F00, 0xFFFF00, 0x00FF00, 0x0000FF, 0x4B0082, 0x9400D3];
var flashCount = 0;
_flashNextColor();
// Reset flashbang variables
eurovisionFlashbang = null;
flashbangTimer = 0;
}
// Cookie Spawn Logic
cookieSpawnTimer++;
if (!currentCookie && cookieSpawnTimer > 12 * 60 && Math.random() < 0.01) {
// Approx. every 12-13 seconds
currentCookie = new Cookie();
var angle = Math.random() * Math.PI * 2;
var distance = Math.random() * (pond.outerRadius * 0.8) + pond.innerRadius * 0.2; // Spawn within pond, not too close to center
currentCookie.x = pond.x + Math.cos(angle) * distance;
currentCookie.y = pond.y + Math.sin(angle) * distance;
game.addChild(currentCookie);
cookieSpawnTimer = 0;
}
// Update current cookie if it exists and handle its self-despawn
if (currentCookie) {
currentCookie.update(); // Cookie handles its own visibility and removal from parent if timed out
if (!currentCookie.visible) {
currentCookie = null;
}
}
// Cookie Collection Logic
if (currentCookie && currentCookie.visible && !currentCookie.isCollected && !gooseHasCookie && goose.intersects(currentCookie)) {
if (currentCookie.collect()) {
// collect() handles animation and sets isCollected
LK.getSound('eat').play();
gooseHasCookie = true;
cookieEffectTimer = cookieEffectDuration;
if (gooseCookieIndicator && gooseCookieIndicator.parent) {
// Remove old one if somehow it exists
gooseCookieIndicator.parent.removeChild(gooseCookieIndicator);
}
gooseCookieIndicator = LK.getAsset('cookieShape', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.25,
scaleY: 0.25,
x: 0,
y: -85 // Position above goose's head
});
goose.addChild(gooseCookieIndicator);
// The currentCookie will become invisible due to its collect animation.
// The check above `if (!currentCookie.visible)` will handle setting `currentCookie = null;`
}
}
// Cookie Effect Update (manages gooseHasCookie timer and indicator)
if (gooseHasCookie) {
cookieEffectTimer--;
if (cookieEffectTimer <= 0) {
gooseHasCookie = false;
if (gooseCookieIndicator && gooseCookieIndicator.parent) {
goose.removeChild(gooseCookieIndicator);
gooseCookieIndicator = null;
}
}
}
// Human spawn logic
humanSpawnTimer--;
if (humanSpawnTimer <= 0 && humans.length < maxHumans) {
spawnHuman();
humanSpawnTimer = 300 + Math.floor(Math.random() * 300);
}
// Update humans and bread
for (var i = humans.length - 1; i >= 0; i--) {
var human = humans[i];
human.update();
// Humans throw bread randomly
if (Math.random() < 0.005 && human.breadCount > 0) {
var breadPosition = human.throwBread(pond.x, pond.y);
if (breadPosition) {
var bread = new Bread();
bread.x = breadPosition.x;
bread.y = breadPosition.y;
// Check if bread landed in water
var dx = bread.x - pond.x;
var dy = bread.y - pond.y;
var distFromCenter = Math.sqrt(dx * dx + dy * dy);
if (distFromCenter < pond.outerRadius) {
bread.startSinking();
}
breadPieces.push(bread);
game.addChild(bread);
}
}
// Human movement around pond
if (Math.random() < 0.01 && gooseChasingHuman !== human) {
var newAngle = Math.random() * Math.PI * 2;
var newDistance = pond.outerRadius + 100 + Math.random() * 200;
human.setTarget(pond.x + Math.cos(newAngle) * newDistance, pond.y + Math.sin(newAngle) * newDistance);
}
// Goose scares human
if (goose.intersects(human) && !human.isAngry && !gooseHasCookie) {
// Human doesn't flee if goose has a cookie!
// Human reacts to goose
if (human.becomeAngry()) {
// Human runs away from goose
var runAngle = Math.atan2(human.y - goose.y, human.x - goose.x);
var runDistance = pond.outerRadius + 300;
human.setTarget(pond.x + Math.cos(runAngle) * runDistance, pond.y + Math.sin(runAngle) * runDistance);
// Running animation
human.speed = 4;
// Chance to drop bread in panic
if (human.breadCount > 0 && Math.random() < 0.5) {
var breadPosition = human.throwBread(human.x + Math.random() * 100 - 50, human.y + Math.random() * 100 - 50);
if (breadPosition) {
var bread = new Bread();
bread.x = breadPosition.x;
bread.y = breadPosition.y;
breadPieces.push(bread);
game.addChild(bread);
}
}
// Add score for scaring human
LK.setScore(LK.getScore() + 2);
scoreTxt.setText("Punkte: " + LK.getScore());
// Show point popup
var pointsTxt = new Text2("+2", {
size: 60,
fill: 0xFFFFFF
});
pointsTxt.anchor.set(0.5, 0.5);
pointsTxt.x = human.x;
pointsTxt.y = human.y - 80;
game.addChild(pointsTxt);
// Animate points popup
tween(pointsTxt, {
y: pointsTxt.y - 80,
alpha: 0
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
game.removeChild(pointsTxt);
}
});
// Set human as target for goose chase effect
gooseChasingHuman = human;
chasingTimeout = 180; // 3 seconds timeout
}
}
// Remove humans that have run too far
var distanceFromPond = Math.sqrt(Math.pow(human.x - pond.x, 2) + Math.pow(human.y - pond.y, 2));
if (distanceFromPond > pond.outerRadius + 800) {
// Human left the scene, remove them
tween(human, {
alpha: 0
}, {
duration: 500,
onFinish: function (index) {
return function () {
game.removeChild(humans[index]);
humans.splice(index, 1);
};
}(i)
});
}
}
// Update chasing timeout
if (gooseChasingHuman !== null) {
chasingTimeout--;
if (chasingTimeout <= 0) {
gooseChasingHuman = null;
}
}
// Update bread pieces
for (var i = breadPieces.length - 1; i >= 0; i--) {
var bread = breadPieces[i];
bread.update();
// Check for bread collection by birds
if (!bread.isConsumed) {
// Goose can collect bread for points
if (goose.intersects(bread)) {
if (bread.consume()) {
// Add score
LK.setScore(LK.getScore() + 1);
scoreTxt.setText("Punkte: " + LK.getScore());
// Remove from array
breadPieces.splice(i, 1);
// Play eat sound
LK.getSound('eat').play();
}
}
// Remove bread that's no longer visible
else if (bread.alpha <= 0) {
breadPieces.splice(i, 1);
game.removeChild(bread);
}
}
}
// Storch spawn logic (early game enemy)
storchSpawnTimer++;
if (storchSpawnTimer > 300 && storchs.length < maxStorchs && LK.getScore() < 40) {
// Only spawn storchs in early game (before score 40)
if (Math.random() < 0.01) {
spawnStorch();
storchSpawnTimer = 0;
}
}
// Update storchs
for (var i = storchs.length - 1; i >= 0; i--) {
var storch = storchs[i];
storch.update();
// Storch AI behavior
if (storch.state === 'wandering') {
// Check distance to goose
var distToGoose = Math.sqrt(Math.pow(goose.x - storch.x, 2) + Math.pow(goose.y - storch.y, 2));
// Start hunting if goose is close
if (distToGoose < 200 && storch.fleeTimer === 0) {
storch.state = 'hunting';
storch.huntTimer = 180; // Hunt for 3 seconds
storch.speed = 2.5;
}
// Wander to new position occasionally
if (Math.random() < 0.005) {
var angle = Math.random() * Math.PI * 2;
var distance = pond.outerRadius - 100 - Math.random() * 300;
storch.setTarget(pond.x + Math.cos(angle) * distance, pond.y + Math.sin(angle) * distance);
}
} else if (storch.state === 'hunting') {
// Chase the goose
storch.setTarget(goose.x, goose.y);
storch.huntTimer--;
// Stop hunting after timer expires
if (storch.huntTimer <= 0) {
storch.state = 'wandering';
storch.speed = 1.5;
}
// Try to peck if close enough
var distToGoose = Math.sqrt(Math.pow(goose.x - storch.x, 2) + Math.pow(goose.y - storch.y, 2));
if (distToGoose < 80 && storch.peck()) {
// Check if actually hit the goose
if (goose.intersects(storch)) {
// Damage goose
LK.getSound('hit').play();
gooseHealth--;
updateHealthDisplay();
// Knockback effect on goose
var knockbackAngle = Math.atan2(goose.y - storch.y, goose.x - storch.x);
goose.x += Math.cos(knockbackAngle) * 50;
goose.y += Math.sin(knockbackAngle) * 50;
// Show damage effect
LK.effects.flashObject(goose, 0xFF0000, 500);
// Check game over
if (gooseHealth <= 0) {
if (LK.getScore() > highScore) {
highScore = LK.getScore();
storage.highScore = highScore;
highScoreTxt.setText("Rekord: " + highScore);
}
LK.effects.flashScreen(0xff0000, 1000);
gameActive = false;
LK.showGameOver();
}
}
}
}
// Storch flees from goose attacks
if (goose.isAttacking && !storch.state === 'fleeing') {
var distToGoose = Math.sqrt(Math.pow(goose.x - storch.x, 2) + Math.pow(goose.y - storch.y, 2));
if (distToGoose < 150) {
storch.flee(goose.x, goose.y);
// Award points for scaring storch
LK.setScore(LK.getScore() + 1);
scoreTxt.setText("Punkte: " + LK.getScore());
// Show point popup
var pointsTxt = new Text2("+1", {
size: 50,
fill: 0xFFFFFF
});
pointsTxt.anchor.set(0.5, 0.5);
pointsTxt.x = storch.x;
pointsTxt.y = storch.y - 60;
game.addChild(pointsTxt);
tween(pointsTxt, {
y: pointsTxt.y - 60,
alpha: 0
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
game.removeChild(pointsTxt);
}
});
}
}
// Remove storchs that wander too far
var distFromPond = Math.sqrt(Math.pow(storch.x - pond.x, 2) + Math.pow(storch.y - pond.y, 2));
if (distFromPond > pond.outerRadius + 400) {
// Storch left the area
tween(storch, {
alpha: 0
}, {
duration: 500,
onFinish: function (index) {
return function () {
game.removeChild(storchs[index]);
storchs.splice(index, 1);
};
}(i)
});
}
}
// Dachshund spawn logic
dachshundSpawnTimer++;
if (dachshundSpawnTimer > 400 && dachshunds.length < maxDachshunds && Math.random() < 0.008) {
spawnDachshund();
dachshundSpawnTimer = 0;
}
// Update dachshunds
for (var i = dachshunds.length - 1; i >= 0; i--) {
var dachshund = dachshunds[i];
dachshund.update();
// Find nearest target (goose or storch)
var nearestTarget = null;
var nearestDistance = Infinity;
// Check distance to goose
var distToGoose = Math.sqrt(Math.pow(goose.x - dachshund.x, 2) + Math.pow(goose.y - dachshund.y, 2));
if (distToGoose < nearestDistance) {
nearestDistance = distToGoose;
nearestTarget = goose;
}
// Check distances to all storchs
for (var j = 0; j < storchs.length; j++) {
var distToStorch = Math.sqrt(Math.pow(storchs[j].x - dachshund.x, 2) + Math.pow(storchs[j].y - dachshund.y, 2));
if (distToStorch < nearestDistance) {
nearestDistance = distToStorch;
nearestTarget = storchs[j];
}
}
// Chase nearest target
if (nearestTarget) {
dachshund.target = nearestTarget;
dachshund.setTarget(nearestTarget.x, nearestTarget.y);
// Bark when getting close
if (nearestDistance < 200 && nearestDistance > 80) {
dachshund.bark();
}
// Try to bite when very close
if (nearestDistance < 60 && dachshund.bite()) {
// Check if actually hit the target
if (dachshund.intersects(nearestTarget)) {
if (nearestTarget === goose) {
// Damage goose
LK.getSound('hit').play();
gooseHealth--;
updateHealthDisplay();
// Knockback effect on goose
var knockbackAngle = Math.atan2(goose.y - dachshund.y, goose.x - dachshund.x);
goose.x += Math.cos(knockbackAngle) * 40;
goose.y += Math.sin(knockbackAngle) * 40;
// Show damage effect
LK.effects.flashObject(goose, 0xFF0000, 500);
// Check game over
if (gooseHealth <= 0) {
if (LK.getScore() > highScore) {
highScore = LK.getScore();
storage.highScore = highScore;
highScoreTxt.setText("Rekord: " + highScore);
}
LK.effects.flashScreen(0xff0000, 1000);
gameActive = false;
LK.showGameOver();
}
} else {
// Hit a storch - make it flee
nearestTarget.flee(dachshund.x, dachshund.y);
// Award small points for helping chase storch
LK.setScore(LK.getScore() + 1);
scoreTxt.setText("Punkte: " + LK.getScore());
}
}
}
}
// Dachshunds flee from goose attacks too
if (goose.isAttacking && dachshund.intersects(goose)) {
// Dachshund gets scared and runs away temporarily
var fleeAngle = Math.atan2(dachshund.y - goose.y, dachshund.x - goose.x);
dachshund.setTarget(dachshund.x + Math.cos(fleeAngle) * 300, dachshund.y + Math.sin(fleeAngle) * 300);
dachshund.speed = 4; // Run faster when scared
// Award points for scaring dachshund
LK.setScore(LK.getScore() + 2);
scoreTxt.setText("Punkte: " + LK.getScore());
// Show point popup
var pointsTxt = new Text2("+2 Dackel!", {
size: 60,
fill: 0xFFD700
});
pointsTxt.anchor.set(0.5, 0.5);
pointsTxt.x = dachshund.x;
pointsTxt.y = dachshund.y - 60;
game.addChild(pointsTxt);
tween(pointsTxt, {
y: pointsTxt.y - 80,
alpha: 0
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
game.removeChild(pointsTxt);
}
});
// Reset speed after some time
LK.setTimeout(function () {
dachshund.speed = 2.5;
}, 2000);
}
// Remove dachshunds that wander too far
var distFromPond = Math.sqrt(Math.pow(dachshund.x - pond.x, 2) + Math.pow(dachshund.y - pond.y, 2));
if (distFromPond > pond.outerRadius + 600) {
// Dachshund left the area
tween(dachshund, {
alpha: 0
}, {
duration: 500,
onFinish: function (index) {
return function () {
game.removeChild(dachshunds[index]);
dachshunds.splice(index, 1);
};
}(i)
});
}
}
// Water mine spawn logic
waterMineSpawnTimer--;
if (waterMineSpawnTimer <= 0 && waterMines.length < maxWaterMines) {
var mine = new WaterMine();
// Position mine randomly within the deep pond area
var angle = Math.random() * Math.PI * 2;
var distance = Math.random() * (pond.innerRadius - 100) + 50; // Between 50 and innerRadius-100 from center
mine.x = pond.x + Math.cos(angle) * distance;
mine.y = pond.y + Math.sin(angle) * distance;
waterMines.push(mine);
game.addChild(mine);
waterMineSpawnTimer = 600 + Math.floor(Math.random() * 300); // Next spawn in 10-15 seconds
}
// Update water mines and check for goose collision
for (var i = waterMines.length - 1; i >= 0; i--) {
var mine = waterMines[i];
// Mines don't have an update function, but we check collision here
// Check for goose collision with mine
if (!mine.isExploded && goose.intersects(mine)) {
if (mine.explode()) {
// Goose hit a mine - take damage
LK.getSound('hit').play();
gooseHealth -= mine.damage;
updateHealthDisplay();
// Damage animation
var damageEffect = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
x: goose.x,
y: goose.y,
scaleX: 2,
scaleY: 2,
alpha: 0.5
});
damageEffect.tint = 0xFF0000;
game.addChild(damageEffect);
// Animate damage effect
tween(damageEffect, {
alpha: 0,
scaleX: 3,
scaleY: 3
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
game.removeChild(damageEffect);
}
});
// Game over if health reaches zero
if (gooseHealth <= 0) {
// Update high score if needed
if (LK.getScore() > highScore) {
highScore = LK.getScore();
storage.highScore = highScore;
highScoreTxt.setText("Rekord: " + highScore);
}
// Flash screen red
LK.effects.flashScreen(0xff0000, 1000);
// End the game
gameActive = false;
LK.showGameOver();
}
// Remove the mine from the array
waterMines.splice(i, 1);
}
} else if (!mine.visible && mine.isExploded) {
// Remove mines that have finished exploding and are no longer visible
waterMines.splice(i, 1);
game.removeChild(mine);
}
}
// Anti-tank grenade spawn logic (spawns when panzer boss appears)
grenadeSpawnTimer++;
if (!antiTankGrenade && !hasGrenade && panzerSpawned && grenadeSpawnTimer > 300 && Math.random() < 0.01) {
antiTankGrenade = new AntiTankGrenade();
var angle = Math.random() * Math.PI * 2;
var distance = Math.random() * 500 + 200;
antiTankGrenade.x = pond.x + Math.cos(angle) * distance;
antiTankGrenade.y = pond.y + Math.sin(angle) * distance;
game.addChild(antiTankGrenade);
grenadeSpawnTimer = 0;
}
// Panzer Boss spawn logic at score 60
if (!panzerSpawned && LK.getScore() >= 60) {
panzerSpawned = true;
panzerBoss = new PanzerBoss();
// Position tank at edge of pond area
var spawnAngle = Math.random() * Math.PI * 2;
var spawnDistance = pond.outerRadius + 200;
panzerBoss.x = pond.x + Math.cos(spawnAngle) * spawnDistance;
panzerBoss.y = pond.y + Math.sin(spawnAngle) * spawnDistance;
// Set initial target near pond edge
var targetAngle = spawnAngle + Math.PI;
panzerBoss.setTarget(pond.x + Math.cos(targetAngle) * (pond.outerRadius + 50), pond.y + Math.sin(targetAngle) * (pond.outerRadius + 50));
game.addChild(panzerBoss);
// Show boss warning
var bossWarning = new Text2("ACHTUNG! PANZER BOSS!", {
size: 100,
fill: 0xFF0000
});
bossWarning.anchor.set(0.5, 0.5);
bossWarning.x = 2048 / 2;
bossWarning.y = 2732 / 2;
game.addChild(bossWarning);
// Flash screen red
LK.effects.flashScreen(0xFF0000, 1000);
// Animate warning text
tween(bossWarning, {
alpha: 0,
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 2000,
easing: tween.easeOut,
onFinish: function onFinish() {
game.removeChild(bossWarning);
}
});
}
// Use anti-tank grenade when attacking with grenade collected
if (hasGrenade && goose.isAttacking && panzerBoss && !panzerBoss.isDestroyed && goose.intersects(panzerBoss)) {
hasGrenade = false;
// Remove grenade indicator
if (goose.children.length > 0) {
goose.removeChild(goose.children[goose.children.length - 1]);
}
// Damage panzer boss with grenade (2 damage)
panzerBoss.takeDamage();
panzerBoss.takeDamage();
// Create explosion effect at panzer
var explosion = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
x: panzerBoss.x,
y: panzerBoss.y,
scaleX: 0.1,
scaleY: 0.1
});
explosion.tint = 0xFF4500; // Orange explosion
game.addChild(explosion);
// Explosion animation
tween(explosion, {
scaleX: 6,
scaleY: 6,
alpha: 0
}, {
duration: 600,
easing: tween.easeOut,
onFinish: function onFinish() {
game.removeChild(explosion);
}
});
// Flash screen orange
LK.effects.flashScreen(0xFF4500, 800);
// Reset grenade variables
antiTankGrenade = null;
grenadeSpawnTimer = 0;
}
// Update panzer boss
if (panzerBoss && !panzerBoss.isDestroyed) {
panzerBoss.update();
// Check for special weapon hits on panzer boss
if (hasFlashbang && goose.isAttacking && goose.intersects(panzerBoss)) {
hasFlashbang = false;
// Remove flashbang indicator
if (goose.children.length > 0) {
goose.removeChild(goose.children[goose.children.length - 1]);
}
// Create explosion at panzer
var explosion = new EurovisionFlashbang();
explosion.x = panzerBoss.x;
explosion.y = panzerBoss.y;
game.addChild(explosion);
explosion.explode();
// Damage panzer boss
panzerBoss.takeDamage();
// Flash screen with eurovision colors
LK.effects.flashScreen(0xFFD700, 800);
}
if (hasBomb && goose.isAttacking && goose.intersects(panzerBoss)) {
hasBomb = false;
// Remove bomb indicator
if (goose.children.length > 0) {
goose.removeChild(goose.children[goose.children.length - 1]);
}
// Create explosion at panzer
var explosion = new AtomicBomb();
explosion.x = panzerBoss.x;
explosion.y = panzerBoss.y;
game.addChild(explosion);
explosion.explode();
// Damage panzer boss
panzerBoss.takeDamage();
// Flash screen blue
LK.effects.flashScreen(0x0066ff, 800);
}
}
// Update panzer shells
for (var i = panzerShells.length - 1; i >= 0; i--) {
var shell = panzerShells[i];
shell.update();
// Check shell collision with goose
if (!shell.isExploded && goose.intersects(shell)) {
shell.explode();
// Damage goose
LK.getSound('hit').play();
gooseHealth--;
updateHealthDisplay();
// Damage animation
var damageEffect = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
x: goose.x,
y: goose.y,
scaleX: 2,
scaleY: 2,
alpha: 0.5
});
damageEffect.tint = 0xFF0000;
game.addChild(damageEffect);
tween(damageEffect, {
alpha: 0,
scaleX: 3,
scaleY: 3
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
game.removeChild(damageEffect);
}
});
// Game over if health reaches zero
if (gooseHealth <= 0) {
if (LK.getScore() > highScore) {
highScore = LK.getScore();
storage.highScore = highScore;
highScoreTxt.setText("Rekord: " + highScore);
}
LK.effects.flashScreen(0xff0000, 1000);
gameActive = false;
LK.showGameOver();
}
// Remove shell from array
panzerShells.splice(i, 1);
} else if (shell.isExploded && !shell.visible) {
// Remove exploded shells
panzerShells.splice(i, 1);
game.removeChild(shell);
}
}
// Pretzel spawn logic
pretzelSpawnTimer++;
if (pretzelSpawnTimer > 450 && pretzels.length < maxPretzels && Math.random() < 0.01) {
var pretzel = new Pretzel();
// Position pretzel around pond edges (German food should be accessible)
var angle = Math.random() * Math.PI * 2;
var distance = Math.random() * 400 + 300; // Between inner and outer pond
pretzel.x = pond.x + Math.cos(angle) * distance;
pretzel.y = pond.y + Math.sin(angle) * distance;
// Ensure within pond boundaries
var dx = pretzel.x - pond.x;
var dy = pretzel.y - pond.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 800) {
pretzel.x = pond.x + dx / dist * 800;
pretzel.y = pond.y + dy / dist * 800;
}
pretzels.push(pretzel);
game.addChild(pretzel);
pretzelSpawnTimer = 0;
}
// Update pretzels and check for collection
for (var i = pretzels.length - 1; i >= 0; i--) {
var pretzel = pretzels[i];
pretzel.update();
// Check for goose collecting pretzel
if (!pretzel.isCollected && goose.intersects(pretzel)) {
if (pretzel.collect()) {
// Add score bonus
LK.setScore(LK.getScore() + pretzel.scoreValue);
scoreTxt.setText("Punkte: " + LK.getScore());
// Show bonus points popup
var bonusTxt = new Text2("+" + pretzel.scoreValue + " Brezel!", {
size: 70,
fill: 0xFFD700
});
bonusTxt.anchor.set(0.5, 0.5);
bonusTxt.x = pretzel.x;
bonusTxt.y = pretzel.y - 100;
game.addChild(bonusTxt);
// Animate bonus text
tween(bonusTxt, {
y: bonusTxt.y - 100,
alpha: 0
}, {
duration: 1500,
easing: tween.easeOut,
onFinish: function onFinish() {
game.removeChild(bonusTxt);
}
});
// Play eat sound
LK.getSound('eat').play();
// Remove from array
pretzels.splice(i, 1);
}
}
// Remove pretzels that are no longer visible
else if (!pretzel.visible) {
pretzels.splice(i, 1);
game.removeChild(pretzel);
}
}
// Check for win condition: collect 75 chips
if (LK.getScore() >= 75) {
// Update high score
if (LK.getScore() > highScore) {
highScore = LK.getScore();
storage.highScore = highScore;
highScoreTxt.setText("Rekord: " + highScore);
}
// End the game with a win
gameActive = false;
LK.showYouWin();
}
};
Modern App Store icon, high definition, square with rounded corners, for a game titled "Goose Chase: Battle for Chips" and with the description "Control a hungry goose collecting chips while battling an aggressive swan. Dodge attacks, counter with wing slaps and beak jabs, and collect as many chips as possible before the swan's fury becomes overwhelming. A hilarious battle of birds ensues as you try to satisfy your goose's appetite!". No text on icon!
A potato chip. In-Game asset. 2d. High contrast. No shadows
A pond. Top down view.. In-Game asset. 2d. High contrast. No shadows
Goose. In-Game asset. 2d. High contrast. No shadows
A fuming swan with 16 cigarettes. In-Game asset. 2d. High contrast. No shadows
chocolate goose goose suren whatever smoke 4444444. In-Game asset. 2d. High contrast. No shadows