/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var DraggableShip = Container.expand(function (length, id) {
var self = Container.call(this);
self.length = length;
self.shipId = id;
self.isHorizontal = true;
self.isBeingDragged = false;
self.isPlaced = false;
self.shipCells = [];
self.smallScale = 0.5; // Scale for when ship is waiting
// Create visual representation of ship
for (var i = 0; i < length; i++) {
var shipCell = self.attachAsset('ship', {
anchorX: 0,
anchorY: 0
});
shipCell.x = i * CELL_SIZE;
shipCell.y = 0;
self.shipCells.push(shipCell);
}
// Start ships at smaller scale
self.scaleX = self.smallScale;
self.scaleY = self.smallScale;
self.rotate = function () {
self.isHorizontal = !self.isHorizontal;
for (var i = 0; i < self.shipCells.length; i++) {
if (self.isHorizontal) {
self.shipCells[i].x = i * CELL_SIZE;
self.shipCells[i].y = 0;
} else {
self.shipCells[i].x = 0;
self.shipCells[i].y = i * CELL_SIZE;
}
}
};
self.canBePlacedAt = function (gridX, gridY) {
for (var i = 0; i < self.length; i++) {
var x = self.isHorizontal ? gridX + i : gridX;
var y = self.isHorizontal ? gridY : gridY + i;
if (x >= GRID_SIZE || y >= GRID_SIZE || x < 0 || y < 0) {
return false;
}
if (playerGrid[x][y].hasShip) {
return false;
}
}
return true;
};
self.placeOnGrid = function (gridX, gridY) {
if (self.canBePlacedAt(gridX, gridY)) {
for (var i = 0; i < self.length; i++) {
var x = self.isHorizontal ? gridX + i : gridX;
var y = self.isHorizontal ? gridY : gridY + i;
playerGrid[x][y].setShip(self.shipId);
}
self.isPlaced = true;
self.visible = false;
return true;
}
return false;
};
self.down = function (x, y, obj) {
if (gameState === 'placement') {
if (self.isPlaced) {
// Remove ship from grid for repositioning
removeShipFromGrid(self);
self.isPlaced = false;
self.visible = true;
placedShipsCount--;
statusText.setText('Place remaining ships (' + (shipLengths.length - placedShipsCount) + ' left)');
startButton.visible = false;
// Position ship at current grid location for smooth dragging
var currentGridX = -1,
currentGridY = -1;
for (var gx = 0; gx < GRID_SIZE; gx++) {
for (var gy = 0; gy < GRID_SIZE; gy++) {
if (playerGrid[gx][gy].shipId === self.shipId) {
currentGridX = gx;
currentGridY = gy;
break;
}
}
if (currentGridX !== -1) {
break;
}
}
if (currentGridX !== -1) {
self.x = CENTER_GRID_X + currentGridX * CELL_SIZE;
self.y = CENTER_GRID_Y + currentGridY * CELL_SIZE;
}
}
self.isBeingDragged = true;
draggedShip = self;
// Scale up to full size when dragging
tween(self, {
alpha: 0.7,
scaleX: 1,
scaleY: 1
}, {
duration: 200
});
}
};
self.up = function (x, y, obj) {
if (self.isBeingDragged && !self.isPlaced) {
self.isBeingDragged = false;
// Try to place ship on grid with better snapping
var gridX = Math.round((self.x - CENTER_GRID_X) / CELL_SIZE);
var gridY = Math.round((self.y - CENTER_GRID_Y) / CELL_SIZE);
// Snap to grid position
var snapX = CENTER_GRID_X + gridX * CELL_SIZE;
var snapY = CENTER_GRID_Y + gridY * CELL_SIZE;
if (self.placeOnGrid(gridX, gridY)) {
// Snap ship to exact grid position before hiding
self.x = snapX;
self.y = snapY;
tween(self, {
alpha: 1
}, {
duration: 200
});
placedShipsCount++;
if (placedShipsCount >= shipLengths.length) {
statusText.setText('All ships placed! Press START GAME to begin');
startButton.visible = true;
} else {
statusText.setText('Place remaining ships (' + (shipLengths.length - placedShipsCount) + ' left)');
}
} else {
// Return to original position and scale down if can't place
tween(self, {
x: self.originalX,
y: self.originalY,
alpha: 1,
scaleX: self.smallScale,
scaleY: self.smallScale
}, {
duration: 300,
easing: tween.easeOut
});
}
}
};
return self;
});
var GridCell = Container.expand(function (x, y, isPlayer) {
var self = Container.call(this);
self.gridX = x;
self.gridY = y;
self.isPlayer = isPlayer;
self.hasShip = false;
self.isHit = false;
self.isMiss = false;
self.shipId = -1;
var cellGraphics = self.attachAsset('gridBox', {
anchorX: 0,
anchorY: 0
});
self.setShip = function (shipId) {
self.hasShip = true;
self.shipId = shipId;
if (self.isPlayer) {
cellGraphics.tint = 0x808080;
if (self.shipAsset) {
self.shipAsset.alpha = 1;
}
}
};
self.markHit = function () {
self.isHit = true;
cellGraphics.tint = 0xFF0000;
// Add hit marker asset on top of the cell
if (!self.hitMarkerAsset) {
self.hitMarkerAsset = self.attachAsset('hitMarker', {
anchorX: 0,
anchorY: 0
});
// Position hit marker at the correct cell position
self.hitMarkerAsset.x = 0;
self.hitMarkerAsset.y = 0;
}
};
self.markMiss = function (isEnemyMiss) {
self.isMiss = true;
if (isEnemyMiss) {
// Enemy missed on player's grid - use orange color
cellGraphics.tint = 0xffaa00;
} else {
// Player missed on enemy's grid - use green color
cellGraphics.tint = 0x00FF00;
}
};
self.markSunk = function () {
cellGraphics.tint = 0x2F2F2F;
};
self.down = function (x, y, obj) {
if (gameState === 'playing' && !self.isPlayer && !self.isHit && !self.isMiss) {
playerShoot(self.gridX, self.gridY);
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB
});
/****
* Game Code
****/
var Ship = function Ship(length, id) {
this.length = length;
this.id = id;
this.hits = 0;
this.cells = [];
this.isSunk = false;
this.addCell = function (x, y) {
this.cells.push({
x: x,
y: y
});
};
this.hit = function () {
this.hits++;
if (this.hits >= this.length) {
this.isSunk = true;
return true;
}
return false;
};
};
var GRID_SIZE = 10;
var CELL_SIZE = 150; // Increased to 150 for larger game area
var GRID_OFFSET_X = 200;
var PLAYER_GRID_Y = 1200;
var AI_GRID_Y = 200;
// Calculate center positions for single grid display
var CENTER_GRID_X = (2048 - GRID_SIZE * CELL_SIZE) / 2;
var CENTER_GRID_Y = (2732 - GRID_SIZE * CELL_SIZE) / 2 - 100; // Move grid up slightly
var GRID_SPACING = 1000; // Distance between the two grids
var playerGrid = [];
var aiGrid = [];
var playerShips = [];
var aiShips = [];
var gameState = 'intro'; // 'intro', 'placement', 'playing', 'gameOver'
var introScreen = null;
var currentPlayer = 'player'; // 'player', 'ai'
var selectedX = -1;
var selectedY = -1;
var currentShipToPlace = 0;
var isHorizontalPlacement = true;
var shipLengths = [5, 4, 3, 3, 2];
var draggableShips = [];
var placedShipsCount = 0;
var draggedShip = null;
// AI hunting variables
var aiLastHitX = -1;
var aiLastHitY = -1;
var aiHuntingDirections = [];
var aiCurrentDirection = 0;
var aiHuntingMode = false;
// Timer and effect variables
var turnTimer = null;
var turnTimeRemaining = 30;
var isWaitingAfterShot = false;
// Timer text
var timerText = new Text2('30', {
size: 50,
fill: 0xFF0000
});
timerText.anchor.set(1, 0);
LK.gui.topRight.addChild(timerText);
var playerGridContainer = new Container();
var aiGridContainer = new Container();
// UI Elements
var statusText = new Text2('Drag ships to your grid', {
size: 60,
fill: 0x000000
});
statusText.anchor.set(0.5, 0);
LK.gui.top.addChild(statusText);
var instructionText = new Text2('Double tap ships to rotate, drag to reposition', {
size: 40,
fill: 0x00FF00
});
instructionText.anchor.set(0.5, 0);
instructionText.y = 200;
instructionText.x = 0; // Starting position for scrolling
// Add to game instead of GUI so it appears in front of monitor
game.addChild(instructionText);
// Position in front of monitor
instructionText.x = CENTER_GRID_Y + GRID_SIZE * CELL_SIZE - 1000;
instructionText.y = CENTER_GRID_Y + GRID_SIZE * CELL_SIZE - 1700;
// Create scrolling text effect
function scrollInstructionText() {
if (gameState === 'placement') {
var startX = CENTER_GRID_Y + GRID_SIZE * CELL_SIZE - 1200;
var endX = CENTER_GRID_Y + GRID_SIZE * CELL_SIZE - 800;
var scrollDuration = 8000; // Duration to reach end position
instructionText.x = startX;
instructionText.alpha = 1;
tween.stop(instructionText); // Stop all existing tweens on instruction text
// First tween: scroll to end position
tween(instructionText, {
x: endX
}, {
duration: scrollDuration,
easing: tween.linear,
onFinish: function onFinish() {
if (gameState === 'placement') {
// Second tween: fade out at end position
tween(instructionText, {
alpha: 0
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
if (gameState === 'placement') {
// Restart immediately from beginning for seamless loop
scrollInstructionText();
}
}
});
}
}
});
}
}
// Start scrolling after placement begins
LK.setTimeout(function () {
if (gameState === 'placement') {
scrollInstructionText();
}
}, 500);
var startButton = new Text2('START GAME', {
size: 60,
fill: 0x00FF00
});
startButton.anchor.set(0.5, 0.5);
startButton.x = 2048 / 2;
startButton.y = 300; // Move button lower
startButton.visible = false;
game.addChild(startButton);
startButton.down = function (x, y, obj) {
if (gameState === 'placement' && placedShipsCount >= shipLengths.length) {
gameState = 'playing';
statusText.setText('Fire at enemy positions!');
instructionText.setText('Tap enemy grid to shoot');
startButton.visible = false;
placeAIShips();
// Switch to AI grid for player's turn to attack with transition effect
tween(playerGridContainer, {
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
playerGridContainer.visible = false;
aiGridContainer.visible = true;
myCommanderContainer.visible = false;
enemyCommanderContainer.visible = true;
aiGridContainer.alpha = 0;
tween(aiGridContainer, {
alpha: 1
}, {
duration: 300
});
}
});
}
};
// Initialize grids
function initializeGrids() {
// Add containers to game - computer monitor first for background layering
game.addChild(playerGridContainer);
game.addChild(aiGridContainer);
// Move computer monitor to back if it exists
if (computerMonitorContainer) {
game.removeChild(computerMonitorContainer);
game.addChildAt(computerMonitorContainer, 0);
}
// Player grid (center during placement, left side during game)
for (var x = 0; x < GRID_SIZE; x++) {
playerGrid[x] = [];
for (var y = 0; y < GRID_SIZE; y++) {
var cell = new GridCell(x, y, true);
cell.x = CENTER_GRID_X + x * CELL_SIZE;
cell.y = CENTER_GRID_Y + y * CELL_SIZE;
playerGrid[x][y] = cell;
playerGridContainer.addChild(cell);
}
}
// AI grid (center during game)
for (var x = 0; x < GRID_SIZE; x++) {
aiGrid[x] = [];
for (var y = 0; y < GRID_SIZE; y++) {
var cell = new GridCell(x, y, false);
cell.x = CENTER_GRID_X + x * CELL_SIZE;
cell.y = CENTER_GRID_Y + y * CELL_SIZE;
aiGrid[x][y] = cell;
aiGridContainer.addChild(cell);
}
}
// Initialize grid visibility - show player grid during placement phase
playerGridContainer.visible = true;
aiGridContainer.visible = false;
// Add grid labels
var playerLabel = new Text2('Your Fleet', {
size: 40,
fill: 0x000000
});
playerLabel.anchor.set(0.5, 0.5);
playerLabel.x = CENTER_GRID_X + GRID_SIZE * CELL_SIZE / 2;
playerLabel.y = CENTER_GRID_Y - 50;
playerGridContainer.addChild(playerLabel);
var aiLabel = new Text2('Enemy Waters', {
size: 40,
fill: 0x000000
});
aiLabel.anchor.set(0.5, 0.5);
aiLabel.x = CENTER_GRID_X + GRID_SIZE * CELL_SIZE / 2;
aiLabel.y = CENTER_GRID_Y - 50;
aiGridContainer.addChild(aiLabel);
// Add coordinate labels for player grid
for (var i = 0; i < GRID_SIZE; i++) {
// Letters A-J on the left side
var letterLabel = new Text2(String.fromCharCode(65 + i), {
size: 20,
fill: 0x000000
});
letterLabel.anchor.set(0.5, 0.5);
letterLabel.x = CENTER_GRID_X - 30;
letterLabel.y = CENTER_GRID_Y + i * CELL_SIZE + CELL_SIZE / 2;
playerGridContainer.addChild(letterLabel);
// Numbers 1-10 on the top
var numberLabel = new Text2((i + 1).toString(), {
size: 20,
fill: 0x000000
});
numberLabel.anchor.set(0.5, 0.5);
numberLabel.x = CENTER_GRID_X + i * CELL_SIZE + CELL_SIZE / 2;
numberLabel.y = CENTER_GRID_Y - 60;
playerGridContainer.addChild(numberLabel);
}
// Add coordinate labels for AI grid
for (var i = 0; i < GRID_SIZE; i++) {
// Letters A-J on the left side
var letterLabel = new Text2(String.fromCharCode(65 + i), {
size: 20,
fill: 0x000000
});
letterLabel.anchor.set(0.5, 0.5);
letterLabel.x = CENTER_GRID_X - 30;
letterLabel.y = CENTER_GRID_Y + i * CELL_SIZE + CELL_SIZE / 2;
aiGridContainer.addChild(letterLabel);
// Numbers 1-10 on the top
var numberLabel = new Text2((i + 1).toString(), {
size: 20,
fill: 0x000000
});
numberLabel.anchor.set(0.5, 0.5);
numberLabel.x = CENTER_GRID_X + i * CELL_SIZE + CELL_SIZE / 2;
numberLabel.y = CENTER_GRID_Y - 60;
aiGridContainer.addChild(numberLabel);
}
// Create ship visual assets for player grid
for (var x = 0; x < GRID_SIZE; x++) {
for (var y = 0; y < GRID_SIZE; y++) {
var shipAsset = LK.getAsset('ship', {
anchorX: 0,
anchorY: 0,
alpha: 0
});
shipAsset.x = CENTER_GRID_X + x * CELL_SIZE;
shipAsset.y = CENTER_GRID_Y + y * CELL_SIZE;
playerGrid[x][y].shipAsset = shipAsset;
playerGridContainer.addChild(shipAsset);
}
}
// Create draggable ships in a grid layout at bottom of screen, avoiding commander area
var shipStartY = 2400; // Move ships lower to avoid commander assets
var shipStartX = 600; // Start further right to avoid commander assets
var shipsPerRow = 3; // Maximum ships per row
var shipSpacingX = 400; // Horizontal spacing between ships
var shipSpacingY = 250; // Vertical spacing between rows
for (var i = 0; i < shipLengths.length; i++) {
var ship = new DraggableShip(shipLengths[i], i);
// Calculate grid position for ship
var row = Math.floor(i / shipsPerRow);
var col = i % shipsPerRow;
ship.x = shipStartX + col * shipSpacingX;
ship.y = shipStartY + row * shipSpacingY;
ship.originalX = ship.x;
ship.originalY = ship.y;
draggableShips.push(ship);
game.addChild(ship);
}
}
function selectCellForPlacement(x, y) {
selectedX = x;
selectedY = y;
if (canPlaceShip(x, y, shipLengths[currentShipToPlace], isHorizontalPlacement, true)) {
placeShip(x, y, shipLengths[currentShipToPlace], isHorizontalPlacement, true, currentShipToPlace);
currentShipToPlace++;
if (currentShipToPlace >= shipLengths.length) {
gameState = 'playing';
statusText.setText('Fire at enemy positions!');
instructionText.setText('Tap enemy grid to shoot');
placeAIShips();
} else {
statusText.setText('Place ship ' + (currentShipToPlace + 1) + ' (length: ' + shipLengths[currentShipToPlace] + ')');
}
}
}
function canPlaceShip(startX, startY, length, horizontal, isPlayer) {
var grid = isPlayer ? playerGrid : aiGrid;
for (var i = 0; i < length; i++) {
var x = horizontal ? startX + i : startX;
var y = horizontal ? startY : startY + i;
if (x >= GRID_SIZE || y >= GRID_SIZE || x < 0 || y < 0) {
return false;
}
if (grid[x][y].hasShip) {
return false;
}
}
return true;
}
function placeShip(startX, startY, length, horizontal, isPlayer, shipId) {
var grid = isPlayer ? playerGrid : aiGrid;
var ships = isPlayer ? playerShips : aiShips;
var ship = new Ship(length, shipId);
for (var i = 0; i < length; i++) {
var x = horizontal ? startX + i : startX;
var y = horizontal ? startY : startY + i;
grid[x][y].setShip(shipId);
ship.addCell(x, y);
}
ships.push(ship);
}
function placeAIShips() {
for (var i = 0; i < shipLengths.length; i++) {
var placed = false;
var attempts = 0;
while (!placed && attempts < 100) {
var x = Math.floor(Math.random() * GRID_SIZE);
var y = Math.floor(Math.random() * GRID_SIZE);
var horizontal = Math.random() < 0.5;
if (canPlaceShip(x, y, shipLengths[i], horizontal, false)) {
placeShip(x, y, shipLengths[i], horizontal, false, i);
placed = true;
}
attempts++;
}
}
}
function playerShoot(x, y) {
if (currentPlayer !== 'player' || isWaitingAfterShot) {
return;
}
// Stop the timer
if (turnTimer) {
LK.clearInterval(turnTimer);
turnTimer = null;
}
// Play shooting sound when firing
LK.getSound('shoot').play();
var cell = aiGrid[x][y];
var hit = cell.hasShip;
// Create visual effect
var effectAsset = hit ? 'hit' : 'miss';
var effect = LK.getAsset(effectAsset, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.1,
scaleY: 0.1
});
effect.x = CENTER_GRID_X + x * CELL_SIZE + CELL_SIZE / 2;
effect.y = CENTER_GRID_Y + y * CELL_SIZE + CELL_SIZE / 2;
aiGridContainer.addChild(effect);
if (cell.hasShip) {
cell.markHit();
hit = true;
LK.getSound('explosion').play();
// Explosion effect for hit
tween(effect, {
scaleX: 2,
scaleY: 2,
alpha: 0.8
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(effect, {
scaleX: 0.1,
scaleY: 0.1,
alpha: 0
}, {
duration: 500,
onFinish: function onFinish() {
effect.destroy();
}
});
}
});
var ship = null;
// Find the ship by ID in the aiShips array
for (var i = 0; i < aiShips.length; i++) {
if (aiShips[i].id === cell.shipId) {
ship = aiShips[i];
break;
}
}
if (ship) {
var sunk = ship.hit();
if (sunk) {
LK.getSound('sunk').play();
markShipAsSunk(ship, false);
// Enemy commander reacts to ship being sunk
showCommanderSpeech(getRandomSpeech(myCommanderSpeech.sunk), false);
if (checkVictory(false)) {
gameState = 'gameOver';
statusText.setText('Victory! You sank all enemy ships!');
instructionText.setText('');
LK.showYouWin();
return;
}
} else {
// Enemy commander reacts to being hit
showCommanderSpeech(getRandomSpeech(myCommanderSpeech.hit), false);
}
}
statusText.setText('Hit! Fire again!');
// No delay for hits - player can continue shooting immediately
startPlayerTurn();
} else {
cell.markMiss(false);
LK.getSound('waterSplash').play();
// Enemy commander reacts to player missing
showCommanderSpeech(getRandomSpeech(myCommanderSpeech.miss), false);
// Water splash effect for miss
effect.tint = 0x00FF00; // Green color to match miss cell tint
tween(effect, {
scaleX: 1.5,
scaleY: 1.5,
alpha: 0.6
}, {
duration: 400,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(effect, {
scaleX: 0.1,
scaleY: 0.1,
alpha: 0
}, {
duration: 600,
onFinish: function onFinish() {
effect.destroy();
}
});
}
});
currentPlayer = 'ai';
statusText.setText('Miss! Enemy is thinking...');
// 5-second delay before AI turn
isWaitingAfterShot = true;
LK.setTimeout(function () {
isWaitingAfterShot = false;
// Switch to player grid when AI attacks with transition effect
tween(aiGridContainer, {
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
aiGridContainer.visible = false;
playerGridContainer.visible = true;
enemyCommanderContainer.visible = false;
myCommanderContainer.visible = true;
playerGridContainer.alpha = 0;
tween(playerGridContainer, {
alpha: 1
}, {
duration: 300
});
}
});
startAiTurn();
}, 5000);
}
}
function aiTurn() {
if (currentPlayer !== 'ai' || isWaitingAfterShot) {
return;
}
// Stop the timer
if (turnTimer) {
LK.clearInterval(turnTimer);
turnTimer = null;
}
var x, y;
var attempts = 0;
// Smart AI: If in hunting mode, try adjacent cells to last hit
if (aiHuntingMode && aiLastHitX !== -1 && aiLastHitY !== -1) {
var found = false;
// Try directions: up, right, down, left
var directions = [{
x: 0,
y: -1
},
// up
{
x: 1,
y: 0
},
// right
{
x: 0,
y: 1
},
// down
{
x: -1,
y: 0
} // left
];
// Try each direction from the last hit
for (var d = 0; d < directions.length && !found; d++) {
var testX = aiLastHitX + directions[d].x;
var testY = aiLastHitY + directions[d].y;
// Check if position is valid and not already attacked
if (testX >= 0 && testX < GRID_SIZE && testY >= 0 && testY < GRID_SIZE && !playerGrid[testX][testY].isHit && !playerGrid[testX][testY].isMiss) {
x = testX;
y = testY;
found = true;
}
}
// If no adjacent cells available, exit hunting mode
if (!found) {
aiHuntingMode = false;
aiLastHitX = -1;
aiLastHitY = -1;
}
}
// If not in hunting mode or no valid adjacent cells, shoot randomly
if (!aiHuntingMode || aiLastHitX === -1 && aiLastHitY === -1) {
do {
x = Math.floor(Math.random() * GRID_SIZE);
y = Math.floor(Math.random() * GRID_SIZE);
attempts++;
} while ((playerGrid[x][y].isHit || playerGrid[x][y].isMiss) && attempts < 100);
}
// Play shooting sound when AI fires
LK.getSound('shoot').play();
var cell = playerGrid[x][y];
var hit = cell.hasShip;
// Create visual effect
var effectAsset = hit ? 'hit' : 'miss';
var effect = LK.getAsset(effectAsset, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.1,
scaleY: 0.1
});
effect.x = CENTER_GRID_X + x * CELL_SIZE + CELL_SIZE / 2;
effect.y = CENTER_GRID_Y + y * CELL_SIZE + CELL_SIZE / 2;
playerGridContainer.addChild(effect);
if (cell.hasShip) {
cell.markHit();
LK.getSound('explosion').play();
// Explosion effect for hit
tween(effect, {
scaleX: 2,
scaleY: 2,
alpha: 0.8
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(effect, {
scaleX: 0.1,
scaleY: 0.1,
alpha: 0
}, {
duration: 500,
onFinish: function onFinish() {
effect.destroy();
}
});
}
});
// Enter hunting mode and remember this hit position
aiHuntingMode = true;
aiLastHitX = x;
aiLastHitY = y;
var ship = null;
// Find the ship by ID in the playerShips array
for (var i = 0; i < playerShips.length; i++) {
if (playerShips[i].id === cell.shipId) {
ship = playerShips[i];
break;
}
}
if (ship) {
var sunk = ship.hit();
if (sunk) {
LK.getSound('sunk').play();
markShipAsSunk(ship, true);
// Exit hunting mode when ship is sunk
aiHuntingMode = false;
aiLastHitX = -1;
aiLastHitY = -1;
// Enemy commander celebrates sinking player's ship
showCommanderSpeech(getRandomSpeech(enemyCommanderSpeech.sunk), true);
if (checkVictory(true)) {
gameState = 'gameOver';
statusText.setText('Defeat! Enemy sank all your ships!');
instructionText.setText('');
LK.showGameOver();
return;
}
} else {
// Enemy commander celebrates hitting player's ship
showCommanderSpeech(getRandomSpeech(enemyCommanderSpeech.hit), true);
}
}
statusText.setText('Enemy hit your ship!');
// 5-second delay before AI continues
isWaitingAfterShot = true;
LK.setTimeout(function () {
isWaitingAfterShot = false;
startAiTurn();
}, 5000);
} else {
cell.markMiss(true);
LK.getSound('waterSplash').play();
// Enemy commander reacts to missing
showCommanderSpeech(getRandomSpeech(enemyCommanderSpeech.miss), true);
// Water splash effect for miss
effect.tint = 0xFFAA00;
tween(effect, {
scaleX: 1.5,
scaleY: 1.5,
alpha: 0.6
}, {
duration: 400,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(effect, {
scaleX: 0.1,
scaleY: 0.1,
alpha: 0
}, {
duration: 600,
onFinish: function onFinish() {
effect.destroy();
}
});
}
});
currentPlayer = 'player';
statusText.setText('Enemy missed! Your turn!');
// 5-second delay before player turn
isWaitingAfterShot = true;
LK.setTimeout(function () {
isWaitingAfterShot = false;
// Switch to AI grid for player's turn to attack with transition effect
tween(playerGridContainer, {
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
playerGridContainer.visible = false;
aiGridContainer.visible = true;
myCommanderContainer.visible = false;
enemyCommanderContainer.visible = true;
aiGridContainer.alpha = 0;
tween(aiGridContainer, {
alpha: 1
}, {
duration: 300
});
}
});
startPlayerTurn();
}, 5000);
}
}
function markShipAsSunk(ship, isPlayer) {
var grid = isPlayer ? playerGrid : aiGrid;
for (var i = 0; i < ship.cells.length; i++) {
var cellPos = ship.cells[i];
grid[cellPos.x][cellPos.y].markSunk();
// Darken hit markers on sunk ship cells
if (grid[cellPos.x][cellPos.y].hitMarkerAsset) {
tween(grid[cellPos.x][cellPos.y].hitMarkerAsset, {
alpha: 0.4
}, {
duration: 500,
easing: tween.easeOut
});
}
}
}
function removeShipFromGrid(ship) {
for (var x = 0; x < GRID_SIZE; x++) {
for (var y = 0; y < GRID_SIZE; y++) {
if (playerGrid[x][y].shipId === ship.shipId) {
playerGrid[x][y].hasShip = false;
playerGrid[x][y].shipId = -1;
var cellGraphics = playerGrid[x][y].children[0];
cellGraphics.tint = 0xFFFFFF;
if (playerGrid[x][y].shipAsset) {
playerGrid[x][y].shipAsset.alpha = 0;
}
}
}
}
}
function checkVictory(playerLost) {
var ships = playerLost ? playerShips : aiShips;
for (var i = 0; i < ships.length; i++) {
if (!ships[i].isSunk) {
return false;
}
}
return true;
}
// Double tap to rotate ship during placement
var lastTapTime = 0;
game.down = function (x, y, obj) {
if (gameState === 'placement') {
var currentTime = Date.now();
if (currentTime - lastTapTime < 300) {
// Find ship being rotated - check both unplaced and placed ships
for (var i = 0; i < draggableShips.length; i++) {
var ship = draggableShips[i];
var shipBounds = {
x: ship.x,
y: ship.y,
width: ship.isHorizontal ? ship.length * CELL_SIZE : CELL_SIZE,
height: ship.isHorizontal ? CELL_SIZE : ship.length * CELL_SIZE
};
if (x >= shipBounds.x && x <= shipBounds.x + shipBounds.width && y >= shipBounds.y && y <= shipBounds.y + shipBounds.height) {
if (ship.isPlaced) {
// Remove ship from grid
removeShipFromGrid(ship);
ship.isPlaced = false;
ship.visible = true;
placedShipsCount--;
}
ship.rotate();
break;
}
}
instructionText.setText('Double tap ships to rotate, drag to reposition');
}
lastTapTime = currentTime;
}
};
game.move = function (x, y, obj) {
if (gameState === 'placement' && draggedShip) {
draggedShip.x = x - draggedShip.width / 2;
draggedShip.y = y - draggedShip.height / 2;
}
};
game.up = function (x, y, obj) {
draggedShip = null;
};
function startPlayerTurn() {
currentPlayer = 'player';
turnTimeRemaining = 30;
timerText.setText(turnTimeRemaining.toString());
timerText.visible = true;
// Clear any existing timer first
if (turnTimer) {
LK.clearInterval(turnTimer);
turnTimer = null;
}
turnTimer = LK.setInterval(function () {
turnTimeRemaining--;
timerText.setText(turnTimeRemaining.toString());
if (turnTimeRemaining <= 0) {
LK.clearInterval(turnTimer);
turnTimer = null;
timerText.visible = false;
// Auto-switch to AI turn on timeout
currentPlayer = 'ai';
statusText.setText('Time up! Enemy is thinking...');
tween(aiGridContainer, {
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
aiGridContainer.visible = false;
playerGridContainer.visible = true;
enemyCommanderContainer.visible = false;
myCommanderContainer.visible = true;
playerGridContainer.alpha = 0;
tween(playerGridContainer, {
alpha: 1
}, {
duration: 300
});
}
});
startAiTurn();
}
}, 1000);
}
function startAiTurn() {
currentPlayer = 'ai';
turnTimeRemaining = 30;
timerText.setText(turnTimeRemaining.toString());
timerText.visible = true;
// Clear any existing timer first
if (turnTimer) {
LK.clearInterval(turnTimer);
turnTimer = null;
}
// AI thinks for 2-5 seconds before shooting
var thinkTime = 2000 + Math.random() * 3000;
turnTimer = LK.setInterval(function () {
turnTimeRemaining--;
timerText.setText(turnTimeRemaining.toString());
if (turnTimeRemaining <= 0) {
LK.clearInterval(turnTimer);
turnTimer = null;
timerText.visible = false;
aiTurn();
}
}, 1000);
LK.setTimeout(function () {
if (currentPlayer === 'ai' && !isWaitingAfterShot) {
aiTurn();
}
}, thinkTime);
}
// Create commander assets
var myCommanderContainer = new Container();
var enemyCommanderContainer = new Container();
// Position commanders higher and at bottom left corner
myCommanderContainer.x = 50;
myCommanderContainer.y = 2732 - 500; // Moved even higher up
enemyCommanderContainer.x = 50;
enemyCommanderContainer.y = 2732 - 500; // Same position as my commander
// Create shadow assets first (positioned slightly offset)
var myCommanderShadow = myCommanderContainer.attachAsset('myCommander', {
anchorX: 0,
anchorY: 0,
scaleX: 2.2,
scaleY: 2.2,
alpha: 0.3,
tint: 0x000000
});
myCommanderShadow.x = 8;
myCommanderShadow.y = 8;
var enemyCommanderShadow = enemyCommanderContainer.attachAsset('enemyCommander', {
anchorX: 0,
anchorY: 0,
scaleX: 2.2,
scaleY: 2.2,
alpha: 0.3,
tint: 0x000000
});
enemyCommanderShadow.x = 8;
enemyCommanderShadow.y = 8;
// Create main commander assets (larger size)
var myCommanderAsset = myCommanderContainer.attachAsset('myCommander', {
anchorX: 0,
anchorY: 0,
scaleX: 2.2,
scaleY: 2.2
});
var enemyCommanderAsset = enemyCommanderContainer.attachAsset('enemyCommander', {
anchorX: 0,
anchorY: 0,
scaleX: 2.2,
scaleY: 2.2
});
// Add commanders to game
game.addChild(myCommanderContainer);
game.addChild(enemyCommanderContainer);
// Initialize commander visibility - show my commander during placement phase
myCommanderContainer.visible = true;
enemyCommanderContainer.visible = false;
// Commander speech arrays
var myCommanderSpeech = {
hit: ["Lanet olsun! Nasıl buldun?", "Bu olamaz! Şanslı atış!", "Beni buldun ama savaş henüz bitmedi!", "İyi atış... ama son olmayacak!"],
miss: ["Hah! Ordumu bulmak kolay değil!", "Boşa atış! Denemeye devam et!", "Su sıçradı ama gemim yerinde!", "Yaklaştın ama yeterli değil!"],
sunk: ["Gemimi batırdın... ama intikam alacağım!", "Bu savaşı kaybettim ama onur hala benimle!", "İyi savaştın... şimdilik kazandın"]
};
var enemyCommanderSpeech = {
hit: ["Mükemmel atış! Hedefi bulduk!", "Doğrudan isabet! Böyle devam!", "Ateş! Düşman gemisini yakaladık!", "Harika! Bu şekilde kazanacağız!"],
miss: ["Lanet! Hedefi kaçırdık!", "Su sıçradı! Tekrar dene!", "Bu sefer olmadı ama pes etmem!", "Yakında hedefimi bulacağım!"],
sunk: ["Bir gemi daha battı! Zafer yakın!", "Düşman filosu eriyor!", "Mükemmel! Böyle devam edersek kazanırız!"]
};
// Current speech display
var currentSpeechText = null;
var speechTimeout = null;
function showCommanderSpeech(text, isEnemyCommander) {
// Clear existing speech
if (currentSpeechText) {
currentSpeechText.destroy();
currentSpeechText = null;
}
if (speechTimeout) {
LK.clearTimeout(speechTimeout);
speechTimeout = null;
}
// Create speech bubble container
currentSpeechText = new Container();
// Create speech bubble background
var speechBubble = currentSpeechText.attachAsset('speechBubble', {
anchorX: 0,
anchorY: 0
});
// Create speech bubble text
var speechText = new Text2(text, {
size: 36,
fill: 0x000000
});
speechText.anchor.set(0.5, 0.5);
speechText.x = 350; // Move text further to the right in bubble
speechText.y = 75; // Center in bubble
currentSpeechText.addChild(speechText);
// Add speech bubble directly to game instead of commander container
game.addChild(currentSpeechText);
// Position speech bubble next to appropriate commander
if (isEnemyCommander && enemyCommanderContainer.visible) {
currentSpeechText.x = enemyCommanderContainer.x + 440; // Position to the right of commander
currentSpeechText.y = enemyCommanderContainer.y + 50; // Align with top of commander
} else if (!isEnemyCommander && myCommanderContainer.visible) {
currentSpeechText.x = myCommanderContainer.x + 440; // Position to the right of commander
currentSpeechText.y = myCommanderContainer.y + 50; // Align with top of commander
} else {
// Fallback positioning if no commander is visible
currentSpeechText.x = 50 + 440;
currentSpeechText.y = 2732 - 500 + 50;
}
// Animate speech appearance
currentSpeechText.alpha = 0;
tween(currentSpeechText, {
alpha: 1
}, {
duration: 300
});
// Remove speech after 3 seconds
speechTimeout = LK.setTimeout(function () {
if (currentSpeechText) {
tween(currentSpeechText, {
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
if (currentSpeechText) {
currentSpeechText.destroy();
currentSpeechText = null;
}
}
});
}
}, 3000);
}
function getRandomSpeech(speechArray) {
return speechArray[Math.floor(Math.random() * speechArray.length)];
}
// Initialize the game
function createIntroScreen() {
introScreen = new Container();
game.addChild(introScreen);
// Create television frame
var tvFrame = LK.getAsset('tvFrame', {
anchorX: 0.5,
anchorY: 0.5
});
tvFrame.x = 2048 / 2;
tvFrame.y = 2732 / 2;
introScreen.addChild(tvFrame);
// Create TV stand
var tvStand = LK.getAsset('tvStand', {
anchorX: 0.5,
anchorY: 0
});
tvStand.x = 2048 / 2;
tvStand.y = 2732 / 2 + 1450;
introScreen.addChild(tvStand);
// Create TV buttons and speakers
var powerButton = LK.getAsset('tvButton', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0xFF4444
});
powerButton.x = 2048 / 2 + 1200;
powerButton.y = 2732 / 2 - 1200;
introScreen.addChild(powerButton);
var volumeButton = LK.getAsset('tvButton', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0x4444FF
});
volumeButton.x = 2048 / 2 + 1200;
volumeButton.y = 2732 / 2 - 1100;
introScreen.addChild(volumeButton);
// Create speakers
for (var s = 0; s < 6; s++) {
var speaker = LK.getAsset('tvSpeaker', {
anchorX: 0.5,
anchorY: 0.5
});
speaker.x = 2048 / 2 + 1200;
speaker.y = 2732 / 2 - 800 + s * 60;
introScreen.addChild(speaker);
}
// Create TV screen (black background)
var tvScreen = LK.getAsset('tvScreen', {
anchorX: 0.5,
anchorY: 0.5
});
tvScreen.x = 2048 / 2;
tvScreen.y = 2732 / 2;
introScreen.addChild(tvScreen);
// Create container for all TV content
var tvContent = new Container();
tvContent.x = 2048 / 2 - 950; // Center content in TV screen
tvContent.y = 2732 / 2 - 1300;
introScreen.addChild(tvContent);
// Create gradient background layers for depth (now inside TV)
var bgLayer1 = LK.getAsset('gridBox', {
anchorX: 0,
anchorY: 0,
scaleX: 16,
scaleY: 21,
tint: 0x001A33,
alpha: 1
});
tvContent.addChild(bgLayer1);
var bgLayer2 = LK.getAsset('gridBox', {
anchorX: 0,
anchorY: 0,
scaleX: 15,
scaleY: 19,
tint: 0x003D66,
alpha: 0.7
});
bgLayer2.x = 80;
bgLayer2.y = 80;
tvContent.addChild(bgLayer2);
// Create multiple water layers for depth
var waterLayer1 = LK.getAsset('water', {
anchorX: 0,
anchorY: 0,
scaleX: 24,
scaleY: 28,
alpha: 0.08,
tint: 0x1B4F72
});
tvContent.addChild(waterLayer1);
var waterLayer2 = LK.getAsset('water', {
anchorX: 0,
anchorY: 0,
scaleX: 20,
scaleY: 24,
alpha: 0.15,
tint: 0x2E86AB
});
tvContent.addChild(waterLayer2);
var waterLayer3 = LK.getAsset('water', {
anchorX: 0,
anchorY: 0,
scaleX: 16,
scaleY: 20,
alpha: 0.12,
tint: 0x5DADE2
});
tvContent.addChild(waterLayer3);
// Create floating water particles
var waterParticles = [];
for (var p = 0; p < 8; p++) {
var particle = LK.getAsset('water', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.3 + Math.random() * 0.2,
scaleY: 0.3 + Math.random() * 0.2,
alpha: 0.2 + Math.random() * 0.1,
tint: 0x87CEEB
});
particle.x = Math.random() * 1900;
particle.y = Math.random() * 2600;
waterParticles.push(particle);
tvContent.addChild(particle);
}
// Animate water layers with wave motion
tween(waterLayer1, {
alpha: 0.12,
x: -50
}, {
duration: 4000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(waterLayer1, {
alpha: 0.08,
x: 0
}, {
duration: 4000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(waterLayer1, {
alpha: 0.12,
x: -50
}, {
duration: 4000,
easing: tween.easeInOut,
onFinish: arguments.callee
});
}
});
}
});
tween(waterLayer2, {
alpha: 0.22,
x: 30
}, {
duration: 3500,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(waterLayer2, {
alpha: 0.15,
x: -30
}, {
duration: 3500,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(waterLayer2, {
alpha: 0.22,
x: 30
}, {
duration: 3500,
easing: tween.easeInOut,
onFinish: arguments.callee
});
}
});
}
});
tween(waterLayer3, {
alpha: 0.18,
y: -20
}, {
duration: 3000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(waterLayer3, {
alpha: 0.12,
y: 20
}, {
duration: 3000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(waterLayer3, {
alpha: 0.18,
y: -20
}, {
duration: 3000,
easing: tween.easeInOut,
onFinish: arguments.callee
});
}
});
}
});
// Animate water particles
for (var p = 0; p < waterParticles.length; p++) {
(function (particle, index) {
function floatParticle() {
if (gameState === 'intro') {
var targetX = Math.random() * 1900;
var targetY = Math.random() * 2600;
tween(particle, {
x: targetX,
y: targetY,
alpha: 0.1 + Math.random() * 0.15,
rotation: Math.random() * Math.PI * 2
}, {
duration: 8000 + Math.random() * 4000,
easing: tween.easeInOut,
onFinish: floatParticle
});
}
}
LK.setTimeout(floatParticle, index * 500);
})(waterParticles[p], p);
}
// Main title with shadow effect
var titleShadow = new Text2('NAVAL COMBAT', {
size: 100,
fill: 0x000000
});
titleShadow.anchor.set(0.5, 0.5);
titleShadow.x = 950 + 6;
titleShadow.y = 406;
titleShadow.alpha = 0;
tvContent.addChild(titleShadow);
var titleText = new Text2('NAVAL COMBAT', {
size: 100,
fill: 0xFFD700
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 950;
titleText.y = 400;
titleText.alpha = 0;
tvContent.addChild(titleText);
// Subtitle with glow effect
var subtitleGlow = new Text2('Strategic Fleet Warfare', {
size: 42,
fill: 0x87CEEB
});
subtitleGlow.anchor.set(0.5, 0.5);
subtitleGlow.x = 950;
subtitleGlow.y = 550;
subtitleGlow.alpha = 0;
tvContent.addChild(subtitleGlow);
var subtitleText = new Text2('Strategic Fleet Warfare', {
size: 42,
fill: 0xFFFFFF
});
subtitleText.anchor.set(0.5, 0.5);
subtitleText.x = 950;
subtitleText.y = 550;
subtitleText.alpha = 0;
tvContent.addChild(subtitleText);
// Create naval battle themed decorative elements
var navyElements = [];
var shipColors = [0x2C3E50, 0x34495E, 0x566573, 0x7F8C8D, 0x95A5A6];
var enemyColors = [0x8B0000, 0xA52A2A, 0xB22222, 0xDC143C, 0xFF4500];
// Create allied fleet formation (left side)
for (var i = 0; i < 4; i++) {
var allyShip = LK.getAsset('ship', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.0 + i * 0.2,
scaleY: 2.0 + i * 0.2,
tint: shipColors[i]
});
allyShip.x = 120 + i * 50;
allyShip.y = 750 + i * 70;
allyShip.alpha = 0;
allyShip.rotation = Math.PI / 8 + i * 0.05;
navyElements.push(allyShip);
tvContent.addChild(allyShip);
}
// Create enemy fleet formation (right side)
for (var i = 0; i < 4; i++) {
var enemyShip = LK.getAsset('ship', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.0 + i * 0.2,
scaleY: 2.0 + i * 0.2,
tint: enemyColors[i]
});
enemyShip.x = 1780 - i * 50;
enemyShip.y = 750 + i * 70;
enemyShip.alpha = 0;
enemyShip.rotation = -Math.PI / 8 - i * 0.05;
navyElements.push(enemyShip);
tvContent.addChild(enemyShip);
}
// Add naval commander silhouettes
var allyCommander = LK.getAsset('myCommander', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2,
alpha: 0,
tint: 0x2C3E50
});
allyCommander.x = 250;
allyCommander.y = 1100;
navyElements.push(allyCommander);
tvContent.addChild(allyCommander);
var enemyCommander = LK.getAsset('enemyCommander', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2,
alpha: 0,
tint: 0x8B0000
});
enemyCommander.x = 1650;
enemyCommander.y = 1100;
navyElements.push(enemyCommander);
tvContent.addChild(enemyCommander);
// Add strategic grid overlay effects
for (var i = 0; i < 6; i++) {
var gridElement = LK.getAsset('gridBox', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.4,
scaleY: 0.4,
alpha: 0,
tint: 0x3498DB
});
gridElement.x = 950 + (i % 3 - 1) * 160;
gridElement.y = 900 + Math.floor(i / 3) * 120;
navyElements.push(gridElement);
tvContent.addChild(gridElement);
}
// Replace shipFormation reference with navyElements
var shipFormation = navyElements;
// Enhanced start button with frame
var buttonFrame = LK.getAsset('gridBox', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 3.2,
scaleY: 1.0,
tint: 0xFFD700,
alpha: 0
});
buttonFrame.x = 950;
buttonFrame.y = 1300;
tvContent.addChild(buttonFrame);
var startGameButton = new Text2('⚓ START BATTLE ⚓', {
size: 58,
fill: 0x000000
});
startGameButton.anchor.set(0.5, 0.5);
startGameButton.x = 950;
startGameButton.y = 1300;
startGameButton.alpha = 0;
tvContent.addChild(startGameButton);
// Additional UI elements
var versionText = new Text2('Admiral Edition v1.0', {
size: 25,
fill: 0x808080
});
versionText.anchor.set(0.5, 0.5);
versionText.x = 950;
versionText.y = 1450;
versionText.alpha = 0;
tvContent.addChild(versionText);
var instructionsText = new Text2('Deploy your fleet strategically and command the seas!', {
size: 36,
fill: 0xE0E0E0
});
instructionsText.anchor.set(0.5, 0.5);
instructionsText.x = 950;
instructionsText.y = 1600;
instructionsText.alpha = 0;
tvContent.addChild(instructionsText);
// Professional animation sequence
// Title entrance with dramatic effect
tween(titleShadow, {
alpha: 0.6,
y: 500,
scaleX: 1.05,
scaleY: 1.05
}, {
duration: 1200,
easing: tween.elasticOut
});
tween(titleText, {
alpha: 1,
y: 500,
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 1200,
easing: tween.elasticOut
});
// Subtitle with sequential glow effect
LK.setTimeout(function () {
tween(subtitleGlow, {
alpha: 0.4,
scaleX: 1.05,
scaleY: 1.05
}, {
duration: 800,
easing: tween.easeOut
});
tween(subtitleText, {
alpha: 1
}, {
duration: 800,
easing: tween.easeOut
});
}, 400);
// Naval fleet formation entrance with battle positioning
LK.setTimeout(function () {
for (var i = 0; i < navyElements.length; i++) {
(function (element, delay) {
LK.setTimeout(function () {
// Different entrance effects based on element type
var isShip = element.x < 1024; // Left side elements are allied ships
var entranceEffect = isShip ? {
alpha: 0.85,
scaleX: element.scaleX * 1.2,
scaleY: element.scaleY * 1.2,
x: element.x + (isShip ? 50 : -50)
} : {
alpha: 0.7,
scaleX: element.scaleX * 1.1,
scaleY: element.scaleY * 1.1
};
tween(element, entranceEffect, {
duration: 1200,
easing: tween.elasticOut
});
// Add naval movement patterns
function navalMovement() {
if (gameState === 'intro') {
var movementPattern = isShip ? {
y: element.y + (10 + Math.random() * 8),
rotation: element.rotation + (Math.random() - 0.5) * 0.1,
alpha: element.alpha * (0.9 + Math.random() * 0.2)
} : {
scaleX: element.scaleX * (0.95 + Math.random() * 0.1),
scaleY: element.scaleY * (0.95 + Math.random() * 0.1),
alpha: element.alpha * (0.8 + Math.random() * 0.4)
};
tween(element, movementPattern, {
duration: 2500 + Math.random() * 1500,
easing: tween.easeInOut,
onFinish: function onFinish() {
var returnPattern = isShip ? {
y: element.y - (10 + Math.random() * 8),
rotation: element.rotation - (Math.random() - 0.5) * 0.1,
alpha: element.alpha / (0.9 + Math.random() * 0.2)
} : {
scaleX: element.scaleX / (0.95 + Math.random() * 0.1),
scaleY: element.scaleY / (0.95 + Math.random() * 0.1),
alpha: element.alpha / (0.8 + Math.random() * 0.4)
};
tween(element, returnPattern, {
duration: 2500 + Math.random() * 1500,
easing: tween.easeInOut,
onFinish: navalMovement
});
}
});
}
}
LK.setTimeout(navalMovement, 1500 + Math.random() * 1000);
}, delay * 120);
})(navyElements[i], i);
}
}, 800);
// Button entrance with frame
LK.setTimeout(function () {
tween(buttonFrame, {
alpha: 0.8,
scaleX: 4.2,
scaleY: 1.3
}, {
duration: 600,
easing: tween.easeOut
});
tween(startGameButton, {
alpha: 1,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 600,
easing: tween.bounceOut
});
tween(versionText, {
alpha: 1
}, {
duration: 600,
easing: tween.easeOut
});
tween(instructionsText, {
alpha: 1
}, {
duration: 600,
easing: tween.easeOut
});
}, 1400);
// Enhanced pulsing effect for start button
LK.setTimeout(function () {
function pulseButton() {
if (gameState === 'intro') {
tween(startGameButton, {
scaleX: 1.15,
scaleY: 1.15,
tint: 0x00FF00
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(startGameButton, {
scaleX: 1.0,
scaleY: 1.0,
tint: 0xFFFFFF
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: pulseButton
});
}
});
tween(buttonFrame, {
alpha: 1,
scaleX: 4.4,
scaleY: 1.4
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(buttonFrame, {
alpha: 0.8,
scaleX: 4.2,
scaleY: 1.3
}, {
duration: 1000,
easing: tween.easeInOut
});
}
});
}
}
pulseButton();
}, 2000);
// Add TV static overlay effect
var tvStatic = LK.getAsset('gridBox', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 16,
scaleY: 21,
alpha: 0.02,
tint: 0xFFFFFF
});
tvStatic.x = 950;
tvStatic.y = 1300;
tvContent.addChild(tvStatic);
// Animate TV static
function animateStatic() {
if (gameState === 'intro') {
tween(tvStatic, {
alpha: 0.05 + Math.random() * 0.03,
scaleX: 16 + Math.random() * 0.2,
scaleY: 21 + Math.random() * 0.2
}, {
duration: 100 + Math.random() * 200,
onFinish: animateStatic
});
}
}
animateStatic();
// Add TV screen glow effect
var screenGlow = LK.getAsset('tvScreen', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.05,
scaleY: 1.05,
tint: 0x4A90E2,
alpha: 0.1
});
screenGlow.x = 2048 / 2;
screenGlow.y = 2732 / 2;
introScreen.addChild(screenGlow);
// Animate screen glow
function animateGlow() {
if (gameState === 'intro') {
tween(screenGlow, {
alpha: 0.15,
scaleX: 1.08,
scaleY: 1.08
}, {
duration: 2000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(screenGlow, {
alpha: 0.1,
scaleX: 1.05,
scaleY: 1.05
}, {
duration: 2000,
easing: tween.easeInOut,
onFinish: animateGlow
});
}
});
}
}
animateGlow();
// Click handler for start button with effect
startGameButton.down = function (x, y, obj) {
if (gameState === 'intro') {
// Button press effect
tween(startGameButton, {
scaleX: 0.95,
scaleY: 0.95,
alpha: 0.8
}, {
duration: 100,
onFinish: function onFinish() {
tween(startGameButton, {
scaleX: 1.0,
scaleY: 1.0,
alpha: 1
}, {
duration: 100
});
}
});
// Fade out intro screen with dramatic effect
tween(introScreen, {
alpha: 0,
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 800,
easing: tween.easeIn,
onFinish: function onFinish() {
introScreen.destroy();
introScreen = null;
gameState = 'placement';
statusText.setText('Drag ships to your grid');
// Start ocean waves music after intro ends
LK.playMusic('oceanWaves');
// Show computer monitor and radar system
computerMonitorContainer.visible = true;
computerMonitorContainer.alpha = 0;
tween(computerMonitorContainer, {
alpha: 1
}, {
duration: 1000,
easing: tween.easeOut
});
initializeGrids();
// Start scrolling text immediately when placement begins
scrollInstructionText();
}
});
}
};
}
createIntroScreen();
// Create computer monitor frame around game area
var computerMonitorContainer = new Container();
computerMonitorContainer.visible = false; // Hide during intro
game.addChild(computerMonitorContainer);
// Position computer monitor behind the game grids
var monitorFrame = computerMonitorContainer.attachAsset('computerMonitor', {
anchorX: 0.5,
anchorY: 0.5
});
monitorFrame.x = 2048 / 2;
monitorFrame.y = CENTER_GRID_Y + GRID_SIZE * CELL_SIZE / 2;
// Computer screen background
var computerScreen = computerMonitorContainer.attachAsset('computerScreen', {
anchorX: 0.5,
anchorY: 0.5
});
computerScreen.x = 2048 / 2;
computerScreen.y = CENTER_GRID_Y + GRID_SIZE * CELL_SIZE / 2;
// Computer base
var computerBase = computerMonitorContainer.attachAsset('computerBase', {
anchorX: 0.5,
anchorY: 0
});
computerBase.x = 2048 / 2;
computerBase.y = CENTER_GRID_Y + GRID_SIZE * CELL_SIZE + 50;
// Create rotating radar system in background
var radarContainer = new Container();
computerMonitorContainer.addChild(radarContainer);
radarContainer.x = 2048 / 2;
radarContainer.y = CENTER_GRID_Y + GRID_SIZE * CELL_SIZE / 2;
// Radar circles (concentric)
for (var i = 1; i <= 3; i++) {
var radarCircle = radarContainer.attachAsset('radarCircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: i * 0.4,
scaleY: i * 0.4,
alpha: 0.15
});
radarCircle.x = 0;
radarCircle.y = 0;
}
// Radar center dot
var radarCenter = radarContainer.attachAsset('radarCenter', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.8
});
radarCenter.x = 0;
radarCenter.y = 0;
// Rotating radar sweep line
var radarSweep = radarContainer.attachAsset('radarSweep', {
anchorX: 0,
anchorY: 0.5,
alpha: 0.6
});
radarSweep.x = 0;
radarSweep.y = 0;
// Start radar sweep rotation
function rotateRadarSweep() {
if (gameState === 'playing' || gameState === 'placement') {
tween(radarSweep, {
rotation: radarSweep.rotation + Math.PI * 2
}, {
duration: 3000,
easing: tween.linear,
onFinish: rotateRadarSweep
});
}
}
// Start radar sweep after placement phase begins
LK.setTimeout(function () {
if (gameState === 'placement') {
rotateRadarSweep();
}
}, 1500);
// Start radar sweep after initialization
LK.setTimeout(function () {
rotateRadarSweep();
}, 500);
// Add computer-style grid overlay
var computerGrid = new Container();
computerMonitorContainer.addChild(computerGrid);
computerGrid.x = 2048 / 2 - 950;
computerGrid.y = CENTER_GRID_Y - 750;
// Create computer grid lines
for (var i = 0; i <= 20; i++) {
// Vertical lines
var vLine = LK.getAsset('gridLine', {
anchorX: 0.5,
anchorY: 0,
scaleX: 0.5,
scaleY: 1.2,
alpha: 0.08,
tint: 0x00FF00
});
vLine.x = i * 95;
vLine.y = 0;
computerGrid.addChild(vLine);
// Horizontal lines
var hLine = LK.getAsset('gridLine', {
anchorX: 0,
anchorY: 0.5,
scaleX: 1.0,
scaleY: 0.5,
alpha: 0.08,
tint: 0x00FF00,
rotation: Math.PI / 2
});
hLine.x = 0;
hLine.y = i * 75;
computerGrid.addChild(hLine);
}
// Add ocean movement to game containers
function addOceanMovement() {
if (gameState === 'playing' || gameState === 'placement') {
// Gentle rocking motion for player grid
tween(playerGridContainer, {
x: playerGridContainer.x + (Math.random() - 0.5) * 8,
y: playerGridContainer.y + (Math.random() - 0.5) * 6,
rotation: playerGridContainer.rotation + (Math.random() - 0.5) * 0.008
}, {
duration: 2000 + Math.random() * 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Return to original position with slight variation
tween(playerGridContainer, {
x: game.children.indexOf(playerGridContainer) >= 0 ? playerGridContainer.x - (Math.random() - 0.5) * 8 : playerGridContainer.x,
y: game.children.indexOf(playerGridContainer) >= 0 ? playerGridContainer.y - (Math.random() - 0.5) * 6 : playerGridContainer.y,
rotation: playerGridContainer.rotation - (Math.random() - 0.5) * 0.008
}, {
duration: 2000 + Math.random() * 1000,
easing: tween.easeInOut,
onFinish: addOceanMovement
});
}
});
// Similar motion for AI grid
tween(aiGridContainer, {
x: aiGridContainer.x + (Math.random() - 0.5) * 8,
y: aiGridContainer.y + (Math.random() - 0.5) * 6,
rotation: aiGridContainer.rotation + (Math.random() - 0.5) * 0.008
}, {
duration: 2200 + Math.random() * 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(aiGridContainer, {
x: game.children.indexOf(aiGridContainer) >= 0 ? aiGridContainer.x - (Math.random() - 0.5) * 8 : aiGridContainer.x,
y: game.children.indexOf(aiGridContainer) >= 0 ? aiGridContainer.y - (Math.random() - 0.5) * 6 : aiGridContainer.y,
rotation: aiGridContainer.rotation - (Math.random() - 0.5) * 0.008
}, {
duration: 2200 + Math.random() * 800,
easing: tween.easeInOut
});
}
});
// Gentle movement for commander containers
tween(myCommanderContainer, {
x: myCommanderContainer.x + (Math.random() - 0.5) * 4,
y: myCommanderContainer.y + (Math.random() - 0.5) * 3
}, {
duration: 3000 + Math.random() * 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(myCommanderContainer, {
x: 50 + (Math.random() - 0.5) * 4,
y: 2732 - 500 + (Math.random() - 0.5) * 3
}, {
duration: 3000 + Math.random() * 1000,
easing: tween.easeInOut
});
}
});
tween(enemyCommanderContainer, {
x: enemyCommanderContainer.x + (Math.random() - 0.5) * 4,
y: enemyCommanderContainer.y + (Math.random() - 0.5) * 3
}, {
duration: 2800 + Math.random() * 1200,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(enemyCommanderContainer, {
x: 50 + (Math.random() - 0.5) * 4,
y: 2732 - 500 + (Math.random() - 0.5) * 3
}, {
duration: 2800 + Math.random() * 1200,
easing: tween.easeInOut
});
}
});
}
}
// Add computer screen effects
function addComputerEffects() {
if (gameState === 'playing' || gameState === 'placement') {
// Screen flicker effect
if (computerScreen) {
var flickerAlpha = 0.95 + Math.random() * 0.05;
tween(computerScreen, {
alpha: flickerAlpha,
tint: 0x001100 + Math.floor(Math.random() * 0x001100)
}, {
duration: 100 + Math.random() * 200,
onFinish: addComputerEffects
});
}
}
}
// Start computer effects
LK.setTimeout(function () {
addComputerEffects();
}, 2000);
// Start ocean movement after a short delay
LK.setTimeout(function () {
addOceanMovement();
}, 1000);
// Ocean waves music will start after intro ends
// Game code saved successfully - Naval Combat Game Complete; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var DraggableShip = Container.expand(function (length, id) {
var self = Container.call(this);
self.length = length;
self.shipId = id;
self.isHorizontal = true;
self.isBeingDragged = false;
self.isPlaced = false;
self.shipCells = [];
self.smallScale = 0.5; // Scale for when ship is waiting
// Create visual representation of ship
for (var i = 0; i < length; i++) {
var shipCell = self.attachAsset('ship', {
anchorX: 0,
anchorY: 0
});
shipCell.x = i * CELL_SIZE;
shipCell.y = 0;
self.shipCells.push(shipCell);
}
// Start ships at smaller scale
self.scaleX = self.smallScale;
self.scaleY = self.smallScale;
self.rotate = function () {
self.isHorizontal = !self.isHorizontal;
for (var i = 0; i < self.shipCells.length; i++) {
if (self.isHorizontal) {
self.shipCells[i].x = i * CELL_SIZE;
self.shipCells[i].y = 0;
} else {
self.shipCells[i].x = 0;
self.shipCells[i].y = i * CELL_SIZE;
}
}
};
self.canBePlacedAt = function (gridX, gridY) {
for (var i = 0; i < self.length; i++) {
var x = self.isHorizontal ? gridX + i : gridX;
var y = self.isHorizontal ? gridY : gridY + i;
if (x >= GRID_SIZE || y >= GRID_SIZE || x < 0 || y < 0) {
return false;
}
if (playerGrid[x][y].hasShip) {
return false;
}
}
return true;
};
self.placeOnGrid = function (gridX, gridY) {
if (self.canBePlacedAt(gridX, gridY)) {
for (var i = 0; i < self.length; i++) {
var x = self.isHorizontal ? gridX + i : gridX;
var y = self.isHorizontal ? gridY : gridY + i;
playerGrid[x][y].setShip(self.shipId);
}
self.isPlaced = true;
self.visible = false;
return true;
}
return false;
};
self.down = function (x, y, obj) {
if (gameState === 'placement') {
if (self.isPlaced) {
// Remove ship from grid for repositioning
removeShipFromGrid(self);
self.isPlaced = false;
self.visible = true;
placedShipsCount--;
statusText.setText('Place remaining ships (' + (shipLengths.length - placedShipsCount) + ' left)');
startButton.visible = false;
// Position ship at current grid location for smooth dragging
var currentGridX = -1,
currentGridY = -1;
for (var gx = 0; gx < GRID_SIZE; gx++) {
for (var gy = 0; gy < GRID_SIZE; gy++) {
if (playerGrid[gx][gy].shipId === self.shipId) {
currentGridX = gx;
currentGridY = gy;
break;
}
}
if (currentGridX !== -1) {
break;
}
}
if (currentGridX !== -1) {
self.x = CENTER_GRID_X + currentGridX * CELL_SIZE;
self.y = CENTER_GRID_Y + currentGridY * CELL_SIZE;
}
}
self.isBeingDragged = true;
draggedShip = self;
// Scale up to full size when dragging
tween(self, {
alpha: 0.7,
scaleX: 1,
scaleY: 1
}, {
duration: 200
});
}
};
self.up = function (x, y, obj) {
if (self.isBeingDragged && !self.isPlaced) {
self.isBeingDragged = false;
// Try to place ship on grid with better snapping
var gridX = Math.round((self.x - CENTER_GRID_X) / CELL_SIZE);
var gridY = Math.round((self.y - CENTER_GRID_Y) / CELL_SIZE);
// Snap to grid position
var snapX = CENTER_GRID_X + gridX * CELL_SIZE;
var snapY = CENTER_GRID_Y + gridY * CELL_SIZE;
if (self.placeOnGrid(gridX, gridY)) {
// Snap ship to exact grid position before hiding
self.x = snapX;
self.y = snapY;
tween(self, {
alpha: 1
}, {
duration: 200
});
placedShipsCount++;
if (placedShipsCount >= shipLengths.length) {
statusText.setText('All ships placed! Press START GAME to begin');
startButton.visible = true;
} else {
statusText.setText('Place remaining ships (' + (shipLengths.length - placedShipsCount) + ' left)');
}
} else {
// Return to original position and scale down if can't place
tween(self, {
x: self.originalX,
y: self.originalY,
alpha: 1,
scaleX: self.smallScale,
scaleY: self.smallScale
}, {
duration: 300,
easing: tween.easeOut
});
}
}
};
return self;
});
var GridCell = Container.expand(function (x, y, isPlayer) {
var self = Container.call(this);
self.gridX = x;
self.gridY = y;
self.isPlayer = isPlayer;
self.hasShip = false;
self.isHit = false;
self.isMiss = false;
self.shipId = -1;
var cellGraphics = self.attachAsset('gridBox', {
anchorX: 0,
anchorY: 0
});
self.setShip = function (shipId) {
self.hasShip = true;
self.shipId = shipId;
if (self.isPlayer) {
cellGraphics.tint = 0x808080;
if (self.shipAsset) {
self.shipAsset.alpha = 1;
}
}
};
self.markHit = function () {
self.isHit = true;
cellGraphics.tint = 0xFF0000;
// Add hit marker asset on top of the cell
if (!self.hitMarkerAsset) {
self.hitMarkerAsset = self.attachAsset('hitMarker', {
anchorX: 0,
anchorY: 0
});
// Position hit marker at the correct cell position
self.hitMarkerAsset.x = 0;
self.hitMarkerAsset.y = 0;
}
};
self.markMiss = function (isEnemyMiss) {
self.isMiss = true;
if (isEnemyMiss) {
// Enemy missed on player's grid - use orange color
cellGraphics.tint = 0xffaa00;
} else {
// Player missed on enemy's grid - use green color
cellGraphics.tint = 0x00FF00;
}
};
self.markSunk = function () {
cellGraphics.tint = 0x2F2F2F;
};
self.down = function (x, y, obj) {
if (gameState === 'playing' && !self.isPlayer && !self.isHit && !self.isMiss) {
playerShoot(self.gridX, self.gridY);
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB
});
/****
* Game Code
****/
var Ship = function Ship(length, id) {
this.length = length;
this.id = id;
this.hits = 0;
this.cells = [];
this.isSunk = false;
this.addCell = function (x, y) {
this.cells.push({
x: x,
y: y
});
};
this.hit = function () {
this.hits++;
if (this.hits >= this.length) {
this.isSunk = true;
return true;
}
return false;
};
};
var GRID_SIZE = 10;
var CELL_SIZE = 150; // Increased to 150 for larger game area
var GRID_OFFSET_X = 200;
var PLAYER_GRID_Y = 1200;
var AI_GRID_Y = 200;
// Calculate center positions for single grid display
var CENTER_GRID_X = (2048 - GRID_SIZE * CELL_SIZE) / 2;
var CENTER_GRID_Y = (2732 - GRID_SIZE * CELL_SIZE) / 2 - 100; // Move grid up slightly
var GRID_SPACING = 1000; // Distance between the two grids
var playerGrid = [];
var aiGrid = [];
var playerShips = [];
var aiShips = [];
var gameState = 'intro'; // 'intro', 'placement', 'playing', 'gameOver'
var introScreen = null;
var currentPlayer = 'player'; // 'player', 'ai'
var selectedX = -1;
var selectedY = -1;
var currentShipToPlace = 0;
var isHorizontalPlacement = true;
var shipLengths = [5, 4, 3, 3, 2];
var draggableShips = [];
var placedShipsCount = 0;
var draggedShip = null;
// AI hunting variables
var aiLastHitX = -1;
var aiLastHitY = -1;
var aiHuntingDirections = [];
var aiCurrentDirection = 0;
var aiHuntingMode = false;
// Timer and effect variables
var turnTimer = null;
var turnTimeRemaining = 30;
var isWaitingAfterShot = false;
// Timer text
var timerText = new Text2('30', {
size: 50,
fill: 0xFF0000
});
timerText.anchor.set(1, 0);
LK.gui.topRight.addChild(timerText);
var playerGridContainer = new Container();
var aiGridContainer = new Container();
// UI Elements
var statusText = new Text2('Drag ships to your grid', {
size: 60,
fill: 0x000000
});
statusText.anchor.set(0.5, 0);
LK.gui.top.addChild(statusText);
var instructionText = new Text2('Double tap ships to rotate, drag to reposition', {
size: 40,
fill: 0x00FF00
});
instructionText.anchor.set(0.5, 0);
instructionText.y = 200;
instructionText.x = 0; // Starting position for scrolling
// Add to game instead of GUI so it appears in front of monitor
game.addChild(instructionText);
// Position in front of monitor
instructionText.x = CENTER_GRID_Y + GRID_SIZE * CELL_SIZE - 1000;
instructionText.y = CENTER_GRID_Y + GRID_SIZE * CELL_SIZE - 1700;
// Create scrolling text effect
function scrollInstructionText() {
if (gameState === 'placement') {
var startX = CENTER_GRID_Y + GRID_SIZE * CELL_SIZE - 1200;
var endX = CENTER_GRID_Y + GRID_SIZE * CELL_SIZE - 800;
var scrollDuration = 8000; // Duration to reach end position
instructionText.x = startX;
instructionText.alpha = 1;
tween.stop(instructionText); // Stop all existing tweens on instruction text
// First tween: scroll to end position
tween(instructionText, {
x: endX
}, {
duration: scrollDuration,
easing: tween.linear,
onFinish: function onFinish() {
if (gameState === 'placement') {
// Second tween: fade out at end position
tween(instructionText, {
alpha: 0
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
if (gameState === 'placement') {
// Restart immediately from beginning for seamless loop
scrollInstructionText();
}
}
});
}
}
});
}
}
// Start scrolling after placement begins
LK.setTimeout(function () {
if (gameState === 'placement') {
scrollInstructionText();
}
}, 500);
var startButton = new Text2('START GAME', {
size: 60,
fill: 0x00FF00
});
startButton.anchor.set(0.5, 0.5);
startButton.x = 2048 / 2;
startButton.y = 300; // Move button lower
startButton.visible = false;
game.addChild(startButton);
startButton.down = function (x, y, obj) {
if (gameState === 'placement' && placedShipsCount >= shipLengths.length) {
gameState = 'playing';
statusText.setText('Fire at enemy positions!');
instructionText.setText('Tap enemy grid to shoot');
startButton.visible = false;
placeAIShips();
// Switch to AI grid for player's turn to attack with transition effect
tween(playerGridContainer, {
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
playerGridContainer.visible = false;
aiGridContainer.visible = true;
myCommanderContainer.visible = false;
enemyCommanderContainer.visible = true;
aiGridContainer.alpha = 0;
tween(aiGridContainer, {
alpha: 1
}, {
duration: 300
});
}
});
}
};
// Initialize grids
function initializeGrids() {
// Add containers to game - computer monitor first for background layering
game.addChild(playerGridContainer);
game.addChild(aiGridContainer);
// Move computer monitor to back if it exists
if (computerMonitorContainer) {
game.removeChild(computerMonitorContainer);
game.addChildAt(computerMonitorContainer, 0);
}
// Player grid (center during placement, left side during game)
for (var x = 0; x < GRID_SIZE; x++) {
playerGrid[x] = [];
for (var y = 0; y < GRID_SIZE; y++) {
var cell = new GridCell(x, y, true);
cell.x = CENTER_GRID_X + x * CELL_SIZE;
cell.y = CENTER_GRID_Y + y * CELL_SIZE;
playerGrid[x][y] = cell;
playerGridContainer.addChild(cell);
}
}
// AI grid (center during game)
for (var x = 0; x < GRID_SIZE; x++) {
aiGrid[x] = [];
for (var y = 0; y < GRID_SIZE; y++) {
var cell = new GridCell(x, y, false);
cell.x = CENTER_GRID_X + x * CELL_SIZE;
cell.y = CENTER_GRID_Y + y * CELL_SIZE;
aiGrid[x][y] = cell;
aiGridContainer.addChild(cell);
}
}
// Initialize grid visibility - show player grid during placement phase
playerGridContainer.visible = true;
aiGridContainer.visible = false;
// Add grid labels
var playerLabel = new Text2('Your Fleet', {
size: 40,
fill: 0x000000
});
playerLabel.anchor.set(0.5, 0.5);
playerLabel.x = CENTER_GRID_X + GRID_SIZE * CELL_SIZE / 2;
playerLabel.y = CENTER_GRID_Y - 50;
playerGridContainer.addChild(playerLabel);
var aiLabel = new Text2('Enemy Waters', {
size: 40,
fill: 0x000000
});
aiLabel.anchor.set(0.5, 0.5);
aiLabel.x = CENTER_GRID_X + GRID_SIZE * CELL_SIZE / 2;
aiLabel.y = CENTER_GRID_Y - 50;
aiGridContainer.addChild(aiLabel);
// Add coordinate labels for player grid
for (var i = 0; i < GRID_SIZE; i++) {
// Letters A-J on the left side
var letterLabel = new Text2(String.fromCharCode(65 + i), {
size: 20,
fill: 0x000000
});
letterLabel.anchor.set(0.5, 0.5);
letterLabel.x = CENTER_GRID_X - 30;
letterLabel.y = CENTER_GRID_Y + i * CELL_SIZE + CELL_SIZE / 2;
playerGridContainer.addChild(letterLabel);
// Numbers 1-10 on the top
var numberLabel = new Text2((i + 1).toString(), {
size: 20,
fill: 0x000000
});
numberLabel.anchor.set(0.5, 0.5);
numberLabel.x = CENTER_GRID_X + i * CELL_SIZE + CELL_SIZE / 2;
numberLabel.y = CENTER_GRID_Y - 60;
playerGridContainer.addChild(numberLabel);
}
// Add coordinate labels for AI grid
for (var i = 0; i < GRID_SIZE; i++) {
// Letters A-J on the left side
var letterLabel = new Text2(String.fromCharCode(65 + i), {
size: 20,
fill: 0x000000
});
letterLabel.anchor.set(0.5, 0.5);
letterLabel.x = CENTER_GRID_X - 30;
letterLabel.y = CENTER_GRID_Y + i * CELL_SIZE + CELL_SIZE / 2;
aiGridContainer.addChild(letterLabel);
// Numbers 1-10 on the top
var numberLabel = new Text2((i + 1).toString(), {
size: 20,
fill: 0x000000
});
numberLabel.anchor.set(0.5, 0.5);
numberLabel.x = CENTER_GRID_X + i * CELL_SIZE + CELL_SIZE / 2;
numberLabel.y = CENTER_GRID_Y - 60;
aiGridContainer.addChild(numberLabel);
}
// Create ship visual assets for player grid
for (var x = 0; x < GRID_SIZE; x++) {
for (var y = 0; y < GRID_SIZE; y++) {
var shipAsset = LK.getAsset('ship', {
anchorX: 0,
anchorY: 0,
alpha: 0
});
shipAsset.x = CENTER_GRID_X + x * CELL_SIZE;
shipAsset.y = CENTER_GRID_Y + y * CELL_SIZE;
playerGrid[x][y].shipAsset = shipAsset;
playerGridContainer.addChild(shipAsset);
}
}
// Create draggable ships in a grid layout at bottom of screen, avoiding commander area
var shipStartY = 2400; // Move ships lower to avoid commander assets
var shipStartX = 600; // Start further right to avoid commander assets
var shipsPerRow = 3; // Maximum ships per row
var shipSpacingX = 400; // Horizontal spacing between ships
var shipSpacingY = 250; // Vertical spacing between rows
for (var i = 0; i < shipLengths.length; i++) {
var ship = new DraggableShip(shipLengths[i], i);
// Calculate grid position for ship
var row = Math.floor(i / shipsPerRow);
var col = i % shipsPerRow;
ship.x = shipStartX + col * shipSpacingX;
ship.y = shipStartY + row * shipSpacingY;
ship.originalX = ship.x;
ship.originalY = ship.y;
draggableShips.push(ship);
game.addChild(ship);
}
}
function selectCellForPlacement(x, y) {
selectedX = x;
selectedY = y;
if (canPlaceShip(x, y, shipLengths[currentShipToPlace], isHorizontalPlacement, true)) {
placeShip(x, y, shipLengths[currentShipToPlace], isHorizontalPlacement, true, currentShipToPlace);
currentShipToPlace++;
if (currentShipToPlace >= shipLengths.length) {
gameState = 'playing';
statusText.setText('Fire at enemy positions!');
instructionText.setText('Tap enemy grid to shoot');
placeAIShips();
} else {
statusText.setText('Place ship ' + (currentShipToPlace + 1) + ' (length: ' + shipLengths[currentShipToPlace] + ')');
}
}
}
function canPlaceShip(startX, startY, length, horizontal, isPlayer) {
var grid = isPlayer ? playerGrid : aiGrid;
for (var i = 0; i < length; i++) {
var x = horizontal ? startX + i : startX;
var y = horizontal ? startY : startY + i;
if (x >= GRID_SIZE || y >= GRID_SIZE || x < 0 || y < 0) {
return false;
}
if (grid[x][y].hasShip) {
return false;
}
}
return true;
}
function placeShip(startX, startY, length, horizontal, isPlayer, shipId) {
var grid = isPlayer ? playerGrid : aiGrid;
var ships = isPlayer ? playerShips : aiShips;
var ship = new Ship(length, shipId);
for (var i = 0; i < length; i++) {
var x = horizontal ? startX + i : startX;
var y = horizontal ? startY : startY + i;
grid[x][y].setShip(shipId);
ship.addCell(x, y);
}
ships.push(ship);
}
function placeAIShips() {
for (var i = 0; i < shipLengths.length; i++) {
var placed = false;
var attempts = 0;
while (!placed && attempts < 100) {
var x = Math.floor(Math.random() * GRID_SIZE);
var y = Math.floor(Math.random() * GRID_SIZE);
var horizontal = Math.random() < 0.5;
if (canPlaceShip(x, y, shipLengths[i], horizontal, false)) {
placeShip(x, y, shipLengths[i], horizontal, false, i);
placed = true;
}
attempts++;
}
}
}
function playerShoot(x, y) {
if (currentPlayer !== 'player' || isWaitingAfterShot) {
return;
}
// Stop the timer
if (turnTimer) {
LK.clearInterval(turnTimer);
turnTimer = null;
}
// Play shooting sound when firing
LK.getSound('shoot').play();
var cell = aiGrid[x][y];
var hit = cell.hasShip;
// Create visual effect
var effectAsset = hit ? 'hit' : 'miss';
var effect = LK.getAsset(effectAsset, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.1,
scaleY: 0.1
});
effect.x = CENTER_GRID_X + x * CELL_SIZE + CELL_SIZE / 2;
effect.y = CENTER_GRID_Y + y * CELL_SIZE + CELL_SIZE / 2;
aiGridContainer.addChild(effect);
if (cell.hasShip) {
cell.markHit();
hit = true;
LK.getSound('explosion').play();
// Explosion effect for hit
tween(effect, {
scaleX: 2,
scaleY: 2,
alpha: 0.8
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(effect, {
scaleX: 0.1,
scaleY: 0.1,
alpha: 0
}, {
duration: 500,
onFinish: function onFinish() {
effect.destroy();
}
});
}
});
var ship = null;
// Find the ship by ID in the aiShips array
for (var i = 0; i < aiShips.length; i++) {
if (aiShips[i].id === cell.shipId) {
ship = aiShips[i];
break;
}
}
if (ship) {
var sunk = ship.hit();
if (sunk) {
LK.getSound('sunk').play();
markShipAsSunk(ship, false);
// Enemy commander reacts to ship being sunk
showCommanderSpeech(getRandomSpeech(myCommanderSpeech.sunk), false);
if (checkVictory(false)) {
gameState = 'gameOver';
statusText.setText('Victory! You sank all enemy ships!');
instructionText.setText('');
LK.showYouWin();
return;
}
} else {
// Enemy commander reacts to being hit
showCommanderSpeech(getRandomSpeech(myCommanderSpeech.hit), false);
}
}
statusText.setText('Hit! Fire again!');
// No delay for hits - player can continue shooting immediately
startPlayerTurn();
} else {
cell.markMiss(false);
LK.getSound('waterSplash').play();
// Enemy commander reacts to player missing
showCommanderSpeech(getRandomSpeech(myCommanderSpeech.miss), false);
// Water splash effect for miss
effect.tint = 0x00FF00; // Green color to match miss cell tint
tween(effect, {
scaleX: 1.5,
scaleY: 1.5,
alpha: 0.6
}, {
duration: 400,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(effect, {
scaleX: 0.1,
scaleY: 0.1,
alpha: 0
}, {
duration: 600,
onFinish: function onFinish() {
effect.destroy();
}
});
}
});
currentPlayer = 'ai';
statusText.setText('Miss! Enemy is thinking...');
// 5-second delay before AI turn
isWaitingAfterShot = true;
LK.setTimeout(function () {
isWaitingAfterShot = false;
// Switch to player grid when AI attacks with transition effect
tween(aiGridContainer, {
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
aiGridContainer.visible = false;
playerGridContainer.visible = true;
enemyCommanderContainer.visible = false;
myCommanderContainer.visible = true;
playerGridContainer.alpha = 0;
tween(playerGridContainer, {
alpha: 1
}, {
duration: 300
});
}
});
startAiTurn();
}, 5000);
}
}
function aiTurn() {
if (currentPlayer !== 'ai' || isWaitingAfterShot) {
return;
}
// Stop the timer
if (turnTimer) {
LK.clearInterval(turnTimer);
turnTimer = null;
}
var x, y;
var attempts = 0;
// Smart AI: If in hunting mode, try adjacent cells to last hit
if (aiHuntingMode && aiLastHitX !== -1 && aiLastHitY !== -1) {
var found = false;
// Try directions: up, right, down, left
var directions = [{
x: 0,
y: -1
},
// up
{
x: 1,
y: 0
},
// right
{
x: 0,
y: 1
},
// down
{
x: -1,
y: 0
} // left
];
// Try each direction from the last hit
for (var d = 0; d < directions.length && !found; d++) {
var testX = aiLastHitX + directions[d].x;
var testY = aiLastHitY + directions[d].y;
// Check if position is valid and not already attacked
if (testX >= 0 && testX < GRID_SIZE && testY >= 0 && testY < GRID_SIZE && !playerGrid[testX][testY].isHit && !playerGrid[testX][testY].isMiss) {
x = testX;
y = testY;
found = true;
}
}
// If no adjacent cells available, exit hunting mode
if (!found) {
aiHuntingMode = false;
aiLastHitX = -1;
aiLastHitY = -1;
}
}
// If not in hunting mode or no valid adjacent cells, shoot randomly
if (!aiHuntingMode || aiLastHitX === -1 && aiLastHitY === -1) {
do {
x = Math.floor(Math.random() * GRID_SIZE);
y = Math.floor(Math.random() * GRID_SIZE);
attempts++;
} while ((playerGrid[x][y].isHit || playerGrid[x][y].isMiss) && attempts < 100);
}
// Play shooting sound when AI fires
LK.getSound('shoot').play();
var cell = playerGrid[x][y];
var hit = cell.hasShip;
// Create visual effect
var effectAsset = hit ? 'hit' : 'miss';
var effect = LK.getAsset(effectAsset, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.1,
scaleY: 0.1
});
effect.x = CENTER_GRID_X + x * CELL_SIZE + CELL_SIZE / 2;
effect.y = CENTER_GRID_Y + y * CELL_SIZE + CELL_SIZE / 2;
playerGridContainer.addChild(effect);
if (cell.hasShip) {
cell.markHit();
LK.getSound('explosion').play();
// Explosion effect for hit
tween(effect, {
scaleX: 2,
scaleY: 2,
alpha: 0.8
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(effect, {
scaleX: 0.1,
scaleY: 0.1,
alpha: 0
}, {
duration: 500,
onFinish: function onFinish() {
effect.destroy();
}
});
}
});
// Enter hunting mode and remember this hit position
aiHuntingMode = true;
aiLastHitX = x;
aiLastHitY = y;
var ship = null;
// Find the ship by ID in the playerShips array
for (var i = 0; i < playerShips.length; i++) {
if (playerShips[i].id === cell.shipId) {
ship = playerShips[i];
break;
}
}
if (ship) {
var sunk = ship.hit();
if (sunk) {
LK.getSound('sunk').play();
markShipAsSunk(ship, true);
// Exit hunting mode when ship is sunk
aiHuntingMode = false;
aiLastHitX = -1;
aiLastHitY = -1;
// Enemy commander celebrates sinking player's ship
showCommanderSpeech(getRandomSpeech(enemyCommanderSpeech.sunk), true);
if (checkVictory(true)) {
gameState = 'gameOver';
statusText.setText('Defeat! Enemy sank all your ships!');
instructionText.setText('');
LK.showGameOver();
return;
}
} else {
// Enemy commander celebrates hitting player's ship
showCommanderSpeech(getRandomSpeech(enemyCommanderSpeech.hit), true);
}
}
statusText.setText('Enemy hit your ship!');
// 5-second delay before AI continues
isWaitingAfterShot = true;
LK.setTimeout(function () {
isWaitingAfterShot = false;
startAiTurn();
}, 5000);
} else {
cell.markMiss(true);
LK.getSound('waterSplash').play();
// Enemy commander reacts to missing
showCommanderSpeech(getRandomSpeech(enemyCommanderSpeech.miss), true);
// Water splash effect for miss
effect.tint = 0xFFAA00;
tween(effect, {
scaleX: 1.5,
scaleY: 1.5,
alpha: 0.6
}, {
duration: 400,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(effect, {
scaleX: 0.1,
scaleY: 0.1,
alpha: 0
}, {
duration: 600,
onFinish: function onFinish() {
effect.destroy();
}
});
}
});
currentPlayer = 'player';
statusText.setText('Enemy missed! Your turn!');
// 5-second delay before player turn
isWaitingAfterShot = true;
LK.setTimeout(function () {
isWaitingAfterShot = false;
// Switch to AI grid for player's turn to attack with transition effect
tween(playerGridContainer, {
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
playerGridContainer.visible = false;
aiGridContainer.visible = true;
myCommanderContainer.visible = false;
enemyCommanderContainer.visible = true;
aiGridContainer.alpha = 0;
tween(aiGridContainer, {
alpha: 1
}, {
duration: 300
});
}
});
startPlayerTurn();
}, 5000);
}
}
function markShipAsSunk(ship, isPlayer) {
var grid = isPlayer ? playerGrid : aiGrid;
for (var i = 0; i < ship.cells.length; i++) {
var cellPos = ship.cells[i];
grid[cellPos.x][cellPos.y].markSunk();
// Darken hit markers on sunk ship cells
if (grid[cellPos.x][cellPos.y].hitMarkerAsset) {
tween(grid[cellPos.x][cellPos.y].hitMarkerAsset, {
alpha: 0.4
}, {
duration: 500,
easing: tween.easeOut
});
}
}
}
function removeShipFromGrid(ship) {
for (var x = 0; x < GRID_SIZE; x++) {
for (var y = 0; y < GRID_SIZE; y++) {
if (playerGrid[x][y].shipId === ship.shipId) {
playerGrid[x][y].hasShip = false;
playerGrid[x][y].shipId = -1;
var cellGraphics = playerGrid[x][y].children[0];
cellGraphics.tint = 0xFFFFFF;
if (playerGrid[x][y].shipAsset) {
playerGrid[x][y].shipAsset.alpha = 0;
}
}
}
}
}
function checkVictory(playerLost) {
var ships = playerLost ? playerShips : aiShips;
for (var i = 0; i < ships.length; i++) {
if (!ships[i].isSunk) {
return false;
}
}
return true;
}
// Double tap to rotate ship during placement
var lastTapTime = 0;
game.down = function (x, y, obj) {
if (gameState === 'placement') {
var currentTime = Date.now();
if (currentTime - lastTapTime < 300) {
// Find ship being rotated - check both unplaced and placed ships
for (var i = 0; i < draggableShips.length; i++) {
var ship = draggableShips[i];
var shipBounds = {
x: ship.x,
y: ship.y,
width: ship.isHorizontal ? ship.length * CELL_SIZE : CELL_SIZE,
height: ship.isHorizontal ? CELL_SIZE : ship.length * CELL_SIZE
};
if (x >= shipBounds.x && x <= shipBounds.x + shipBounds.width && y >= shipBounds.y && y <= shipBounds.y + shipBounds.height) {
if (ship.isPlaced) {
// Remove ship from grid
removeShipFromGrid(ship);
ship.isPlaced = false;
ship.visible = true;
placedShipsCount--;
}
ship.rotate();
break;
}
}
instructionText.setText('Double tap ships to rotate, drag to reposition');
}
lastTapTime = currentTime;
}
};
game.move = function (x, y, obj) {
if (gameState === 'placement' && draggedShip) {
draggedShip.x = x - draggedShip.width / 2;
draggedShip.y = y - draggedShip.height / 2;
}
};
game.up = function (x, y, obj) {
draggedShip = null;
};
function startPlayerTurn() {
currentPlayer = 'player';
turnTimeRemaining = 30;
timerText.setText(turnTimeRemaining.toString());
timerText.visible = true;
// Clear any existing timer first
if (turnTimer) {
LK.clearInterval(turnTimer);
turnTimer = null;
}
turnTimer = LK.setInterval(function () {
turnTimeRemaining--;
timerText.setText(turnTimeRemaining.toString());
if (turnTimeRemaining <= 0) {
LK.clearInterval(turnTimer);
turnTimer = null;
timerText.visible = false;
// Auto-switch to AI turn on timeout
currentPlayer = 'ai';
statusText.setText('Time up! Enemy is thinking...');
tween(aiGridContainer, {
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
aiGridContainer.visible = false;
playerGridContainer.visible = true;
enemyCommanderContainer.visible = false;
myCommanderContainer.visible = true;
playerGridContainer.alpha = 0;
tween(playerGridContainer, {
alpha: 1
}, {
duration: 300
});
}
});
startAiTurn();
}
}, 1000);
}
function startAiTurn() {
currentPlayer = 'ai';
turnTimeRemaining = 30;
timerText.setText(turnTimeRemaining.toString());
timerText.visible = true;
// Clear any existing timer first
if (turnTimer) {
LK.clearInterval(turnTimer);
turnTimer = null;
}
// AI thinks for 2-5 seconds before shooting
var thinkTime = 2000 + Math.random() * 3000;
turnTimer = LK.setInterval(function () {
turnTimeRemaining--;
timerText.setText(turnTimeRemaining.toString());
if (turnTimeRemaining <= 0) {
LK.clearInterval(turnTimer);
turnTimer = null;
timerText.visible = false;
aiTurn();
}
}, 1000);
LK.setTimeout(function () {
if (currentPlayer === 'ai' && !isWaitingAfterShot) {
aiTurn();
}
}, thinkTime);
}
// Create commander assets
var myCommanderContainer = new Container();
var enemyCommanderContainer = new Container();
// Position commanders higher and at bottom left corner
myCommanderContainer.x = 50;
myCommanderContainer.y = 2732 - 500; // Moved even higher up
enemyCommanderContainer.x = 50;
enemyCommanderContainer.y = 2732 - 500; // Same position as my commander
// Create shadow assets first (positioned slightly offset)
var myCommanderShadow = myCommanderContainer.attachAsset('myCommander', {
anchorX: 0,
anchorY: 0,
scaleX: 2.2,
scaleY: 2.2,
alpha: 0.3,
tint: 0x000000
});
myCommanderShadow.x = 8;
myCommanderShadow.y = 8;
var enemyCommanderShadow = enemyCommanderContainer.attachAsset('enemyCommander', {
anchorX: 0,
anchorY: 0,
scaleX: 2.2,
scaleY: 2.2,
alpha: 0.3,
tint: 0x000000
});
enemyCommanderShadow.x = 8;
enemyCommanderShadow.y = 8;
// Create main commander assets (larger size)
var myCommanderAsset = myCommanderContainer.attachAsset('myCommander', {
anchorX: 0,
anchorY: 0,
scaleX: 2.2,
scaleY: 2.2
});
var enemyCommanderAsset = enemyCommanderContainer.attachAsset('enemyCommander', {
anchorX: 0,
anchorY: 0,
scaleX: 2.2,
scaleY: 2.2
});
// Add commanders to game
game.addChild(myCommanderContainer);
game.addChild(enemyCommanderContainer);
// Initialize commander visibility - show my commander during placement phase
myCommanderContainer.visible = true;
enemyCommanderContainer.visible = false;
// Commander speech arrays
var myCommanderSpeech = {
hit: ["Lanet olsun! Nasıl buldun?", "Bu olamaz! Şanslı atış!", "Beni buldun ama savaş henüz bitmedi!", "İyi atış... ama son olmayacak!"],
miss: ["Hah! Ordumu bulmak kolay değil!", "Boşa atış! Denemeye devam et!", "Su sıçradı ama gemim yerinde!", "Yaklaştın ama yeterli değil!"],
sunk: ["Gemimi batırdın... ama intikam alacağım!", "Bu savaşı kaybettim ama onur hala benimle!", "İyi savaştın... şimdilik kazandın"]
};
var enemyCommanderSpeech = {
hit: ["Mükemmel atış! Hedefi bulduk!", "Doğrudan isabet! Böyle devam!", "Ateş! Düşman gemisini yakaladık!", "Harika! Bu şekilde kazanacağız!"],
miss: ["Lanet! Hedefi kaçırdık!", "Su sıçradı! Tekrar dene!", "Bu sefer olmadı ama pes etmem!", "Yakında hedefimi bulacağım!"],
sunk: ["Bir gemi daha battı! Zafer yakın!", "Düşman filosu eriyor!", "Mükemmel! Böyle devam edersek kazanırız!"]
};
// Current speech display
var currentSpeechText = null;
var speechTimeout = null;
function showCommanderSpeech(text, isEnemyCommander) {
// Clear existing speech
if (currentSpeechText) {
currentSpeechText.destroy();
currentSpeechText = null;
}
if (speechTimeout) {
LK.clearTimeout(speechTimeout);
speechTimeout = null;
}
// Create speech bubble container
currentSpeechText = new Container();
// Create speech bubble background
var speechBubble = currentSpeechText.attachAsset('speechBubble', {
anchorX: 0,
anchorY: 0
});
// Create speech bubble text
var speechText = new Text2(text, {
size: 36,
fill: 0x000000
});
speechText.anchor.set(0.5, 0.5);
speechText.x = 350; // Move text further to the right in bubble
speechText.y = 75; // Center in bubble
currentSpeechText.addChild(speechText);
// Add speech bubble directly to game instead of commander container
game.addChild(currentSpeechText);
// Position speech bubble next to appropriate commander
if (isEnemyCommander && enemyCommanderContainer.visible) {
currentSpeechText.x = enemyCommanderContainer.x + 440; // Position to the right of commander
currentSpeechText.y = enemyCommanderContainer.y + 50; // Align with top of commander
} else if (!isEnemyCommander && myCommanderContainer.visible) {
currentSpeechText.x = myCommanderContainer.x + 440; // Position to the right of commander
currentSpeechText.y = myCommanderContainer.y + 50; // Align with top of commander
} else {
// Fallback positioning if no commander is visible
currentSpeechText.x = 50 + 440;
currentSpeechText.y = 2732 - 500 + 50;
}
// Animate speech appearance
currentSpeechText.alpha = 0;
tween(currentSpeechText, {
alpha: 1
}, {
duration: 300
});
// Remove speech after 3 seconds
speechTimeout = LK.setTimeout(function () {
if (currentSpeechText) {
tween(currentSpeechText, {
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
if (currentSpeechText) {
currentSpeechText.destroy();
currentSpeechText = null;
}
}
});
}
}, 3000);
}
function getRandomSpeech(speechArray) {
return speechArray[Math.floor(Math.random() * speechArray.length)];
}
// Initialize the game
function createIntroScreen() {
introScreen = new Container();
game.addChild(introScreen);
// Create television frame
var tvFrame = LK.getAsset('tvFrame', {
anchorX: 0.5,
anchorY: 0.5
});
tvFrame.x = 2048 / 2;
tvFrame.y = 2732 / 2;
introScreen.addChild(tvFrame);
// Create TV stand
var tvStand = LK.getAsset('tvStand', {
anchorX: 0.5,
anchorY: 0
});
tvStand.x = 2048 / 2;
tvStand.y = 2732 / 2 + 1450;
introScreen.addChild(tvStand);
// Create TV buttons and speakers
var powerButton = LK.getAsset('tvButton', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0xFF4444
});
powerButton.x = 2048 / 2 + 1200;
powerButton.y = 2732 / 2 - 1200;
introScreen.addChild(powerButton);
var volumeButton = LK.getAsset('tvButton', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0x4444FF
});
volumeButton.x = 2048 / 2 + 1200;
volumeButton.y = 2732 / 2 - 1100;
introScreen.addChild(volumeButton);
// Create speakers
for (var s = 0; s < 6; s++) {
var speaker = LK.getAsset('tvSpeaker', {
anchorX: 0.5,
anchorY: 0.5
});
speaker.x = 2048 / 2 + 1200;
speaker.y = 2732 / 2 - 800 + s * 60;
introScreen.addChild(speaker);
}
// Create TV screen (black background)
var tvScreen = LK.getAsset('tvScreen', {
anchorX: 0.5,
anchorY: 0.5
});
tvScreen.x = 2048 / 2;
tvScreen.y = 2732 / 2;
introScreen.addChild(tvScreen);
// Create container for all TV content
var tvContent = new Container();
tvContent.x = 2048 / 2 - 950; // Center content in TV screen
tvContent.y = 2732 / 2 - 1300;
introScreen.addChild(tvContent);
// Create gradient background layers for depth (now inside TV)
var bgLayer1 = LK.getAsset('gridBox', {
anchorX: 0,
anchorY: 0,
scaleX: 16,
scaleY: 21,
tint: 0x001A33,
alpha: 1
});
tvContent.addChild(bgLayer1);
var bgLayer2 = LK.getAsset('gridBox', {
anchorX: 0,
anchorY: 0,
scaleX: 15,
scaleY: 19,
tint: 0x003D66,
alpha: 0.7
});
bgLayer2.x = 80;
bgLayer2.y = 80;
tvContent.addChild(bgLayer2);
// Create multiple water layers for depth
var waterLayer1 = LK.getAsset('water', {
anchorX: 0,
anchorY: 0,
scaleX: 24,
scaleY: 28,
alpha: 0.08,
tint: 0x1B4F72
});
tvContent.addChild(waterLayer1);
var waterLayer2 = LK.getAsset('water', {
anchorX: 0,
anchorY: 0,
scaleX: 20,
scaleY: 24,
alpha: 0.15,
tint: 0x2E86AB
});
tvContent.addChild(waterLayer2);
var waterLayer3 = LK.getAsset('water', {
anchorX: 0,
anchorY: 0,
scaleX: 16,
scaleY: 20,
alpha: 0.12,
tint: 0x5DADE2
});
tvContent.addChild(waterLayer3);
// Create floating water particles
var waterParticles = [];
for (var p = 0; p < 8; p++) {
var particle = LK.getAsset('water', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.3 + Math.random() * 0.2,
scaleY: 0.3 + Math.random() * 0.2,
alpha: 0.2 + Math.random() * 0.1,
tint: 0x87CEEB
});
particle.x = Math.random() * 1900;
particle.y = Math.random() * 2600;
waterParticles.push(particle);
tvContent.addChild(particle);
}
// Animate water layers with wave motion
tween(waterLayer1, {
alpha: 0.12,
x: -50
}, {
duration: 4000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(waterLayer1, {
alpha: 0.08,
x: 0
}, {
duration: 4000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(waterLayer1, {
alpha: 0.12,
x: -50
}, {
duration: 4000,
easing: tween.easeInOut,
onFinish: arguments.callee
});
}
});
}
});
tween(waterLayer2, {
alpha: 0.22,
x: 30
}, {
duration: 3500,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(waterLayer2, {
alpha: 0.15,
x: -30
}, {
duration: 3500,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(waterLayer2, {
alpha: 0.22,
x: 30
}, {
duration: 3500,
easing: tween.easeInOut,
onFinish: arguments.callee
});
}
});
}
});
tween(waterLayer3, {
alpha: 0.18,
y: -20
}, {
duration: 3000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(waterLayer3, {
alpha: 0.12,
y: 20
}, {
duration: 3000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(waterLayer3, {
alpha: 0.18,
y: -20
}, {
duration: 3000,
easing: tween.easeInOut,
onFinish: arguments.callee
});
}
});
}
});
// Animate water particles
for (var p = 0; p < waterParticles.length; p++) {
(function (particle, index) {
function floatParticle() {
if (gameState === 'intro') {
var targetX = Math.random() * 1900;
var targetY = Math.random() * 2600;
tween(particle, {
x: targetX,
y: targetY,
alpha: 0.1 + Math.random() * 0.15,
rotation: Math.random() * Math.PI * 2
}, {
duration: 8000 + Math.random() * 4000,
easing: tween.easeInOut,
onFinish: floatParticle
});
}
}
LK.setTimeout(floatParticle, index * 500);
})(waterParticles[p], p);
}
// Main title with shadow effect
var titleShadow = new Text2('NAVAL COMBAT', {
size: 100,
fill: 0x000000
});
titleShadow.anchor.set(0.5, 0.5);
titleShadow.x = 950 + 6;
titleShadow.y = 406;
titleShadow.alpha = 0;
tvContent.addChild(titleShadow);
var titleText = new Text2('NAVAL COMBAT', {
size: 100,
fill: 0xFFD700
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 950;
titleText.y = 400;
titleText.alpha = 0;
tvContent.addChild(titleText);
// Subtitle with glow effect
var subtitleGlow = new Text2('Strategic Fleet Warfare', {
size: 42,
fill: 0x87CEEB
});
subtitleGlow.anchor.set(0.5, 0.5);
subtitleGlow.x = 950;
subtitleGlow.y = 550;
subtitleGlow.alpha = 0;
tvContent.addChild(subtitleGlow);
var subtitleText = new Text2('Strategic Fleet Warfare', {
size: 42,
fill: 0xFFFFFF
});
subtitleText.anchor.set(0.5, 0.5);
subtitleText.x = 950;
subtitleText.y = 550;
subtitleText.alpha = 0;
tvContent.addChild(subtitleText);
// Create naval battle themed decorative elements
var navyElements = [];
var shipColors = [0x2C3E50, 0x34495E, 0x566573, 0x7F8C8D, 0x95A5A6];
var enemyColors = [0x8B0000, 0xA52A2A, 0xB22222, 0xDC143C, 0xFF4500];
// Create allied fleet formation (left side)
for (var i = 0; i < 4; i++) {
var allyShip = LK.getAsset('ship', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.0 + i * 0.2,
scaleY: 2.0 + i * 0.2,
tint: shipColors[i]
});
allyShip.x = 120 + i * 50;
allyShip.y = 750 + i * 70;
allyShip.alpha = 0;
allyShip.rotation = Math.PI / 8 + i * 0.05;
navyElements.push(allyShip);
tvContent.addChild(allyShip);
}
// Create enemy fleet formation (right side)
for (var i = 0; i < 4; i++) {
var enemyShip = LK.getAsset('ship', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.0 + i * 0.2,
scaleY: 2.0 + i * 0.2,
tint: enemyColors[i]
});
enemyShip.x = 1780 - i * 50;
enemyShip.y = 750 + i * 70;
enemyShip.alpha = 0;
enemyShip.rotation = -Math.PI / 8 - i * 0.05;
navyElements.push(enemyShip);
tvContent.addChild(enemyShip);
}
// Add naval commander silhouettes
var allyCommander = LK.getAsset('myCommander', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2,
alpha: 0,
tint: 0x2C3E50
});
allyCommander.x = 250;
allyCommander.y = 1100;
navyElements.push(allyCommander);
tvContent.addChild(allyCommander);
var enemyCommander = LK.getAsset('enemyCommander', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2,
alpha: 0,
tint: 0x8B0000
});
enemyCommander.x = 1650;
enemyCommander.y = 1100;
navyElements.push(enemyCommander);
tvContent.addChild(enemyCommander);
// Add strategic grid overlay effects
for (var i = 0; i < 6; i++) {
var gridElement = LK.getAsset('gridBox', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.4,
scaleY: 0.4,
alpha: 0,
tint: 0x3498DB
});
gridElement.x = 950 + (i % 3 - 1) * 160;
gridElement.y = 900 + Math.floor(i / 3) * 120;
navyElements.push(gridElement);
tvContent.addChild(gridElement);
}
// Replace shipFormation reference with navyElements
var shipFormation = navyElements;
// Enhanced start button with frame
var buttonFrame = LK.getAsset('gridBox', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 3.2,
scaleY: 1.0,
tint: 0xFFD700,
alpha: 0
});
buttonFrame.x = 950;
buttonFrame.y = 1300;
tvContent.addChild(buttonFrame);
var startGameButton = new Text2('⚓ START BATTLE ⚓', {
size: 58,
fill: 0x000000
});
startGameButton.anchor.set(0.5, 0.5);
startGameButton.x = 950;
startGameButton.y = 1300;
startGameButton.alpha = 0;
tvContent.addChild(startGameButton);
// Additional UI elements
var versionText = new Text2('Admiral Edition v1.0', {
size: 25,
fill: 0x808080
});
versionText.anchor.set(0.5, 0.5);
versionText.x = 950;
versionText.y = 1450;
versionText.alpha = 0;
tvContent.addChild(versionText);
var instructionsText = new Text2('Deploy your fleet strategically and command the seas!', {
size: 36,
fill: 0xE0E0E0
});
instructionsText.anchor.set(0.5, 0.5);
instructionsText.x = 950;
instructionsText.y = 1600;
instructionsText.alpha = 0;
tvContent.addChild(instructionsText);
// Professional animation sequence
// Title entrance with dramatic effect
tween(titleShadow, {
alpha: 0.6,
y: 500,
scaleX: 1.05,
scaleY: 1.05
}, {
duration: 1200,
easing: tween.elasticOut
});
tween(titleText, {
alpha: 1,
y: 500,
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 1200,
easing: tween.elasticOut
});
// Subtitle with sequential glow effect
LK.setTimeout(function () {
tween(subtitleGlow, {
alpha: 0.4,
scaleX: 1.05,
scaleY: 1.05
}, {
duration: 800,
easing: tween.easeOut
});
tween(subtitleText, {
alpha: 1
}, {
duration: 800,
easing: tween.easeOut
});
}, 400);
// Naval fleet formation entrance with battle positioning
LK.setTimeout(function () {
for (var i = 0; i < navyElements.length; i++) {
(function (element, delay) {
LK.setTimeout(function () {
// Different entrance effects based on element type
var isShip = element.x < 1024; // Left side elements are allied ships
var entranceEffect = isShip ? {
alpha: 0.85,
scaleX: element.scaleX * 1.2,
scaleY: element.scaleY * 1.2,
x: element.x + (isShip ? 50 : -50)
} : {
alpha: 0.7,
scaleX: element.scaleX * 1.1,
scaleY: element.scaleY * 1.1
};
tween(element, entranceEffect, {
duration: 1200,
easing: tween.elasticOut
});
// Add naval movement patterns
function navalMovement() {
if (gameState === 'intro') {
var movementPattern = isShip ? {
y: element.y + (10 + Math.random() * 8),
rotation: element.rotation + (Math.random() - 0.5) * 0.1,
alpha: element.alpha * (0.9 + Math.random() * 0.2)
} : {
scaleX: element.scaleX * (0.95 + Math.random() * 0.1),
scaleY: element.scaleY * (0.95 + Math.random() * 0.1),
alpha: element.alpha * (0.8 + Math.random() * 0.4)
};
tween(element, movementPattern, {
duration: 2500 + Math.random() * 1500,
easing: tween.easeInOut,
onFinish: function onFinish() {
var returnPattern = isShip ? {
y: element.y - (10 + Math.random() * 8),
rotation: element.rotation - (Math.random() - 0.5) * 0.1,
alpha: element.alpha / (0.9 + Math.random() * 0.2)
} : {
scaleX: element.scaleX / (0.95 + Math.random() * 0.1),
scaleY: element.scaleY / (0.95 + Math.random() * 0.1),
alpha: element.alpha / (0.8 + Math.random() * 0.4)
};
tween(element, returnPattern, {
duration: 2500 + Math.random() * 1500,
easing: tween.easeInOut,
onFinish: navalMovement
});
}
});
}
}
LK.setTimeout(navalMovement, 1500 + Math.random() * 1000);
}, delay * 120);
})(navyElements[i], i);
}
}, 800);
// Button entrance with frame
LK.setTimeout(function () {
tween(buttonFrame, {
alpha: 0.8,
scaleX: 4.2,
scaleY: 1.3
}, {
duration: 600,
easing: tween.easeOut
});
tween(startGameButton, {
alpha: 1,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 600,
easing: tween.bounceOut
});
tween(versionText, {
alpha: 1
}, {
duration: 600,
easing: tween.easeOut
});
tween(instructionsText, {
alpha: 1
}, {
duration: 600,
easing: tween.easeOut
});
}, 1400);
// Enhanced pulsing effect for start button
LK.setTimeout(function () {
function pulseButton() {
if (gameState === 'intro') {
tween(startGameButton, {
scaleX: 1.15,
scaleY: 1.15,
tint: 0x00FF00
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(startGameButton, {
scaleX: 1.0,
scaleY: 1.0,
tint: 0xFFFFFF
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: pulseButton
});
}
});
tween(buttonFrame, {
alpha: 1,
scaleX: 4.4,
scaleY: 1.4
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(buttonFrame, {
alpha: 0.8,
scaleX: 4.2,
scaleY: 1.3
}, {
duration: 1000,
easing: tween.easeInOut
});
}
});
}
}
pulseButton();
}, 2000);
// Add TV static overlay effect
var tvStatic = LK.getAsset('gridBox', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 16,
scaleY: 21,
alpha: 0.02,
tint: 0xFFFFFF
});
tvStatic.x = 950;
tvStatic.y = 1300;
tvContent.addChild(tvStatic);
// Animate TV static
function animateStatic() {
if (gameState === 'intro') {
tween(tvStatic, {
alpha: 0.05 + Math.random() * 0.03,
scaleX: 16 + Math.random() * 0.2,
scaleY: 21 + Math.random() * 0.2
}, {
duration: 100 + Math.random() * 200,
onFinish: animateStatic
});
}
}
animateStatic();
// Add TV screen glow effect
var screenGlow = LK.getAsset('tvScreen', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.05,
scaleY: 1.05,
tint: 0x4A90E2,
alpha: 0.1
});
screenGlow.x = 2048 / 2;
screenGlow.y = 2732 / 2;
introScreen.addChild(screenGlow);
// Animate screen glow
function animateGlow() {
if (gameState === 'intro') {
tween(screenGlow, {
alpha: 0.15,
scaleX: 1.08,
scaleY: 1.08
}, {
duration: 2000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(screenGlow, {
alpha: 0.1,
scaleX: 1.05,
scaleY: 1.05
}, {
duration: 2000,
easing: tween.easeInOut,
onFinish: animateGlow
});
}
});
}
}
animateGlow();
// Click handler for start button with effect
startGameButton.down = function (x, y, obj) {
if (gameState === 'intro') {
// Button press effect
tween(startGameButton, {
scaleX: 0.95,
scaleY: 0.95,
alpha: 0.8
}, {
duration: 100,
onFinish: function onFinish() {
tween(startGameButton, {
scaleX: 1.0,
scaleY: 1.0,
alpha: 1
}, {
duration: 100
});
}
});
// Fade out intro screen with dramatic effect
tween(introScreen, {
alpha: 0,
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 800,
easing: tween.easeIn,
onFinish: function onFinish() {
introScreen.destroy();
introScreen = null;
gameState = 'placement';
statusText.setText('Drag ships to your grid');
// Start ocean waves music after intro ends
LK.playMusic('oceanWaves');
// Show computer monitor and radar system
computerMonitorContainer.visible = true;
computerMonitorContainer.alpha = 0;
tween(computerMonitorContainer, {
alpha: 1
}, {
duration: 1000,
easing: tween.easeOut
});
initializeGrids();
// Start scrolling text immediately when placement begins
scrollInstructionText();
}
});
}
};
}
createIntroScreen();
// Create computer monitor frame around game area
var computerMonitorContainer = new Container();
computerMonitorContainer.visible = false; // Hide during intro
game.addChild(computerMonitorContainer);
// Position computer monitor behind the game grids
var monitorFrame = computerMonitorContainer.attachAsset('computerMonitor', {
anchorX: 0.5,
anchorY: 0.5
});
monitorFrame.x = 2048 / 2;
monitorFrame.y = CENTER_GRID_Y + GRID_SIZE * CELL_SIZE / 2;
// Computer screen background
var computerScreen = computerMonitorContainer.attachAsset('computerScreen', {
anchorX: 0.5,
anchorY: 0.5
});
computerScreen.x = 2048 / 2;
computerScreen.y = CENTER_GRID_Y + GRID_SIZE * CELL_SIZE / 2;
// Computer base
var computerBase = computerMonitorContainer.attachAsset('computerBase', {
anchorX: 0.5,
anchorY: 0
});
computerBase.x = 2048 / 2;
computerBase.y = CENTER_GRID_Y + GRID_SIZE * CELL_SIZE + 50;
// Create rotating radar system in background
var radarContainer = new Container();
computerMonitorContainer.addChild(radarContainer);
radarContainer.x = 2048 / 2;
radarContainer.y = CENTER_GRID_Y + GRID_SIZE * CELL_SIZE / 2;
// Radar circles (concentric)
for (var i = 1; i <= 3; i++) {
var radarCircle = radarContainer.attachAsset('radarCircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: i * 0.4,
scaleY: i * 0.4,
alpha: 0.15
});
radarCircle.x = 0;
radarCircle.y = 0;
}
// Radar center dot
var radarCenter = radarContainer.attachAsset('radarCenter', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.8
});
radarCenter.x = 0;
radarCenter.y = 0;
// Rotating radar sweep line
var radarSweep = radarContainer.attachAsset('radarSweep', {
anchorX: 0,
anchorY: 0.5,
alpha: 0.6
});
radarSweep.x = 0;
radarSweep.y = 0;
// Start radar sweep rotation
function rotateRadarSweep() {
if (gameState === 'playing' || gameState === 'placement') {
tween(radarSweep, {
rotation: radarSweep.rotation + Math.PI * 2
}, {
duration: 3000,
easing: tween.linear,
onFinish: rotateRadarSweep
});
}
}
// Start radar sweep after placement phase begins
LK.setTimeout(function () {
if (gameState === 'placement') {
rotateRadarSweep();
}
}, 1500);
// Start radar sweep after initialization
LK.setTimeout(function () {
rotateRadarSweep();
}, 500);
// Add computer-style grid overlay
var computerGrid = new Container();
computerMonitorContainer.addChild(computerGrid);
computerGrid.x = 2048 / 2 - 950;
computerGrid.y = CENTER_GRID_Y - 750;
// Create computer grid lines
for (var i = 0; i <= 20; i++) {
// Vertical lines
var vLine = LK.getAsset('gridLine', {
anchorX: 0.5,
anchorY: 0,
scaleX: 0.5,
scaleY: 1.2,
alpha: 0.08,
tint: 0x00FF00
});
vLine.x = i * 95;
vLine.y = 0;
computerGrid.addChild(vLine);
// Horizontal lines
var hLine = LK.getAsset('gridLine', {
anchorX: 0,
anchorY: 0.5,
scaleX: 1.0,
scaleY: 0.5,
alpha: 0.08,
tint: 0x00FF00,
rotation: Math.PI / 2
});
hLine.x = 0;
hLine.y = i * 75;
computerGrid.addChild(hLine);
}
// Add ocean movement to game containers
function addOceanMovement() {
if (gameState === 'playing' || gameState === 'placement') {
// Gentle rocking motion for player grid
tween(playerGridContainer, {
x: playerGridContainer.x + (Math.random() - 0.5) * 8,
y: playerGridContainer.y + (Math.random() - 0.5) * 6,
rotation: playerGridContainer.rotation + (Math.random() - 0.5) * 0.008
}, {
duration: 2000 + Math.random() * 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Return to original position with slight variation
tween(playerGridContainer, {
x: game.children.indexOf(playerGridContainer) >= 0 ? playerGridContainer.x - (Math.random() - 0.5) * 8 : playerGridContainer.x,
y: game.children.indexOf(playerGridContainer) >= 0 ? playerGridContainer.y - (Math.random() - 0.5) * 6 : playerGridContainer.y,
rotation: playerGridContainer.rotation - (Math.random() - 0.5) * 0.008
}, {
duration: 2000 + Math.random() * 1000,
easing: tween.easeInOut,
onFinish: addOceanMovement
});
}
});
// Similar motion for AI grid
tween(aiGridContainer, {
x: aiGridContainer.x + (Math.random() - 0.5) * 8,
y: aiGridContainer.y + (Math.random() - 0.5) * 6,
rotation: aiGridContainer.rotation + (Math.random() - 0.5) * 0.008
}, {
duration: 2200 + Math.random() * 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(aiGridContainer, {
x: game.children.indexOf(aiGridContainer) >= 0 ? aiGridContainer.x - (Math.random() - 0.5) * 8 : aiGridContainer.x,
y: game.children.indexOf(aiGridContainer) >= 0 ? aiGridContainer.y - (Math.random() - 0.5) * 6 : aiGridContainer.y,
rotation: aiGridContainer.rotation - (Math.random() - 0.5) * 0.008
}, {
duration: 2200 + Math.random() * 800,
easing: tween.easeInOut
});
}
});
// Gentle movement for commander containers
tween(myCommanderContainer, {
x: myCommanderContainer.x + (Math.random() - 0.5) * 4,
y: myCommanderContainer.y + (Math.random() - 0.5) * 3
}, {
duration: 3000 + Math.random() * 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(myCommanderContainer, {
x: 50 + (Math.random() - 0.5) * 4,
y: 2732 - 500 + (Math.random() - 0.5) * 3
}, {
duration: 3000 + Math.random() * 1000,
easing: tween.easeInOut
});
}
});
tween(enemyCommanderContainer, {
x: enemyCommanderContainer.x + (Math.random() - 0.5) * 4,
y: enemyCommanderContainer.y + (Math.random() - 0.5) * 3
}, {
duration: 2800 + Math.random() * 1200,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(enemyCommanderContainer, {
x: 50 + (Math.random() - 0.5) * 4,
y: 2732 - 500 + (Math.random() - 0.5) * 3
}, {
duration: 2800 + Math.random() * 1200,
easing: tween.easeInOut
});
}
});
}
}
// Add computer screen effects
function addComputerEffects() {
if (gameState === 'playing' || gameState === 'placement') {
// Screen flicker effect
if (computerScreen) {
var flickerAlpha = 0.95 + Math.random() * 0.05;
tween(computerScreen, {
alpha: flickerAlpha,
tint: 0x001100 + Math.floor(Math.random() * 0x001100)
}, {
duration: 100 + Math.random() * 200,
onFinish: addComputerEffects
});
}
}
}
// Start computer effects
LK.setTimeout(function () {
addComputerEffects();
}, 2000);
// Start ocean movement after a short delay
LK.setTimeout(function () {
addOceanMovement();
}, 1000);
// Ocean waves music will start after intro ends
// Game code saved successfully - Naval Combat Game Complete;
water look on top. In-Game asset. 2d. High contrast. No shadows
white location icon look on top. In-Game asset. 2d. High contrast. No shadows
explosion look on top. In-Game asset. 2d. High contrast. No shadows
white smoke look on top. In-Game asset. 2d. High contrast. No shadows
red point icon. In-Game asset. 2d. High contrast. No shadows
2d sea mine In-Game asset. 2d. High contrast. No shadows
warship commander head looking right in game asset. In-Game asset. 2d. High contrast. No shadows
warship commander head looking left in game asset. In-Game asset. 2d. High contrast. No shadows
speech bubble 2d. In-Game asset. 2d. High contrast. No shadows
metal border. In-Game asset. 2d. High contrast. No shadows
metal line. In-Game asset. 2d. High contrast. No shadows