/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Device: a cyberpunk device/friend to energize
var Device = Container.expand(function () {
var self = Container.call(this);
var deviceAsset = self.attachAsset('device', {
anchorX: 0.5,
anchorY: 0.5
});
// Energy state
self.energized = false;
self.energy = 1; // 1 = full, 0 = empty
// For pulsing effect when energized
self.update = function () {
if (self.energized) {
deviceAsset.alpha = 0.95 + 0.05 * Math.sin(LK.ticks / 6 + self.x * 0.01);
} else {
deviceAsset.alpha = 0.7;
}
};
// Flash when energized
self.flash = function () {
tween(deviceAsset, {
tint: 0xffffff
}, {
duration: 120,
onFinish: function onFinish() {
tween(deviceAsset, {
tint: 0xff00c8
}, {
duration: 200
});
}
});
};
return self;
});
// NeonLine: a segment between two points, visually a rotated rectangle
var NeonLine = Container.expand(function () {
var self = Container.call(this);
// Set up endpoints
self.x1 = 0;
self.y1 = 0;
self.x2 = 0;
self.y2 = 0;
// The visual line asset
var lineAsset = self.attachAsset('neonLine', {
anchorX: 0.5,
anchorY: 0.5
});
// Set endpoints and update position/rotation/length
self.setEndpoints = function (x1, y1, x2, y2) {
self.x1 = x1;
self.y1 = y1;
self.x2 = x2;
self.y2 = y2;
// Center of the line
self.x = (x1 + x2) / 2;
self.y = (y1 + y2) / 2;
// Angle
var dx = x2 - x1;
var dy = y2 - y1;
var len = Math.sqrt(dx * dx + dy * dy);
self.rotation = Math.atan2(dy, dx);
// Set length
lineAsset.width = len;
// Simulate glow by alpha pulse
lineAsset.alpha = 0.85 + 0.15 * Math.sin(LK.ticks / 8);
};
// For update pulse
self.update = function () {
// Animate glow
var lineAsset = self.children[0];
lineAsset.alpha = 0.85 + 0.15 * Math.sin(LK.ticks / 8 + self.x * 0.01 + self.y * 0.01);
};
return self;
});
// PowerSource: the starting node for power lines
var PowerSource = Container.expand(function () {
var self = Container.call(this);
var sourceAsset = self.attachAsset('powerSource', {
anchorX: 0.5,
anchorY: 0.5
});
// Pulse effect
self.update = function () {
sourceAsset.alpha = 0.95 + 0.05 * Math.sin(LK.ticks / 8);
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x0a0a1a
});
/****
* Game Code
****/
// Tutorial button
// Power source node
// Device node (cyberpunk device/friend)
// Neon line segment (glowing effect simulated by color)
// --- Game constants ---
var GAME_WIDTH = 2048;
var GAME_HEIGHT = 2732;
var DEVICE_COUNT = 5;
var POWER_DRAIN_PER_PIXEL = 0.00012; // Power cost per pixel of line
var POWER_REGEN_PER_TICK = 0.0002; // Power regen per tick (if desired)
var DEVICE_ENERGY_LOSS_PER_TICK = 0.0012; // How fast devices lose energy
var DEVICE_ENERGIZE_RADIUS = 100; // px, how close a line endpoint must be to energize
var POWER_MIN = 0;
var POWER_MAX = 1;
// --- Game state ---
var power = 1; // Shared power meter (0-1)
var devices = [];
var lines = [];
var powerSource = null;
var drawing = false;
var drawStart = null; // {x, y}
var drawLine = null; // NeonLine being drawn
var drawFromSource = false;
var energizedDevices = 0;
var tutorialOpen = false;
// --- UI elements ---
var powerBarBg = null;
var powerBarFg = null;
var tutorialBtn = null;
var tutorialText = null;
var winText = null;
// --- Helper functions ---
// Clamp value between min and max
function clamp(val, min, max) {
return Math.max(min, Math.min(max, val));
}
// Distance between two points
function dist(x1, y1, x2, y2) {
var dx = x2 - x1;
var dy = y2 - y1;
return Math.sqrt(dx * dx + dy * dy);
}
// Check if a point is inside a device (for connecting)
function pointInDevice(x, y, device) {
var dx = x - device.x;
var dy = y - device.y;
var r = device.children[0].width / 2;
return dx * dx + dy * dy <= r * r;
}
// --- UI Setup ---
// Power bar (top center, not in top left 100x100)
powerBarBg = new Container();
var bgBar = LK.getAsset('neonLine', {
width: 600,
height: 36,
anchorX: 0,
anchorY: 0.5
});
bgBar.tint = 0x222244;
powerBarBg.addChild(bgBar);
powerBarFg = LK.getAsset('neonLine', {
width: 600,
height: 36,
anchorX: 0,
anchorY: 0.5
});
powerBarFg.tint = 0x00fff7;
powerBarBg.addChild(powerBarFg);
powerBarBg.x = (LK.gui.width - 600) / 2;
powerBarBg.y = 110;
LK.gui.top.addChild(powerBarBg);
// Tutorial button (top right, not in top left)
tutorialBtn = LK.getAsset('tutorialBtn', {
anchorX: 0.5,
anchorY: 0.5
});
tutorialBtn.x = LK.gui.width - 120;
tutorialBtn.y = 110;
LK.gui.top.addChild(tutorialBtn);
var tutorialBtnText = new Text2('?', {
size: 60,
fill: 0xFFFFFF
});
tutorialBtnText.anchor.set(0.5, 0.5);
tutorialBtnText.x = tutorialBtn.x;
tutorialBtnText.y = tutorialBtn.y;
LK.gui.top.addChild(tutorialBtnText);
// Tutorial popup (hidden by default)
tutorialText = new Text2("How to Play:\n\n" + "1. Draw neon lines from the green power source to pink devices (your friends).\n" + "2. Every line drains the shared power meter at the top.\n" + "3. Connect all devices before power runs out!\n" + "4. Lines must touch a device to energize it.\n\n" + "Tip: Plan your path to use as little power as possible.\n\n" + "Tap the '?' button anytime for help.", {
size: 70,
fill: 0x00FFF7,
align: "center",
wordWrap: true,
wordWrapWidth: 1200
});
tutorialText.anchor.set(0.5, 0.5);
tutorialText.x = LK.gui.width / 2;
tutorialText.y = LK.gui.height / 2;
tutorialText.visible = false;
LK.gui.center.addChild(tutorialText);
// Win text (hidden by default)
winText = new Text2("All friends powered up!\nYou win!", {
size: 120,
fill: 0xFF00C8,
align: "center"
});
winText.anchor.set(0.5, 0.5);
winText.x = LK.gui.width / 2;
winText.y = LK.gui.height / 2;
winText.visible = false;
LK.gui.center.addChild(winText);
// --- Game Setup ---
// Place power source (bottom center)
powerSource = new PowerSource();
powerSource.x = GAME_WIDTH / 2;
powerSource.y = GAME_HEIGHT - 300;
game.addChild(powerSource);
// Place devices (scattered, not overlapping, not too close to power source)
devices = [];
var placed = 0;
while (placed < DEVICE_COUNT) {
var angle = Math.PI * (0.3 + 1.4 * placed / DEVICE_COUNT);
var radius = 700 + 400 * (placed % 2);
var x = GAME_WIDTH / 2 + Math.cos(angle) * radius + (Math.random() - 0.5) * 120;
var y = 600 + Math.sin(angle) * radius + (Math.random() - 0.5) * 120;
// Don't overlap with other devices or power source
var ok = true;
for (var i = 0; i < devices.length; i++) {
if (dist(x, y, devices[i].x, devices[i].y) < 220) ok = false;
}
if (dist(x, y, powerSource.x, powerSource.y) < 400) ok = false;
if (ok) {
var d = new Device();
d.x = x;
d.y = y;
devices.push(d);
game.addChild(d);
placed++;
}
}
// --- Drawing logic ---
// Helper: find device at (x, y)
function findDeviceAt(x, y) {
for (var i = 0; i < devices.length; i++) {
if (pointInDevice(x, y, devices[i])) return devices[i];
}
return null;
}
// Helper: check if a line endpoint is close enough to a device to energize
function deviceInRadius(x, y) {
for (var i = 0; i < devices.length; i++) {
if (!devices[i].energized && dist(x, y, devices[i].x, devices[i].y) < DEVICE_ENERGIZE_RADIUS) {
return devices[i];
}
}
return null;
}
// Helper: check if a point is close to the power source
function pointNearPowerSource(x, y) {
var dx = x - powerSource.x;
var dy = y - powerSource.y;
var r = powerSource.children[0].width / 2 + 30;
return dx * dx + dy * dy <= r * r;
}
// --- Input handlers ---
// Only allow drawing if not in tutorial or win
function canDraw() {
return !tutorialOpen && !winText.visible && power > 0;
}
// Start drawing: must start from power source or an energized device
game.down = function (x, y, obj) {
if (!canDraw()) return;
// Convert to game coordinates
var gx = x,
gy = y;
// Start from power source?
if (pointNearPowerSource(gx, gy)) {
drawFromSource = true;
drawStart = {
x: powerSource.x,
y: powerSource.y
};
} else {
// Start from energized device?
for (var i = 0; i < devices.length; i++) {
if (devices[i].energized && pointInDevice(gx, gy, devices[i])) {
drawFromSource = false;
drawStart = {
x: devices[i].x,
y: devices[i].y
};
break;
}
}
}
if (drawStart) {
drawing = true;
drawLine = new NeonLine();
drawLine.setEndpoints(drawStart.x, drawStart.y, gx, gy);
game.addChild(drawLine);
}
};
// Drawing in progress
game.move = function (x, y, obj) {
if (!drawing || !drawLine) return;
if (!canDraw()) return;
var gx = x,
gy = y;
drawLine.setEndpoints(drawStart.x, drawStart.y, gx, gy);
// Show line in real time, but don't finalize until up
};
// Finish drawing: if endpoint is on an unenergized device, connect and energize
game.up = function (x, y, obj) {
if (!drawing || !drawLine) {
drawing = false;
drawStart = null;
return;
}
if (!canDraw()) {
// Remove preview line
if (drawLine) {
drawLine.destroy();
drawLine = null;
}
drawing = false;
drawStart = null;
return;
}
var gx = x,
gy = y;
drawLine.setEndpoints(drawStart.x, drawStart.y, gx, gy);
// Check if endpoint is close to an unenergized device
var targetDevice = deviceInRadius(gx, gy);
// Only allow connecting to unenergized device
if (targetDevice) {
// Calculate line length
var len = dist(drawStart.x, drawStart.y, targetDevice.x, targetDevice.y);
var cost = len * POWER_DRAIN_PER_PIXEL;
if (power >= cost) {
// Snap endpoint to device center
drawLine.setEndpoints(drawStart.x, drawStart.y, targetDevice.x, targetDevice.y);
lines.push(drawLine);
// Drain power
power = clamp(power - cost, POWER_MIN, POWER_MAX);
// Energize device
targetDevice.energized = true;
targetDevice.energy = 1;
targetDevice.flash();
energizedDevices++;
// Win condition
if (energizedDevices === devices.length) {
winText.visible = true;
LK.effects.flashScreen(0x00fff7, 1200);
LK.setTimeout(function () {
LK.showYouWin();
}, 1800);
}
drawLine = null;
drawing = false;
drawStart = null;
return;
} else {
// Not enough power, flash bar
LK.effects.flashObject(powerBarFg, 0xff0000, 400);
}
}
// Not a valid connection, remove preview line
if (drawLine) {
drawLine.destroy();
drawLine = null;
}
drawing = false;
drawStart = null;
};
// --- Tutorial button handler ---
tutorialBtn.down = function (x, y, obj) {
if (tutorialOpen) {
tutorialText.visible = false;
tutorialOpen = false;
} else {
tutorialText.visible = true;
tutorialOpen = true;
}
};
tutorialBtnText.down = tutorialBtn.down;
// --- Game update loop ---
game.update = function () {
// Update power bar
var barW = 600 * power;
powerBarFg.width = barW;
if (power < 0.18) {
powerBarFg.tint = 0xff0033;
} else {
powerBarFg.tint = 0x00fff7;
}
// Devices lose energy if not energized
for (var i = 0; i < devices.length; i++) {
var d = devices[i];
if (!d.energized) {
d.energy = clamp(d.energy - DEVICE_ENERGY_LOSS_PER_TICK, 0, 1);
// If energy runs out, game over
if (d.energy <= 0) {
LK.effects.flashScreen(0xff0033, 1200);
LK.setTimeout(function () {
LK.showGameOver();
}, 1200);
return;
}
}
}
// Power regen (optional, comment out to disable)
// power = clamp(power + POWER_REGEN_PER_TICK, POWER_MIN, POWER_MAX);
// Animate lines
for (var i = 0; i < lines.length; i++) {
if (lines[i].update) lines[i].update();
}
// Animate devices and power source
for (var i = 0; i < devices.length; i++) {
if (devices[i].update) devices[i].update();
}
if (powerSource && powerSource.update) powerSource.update();
if (drawLine && drawLine.update) drawLine.update();
};
// --- End of file --- ===================================================================
--- original.js
+++ change.js
@@ -1,6 +1,431 @@
-/****
+/****
+* Plugins
+****/
+var tween = LK.import("@upit/tween.v1");
+
+/****
+* Classes
+****/
+// Device: a cyberpunk device/friend to energize
+var Device = Container.expand(function () {
+ var self = Container.call(this);
+ var deviceAsset = self.attachAsset('device', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ // Energy state
+ self.energized = false;
+ self.energy = 1; // 1 = full, 0 = empty
+ // For pulsing effect when energized
+ self.update = function () {
+ if (self.energized) {
+ deviceAsset.alpha = 0.95 + 0.05 * Math.sin(LK.ticks / 6 + self.x * 0.01);
+ } else {
+ deviceAsset.alpha = 0.7;
+ }
+ };
+ // Flash when energized
+ self.flash = function () {
+ tween(deviceAsset, {
+ tint: 0xffffff
+ }, {
+ duration: 120,
+ onFinish: function onFinish() {
+ tween(deviceAsset, {
+ tint: 0xff00c8
+ }, {
+ duration: 200
+ });
+ }
+ });
+ };
+ return self;
+});
+// NeonLine: a segment between two points, visually a rotated rectangle
+var NeonLine = Container.expand(function () {
+ var self = Container.call(this);
+ // Set up endpoints
+ self.x1 = 0;
+ self.y1 = 0;
+ self.x2 = 0;
+ self.y2 = 0;
+ // The visual line asset
+ var lineAsset = self.attachAsset('neonLine', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ // Set endpoints and update position/rotation/length
+ self.setEndpoints = function (x1, y1, x2, y2) {
+ self.x1 = x1;
+ self.y1 = y1;
+ self.x2 = x2;
+ self.y2 = y2;
+ // Center of the line
+ self.x = (x1 + x2) / 2;
+ self.y = (y1 + y2) / 2;
+ // Angle
+ var dx = x2 - x1;
+ var dy = y2 - y1;
+ var len = Math.sqrt(dx * dx + dy * dy);
+ self.rotation = Math.atan2(dy, dx);
+ // Set length
+ lineAsset.width = len;
+ // Simulate glow by alpha pulse
+ lineAsset.alpha = 0.85 + 0.15 * Math.sin(LK.ticks / 8);
+ };
+ // For update pulse
+ self.update = function () {
+ // Animate glow
+ var lineAsset = self.children[0];
+ lineAsset.alpha = 0.85 + 0.15 * Math.sin(LK.ticks / 8 + self.x * 0.01 + self.y * 0.01);
+ };
+ return self;
+});
+// PowerSource: the starting node for power lines
+var PowerSource = Container.expand(function () {
+ var self = Container.call(this);
+ var sourceAsset = self.attachAsset('powerSource', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ // Pulse effect
+ self.update = function () {
+ sourceAsset.alpha = 0.95 + 0.05 * Math.sin(LK.ticks / 8);
+ };
+ return self;
+});
+
+/****
* Initialize Game
-****/
+****/
var game = new LK.Game({
- backgroundColor: 0x000000
-});
\ No newline at end of file
+ backgroundColor: 0x0a0a1a
+});
+
+/****
+* Game Code
+****/
+// Tutorial button
+// Power source node
+// Device node (cyberpunk device/friend)
+// Neon line segment (glowing effect simulated by color)
+// --- Game constants ---
+var GAME_WIDTH = 2048;
+var GAME_HEIGHT = 2732;
+var DEVICE_COUNT = 5;
+var POWER_DRAIN_PER_PIXEL = 0.00012; // Power cost per pixel of line
+var POWER_REGEN_PER_TICK = 0.0002; // Power regen per tick (if desired)
+var DEVICE_ENERGY_LOSS_PER_TICK = 0.0012; // How fast devices lose energy
+var DEVICE_ENERGIZE_RADIUS = 100; // px, how close a line endpoint must be to energize
+var POWER_MIN = 0;
+var POWER_MAX = 1;
+// --- Game state ---
+var power = 1; // Shared power meter (0-1)
+var devices = [];
+var lines = [];
+var powerSource = null;
+var drawing = false;
+var drawStart = null; // {x, y}
+var drawLine = null; // NeonLine being drawn
+var drawFromSource = false;
+var energizedDevices = 0;
+var tutorialOpen = false;
+// --- UI elements ---
+var powerBarBg = null;
+var powerBarFg = null;
+var tutorialBtn = null;
+var tutorialText = null;
+var winText = null;
+// --- Helper functions ---
+// Clamp value between min and max
+function clamp(val, min, max) {
+ return Math.max(min, Math.min(max, val));
+}
+// Distance between two points
+function dist(x1, y1, x2, y2) {
+ var dx = x2 - x1;
+ var dy = y2 - y1;
+ return Math.sqrt(dx * dx + dy * dy);
+}
+// Check if a point is inside a device (for connecting)
+function pointInDevice(x, y, device) {
+ var dx = x - device.x;
+ var dy = y - device.y;
+ var r = device.children[0].width / 2;
+ return dx * dx + dy * dy <= r * r;
+}
+// --- UI Setup ---
+// Power bar (top center, not in top left 100x100)
+powerBarBg = new Container();
+var bgBar = LK.getAsset('neonLine', {
+ width: 600,
+ height: 36,
+ anchorX: 0,
+ anchorY: 0.5
+});
+bgBar.tint = 0x222244;
+powerBarBg.addChild(bgBar);
+powerBarFg = LK.getAsset('neonLine', {
+ width: 600,
+ height: 36,
+ anchorX: 0,
+ anchorY: 0.5
+});
+powerBarFg.tint = 0x00fff7;
+powerBarBg.addChild(powerBarFg);
+powerBarBg.x = (LK.gui.width - 600) / 2;
+powerBarBg.y = 110;
+LK.gui.top.addChild(powerBarBg);
+// Tutorial button (top right, not in top left)
+tutorialBtn = LK.getAsset('tutorialBtn', {
+ anchorX: 0.5,
+ anchorY: 0.5
+});
+tutorialBtn.x = LK.gui.width - 120;
+tutorialBtn.y = 110;
+LK.gui.top.addChild(tutorialBtn);
+var tutorialBtnText = new Text2('?', {
+ size: 60,
+ fill: 0xFFFFFF
+});
+tutorialBtnText.anchor.set(0.5, 0.5);
+tutorialBtnText.x = tutorialBtn.x;
+tutorialBtnText.y = tutorialBtn.y;
+LK.gui.top.addChild(tutorialBtnText);
+// Tutorial popup (hidden by default)
+tutorialText = new Text2("How to Play:\n\n" + "1. Draw neon lines from the green power source to pink devices (your friends).\n" + "2. Every line drains the shared power meter at the top.\n" + "3. Connect all devices before power runs out!\n" + "4. Lines must touch a device to energize it.\n\n" + "Tip: Plan your path to use as little power as possible.\n\n" + "Tap the '?' button anytime for help.", {
+ size: 70,
+ fill: 0x00FFF7,
+ align: "center",
+ wordWrap: true,
+ wordWrapWidth: 1200
+});
+tutorialText.anchor.set(0.5, 0.5);
+tutorialText.x = LK.gui.width / 2;
+tutorialText.y = LK.gui.height / 2;
+tutorialText.visible = false;
+LK.gui.center.addChild(tutorialText);
+// Win text (hidden by default)
+winText = new Text2("All friends powered up!\nYou win!", {
+ size: 120,
+ fill: 0xFF00C8,
+ align: "center"
+});
+winText.anchor.set(0.5, 0.5);
+winText.x = LK.gui.width / 2;
+winText.y = LK.gui.height / 2;
+winText.visible = false;
+LK.gui.center.addChild(winText);
+// --- Game Setup ---
+// Place power source (bottom center)
+powerSource = new PowerSource();
+powerSource.x = GAME_WIDTH / 2;
+powerSource.y = GAME_HEIGHT - 300;
+game.addChild(powerSource);
+// Place devices (scattered, not overlapping, not too close to power source)
+devices = [];
+var placed = 0;
+while (placed < DEVICE_COUNT) {
+ var angle = Math.PI * (0.3 + 1.4 * placed / DEVICE_COUNT);
+ var radius = 700 + 400 * (placed % 2);
+ var x = GAME_WIDTH / 2 + Math.cos(angle) * radius + (Math.random() - 0.5) * 120;
+ var y = 600 + Math.sin(angle) * radius + (Math.random() - 0.5) * 120;
+ // Don't overlap with other devices or power source
+ var ok = true;
+ for (var i = 0; i < devices.length; i++) {
+ if (dist(x, y, devices[i].x, devices[i].y) < 220) ok = false;
+ }
+ if (dist(x, y, powerSource.x, powerSource.y) < 400) ok = false;
+ if (ok) {
+ var d = new Device();
+ d.x = x;
+ d.y = y;
+ devices.push(d);
+ game.addChild(d);
+ placed++;
+ }
+}
+// --- Drawing logic ---
+// Helper: find device at (x, y)
+function findDeviceAt(x, y) {
+ for (var i = 0; i < devices.length; i++) {
+ if (pointInDevice(x, y, devices[i])) return devices[i];
+ }
+ return null;
+}
+// Helper: check if a line endpoint is close enough to a device to energize
+function deviceInRadius(x, y) {
+ for (var i = 0; i < devices.length; i++) {
+ if (!devices[i].energized && dist(x, y, devices[i].x, devices[i].y) < DEVICE_ENERGIZE_RADIUS) {
+ return devices[i];
+ }
+ }
+ return null;
+}
+// Helper: check if a point is close to the power source
+function pointNearPowerSource(x, y) {
+ var dx = x - powerSource.x;
+ var dy = y - powerSource.y;
+ var r = powerSource.children[0].width / 2 + 30;
+ return dx * dx + dy * dy <= r * r;
+}
+// --- Input handlers ---
+// Only allow drawing if not in tutorial or win
+function canDraw() {
+ return !tutorialOpen && !winText.visible && power > 0;
+}
+// Start drawing: must start from power source or an energized device
+game.down = function (x, y, obj) {
+ if (!canDraw()) return;
+ // Convert to game coordinates
+ var gx = x,
+ gy = y;
+ // Start from power source?
+ if (pointNearPowerSource(gx, gy)) {
+ drawFromSource = true;
+ drawStart = {
+ x: powerSource.x,
+ y: powerSource.y
+ };
+ } else {
+ // Start from energized device?
+ for (var i = 0; i < devices.length; i++) {
+ if (devices[i].energized && pointInDevice(gx, gy, devices[i])) {
+ drawFromSource = false;
+ drawStart = {
+ x: devices[i].x,
+ y: devices[i].y
+ };
+ break;
+ }
+ }
+ }
+ if (drawStart) {
+ drawing = true;
+ drawLine = new NeonLine();
+ drawLine.setEndpoints(drawStart.x, drawStart.y, gx, gy);
+ game.addChild(drawLine);
+ }
+};
+// Drawing in progress
+game.move = function (x, y, obj) {
+ if (!drawing || !drawLine) return;
+ if (!canDraw()) return;
+ var gx = x,
+ gy = y;
+ drawLine.setEndpoints(drawStart.x, drawStart.y, gx, gy);
+ // Show line in real time, but don't finalize until up
+};
+// Finish drawing: if endpoint is on an unenergized device, connect and energize
+game.up = function (x, y, obj) {
+ if (!drawing || !drawLine) {
+ drawing = false;
+ drawStart = null;
+ return;
+ }
+ if (!canDraw()) {
+ // Remove preview line
+ if (drawLine) {
+ drawLine.destroy();
+ drawLine = null;
+ }
+ drawing = false;
+ drawStart = null;
+ return;
+ }
+ var gx = x,
+ gy = y;
+ drawLine.setEndpoints(drawStart.x, drawStart.y, gx, gy);
+ // Check if endpoint is close to an unenergized device
+ var targetDevice = deviceInRadius(gx, gy);
+ // Only allow connecting to unenergized device
+ if (targetDevice) {
+ // Calculate line length
+ var len = dist(drawStart.x, drawStart.y, targetDevice.x, targetDevice.y);
+ var cost = len * POWER_DRAIN_PER_PIXEL;
+ if (power >= cost) {
+ // Snap endpoint to device center
+ drawLine.setEndpoints(drawStart.x, drawStart.y, targetDevice.x, targetDevice.y);
+ lines.push(drawLine);
+ // Drain power
+ power = clamp(power - cost, POWER_MIN, POWER_MAX);
+ // Energize device
+ targetDevice.energized = true;
+ targetDevice.energy = 1;
+ targetDevice.flash();
+ energizedDevices++;
+ // Win condition
+ if (energizedDevices === devices.length) {
+ winText.visible = true;
+ LK.effects.flashScreen(0x00fff7, 1200);
+ LK.setTimeout(function () {
+ LK.showYouWin();
+ }, 1800);
+ }
+ drawLine = null;
+ drawing = false;
+ drawStart = null;
+ return;
+ } else {
+ // Not enough power, flash bar
+ LK.effects.flashObject(powerBarFg, 0xff0000, 400);
+ }
+ }
+ // Not a valid connection, remove preview line
+ if (drawLine) {
+ drawLine.destroy();
+ drawLine = null;
+ }
+ drawing = false;
+ drawStart = null;
+};
+// --- Tutorial button handler ---
+tutorialBtn.down = function (x, y, obj) {
+ if (tutorialOpen) {
+ tutorialText.visible = false;
+ tutorialOpen = false;
+ } else {
+ tutorialText.visible = true;
+ tutorialOpen = true;
+ }
+};
+tutorialBtnText.down = tutorialBtn.down;
+// --- Game update loop ---
+game.update = function () {
+ // Update power bar
+ var barW = 600 * power;
+ powerBarFg.width = barW;
+ if (power < 0.18) {
+ powerBarFg.tint = 0xff0033;
+ } else {
+ powerBarFg.tint = 0x00fff7;
+ }
+ // Devices lose energy if not energized
+ for (var i = 0; i < devices.length; i++) {
+ var d = devices[i];
+ if (!d.energized) {
+ d.energy = clamp(d.energy - DEVICE_ENERGY_LOSS_PER_TICK, 0, 1);
+ // If energy runs out, game over
+ if (d.energy <= 0) {
+ LK.effects.flashScreen(0xff0033, 1200);
+ LK.setTimeout(function () {
+ LK.showGameOver();
+ }, 1200);
+ return;
+ }
+ }
+ }
+ // Power regen (optional, comment out to disable)
+ // power = clamp(power + POWER_REGEN_PER_TICK, POWER_MIN, POWER_MAX);
+ // Animate lines
+ for (var i = 0; i < lines.length; i++) {
+ if (lines[i].update) lines[i].update();
+ }
+ // Animate devices and power source
+ for (var i = 0; i < devices.length; i++) {
+ if (devices[i].update) devices[i].update();
+ }
+ if (powerSource && powerSource.update) powerSource.update();
+ if (drawLine && drawLine.update) drawLine.update();
+};
+// --- End of file ---
\ No newline at end of file
bullets arranged from top to bottom. In-Game asset. 2d. High contrast. No shadows
a topdown policeman and he's pointing a gun. In-Game asset. 2d. High contrast. No shadows. In-Game asset. 2d. High contrast. No shadows
topdown thief. In-Game asset. 2d. High contrast. No shadows
a top down white black theme prison. In-Game asset. 2d. High contrast. No shadows. In-Game asset. 2d. High contrast. No shadows