Code edit (9 edits merged)
Please save this source code
User prompt
Please fix the bug: 'ReferenceError: newCell is not defined' in or related to this line: 'self.cellX = Math.floor(newCell.cellX / tileSize);' Line Number: 805
Code edit (1 edits merged)
Please save this source code
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading '8')' in or related to this line: 'if (self.harvestingMode == 1 && self.harvestedSpiceOnCellCounter < 200 && gameMap.cells[self.cellX][self.cellY].spice) {' Line Number: 833
Code edit (1 edits merged)
Please save this source code
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading '7')' in or related to this line: 'if (self.harvestingMode == 1 && self.harvestedSpiceOnCellCounter < 200 && gameMap.cells[self.cellX][self.cellY].spice) {' Line Number: 833
Code edit (1 edits merged)
Please save this source code
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading '6')' in or related to this line: 'if (self.harvestingMode == 1 && self.harvestedSpiceOnCellCounter < 200 && gameMap.cells[self.cellX][self.cellY].spice) {' Line Number: 833
Code edit (1 edits merged)
Please save this source code
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'spice')' in or related to this line: 'if (self.harvestingMode == 1 && self.harvestedSpiceOnCellCounter < 200 && gameMap.cells[self.cellX][self.cellY].spice) {' Line Number: 833
Code edit (2 edits merged)
Please save this source code
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'spice')' in or related to this line: 'if (self.harvestingMode == 1 && self.harvestedSpiceOnCellCounter < 200 && gameMap.cells[self.cellX][self.cellY].spice) {' Line Number: 833
Code edit (2 edits merged)
Please save this source code
User prompt
Please fix the bug: 'TypeError: Cannot set properties of undefined (setting 'unit')' in or related to this line: 'gameMap.cells[self.cellX][self.cellY].unit = self;' Line Number: 747
Code edit (1 edits merged)
Please save this source code
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'spice')' in or related to this line: 'if (self.harvestingMode == 1 && self.harvestedSpiceOnCellCounter < 200 && gameMap.cells[self.cellX][self.cellY].spice) {' Line Number: 833
Code edit (1 edits merged)
Please save this source code
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'spice')' in or related to this line: 'if (self.harvestingMode == 1 && self.harvestedSpiceOnCellCounter < 200 && gameMap.cells[self.cellX][self.cellY].spice) {' Line Number: 833
Code edit (2 edits merged)
Please save this source code
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading '9.366666666666676')' in or related to this line: 'if (self.harvestingMode == 1 && self.harvestedSpiceOnCellCounter < 200 && gameMap.cells[self.cellX][self.cellY].spice) {' Line Number: 833
Code edit (1 edits merged)
Please save this source code
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'spice')' in or related to this line: 'if (self.harvestingMode == 1 && self.harvestedSpiceOnCellCounter < 200 && gameMap.cells[self.cellX][self.cellY].spice) {' Line Number: 833
Code edit (3 edits merged)
Please save this source code
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'spice')' in or related to this line: 'if (self.harvestingMode == 1 && self.harvestedSpiceOnCellCounter < 200 && gameMap.cells[self.cellX][self.cellY].spice) {' Line Number: 833
Code edit (1 edits merged)
Please save this source code
/**** * Classes ****/ var ActionItemIcon = Container.expand(function (action, x, y) { var self = Container.call(this); self.action = action; self.asset = self.attachAsset(action.icon, { anchorX: 0.5, anchorY: 0.5, x: x, y: y, width: 200, height: 200 }); self.asset.on('down', function () { if (self.action && typeof self.action.handler === 'function') { currentSelection.selectedAction = self.action.code; currentUserActionState = UserActionState.SET_ORDER_TARGET; console.log('Wait target for action ' + self.action.name); //self.action.handler(); if (!targetMoveCursor) { targetMoveCursor = game.addChild(new TargetMoveCursor()); } highlightBorder(self.asset.x); } else { currentSelection.selectedAction = null; } }); self.label = new Text2(action.name, { size: 30, fill: '#000000', font: "'GillSans-Bold',Impact,'Arial Black',Tahoma" }); self.label.x = self.asset.x - action.name.length / 2 * 13; self.label.y = self.asset.y + 120; self.addChild(self.label); return self; }); var ActionRepository = Container.expand(function () { var self = Container.call(this); self.actions = { 'harvest': { 'code': 'harvest', 'name': 'Harvest', 'icon': 'harvestIcon', 'handler': harvestActionLogic }, 'move': { 'code': 'move', 'name': 'Move', 'icon': 'moveIcon', 'handler': moveActionLogic }, 'return': { 'code': 'return', 'name': 'Retreat', 'icon': 'returnIcon', 'handler': function handler() {/* Return action logic */} } }; self.getActionInfo = function (actionType) { return self.actions[actionType]; }; return self; }); var BuildableItemIcon = Container.expand(function (type, x, y) { var self = Container.call(this); self.type = type; self.asset = self.attachAsset(type, { anchorX: 0.5, anchorY: 0.5, x: x, y: y, width: 200, height: 200 }); self.asset.on('down', function () { if (!self.asset.interactive) { return; } if (currentBuildingForPlacement) { currentUserActionState = UserActionState.PLACING_BUILDINGS; console.log("User is placing ", currentBuildingForPlacement); game.addChild(currentBuildingForPlacement); return; } var progressDisplay = new BuildingProgressDisplay(self); game.addChild(progressDisplay); enqueueBuildable(self, progressDisplay); game.children.forEach(function (child) { if (child instanceof BuildableItemIcon) { child.alpha = 0.75; } }); }); var buildableInfo = buildableRepository.getBuildableInfo(type); self.label = new Text2(buildableInfo.name, { size: 30, fill: '#000000', font: "'GillSans-Bold',Impact,'Arial Black',Tahoma" }); self.label.x = self.asset.x - buildableInfo.name.length / 2 * 13; self.label.y = self.asset.y + 120; self.addChild(self.label); self.setLabelToPlace = function () { self.label.setText('Place'); self.label.x = self.asset.x - 38; // Recalculate x position for new text }; self.restoreLabel = function () { self.label.setText(buildableInfo.name); self.label.x = self.asset.x - buildableInfo.name.length / 2 * 13; // Recalculate x position for new text }; return self; }); // BuildableRepository class to store reference information about all buildables var BuildableRepository = Container.expand(function () { var self = Container.call(this); self.buildables = { 'constructionYard': { 'name': 'Construction Yard', 'cost': 300, 'energy': 0, 'constructionTime': 10, 'className': 'ConstructionYard', 'buildable': ['windTrap', 'spiceRefinery'] }, 'windTrap': { 'name': 'Wind Trap', 'cost': 300, 'energy': 100, 'constructionTime': 2, 'className': 'WindTrap', 'buildable': [] }, 'spiceRefinery': { 'name': 'Spice Refinery', 'cost': 600, 'energy': -50, 'constructionTime': 1, 'className': 'SpiceRefinery', 'buildable': [] } // Add more buildables as needed }; self.getBuildableInfo = function (type) { return self.buildables[type]; }; return self; }); // Base Building class var Building = Container.expand(function (x, y, type, name, playerId, cellW, cellH, buildable) { var self = Container.call(this); self.cellX = x; self.cellY = y; self.cellW = cellW || 1; // Default to 1x1 if not specified self.cellH = cellH || 1; // Default to 1x1 if not specified self.x = x * tileSize; self.y = y * tileSize; self.type = type; self.isBuilding = true; self.playerId = playerId; self.name = name; self.buildable = buildable || []; // New property to store what the building can build self.asset = self.attachAsset(type, { anchorX: 0.5, anchorY: 0.5 //tint: getPlayerTint(playerId), // Color building to player tint }); self.asset.x = self.x; self.asset.y = self.y; self.buildingQueue = []; // Initialize building-specific properties here // ... return self; }); var WindTrap = Building.expand(function (x, y, playerId) { var self = Building.call(this, x, y, 'windTrap', 'Wind Trap', playerId, 2, 2); // Additional properties and methods for WindTrap can be added here return self; }); var SpiceRefinery = Building.expand(function (x, y, playerId) { var self = Building.call(this, x, y, 'spiceRefinery', 'Spice Refinery', playerId, 3, 2); // Additional properties and methods for SpiceRefinery can be added here return self; }); var ConstructionYard = Building.expand(function (x, y, playerId) { var self = Building.call(this, x, y, 'constructionYard', 'Construction Yard', playerId, 2, 2, buildableRepository.getBuildableInfo('constructionYard').buildable); // Additional properties and methods for ConstructionYard can be added here return self; }); var BuildingProgressDisplay = Container.expand(function (parentIcon) { var self = Container.call(this); self.parentIcon = parentIcon; self.progressAsset = self.attachAsset('buildingProgress', { anchorX: 0, anchorY: .5, alpha: 0.5, width: 0, x: parentIcon.asset.x - parentIcon.asset.width / 2, y: parentIcon.asset.y }); self.setProgress = function (progress) { self.progressAsset.width = parentIcon.asset.width * progress; }; self.hide = function () { self.visible = false; }; self.show = function () { self.visible = true; }; return self; }); var CancelActionButton = Container.expand(function (x, y) { var self = Container.call(this); self.asset = self.attachAsset('cancelAction', { anchorX: 0.5, anchorY: 0.5, x: x, y: y }); // Add a label 'Cancel' below the cancel action button self.label = new Text2('Cancel', { size: 30, fill: '#000000', font: "'GillSans-Bold',Impact,'Arial Black',Tahoma" }); self.label.x = self.asset.x - 40; self.label.y = self.asset.y + 120; self.addChild(self.label); self.asset.on('down', function () { // Handle cancel action logic here if (currentBuildingForPlacement) { player1.spice += buildableRepository.getBuildableInfo(currentBuildingForPlacement.type).cost; updateBaseInfo(); currentBuildingForPlacement.destroy(); currentBuildingForPlacement = null; currentUserActionState = UserActionState.NAVIGATING; self.visible = false; // Hide the CancelActionButton } // Restore labels on all BuildableItemIcon instances game.children.forEach(function (child) { if (child instanceof BuildableItemIcon) { child.restoreLabel(); } }); console.log('Cancel action button pressed and building placement cancelled.'); }); return self; }); // Command Panel class var CommandPanel = Container.expand(function () { var self = Container.call(this); self.graphics = self.attachAsset('boardBackground', { width: game.width, height: game.height * 0.22, color: 0x333333 }); // Set the center box position to the center of the screen self.x = game.width / 2 - self.graphics.width / 2; self.y = game.height - self.height + game.height * 0.01; }); var IconBorder = Container.expand(function (x, y) { var self = Container.call(this); self.asset = self.attachAsset('iconBorder', { anchorX: 0.5, anchorY: 0.5, x: x, y: y }); return self; }); // Initialize game elements // Map class to represent the grid-based map system var Map = Container.expand(function () { var self = Container.call(this); // Method to clear spice from a specified cell self.clearCellSpice = function (x, y) { if (self.cells[x] && self.cells[x][y]) { self.cells[x][y].spice = false; if (self.cells[x][y].spiceAsset) { self.cells[x][y].spiceAsset.destroy(); self.cells[x][y].spiceAsset = null; } // Update spiceSpots array spiceSpots = spiceSpots.filter(function (spot) { return spot.x !== x || spot.y !== y; }); } }; self.cells = []; self.init = function (width, height) { for (var x = 0; x < width; x++) { self.cells[x] = []; for (var y = 0; y < height; y++) { // Initialize each cell with default terrain, height, resources self.cells[x][y] = { height: 0, resources: null, terrain: null, asset: null, building: null, spiceAsset: null }; } } }; self.initTerrain = function (width, height) { for (var x = 0; x < width; x++) { for (var y = 0; y < height; y++) { // Initialize each cell with default terrain, height, resources self.cells[x][y].terrain = globalTerrain[x][y] === 1 ? 'rock' : 'sand'; self.cells[x][y].asset = globalTerrain[x][y] === 1 ? new Rock(x, y) : new Sand(x, y); } } }; self.currentViewCenter = { x: 15, y: 20 }; // Create a Text2 object to display the currentViewCenter coordinates self.viewCenterText = new Text2(self.currentViewCenter.x + ', ' + self.currentViewCenter.y, { size: 50, fill: '#ffffff', align: 'center' }); // Position the text at the top center of the screen LK.gui.top.addChild(self.viewCenterText); self.render = function () { self.removeChildren(); // Move tiles instead of the view //console.log("viewPort ", viewPort); for (var x = viewPort.wCellX; x < viewPort.wCellX + viewPort.cellW; x++) { for (var y = viewPort.wCellY; y < viewPort.wCellY + viewPort.cellH; y++) { if (x >= 0 && x < self.cells.length && y >= 0 && y < self.cells[x].length) { var cell = self.cells[x][y]; var asset = cell.asset; /* var coord = worldCellToScreenCell(x, y); var screenX = coord.cellX * 100; var screenY = coord.cellY * 100; */ //console.log("cell " + x, ',' + y + " =>" + screenX, screenY); var screenCoord = worldCellToScreenCoord(x, y); var screenX = screenCoord.x; var screenY = screenCoord.y; asset.x = screenX; asset.y = screenY; if (!asset.parent) { self.addChild(asset); } // Render spice terrain if (cell.spice) { var spiceAsset = cell.spiceAsset; spiceAsset.x = screenX; spiceAsset.y = screenY; if (!spiceAsset.parent) { self.addChild(spiceAsset); } } // Render buildings var building = cell.building; if (building) { //console.log("Building at ", x, y, " screen : ", screenX, screenY); building.asset.x = screenX - (building.cellW - 2) / 2 * tileSize; // Adjust for building size building.asset.y = screenY - (building.cellH - 2) / 2 * tileSize; // Adjust for building size self.addChild(building.asset); } } } } }; self.getNavigationMesh = function () { // Create and return the navigation mesh for pathfinding }; self.findPath = function (start, end, ignoreSpecificBuilding) { console.log("findPath ", start, end); // A* pathfinding algorithm implementation // Avoid buildings by checking if the cell is occupied var openSet = []; var closedSet = []; var path = []; var startNode = { x: start.x, y: start.y, f: 0, g: 0, h: 0, parent: null }; var endNode = { x: end.x, y: end.y, f: 0, g: 0, h: 0, parent: null }; openSet.push(startNode); while (openSet.length > 0) { var lowestIndex = 0; for (var i = 0; i < openSet.length; i++) { if (openSet[i].f < openSet[lowestIndex].f) { lowestIndex = i; } } var currentNode = openSet[lowestIndex]; if (currentNode.x === endNode.x && currentNode.y === endNode.y) { var curr = currentNode; while (curr.parent) { var prev = curr.parent; if (prev) { // Calculate relative move var moveX = curr.x - prev.x; var moveY = curr.y - prev.y; console.log("Pushing : " + moveX, ',', moveY); path.push({ cellX: moveX, cellY: moveY }); } curr = curr.parent; } path.reverse(); console.log("Return 1", path); return path; } openSet.splice(lowestIndex, 1); closedSet.push(currentNode); var neighbors = getNeighbors(currentNode); for (i = 0; i < neighbors.length; i++) { var neighbor = neighbors[i]; if (closedSet.findIndex(function (node) { return node.x === neighbor.x && node.y === neighbor.y; }) !== -1 || self.cells[neighbor.x][neighbor.y].building && !ignoreSpecificBuilding) { // TODO : Be more specific here ! ignore just 1 building continue; } var gScore = currentNode.g + 1; // 1 is the distance from a node to a neighbor var gScoreIsBest = false; if (openSet.findIndex(function (node) { return node.x === neighbor.x && node.y === neighbor.y; }) === -1) { gScoreIsBest = true; neighbor.h = heuristic(neighbor, endNode); openSet.push(neighbor); } else if (gScore < neighbor.g) { gScoreIsBest = true; } if (gScoreIsBest) { neighbor.parent = currentNode; neighbor.g = gScore; neighbor.f = neighbor.g + neighbor.h; } } } console.log("Return 2", path); return path; }; function heuristic(node, endNode) { // Use Manhattan distance as heuristic return Math.abs(node.x - endNode.x) + Math.abs(node.y - endNode.y); } function getNeighbors(node) { // Get all valid neighbors (up, down, left, right) var neighbors = []; var directions = [{ x: -1, y: 0 }, { x: 1, y: 0 }, { x: 0, y: -1 }, { x: 0, y: 1 }]; directions.forEach(function (dir) { var newX = node.x + dir.x; var newY = node.y + dir.y; if (newX >= 0 && newX < self.cells.length && newY >= 0 && newY < self.cells[0].length) { neighbors.push({ x: newX, y: newY }); } }); return neighbors; } self.lastInputPosition = null; self.handleDrag = function (input) { // Clamp the view center to the map boundaries /*var targetX = Math.max(11, Math.min(self.currentViewCenter.x + input.x, mapXSize - 4)); var targetY = Math.max(14, Math.min(self.currentViewCenter.y + input.y, mapYSize - 9)); self.currentViewCenter.x = Math.round(self.currentViewCenter.x + (targetX - self.currentViewCenter.x) * dragSpeed); self.currentViewCenter.y = Math.round(self.currentViewCenter.y + (targetY - self.currentViewCenter.y) * dragSpeed); */ /* viewPort.wX = Math.max(0, Math.min(mapXSize - viewPort.cellW, viewPort.wX + input.x)); viewPort.wY = Math.max(0, Math.min(mapYSize - viewPort.cellH, viewPort.wY + input.y)); viewPort.wCellX = Math.max(0, Math.min(mapXSize - viewPort.cellW, viewPort.wX + input.x)); viewPort.wCellY = Math.max(0, Math.min(mapYSize - viewPort.cellH, viewPort.wY + input.y)); */ viewPort.wCellX = Math.max(0, Math.min(mapXSize - viewPort.cellW, viewPort.wCellX + input.x)); viewPort.wCellY = Math.max(0, Math.min(mapYSize - viewPort.cellH, viewPort.wCellY + input.y)); viewPort.wX = viewPort.wCellX * tileSize; viewPort.wY = viewPort.wCellY * tileSize; console.log("handling drag...", input, input.x, input.y); // Update the Text2 object with the new coordinates self.viewCenterText.setText(self.currentViewCenter.x + ', ' + self.currentViewCenter.y + '\r\n' + viewPort.wCellX + ',' + viewPort.wCellY); //selectionMarker.setOnElement(currentSelection); }; self.checkCollisions = function () { // Handle collisions between units and obstacles }; self.serialize = function () { // Serialize map data to a file }; self.load = function (data) { // Load map data from a file }; }); var Player = Container.expand(function (playerId, tint) { var self = Container.call(this); self.playerId = playerId; self.resources = 0; self.tint = 0xFFFFFF; self.spice = 1000; // Initialize spice property with 1000 self.energy = 0; // Initialize spice property with 1000 // Initialize player-specific properties here self.buildings = []; // Array to store all the player's buildings self.units = []; // Array to store all the player's units // ... self.addUnit = function (unit) { // Add the unit to the player's units array self.units.push(unit); // Update any unit-related properties or behaviors // ... }; self.addBuilding = function (building) { // Add the building to the player's buildings array self.buildings.push(building); // Update the energy production based on the new building self.updateEnergy(); // If the building can produce or store resources, update those as well // ... (additional resource management code can be added here) }; self.updateEnergy = function () { var counter = 0; // Iterate through all buildings owned by the player self.buildings.forEach(function (building) { // Sum the energy provided by the building var buildingInfo = buildableRepository.getBuildableInfo(building.type); console.log("Count energy of " + buildingInfo.name); var buildingInfo = buildableRepository.getBuildableInfo(building.type); counter = Math.min(Math.max(counter + buildingInfo.energy, 0), 100); }); self.energy = counter; console.log("Player " + self.playerId + " energy updated: " + self.energy); }; return self; }); var Rock = Container.expand(function (x, y) { var self = Container.call(this); self.asset = LK.getAsset('rock', { x: x * 100, y: y * 100 }); // Pre-create the asset for this cell return self.asset; }); var Sand = Container.expand(function (x, y) { var self = Container.call(this); self.asset = LK.getAsset('sand', { x: x * 100, y: y * 100 }); // Pre-create the asset for this cell return self.asset; }); var SelectionMarker = Container.expand(function () { var self = Container.call(this); self.selectionCross = self.attachAsset('selectionCross', { anchorX: 0.5, anchorY: 0.5, alpha: 1 }); self.selectionCircle = self.attachAsset('selectionCircle', { anchorX: 0.5, anchorY: 0.5, alpha: 0 }); self.alpha = 0.5; self.visible = false; // Initially, we display the selectionCross self.addChild(self.selectionCross); self.currentElement = null; self.setOnElement = function (element) { //console.log('SelectionMarker setOnElement:', element); self.currentElement = element; if (!element) { self.visible = false; return; } var elementDeltaX = 0; var elementDeltaY = 0; if (element.isBuilding) { elementDeltaX = element.cellW / 2 * tileSize; elementDeltaY = element.cellH / 2 * tileSize; self.selectionCross.alpha = 1; self.selectionCircle.alpha = 0; } if (element.isUnit) { elementDeltaX = 0; elementDeltaY = 500; self.selectionCross.alpha = 0; self.selectionCircle.alpha = 0.9; } var centerDeltaX = (gameMap.currentViewCenter.x - 15) * 100; var centerDeltaY = (gameMap.currentViewCenter.y - 15) * 100; //var cellElt = screenCoordToWorldCell(element.x, element.y); var cellElt = worldCoordToScreenCell(element.x, element.y); console.log("element at : " + element.x + ',' + element.y); //self.x = element.x - centerDeltaX + elementDeltaX; //self.y = element.y - centerDeltaY + elementDeltaY; self.x = cellElt.cellX * tileSize + elementDeltaX; self.y = cellElt.cellY * tileSize + elementDeltaY; console.log("SelectionMarker at : " + cellElt.wCellX + ',' + cellElt.wCellY + ' => ' + self.x + ',' + self.y); self.visible = true; }; self.hide = function () { console.log('SelectionMarker hidden'); self.visible = false; }; return self; }); var TargetMoveCursor = Container.expand(function () { var self = Container.call(this); self.asset = self.attachAsset('targetMoveCursor', { anchorX: 0.5, anchorY: 0.5 }); self.updatePosition = function (position) { //console.log("moving at : " + position.x + ',' + position.y); self.x = position.x; self.y = position.y; }; game.on('move', function (obj) { if (currentUserActionState != UserActionState.SET_ORDER_TARGET) { return; } //console.log("moving cursor"); var pos = obj.event.getLocalPosition(game); if (pos.y > game.height * 0.80) { self.visible = false; } else { self.visible = true; self.updatePosition(pos); } }); /*game.on('up', function () { self.destroy(); });*/ return self; }); var Unit = Container.expand(function (cellX, cellY, playerId, type) { var self = Container.call(this); self.moveAlongPath = function (path, callback) { console.log("moveAlongPath", path, callback); self.path = path; self.pathIndex = 0; self.isMoving = true; self.onArrivedCallback = callback; }; self.updateMovement = function (delta) { //console.log("updateMovement", delta); if (!self.isMoving) { //console.log("updateMovement not moving ", self.path, self.pathIndex, self.onArrivedCallback); return; } if (!self.path || self.pathIndex >= self.path.length) { console.log("updateMovement will stop ", self.path, self.pathIndex, self.onArrivedCallback); self.isMoving = false; if (self.onArrivedCallback) { console.log("updateMovement call onArrivedCallback 1"); self.onArrivedCallback(); self.onArrivedCallback = null; } return; } var targetPathStep = self.path[self.pathIndex]; var targetCell = { cellX: self.cellX + targetPathStep.cellX, cellY: self.cellY + targetPathStep.cellY }; var fixedX = Math.floor((self.x - (gameMap.currentViewCenter.x + viewSize) * 100) / 100); var fixedY = Math.floor((self.y - (gameMap.currentViewCenter.y + viewSize) * 100) / 100); var coords = getCoordsForUnit(self); //console.log("self.x/y", self.x, self.y); //console.log("asset.x/y", self.asset.x, self.asset.y); //console.log("parent.x/y", self.parent.x, self.parent.y); //console.log("coords", coords.x, coords.y); //console.log("moving...", { // x: self.cellX, // y: self.cellY //}, ' to ', targetCell, ' fixed :' + fixedX + ',' + fixedY); //var targetCoords = getCoordsForUnit(targetCell); var targetCoords = worldCellToScreenCoord(targetCell.cellX, targetCell.cellY); console.log("targetCoords", targetCoords.x, targetCoords.y); var dx = targetCoords.x + tileSize / 2 - self.x; var dy = targetCoords.y + tileSize / 2 - self.y; var distance = Math.sqrt(dx * dx + dy * dy); //console.log("distance", distance, ' / dx,dy=' + dx, ',', dy); var step = self.speed * delta; if (distance < step) { //console.log("reached step", distance); self.x = targetCoords.x + tileSize / 2; self.y = targetCoords.y + tileSize / 2; // Update map gameMap.cells[self.cellX][self.cellY].unit = null; self.cellX = targetCell.cellX; self.cellY = targetCell.cellY; // Update map gameMap.cells[self.cellX][self.cellY].unit = self; self.pathIndex++; if (self.pathIndex >= self.path.length) { self.isMoving = false; if (self.onArrivedCallback) { console.log("updateMovement call onArrivedCallback 2"); self.onArrivedCallback(); self.onArrivedCallback = null; } } } else { //console.log("advance by ", dx / distance * step); var angle = Math.atan2(dy, dx); self.asset.rotation = angle - Math.PI / 2; self.x += Math.cos(angle) * step; self.y += Math.sin(angle) * step; } if (selectionMarker.currentElement == self) { //console.log("current selection moving..."); selectionMarker.setOnElement(self); } }; self.playerId = playerId; var unitInfo = unitRepository.getUnitInfo(type); self.name = unitInfo.name; self.type = type; self.isUnit = true; self.actions = unitInfo.actions; self.asset = self.attachAsset(type, { anchorX: 0.5, anchorY: 0.5, tint: getPlayerTint(playerId) }); self.speed = 200; // Set the unit speed self.cellX = cellX; self.cellY = cellY; self.x = cellX * tileSize; self.y = cellY * tileSize; self.cellW = 1; self.cellH = 1; /* var targetCoords = getCoordsForUnit(self); self.x = targetCoords.x; self.y = targetCoords.y; */ console.log("New unit " + self.name + ' at ', self.x, ',', self.y, ' [' + self.cellX + ',' + self.cellY + ']'); self.asset.on('down', function () { console.log("Unit selected"); currentSelection = self; selectionMarker.setOnElement(currentSelection); currentUserActionState = UserActionState.GIVING_ORDERS; updateActionBoard(); }); self.onArrivedCallback = null; return self; }); var UnitHarvester = Unit.expand(function (x, y, playerId) { var self = Unit.call(this, x, y, playerId, 'unitHarvester'); self.harvestedSpiceCapacity = 600; self.harvestedSpiceOnTripCounter = 0; self.harvestedSpiceOnCellCounter = 0; self.harvestingMode = 0; // 0 : Idle / 1 : harvesting / 2 : unload self.harvestSpeed = 2; // TEMP DEBUG !!!TEMP DEBUG !!!TEMP DEBUG !!! 0.25; // Adjust this value to control the speed of harvesting self.unloadSpeed = 1; // TEMP DEBUG !!!TEMP DEBUG !!!TEMP DEBUG !!! 0.25; // Adjust this value to control the speed of harvesting self.startHarvesting = function () { console.log("startHarvesting..."); var closestSpiceSpot = findClosestSpiceSpot(self.cellX, self.cellY); if (closestSpiceSpot) { console.log("closestSpiceSpot :", closestSpiceSpot); var path = gameMap.findPath({ x: self.cellX, y: self.cellY }, { x: closestSpiceSpot.x, y: closestSpiceSpot.y }); console.log("path :", path); self.moveAlongPath(path); self.harvestingMode = 1; } }; self.startUnloading = function () { self.harvestingMode = 2; console.log("Unloading spice..."); }; self.update = function () { if (self.harvestingMode == 1 && self.harvestedSpiceOnCellCounter < 200 && gameMap.cells[self.cellX][self.cellY].spice) { self.harvestedSpiceOnTripCounter += self.harvestSpeed; self.harvestedSpiceOnCellCounter += self.harvestSpeed; //console.log('Harvested Spice Counter:', self.harvestedSpiceOnCellCounter); //, ' cell ' + self.cellX + ',' + self.cellY, ' of map ', gameMap.cells[self.cellX][self.cellY]); if (self.harvestedSpiceOnCellCounter >= 200) { self.asset.tint = 0xFFFFFF; gameMap.clearCellSpice(self.cellX, self.cellY); if (self.harvestedSpiceOnTripCounter >= self.harvestedSpiceCapacity) { self.harvestedSpiceOnCellCounter = 0; var closestRefinery = findClosestRefinery(self); if (closestRefinery) { var path = gameMap.findPath({ x: self.cellX, y: self.cellY }, { x: closestRefinery.cellX, y: closestRefinery.cellY }, closestRefinery); if (path.length > 0) { console.log("Returning to Refiniery..."); self.moveAlongPath(path, self.startUnloading); } else { console.warn("No path to Refinery !"); } } } else { self.harvestedSpiceOnCellCounter = 0; self.startHarvesting(); } } else { // Make the unit blink in orange more smoothly var blinkPhase = Math.sin(Date.now() * 0.01) * 0.5 + 0.5; self.asset.tint = blinkPhase < 0.5 ? 0xFFA500 : 0xFFFFFF; self.asset.rotation += 45 / 400 * (Math.PI / 180); } } if (self.harvestingMode == 2) { self.harvestedSpiceOnTripCounter -= self.unloadSpeed; // Add the unloaded spice to the player's spice counter player1.spice += self.unloadSpeed; // TODO : update for Player 2 updateBaseInfo(); // Make the unit blink in green to indicate unloading var blinkPhase = Math.sin(Date.now() * 0.01) * 0.5 + 0.5; self.asset.tint = blinkPhase < 0.5 ? 0x00FFA5 : 0xFFFFFF; if (self.harvestedSpiceOnTripCounter <= 0) { console.log("Unloading finished..."); self.asset.tint = 0xFFFFFF; self.harvestedSpiceOnTripCounter = 0; self.harvestingMode = 0; // Reset harvesting mode self.startHarvesting(); // Start a new harvesting cycle } } }; // Additional properties and methods for UnitHarvester can be added here return self; }); //{15.1} var UnitRepository = Container.expand(function () { var self = Container.call(this); self.units = { 'unitHarvester': { 'name': 'Spice Harvester', 'cost': 400, 'energy': 0, 'constructionTime': 5, 'className': 'UnitHarvester', 'actions': ['harvest', 'move', 'return'] } // Add more units as needed }; self.getUnitInfo = function (type) { return self.units[type]; }; return self; }); /**** * Initialize Game ****/ // Event listeners // Instantiate and initialize the Map var game = new LK.Game({ backgroundColor: 0x000000 // Init game with black background }); /**** * Game Code ****/ // Global function to find the closest refinery to a given unit function findClosestRefinery(unit) { var closestRefinery = null; var minDistance = Number.MAX_VALUE; var playerBuildings = unit.playerId === player1.playerId ? player1.buildings : player2.buildings; console.log("Player has " + playerBuildings.length + " buildings"); playerBuildings.forEach(function (building) { if (building instanceof SpiceRefinery) { console.log("Found Refinery at " + building.cellX + "," + building.cellY); var dx = unit.cellX - building.cellX; var dy = unit.cellY - building.cellY; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < minDistance) { closestRefinery = building; minDistance = distance; } } }); console.log("OK result ", closestRefinery); return closestRefinery ? { cellX: closestRefinery.cellX, cellY: closestRefinery.cellY } : null; } function spawnUnit(unitType, x, y, playerId) { var unitInfo = unitRepository.getUnitInfo(unitType); var unit; switch (unitInfo.className) { case 'UnitHarvester': unit = new UnitHarvester(x, y, playerId); // Find the first available place around the refinery var path = findAvailablePositionAroundRefinery(x, y); if (path.length > 0) { unit.moveAlongPath(path, function () { harvestActionLogic(unit); }); } break; // Add additional cases for other unit classes as needed default: throw new Error('Unknown unit class: ' + unitInfo.className); } gameMap.cells[x][y].unit = unit; if (playerId === player1.playerId) { player1.addUnit(unit); } else if (playerId === player2.playerId) { player2.addUnit(unit); } game.addChild(unit); return unit; } function findAvailablePositionAroundRefinery(refineryX, refineryY) { var directions = [{ x: -1, y: 0 }, { x: 1, y: 0 }, { x: 0, y: -1 }, { x: 0, y: 1 }]; for (var i = 0; i < directions.length; i++) { var checkX = refineryX + directions[i].x; var checkY = refineryY + directions[i].y; if (gameMap.cells[checkX] && gameMap.cells[checkX][checkY] && !gameMap.cells[checkX][checkY].unit && !gameMap.cells[checkX][checkY].building) { return [{ cellX: directions[i].x, cellY: directions[i].y }]; // Return relative move to the first available cell } } return []; // No available position found } function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } function moveActionLogic(targetUnit, destinationX, destinationY) { console.log("MoveActionLogic...", destinationX, ',', destinationY); if (targetUnit && targetUnit.isUnit) { var path = gameMap.findPath({ x: targetUnit.cellX, y: targetUnit.cellY }, { x: destinationX, y: destinationY }); targetUnit.moveAlongPath(path); } } function harvestActionLogic(targetUnit, destinationX, destinationY) { console.log("HarvestActionLogic...", targetUnit, ' pos=', destinationX, ',', destinationY); if (targetUnit && targetUnit.isUnit && targetUnit.type === "unitHarvester") { var path = []; if (destinationX && destinationY) { path = gameMap.findPath({ x: targetUnit.cellX, y: targetUnit.cellY }, { x: destinationX, y: destinationY }); } if (path.length > 0) { console.log("Valid harvesting, path:", path); targetUnit.moveAlongPath(path, targetUnit.startHarvesting); } else { console.log("No path, direct harvesting "); targetUnit.startHarvesting(); } } } function highlightBorder(borderX) { var iconBorders = game.children.filter(function (child) { return child instanceof IconBorder; }); for (var i = 0; i < iconBorders.length; i++) { var iconAsset = iconBorders[i].asset; iconAsset.tint = iconAsset.x === borderX ? 0xffAAAA : 0xFFFFFF; } } function getEnergyColor(energy) { if (energy < 25) { return '#ff1100'; // Red color for low energy } else if (energy < 75) { return '#d26600'; // Orange color for medium energy } else { return '#037d50'; // Original green color for high energy } } function checkBuildingPlacement(newBuilding, cellX, cellY) { if (newBuilding && 'cellW' in newBuilding) { for (var w = 0; w < newBuilding.cellW; w++) { for (var h = 0; h < newBuilding.cellH; h++) { if (!gameMap.cells[cellX + w] || !gameMap.cells[cellX + w][cellY + h] || gameMap.cells[cellX + w][cellY + h].terrain !== 'rock' || gameMap.cells[cellX + w][cellY + h].building) { return false; } } } } return true; } function enqueueBuildable(selectedBuildable, progressDisplay) { console.log("enqueueBuildable...", selectedBuildable); if (!currentSelection || !currentSelection.buildable.includes(selectedBuildable.type)) { console.log("Cannot build this item here."); return; } var buildableInfo = buildableRepository.getBuildableInfo(selectedBuildable.type); if (player1.spice < buildableInfo.cost) { console.log("Not enough resources to build."); return; } updateBaseInfo(); var constructionTime = buildableInfo.constructionTime; var building; switch (buildableInfo.className) { case 'ConstructionYard': building = new ConstructionYard(0, 0, player1.playerId); break; case 'WindTrap': building = new WindTrap(0, 0, player1.playerId); break; case 'SpiceRefinery': building = new SpiceRefinery(0, 0, player1.playerId); break; // Add cases for other buildings as needed } building.constructionProgress = 0; building.constructionTimer = LK.setInterval(function () { building.constructionProgress += 0.1; var progressFraction = building.constructionProgress / constructionTime; building.progressDisplay.setProgress(progressFraction); // Deduct spice progressively based on construction progress var costPerTick = buildableInfo.cost * 0.1 / constructionTime; player1.spice -= costPerTick; updateBaseInfo(); if (building.constructionProgress >= constructionTime) { LK.clearInterval(building.constructionTimer); console.log(selectedBuildable.type + " construction completed."); building.constructionTimer = null; building.progressDisplay.hide(); if (progressDisplay.parentIcon && typeof progressDisplay.parentIcon.setLabelToPlace === 'function') { progressDisplay.parentIcon.setLabelToPlace(); // Change label text to 'Place' } console.log("Building Ready for placement ", building); currentBuildingForPlacement = building; game.children.forEach(function (child) { if (child instanceof BuildableItemIcon) { child.asset.interactive = true; child.alpha = 1.0; } }); } }, 100); building.progressDisplay = progressDisplay; currentSelection.buildingQueue.push(building); game.children.forEach(function (child) { if (child instanceof BuildableItemIcon) { child.asset.interactive = false; } }); // Instantiate and display the CancelActionButton on the command panel cancelActionBtn = new CancelActionButton(commandPanel.x + commandPanel.width - 200, commandPanel.y + 200); game.addChild(cancelActionBtn); } var applyCellOccupation = function applyCellOccupation(cellX, cellY) { var building = gameMap.cells[cellX][cellY].building; if (building) { for (var w = 0; w < building.cellW; w++) { for (var h = 0; h < building.cellH; h++) { if (cellX + w < gameMap.cells.length && cellY + h < gameMap.cells[0].length) { console.log("applyCellOccupation", cellX, cellY, " to ", cellX + w, cellY + h); gameMap.cells[cellX + w][cellY + h].building = building; } } } } }; var getPlayerTint = function getPlayerTint(id) { return player1.playerId === id ? player1.tint : player2.tint; }; var gameIsRunning = false; var mapXSize = 20 * 2; var mapYSize = 21 * 2; var tileSize = 100; var mapHeight = game.height * 0.80; var viewSize = Math.ceil(Math.max(game.width, game.height) / 2 / 100); var viewPort = { wX: 0, wY: 0, wCellX: 0, wCellY: 0, cellW: Math.floor(game.width / tileSize), // ~20 cellH: Math.floor(mapHeight / tileSize) // ~21 }; // Init view port viewPort.wCellX = Math.max(0, Math.min(mapXSize - viewPort.cellW, viewPort.wCellX)); // + game.width/2)); viewPort.wCellY = Math.max(0, Math.min(mapYSize - viewPort.cellH, viewPort.wCellY)); // + game.height/2)); viewPort.wX = viewPort.wCellX * tileSize; viewPort.wY = viewPort.wCellY * tileSize; var dragSpeed = 0.15; var gameMap = new Map(); var buildableRepository = new BuildableRepository(); var unitRepository = new UnitRepository(); var actionRepository = new ActionRepository(); // Define user action states var UserActionState = { NAVIGATING: 'navigating', BUILDING: 'building', PLACING_BUILDINGS: 'placing_buildings', GIVING_ORDERS: 'giving_orders', SET_ORDER_TARGET: 'set_order_target' }; // Current state of user action var currentUserActionState = UserActionState.NAVIGATING; var globalTerrain = null; var player1 = null; var player2 = null; var spiceSpots = []; // Global variable to keep track of the previous energy level var previousEnergyLevel = 0; var currentSelection = null; var currentBuildingForPlacement = null; var selectionMarker = null; var tickCounter = 0; var fps = 0; // Gui var commandPanel = null; var player1SpiceText = null; var player1EnergyText = null; var energyOffsetSufix = '% '; var currentSelectionText = null; var fpsText = null; var targetMoveCursor = null; var cancelActionBtn = null; var rockIlot1Center = { x: 0, y: 0 }; // Prepare the map function prepareMap() { globalTerrain = new Array(mapXSize).fill(0).map(function () { return new Array(mapYSize).fill(0); }); gameMap = new Map(); gameMap.init(mapXSize, mapYSize); // Initialize with a 20x20 grid // Define a fixed rock ilot near the center left of the map rockIlot1Center = { x: Math.floor(mapXSize * 0.15), y: Math.floor(mapYSize * 0.25) }; console.log("rockIlot1Center : ", rockIlot1Center); var rockIlot1Radius = 4; for (var x = rockIlot1Center.x - rockIlot1Radius; x <= rockIlot1Center.x + rockIlot1Radius; x++) { for (var y = rockIlot1Center.y - rockIlot1Radius; y <= rockIlot1Center.y + rockIlot1Radius; y++) { if (x >= 0 && x < mapXSize && y >= 0 && y < mapYSize) { globalTerrain[x][y] = 1; } } } console.log("rockIlot1Center at " + rockIlot1Center.x + ',' + rockIlot1Center.y); var initialConstructionYard = new ConstructionYard(rockIlot1Center.x, rockIlot1Center.y, 1); gameMap.cells[rockIlot1Center.x][rockIlot1Center.y].building = initialConstructionYard; applyCellOccupation(rockIlot1Center.x, rockIlot1Center.y); player1.addBuilding(initialConstructionYard); // Add a new harvester to player 1 //spawnUnit('unitHarvester', rockIlot1Center.x, rockIlot1Center.y - 2, player1.playerId); // Define a fixed rock ilot near the center right of the map var rockIlot2Center = { x: Math.floor(mapXSize * 0.85), y: Math.floor(mapYSize * 0.5) }; var rockIlot2Radius = 4; for (var x = rockIlot2Center.x - rockIlot2Radius; x <= rockIlot2Center.x + rockIlot2Radius; x++) { for (var y = rockIlot2Center.y - rockIlot2Radius; y <= rockIlot2Center.y + rockIlot2Radius; y++) { if (x >= 0 && x < mapXSize && y >= 0 && y < mapYSize) { globalTerrain[x][y] = 1; } } } console.log("rockIlot2Center at " + rockIlot2Center.x + ',' + rockIlot2Center.y); var initialConstructionYard2 = new ConstructionYard(rockIlot2Center.x, rockIlot2Center.y, 2); gameMap.cells[rockIlot2Center.x][rockIlot2Center.y].building = initialConstructionYard2; applyCellOccupation(rockIlot2Center.x, rockIlot2Center.y); player2.addBuilding(initialConstructionYard2); gameMap.initTerrain(mapXSize, mapYSize); // Initialize with a 20x20 grid initSpiceSpots(); console.log('ConstructionYard1 cell :', gameMap.cells[rockIlot1Center.x][rockIlot1Center.y]); selectionMarker = new SelectionMarker(); // Add the map to the game game.addChild(gameMap); game.addChild(selectionMarker); } function initSpiceSpots() { var quarterWidth = Math.floor(mapXSize / 2); var quarterHeight = Math.floor(mapYSize / 2); for (var i = 0; i < 4; i++) { var startX = i % 2 * quarterWidth; var startY = Math.floor(i / 2) * quarterHeight; var ilotCenterX = startX + Math.floor(Math.random() * quarterWidth); var ilotCenterY = startY + Math.floor(Math.random() * quarterHeight); var ilotRadius = 2 + Math.floor(Math.random() * 3); // Radius between 2 and 4 for (var x = ilotCenterX - ilotRadius; x <= ilotCenterX + ilotRadius; x++) { for (var y = ilotCenterY - ilotRadius; y <= ilotCenterY + ilotRadius; y++) { if (x >= 0 && x < mapXSize && y >= 0 && y < mapYSize && globalTerrain[x][y] === 0) { globalTerrain[x][y] = 2; // Mark as spice spiceSpots.push({ x: x, y: y }); gameMap.cells[x][y].spice = true; gameMap.cells[x][y].spiceAsset = LK.getAsset('terrainSpice', { x: x * 100, y: y * 100 }); } } } } } //#region Event listeners var dragStart = null; var dragDelta = 0; function handleDragStart(obj) { console.log("Drag start..."); dragStart = obj.event.getLocalPosition(game); } function handleDragMove(obj) { var currentPos = obj.event.getLocalPosition(game); var input = { x: currentPos.x, y: currentPos.y }; updateMouseCoords(input.x, input.y); if (currentUserActionState === UserActionState.PLACING_BUILDINGS) { //console.log("User is moving building..." + Math.floor(input.x) + ',' + Math.floor(input.y), currentBuildingForPlacement); var cellCoord = screenCoordToWorldCell(input.x, input.y); //getCellForPlacement(input.x, input.y, currentBuildingForPlacement); var cellX = cellCoord.wCellX; var cellY = cellCoord.wCellY; var isValidPlacement = checkBuildingPlacement(currentBuildingForPlacement, cellX, cellY); //console.log("Verif coords : " + cellX + ',' + cellY); if (currentBuildingForPlacement && currentBuildingForPlacement.asset) { currentBuildingForPlacement.asset.tint = isValidPlacement ? 0x00FF00 : 0xFF0000; currentBuildingForPlacement.visible = input.y + currentBuildingForPlacement.cellH * tileSize < mapHeight; } //var cursorCellCoord = getCursorCellForMovement(input, currentBuildingForPlacement); currentBuildingForPlacement.x = (cellX + currentBuildingForPlacement.cellW / 2) * tileSize; //cursorCellCoord.cellX; currentBuildingForPlacement.y = (cellY + currentBuildingForPlacement.cellH / 2) * tileSize; //cursorCellCoord.cellY; //console.log("Follow coords : " + currentBuildingForPlacement.x + ',' + currentBuildingForPlacement.y); } else if (dragStart) { //console.log("Drag move..."); var deltaX = currentPos.x - dragStart.x; var deltaY = currentPos.y - dragStart.y; var inputPosition = { x: Math.round(-deltaX / tileSize), y: Math.round(-deltaY / tileSize) }; var allUnits = player1.units.concat(player2.units); allUnits.forEach(function (unit) { var targetX = Math.max(11, Math.min(gameMap.currentViewCenter.x + inputPosition.x, mapXSize - 4)); var targetY = Math.max(14, Math.min(gameMap.currentViewCenter.y + inputPosition.y, mapYSize - 9)); var newCenterX = Math.round(gameMap.currentViewCenter.x + (targetX - gameMap.currentViewCenter.x) * dragSpeed); var newCenterY = Math.round(gameMap.currentViewCenter.y + (targetY - gameMap.currentViewCenter.y) * dragSpeed); var deltaX = gameMap.currentViewCenter.x - newCenterX; var deltaY = gameMap.currentViewCenter.y - newCenterY; console.log("unit coords : " + unit.x + ',' + unit.y); //console.log("target coords : " + targetX + ',' + targetY); //console.log("center coords : " + gameMap.currentViewCenter.x + ',' + gameMap.currentViewCenter.y); //console.log("input coords : " + inputPosition.x + ',' + inputPosition.y); console.log("delta coords : " + deltaX + ',' + deltaY); unit.x += deltaX * tileSize; unit.y += deltaY * tileSize; }); gameMap.handleDrag(inputPosition); dragDelta = Math.sqrt(deltaX * deltaX + deltaY * deltaY); selectionMarker.setOnElement(currentSelection); } } function handleDragEnd(obj) { var currentPos = obj.event.getLocalPosition(game); var input = { x: currentPos.x, y: currentPos.y }; console.log("Clicked at " + input.x + ',' + input.y); if (input.y > game.height * 0.80) { console.log("Clicked on board at " + input.x + ',' + input.y); dragStart = null; dragDelta = 0; return; } if (currentUserActionState === UserActionState.PLACING_BUILDINGS) { var cellCoord = screenCoordToWorldCell(input.x, input.y); //getCellForPlacement(input.x, input.y, currentBuildingForPlacement); var cellX = cellCoord.wCellX; var cellY = cellCoord.wCellY; /* var cellCoord = getCellForPlacement(input.x, input.y, currentBuildingForPlacement); var cellX = cellCoord.cellX; var cellY = cellCoord.cellY; */ var isValidPlacement = checkBuildingPlacement(currentBuildingForPlacement, cellX, cellY); if (!isValidPlacement) { return; } console.log("Placing building ", currentBuildingForPlacement, " at " + cellX + ',' + cellY); handleBuildingPlacement(currentBuildingForPlacement, cellX, cellY); currentUserActionState = UserActionState.NAVIGATING; dragStart = null; dragDelta = 0; } else if (currentUserActionState === UserActionState.SET_ORDER_TARGET) { if (currentSelection && currentSelection.isUnit) { var cellCoord = convertCoordsToCell(input.x, input.y); currentSelection.destinationTarget = { x: cellCoord.cellX, y: cellCoord.cellY }; console.log(currentSelection.name + ' received new destination target: ' + cellCoord.cellX + ',' + cellCoord.cellY); // Call the action handler with the target position if (currentSelection.actions && currentSelection.selectedAction) { console.log(currentSelection.selectedAction + ' received '); var actionInfo = actionRepository.getActionInfo(currentSelection.selectedAction); if (actionInfo && actionInfo.handler) { console.log('Call action handler : ', actionInfo); actionInfo.handler(currentSelection, cellCoord.cellX, cellCoord.cellY); } } if (targetMoveCursor) { console.log('hiding move cursor ...'); targetMoveCursor.visible = false; } } highlightBorder(); currentUserActionState = UserActionState.NAVIGATING; dragStart = null; dragDelta = 0; } else { // Normal click var clickCell = screenCoordToWorldCell(input.x, input.y); var cellX = clickCell.wCellX; var cellY = clickCell.wCellY; console.log("Click at cell " + cellX + ',' + cellY); var deltaToSelection = 99; if (currentSelection && currentSelection.isUnit) { var selCell = getCellForUnit(currentSelection); console.log("currentSelection = " + currentSelection.name + " at " + selCell.cellX + ',' + selCell.cellY); deltaToSelection = Math.sqrt(Math.pow(Math.abs(selCell.cellX - cellX), 2) + Math.pow(Math.abs(selCell.cellY - cellY), 2)); } if (cellX >= 0 && cellX < gameMap.cells.length && cellY >= 0 && cellY < gameMap.cells[cellX].length) { var cell = gameMap.cells[cellX][cellY]; if (!cell.building && !cell.unit && deltaToSelection > 1) { if (dragDelta < tileSize * 0.25) { currentSelection = null; selectionMarker.setOnElement(); selectionMarker.hide(); console.log("Nothing selected at " + cellX + ',' + cellY, " deltaToSelection=" + deltaToSelection, " dragDelta=", dragDelta); updateActionBoard(); } } else if (cell.building) { console.log("Selected building at " + cellX + ',' + cellY); currentSelection = cell.building; selectionMarker.setOnElement(currentSelection); updateActionBoard(); } else if (cell.unit) { console.log("Selected cell with unit at " + cellX + ',' + cellY); console.log("unit at " + cell.unit.x + ',' + cell.unit.y); } } dragStart = null; dragDelta = 0; } } game.on('down', handleDragStart); game.on('move', handleDragMove); game.on('up', handleDragEnd); //#endregion Event listeners // Global function to handle building placement var handleBuildingPlacement = function handleBuildingPlacement(building, cellX, cellY) { console.log("handle " + building.name + " Placement at " + cellX + ',' + cellY); if (!gameMap.cells[cellX] || !gameMap.cells[cellX][cellY]) { console.log('Invalid cell for building placement.'); return; } var cell = gameMap.cells[cellX][cellY]; if (cell.building) { console.log('Cell is already occupied.'); return; } // Place the building on the map cell.building = building; building.cellX = cellX; building.cellY = cellY; building.x = cellX * tileSize; building.y = cellY * tileSize; building.asset.tint = 0xFFFFFF; gameMap.addChild(building); // Call addBuilding for the player who owns the building if (building.playerId === player1.playerId) { player1.addBuilding(building); } else if (building.playerId === player2.playerId) { player2.addBuilding(building); } applyCellOccupation(cellX, cellY); console.log(building.name + ' placed at ' + cellX + ',' + cellY); if (player1.playerId === building.playerId) { player1.updateEnergy(); updateBaseInfo(); } if (building instanceof SpiceRefinery) { spawnUnit('unitHarvester', cellX, cellY, building.playerId); } currentUserActionState = UserActionState.NAVIGATING; currentBuildingForPlacement = null; if (cancelActionBtn) { cancelActionBtn.visible = false; } updateActionBoard(); }; // Screen <-> World Coordinates var screenCoordToWorldCell = function screenCoordToWorldCell(x, y) { var wCellX = Math.floor(x / tileSize) + viewPort.wCellX; var wCellY = Math.floor(y / tileSize) + viewPort.wCellY; return { wCellX: wCellX, wCellY: wCellY }; }; var screenCoordToWorldCoord = function screenCoordToWorldCoord(x, y) { var wX = x + viewPort.wX; var wY = y + viewPort.wY; return { wX: wX, wY: wY }; }; var screenCellToWorldCell = function screenCellToWorldCell(cellX, cellY) { var wCellX = cellX + viewPort.wCellX; var wCellY = cellY + viewPort.wCellY; return { wCellX: wCellX, wCellY: wCellY }; }; var screenCellToWorldCoord = function screenCellToWorldCoord(cellX, cellY) { var wX = cellX * tileSize + viewPort.wX; var wY = cellY * tileSize + viewPort.wY; return { wX: wX, wY: wY }; }; // World <-> Screen Coordinates var worldCoordToScreenCell = function worldCoordToScreenCell(wX, wY) { var cellX = Math.floor(wX / tileSize) - viewPort.wCellX; var cellY = Math.floor(wY / tileSize) - viewPort.wCellY; return { cellX: cellX, cellY: cellY }; }; var worldCoordToScreenCoord = function worldCoordToScreenCoord(wX, wY) { var x = wX - viewPort.wX; var y = wY - viewPort.wY; return { x: x, y: y }; }; var worldCellToScreenCell = function worldCellToScreenCell(wCellX, wCellY) { var cellX = wCellX - viewPort.wCellX; var cellY = wCellY - viewPort.wCellY; return { cellX: cellX, cellY: cellY }; }; var worldCellToScreenCoord = function worldCellToScreenCoord(wCellX, wCellY) { var x = wCellX * tileSize - viewPort.wX; var y = wCellY * tileSize - viewPort.wY; return { x: x, y: y }; }; var getScreenToWorldCell = function getScreenToWorldCell(x, y) { var wCellX = Math.floor(x / tileSize) + viewPort.wX; var wCellY = Math.floor(y / tileSize) + viewPort.wY; return { wCellX: wCellX, wCellY: wCellY }; }; var getScreenToWorldCoord = function getScreenToWorldCoord(x, y) { var wX = x + viewPort.wX * tileSize; var wY = y + viewPort.wY * tileSize; return { wX: wX, wY: wY }; }; var convertCoordsToCell = function convertCoordsToCell(x, y) { return { cellX: Math.floor(x / 100) + gameMap.currentViewCenter.x - Math.ceil(game.width / 2 / 100) - 3, cellY: Math.floor(y / 100) + gameMap.currentViewCenter.y - Math.ceil(game.height / 2 / 100) }; }; var getCellForPlacement = function getCellForPlacement(x, y, building) { var cX = Math.floor(x / 100) + gameMap.currentViewCenter.x - Math.ceil(game.width / 2 / 100) - 4; var cY = Math.floor(y / 100) + gameMap.currentViewCenter.y - Math.ceil(game.height / 2 / 100) - 1; if (building && building.cellW && building.cellH) { return { cellX: cX + Math.floor(building.cellW / 2), cellY: cY + Math.floor(building.cellH / 2) }; } else { return { cellX: cX, cellY: cY }; } }; var getCellForUnit = function getCellForUnit(unit) { var centerDeltaX = gameMap.currentViewCenter.x - Math.ceil(game.width / 2 / 100); var centerDeltaY = gameMap.currentViewCenter.y - Math.ceil(game.height / 2 / 100); var cX = Math.floor(unit.x / 100) + centerDeltaX + unit.cellW / 2 + Math.floor(unit.cellW / 2) - 5; var cY = Math.floor(unit.y / 100) + centerDeltaY + Math.floor(unit.cellH / 2) + unit.cellH / 2 - 7; return { cellX: cX, cellY: cY }; }; var getCoordsForUnit = function getCoordsForCell(cell) { //console.log("getCoordsForUnit :", cell.cellX, ',', cell.cellY); //console.log("currentViewCenter :", gameMap.currentViewCenter.x, ',', gameMap.currentViewCenter.y); var centerDeltaX = -1; var centerDeltaY = -6; var x = (cell.cellX + centerDeltaX) * 100 + 50; var y = (cell.cellY + centerDeltaY) * 100 + 50; /* var centerDeltaX = gameMap.currentViewCenter.x - Math.ceil(game.width / 2 / 100) - 4; var centerDeltaY = gameMap.currentViewCenter.y - Math.ceil(game.height / 2 / 100) - 6; var x = (cell.cellX + centerDeltaX) * 100; var y = (cell.cellY + centerDeltaY) * 100; */ //console.log("=> :", x, ',', y); return { x: x, y: y }; }; var getCursorCellForMovement = function getCursorCellForMovement(input, building) { var centerDeltaX = gameMap.currentViewCenter.x - Math.ceil(game.width / 2 / 100); var centerDeltaY = gameMap.currentViewCenter.y - Math.ceil(game.height / 2 / 100); var cX = (Math.floor(input.x / 100) + centerDeltaX + building.cellW / 2 + Math.floor(building.cellW / 2) - 5) * 100; var cY = (Math.floor(input.y / 100) + centerDeltaY + Math.floor(building.cellH / 2) + building.cellH / 2 - 7) * 100; return { cellX: cX, cellY: cY }; }; // Global function to find the closest spice spot to a given position var findClosestSpiceSpot = function findClosestSpiceSpot(x, y) { var closestSpot = null; var minDistance = Number.MAX_VALUE; spiceSpots.forEach(function (spot) { var dx = x - spot.x; var dy = y - spot.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < minDistance) { closestSpot = spot; minDistance = distance; } }); return closestSpot; }; // Global function to handle action board updates var updateActionBoard = function updateActionBoard() { console.log('updateActionBoard...' + (currentSelection ? currentSelection.name : 'No selection')); currentSelectionText.setText(currentSelection ? currentSelection.name : ''); clearIconBorders(); displayBuildableItems(); // Call displayBuildableItems to show items that can be built displayActionItems(); // Call displayActionItems to show action items }; function clearIconBorders() { var iconBorders = game.children.filter(function (child) { return child instanceof IconBorder; }); iconBorders.forEach(function (border) { border.destroy(); }); } function displayBuildableItems() { console.log('updateActionBoard...', currentSelection); var buildableItemIcons = game.children.filter(function (child) { return child instanceof BuildableItemIcon; }); buildableItemIcons.forEach(function (icon) { //console.log('removing...', icon.type); icon.destroy(); }); if (currentSelection && currentSelection.playerId === player1.playerId && currentSelection.buildable && currentSelection.buildable.length) { var iconX = commandPanel.x + 200; // Starting X position for the first icon var iconY = commandPanel.y + 220; // Y position for all icons currentSelection.buildable.forEach(function (itemType) { //console.log('Add build button for ' + itemType); var border = new IconBorder(iconX, iconY); game.addChild(border); var icon = new BuildableItemIcon(itemType, iconX, iconY); game.addChild(icon); iconX += 300; // Increment X position for the next icon }); } } // Global function to display action items var displayActionItems = function displayActionItems() { console.log('displayActionItems...', currentSelection); var actionItemIcons = game.children.filter(function (child) { return child instanceof ActionItemIcon; }); actionItemIcons.forEach(function (icon) { console.log('removing...', icon.action.name); icon.destroy(); }); if (currentSelection && currentSelection.isUnit && currentSelection.actions && currentSelection.actions.length) { var iconX = commandPanel.x + 200; // Starting X position for the first icon var iconY = commandPanel.y + 220; // Y position for all icons currentSelection.actions.forEach(function (actionType) { console.log('Add action button for ', actionType); var actionInfo = actionRepository.getActionInfo(actionType); if (actionInfo) { console.log('ok Action found => display', actionInfo); var border = new IconBorder(iconX, iconY); game.addChild(border); var icon = new ActionItemIcon(actionInfo, iconX, iconY); game.addChild(icon); iconX += 300; // Increment X position for the next icon } else { console.log('Action not found', actionType); } }); } }; // Global function to update mouse coordinates text var updateMouseCoords = function updateMouseCoords(x, y) { /*var cellCoord = convertCoordsToCell(x, y); if (game.mouseCoordsText) { game.mouseCoordsText.setText(Math.floor(x) + ',' + Math.floor(y) + '\r\n' + cellCoord.cellX + ',' + cellCoord.cellY); }*/ /* var wCellCoords = getScreenToWorldCell(x, y); var wCoordCoords = getScreenToWorldCoord(x, y); if (game.mouseCoordsText) { game.mouseCoordsText.setText("S:" + Math.floor(x) + ',' + Math.floor(y) + '\r\n' + Math.floor(x / tileSize) + ',' + Math.floor(y / tileSize) + '\r\nW:' + Math.floor(wCellCoords.wCellX) + ',' + Math.floor(wCellCoords.wCellY) + '\r\n' + Math.floor(wCoordCoords.wX) + ',' + Math.floor(wCoordCoords.wY)); } */ var wCell = screenCoordToWorldCell(x, y); if (game.mouseCoordsText) { game.mouseCoordsText.setText("S:" + Math.floor(x) + ',' + Math.floor(y) + '\r\n' + Math.floor(x / tileSize) + ',' + Math.floor(y / tileSize) + '\r\nW:' + Math.floor(wCell.wCellX) + ',' + Math.floor(wCell.wCellY)); } gameMap.viewCenterText.setText(gameMap.currentViewCenter.x + ', ' + gameMap.currentViewCenter.y + '\r\n' + viewPort.wCellX + ',' + viewPort.wCellY); }; // Global function to update base info text var updateBaseInfo = function updateBaseInfo() { player1SpiceText.setText('| ' + player1.spice.toString()); // Animate the change of the energy value if (previousEnergyLevel !== player1.energy) { var energyDifference = player1.energy - previousEnergyLevel; var duration = 2000; // Duration of the animation in milliseconds var steps = duration / (1000 / 60); // Number of steps based on 60FPS var stepValue = energyDifference / steps; var currentStep = 0; var animateEnergyChange = function animateEnergyChange() { var energyColor = getEnergyColor(previousEnergyLevel); player1EnergyText.setStyle({ fill: energyColor }); if (currentStep < steps) { previousEnergyLevel += stepValue; player1EnergyText.setText(previousEnergyLevel.toFixed(0).toString() + energyOffsetSufix); currentStep++; LK.setTimeout(animateEnergyChange, 1000 / 60); } else { // Ensure the final value is set correctly player1EnergyText.setText(player1.energy.toString() + energyOffsetSufix); previousEnergyLevel = player1.energy; // Update the previous energy level } }; animateEnergyChange(); } else { player1EnergyText.setText(player1.energy.toString() + energyOffsetSufix); } }; var startFpsCounter = function startFpsCounter() { var fpsInterval = LK.setInterval(function () { // Set the FPS value to the tick counter fps = tickCounter; // Reset the tick counter tickCounter = 0; // Update the FPS text on the screen fpsText.setText('FPS: ' + fps); }, 1000); // 1000 milliseconds = 1 second }; function initGame() { // Create players player1 = new Player(1, 0x5e86ff); player2 = new Player(2, 0xffAAAA); // Prepare the map prepareMap(); // Instantiate CommandPanel commandPanel = game.addChild(new CommandPanel()); // Create a Text2 object for current selection currentSelectionText = new Text2('', { size: 50, fill: '#000000', font: "'GillSans-Bold',Impact,'Arial Black',Tahoma" }); currentSelectionText.anchor.set(0.5, 6.8); LK.gui.bottom.addChild(currentSelectionText); // Create a Text2 object to display mouse coordinates if (!game.mouseCoordsText) { game.mouseCoordsText = new Text2('0,0\r\n0,0', { size: 50, fill: '#ffffff', font: "'GillSans-Bold',Impact,'Arial Black',Tahoma" }); game.mouseCoordsText.anchor.set(0, 0); LK.gui.topLeft.addChild(game.mouseCoordsText); } // Create a Text2 object to display player1's spice level player1SpiceText = new Text2('| ' + player1.spice.toString(), { size: 50, fill: '#000000', font: "'GillSans-Bold',Impact,'Arial Black',Tahoma" }); player1SpiceText.anchor.set(1.0, 0.25); LK.gui.topRight.addChild(player1SpiceText); // Create a Text2 object to display player1's energy level player1EnergyText = new Text2(player1.energy.toString() + energyOffsetSufix, { size: 50, fill: '#000000', font: "'GillSans-Bold',Impact,'Arial Black',Tahoma" }); player1EnergyText.anchor.set(1.0, 0.25); LK.gui.topRight.addChild(player1EnergyText); // Create a Text2 object to display the FPS in the bottom right corner fpsText = new Text2('', { size: 50, fill: '#000000', font: "'GillSans-Bold',Impact,'Arial Black',Tahoma" }); fpsText.anchor.set(1.5, 1.0); LK.gui.bottomRight.addChild(fpsText); gameIsRunning = true; startFpsCounter(); } // Game tick LK.on('tick', function () { // Render the map and update unit movement each tick if (gameIsRunning) { gameMap.render(); /*if (currentSelection && currentSelection.isUnit) { currentSelection.updateMovement(1 / 60); // Assuming tick operates at 60FPS }*/ //game.addChild(newHarvester.asset); // TEMP DEBUG var allUnits = player1.units.concat(player2.units); allUnits.forEach(function (unit) { //console.log("render unit " + unit.name, unit.x, unit.y); // Ensure the unit is added to the game container, not 'self' which is not defined in this context //console.log(" unit parent ", unit.asset.parent.parent.parent); /*if (!unit.asset.parent.parent.parent) { console.log("First add unit !", unit.asset.parent.parent.parent); game.addChild(unit.asset); } else { }*/ unit.updateMovement(1 / 60); // Assuming tick operates at 60FPS if (unit.update) { unit.update(); } game.addChild(unit); /*var screenX = (unit.cellX - 2 - gameMap.currentViewCenter.x + viewSize) * unit.asset.width; var screenY = (unit.cellY - 3 - gameMap.currentViewCenter.y + viewSize) * unit.asset.height; unit.x = screenX; unit.y = screenY;*/ }); } tickCounter++; }); // Start the game with Player 1 construction yard preselected LK.setTimeout(function () { initGame(); currentSelection = gameMap.cells[rockIlot1Center.x][rockIlot1Center.y].building; selectionMarker.setOnElement(currentSelection); updateActionBoard(); }, 100);
/****
* Classes
****/
var ActionItemIcon = Container.expand(function (action, x, y) {
var self = Container.call(this);
self.action = action;
self.asset = self.attachAsset(action.icon, {
anchorX: 0.5,
anchorY: 0.5,
x: x,
y: y,
width: 200,
height: 200
});
self.asset.on('down', function () {
if (self.action && typeof self.action.handler === 'function') {
currentSelection.selectedAction = self.action.code;
currentUserActionState = UserActionState.SET_ORDER_TARGET;
console.log('Wait target for action ' + self.action.name);
//self.action.handler();
if (!targetMoveCursor) {
targetMoveCursor = game.addChild(new TargetMoveCursor());
}
highlightBorder(self.asset.x);
} else {
currentSelection.selectedAction = null;
}
});
self.label = new Text2(action.name, {
size: 30,
fill: '#000000',
font: "'GillSans-Bold',Impact,'Arial Black',Tahoma"
});
self.label.x = self.asset.x - action.name.length / 2 * 13;
self.label.y = self.asset.y + 120;
self.addChild(self.label);
return self;
});
var ActionRepository = Container.expand(function () {
var self = Container.call(this);
self.actions = {
'harvest': {
'code': 'harvest',
'name': 'Harvest',
'icon': 'harvestIcon',
'handler': harvestActionLogic
},
'move': {
'code': 'move',
'name': 'Move',
'icon': 'moveIcon',
'handler': moveActionLogic
},
'return': {
'code': 'return',
'name': 'Retreat',
'icon': 'returnIcon',
'handler': function handler() {/* Return action logic */}
}
};
self.getActionInfo = function (actionType) {
return self.actions[actionType];
};
return self;
});
var BuildableItemIcon = Container.expand(function (type, x, y) {
var self = Container.call(this);
self.type = type;
self.asset = self.attachAsset(type, {
anchorX: 0.5,
anchorY: 0.5,
x: x,
y: y,
width: 200,
height: 200
});
self.asset.on('down', function () {
if (!self.asset.interactive) {
return;
}
if (currentBuildingForPlacement) {
currentUserActionState = UserActionState.PLACING_BUILDINGS;
console.log("User is placing ", currentBuildingForPlacement);
game.addChild(currentBuildingForPlacement);
return;
}
var progressDisplay = new BuildingProgressDisplay(self);
game.addChild(progressDisplay);
enqueueBuildable(self, progressDisplay);
game.children.forEach(function (child) {
if (child instanceof BuildableItemIcon) {
child.alpha = 0.75;
}
});
});
var buildableInfo = buildableRepository.getBuildableInfo(type);
self.label = new Text2(buildableInfo.name, {
size: 30,
fill: '#000000',
font: "'GillSans-Bold',Impact,'Arial Black',Tahoma"
});
self.label.x = self.asset.x - buildableInfo.name.length / 2 * 13;
self.label.y = self.asset.y + 120;
self.addChild(self.label);
self.setLabelToPlace = function () {
self.label.setText('Place');
self.label.x = self.asset.x - 38; // Recalculate x position for new text
};
self.restoreLabel = function () {
self.label.setText(buildableInfo.name);
self.label.x = self.asset.x - buildableInfo.name.length / 2 * 13; // Recalculate x position for new text
};
return self;
});
// BuildableRepository class to store reference information about all buildables
var BuildableRepository = Container.expand(function () {
var self = Container.call(this);
self.buildables = {
'constructionYard': {
'name': 'Construction Yard',
'cost': 300,
'energy': 0,
'constructionTime': 10,
'className': 'ConstructionYard',
'buildable': ['windTrap', 'spiceRefinery']
},
'windTrap': {
'name': 'Wind Trap',
'cost': 300,
'energy': 100,
'constructionTime': 2,
'className': 'WindTrap',
'buildable': []
},
'spiceRefinery': {
'name': 'Spice Refinery',
'cost': 600,
'energy': -50,
'constructionTime': 1,
'className': 'SpiceRefinery',
'buildable': []
}
// Add more buildables as needed
};
self.getBuildableInfo = function (type) {
return self.buildables[type];
};
return self;
});
// Base Building class
var Building = Container.expand(function (x, y, type, name, playerId, cellW, cellH, buildable) {
var self = Container.call(this);
self.cellX = x;
self.cellY = y;
self.cellW = cellW || 1; // Default to 1x1 if not specified
self.cellH = cellH || 1; // Default to 1x1 if not specified
self.x = x * tileSize;
self.y = y * tileSize;
self.type = type;
self.isBuilding = true;
self.playerId = playerId;
self.name = name;
self.buildable = buildable || []; // New property to store what the building can build
self.asset = self.attachAsset(type, {
anchorX: 0.5,
anchorY: 0.5
//tint: getPlayerTint(playerId), // Color building to player tint
});
self.asset.x = self.x;
self.asset.y = self.y;
self.buildingQueue = [];
// Initialize building-specific properties here
// ...
return self;
});
var WindTrap = Building.expand(function (x, y, playerId) {
var self = Building.call(this, x, y, 'windTrap', 'Wind Trap', playerId, 2, 2);
// Additional properties and methods for WindTrap can be added here
return self;
});
var SpiceRefinery = Building.expand(function (x, y, playerId) {
var self = Building.call(this, x, y, 'spiceRefinery', 'Spice Refinery', playerId, 3, 2);
// Additional properties and methods for SpiceRefinery can be added here
return self;
});
var ConstructionYard = Building.expand(function (x, y, playerId) {
var self = Building.call(this, x, y, 'constructionYard', 'Construction Yard', playerId, 2, 2, buildableRepository.getBuildableInfo('constructionYard').buildable);
// Additional properties and methods for ConstructionYard can be added here
return self;
});
var BuildingProgressDisplay = Container.expand(function (parentIcon) {
var self = Container.call(this);
self.parentIcon = parentIcon;
self.progressAsset = self.attachAsset('buildingProgress', {
anchorX: 0,
anchorY: .5,
alpha: 0.5,
width: 0,
x: parentIcon.asset.x - parentIcon.asset.width / 2,
y: parentIcon.asset.y
});
self.setProgress = function (progress) {
self.progressAsset.width = parentIcon.asset.width * progress;
};
self.hide = function () {
self.visible = false;
};
self.show = function () {
self.visible = true;
};
return self;
});
var CancelActionButton = Container.expand(function (x, y) {
var self = Container.call(this);
self.asset = self.attachAsset('cancelAction', {
anchorX: 0.5,
anchorY: 0.5,
x: x,
y: y
});
// Add a label 'Cancel' below the cancel action button
self.label = new Text2('Cancel', {
size: 30,
fill: '#000000',
font: "'GillSans-Bold',Impact,'Arial Black',Tahoma"
});
self.label.x = self.asset.x - 40;
self.label.y = self.asset.y + 120;
self.addChild(self.label);
self.asset.on('down', function () {
// Handle cancel action logic here
if (currentBuildingForPlacement) {
player1.spice += buildableRepository.getBuildableInfo(currentBuildingForPlacement.type).cost;
updateBaseInfo();
currentBuildingForPlacement.destroy();
currentBuildingForPlacement = null;
currentUserActionState = UserActionState.NAVIGATING;
self.visible = false; // Hide the CancelActionButton
}
// Restore labels on all BuildableItemIcon instances
game.children.forEach(function (child) {
if (child instanceof BuildableItemIcon) {
child.restoreLabel();
}
});
console.log('Cancel action button pressed and building placement cancelled.');
});
return self;
});
// Command Panel class
var CommandPanel = Container.expand(function () {
var self = Container.call(this);
self.graphics = self.attachAsset('boardBackground', {
width: game.width,
height: game.height * 0.22,
color: 0x333333
});
// Set the center box position to the center of the screen
self.x = game.width / 2 - self.graphics.width / 2;
self.y = game.height - self.height + game.height * 0.01;
});
var IconBorder = Container.expand(function (x, y) {
var self = Container.call(this);
self.asset = self.attachAsset('iconBorder', {
anchorX: 0.5,
anchorY: 0.5,
x: x,
y: y
});
return self;
});
// Initialize game elements
// Map class to represent the grid-based map system
var Map = Container.expand(function () {
var self = Container.call(this);
// Method to clear spice from a specified cell
self.clearCellSpice = function (x, y) {
if (self.cells[x] && self.cells[x][y]) {
self.cells[x][y].spice = false;
if (self.cells[x][y].spiceAsset) {
self.cells[x][y].spiceAsset.destroy();
self.cells[x][y].spiceAsset = null;
}
// Update spiceSpots array
spiceSpots = spiceSpots.filter(function (spot) {
return spot.x !== x || spot.y !== y;
});
}
};
self.cells = [];
self.init = function (width, height) {
for (var x = 0; x < width; x++) {
self.cells[x] = [];
for (var y = 0; y < height; y++) {
// Initialize each cell with default terrain, height, resources
self.cells[x][y] = {
height: 0,
resources: null,
terrain: null,
asset: null,
building: null,
spiceAsset: null
};
}
}
};
self.initTerrain = function (width, height) {
for (var x = 0; x < width; x++) {
for (var y = 0; y < height; y++) {
// Initialize each cell with default terrain, height, resources
self.cells[x][y].terrain = globalTerrain[x][y] === 1 ? 'rock' : 'sand';
self.cells[x][y].asset = globalTerrain[x][y] === 1 ? new Rock(x, y) : new Sand(x, y);
}
}
};
self.currentViewCenter = {
x: 15,
y: 20
};
// Create a Text2 object to display the currentViewCenter coordinates
self.viewCenterText = new Text2(self.currentViewCenter.x + ', ' + self.currentViewCenter.y, {
size: 50,
fill: '#ffffff',
align: 'center'
});
// Position the text at the top center of the screen
LK.gui.top.addChild(self.viewCenterText);
self.render = function () {
self.removeChildren();
// Move tiles instead of the view
//console.log("viewPort ", viewPort);
for (var x = viewPort.wCellX; x < viewPort.wCellX + viewPort.cellW; x++) {
for (var y = viewPort.wCellY; y < viewPort.wCellY + viewPort.cellH; y++) {
if (x >= 0 && x < self.cells.length && y >= 0 && y < self.cells[x].length) {
var cell = self.cells[x][y];
var asset = cell.asset;
/*
var coord = worldCellToScreenCell(x, y);
var screenX = coord.cellX * 100;
var screenY = coord.cellY * 100;
*/
//console.log("cell " + x, ',' + y + " =>" + screenX, screenY);
var screenCoord = worldCellToScreenCoord(x, y);
var screenX = screenCoord.x;
var screenY = screenCoord.y;
asset.x = screenX;
asset.y = screenY;
if (!asset.parent) {
self.addChild(asset);
}
// Render spice terrain
if (cell.spice) {
var spiceAsset = cell.spiceAsset;
spiceAsset.x = screenX;
spiceAsset.y = screenY;
if (!spiceAsset.parent) {
self.addChild(spiceAsset);
}
}
// Render buildings
var building = cell.building;
if (building) {
//console.log("Building at ", x, y, " screen : ", screenX, screenY);
building.asset.x = screenX - (building.cellW - 2) / 2 * tileSize; // Adjust for building size
building.asset.y = screenY - (building.cellH - 2) / 2 * tileSize; // Adjust for building size
self.addChild(building.asset);
}
}
}
}
};
self.getNavigationMesh = function () {
// Create and return the navigation mesh for pathfinding
};
self.findPath = function (start, end, ignoreSpecificBuilding) {
console.log("findPath ", start, end);
// A* pathfinding algorithm implementation
// Avoid buildings by checking if the cell is occupied
var openSet = [];
var closedSet = [];
var path = [];
var startNode = {
x: start.x,
y: start.y,
f: 0,
g: 0,
h: 0,
parent: null
};
var endNode = {
x: end.x,
y: end.y,
f: 0,
g: 0,
h: 0,
parent: null
};
openSet.push(startNode);
while (openSet.length > 0) {
var lowestIndex = 0;
for (var i = 0; i < openSet.length; i++) {
if (openSet[i].f < openSet[lowestIndex].f) {
lowestIndex = i;
}
}
var currentNode = openSet[lowestIndex];
if (currentNode.x === endNode.x && currentNode.y === endNode.y) {
var curr = currentNode;
while (curr.parent) {
var prev = curr.parent;
if (prev) {
// Calculate relative move
var moveX = curr.x - prev.x;
var moveY = curr.y - prev.y;
console.log("Pushing : " + moveX, ',', moveY);
path.push({
cellX: moveX,
cellY: moveY
});
}
curr = curr.parent;
}
path.reverse();
console.log("Return 1", path);
return path;
}
openSet.splice(lowestIndex, 1);
closedSet.push(currentNode);
var neighbors = getNeighbors(currentNode);
for (i = 0; i < neighbors.length; i++) {
var neighbor = neighbors[i];
if (closedSet.findIndex(function (node) {
return node.x === neighbor.x && node.y === neighbor.y;
}) !== -1 || self.cells[neighbor.x][neighbor.y].building && !ignoreSpecificBuilding) {
// TODO : Be more specific here ! ignore just 1 building
continue;
}
var gScore = currentNode.g + 1; // 1 is the distance from a node to a neighbor
var gScoreIsBest = false;
if (openSet.findIndex(function (node) {
return node.x === neighbor.x && node.y === neighbor.y;
}) === -1) {
gScoreIsBest = true;
neighbor.h = heuristic(neighbor, endNode);
openSet.push(neighbor);
} else if (gScore < neighbor.g) {
gScoreIsBest = true;
}
if (gScoreIsBest) {
neighbor.parent = currentNode;
neighbor.g = gScore;
neighbor.f = neighbor.g + neighbor.h;
}
}
}
console.log("Return 2", path);
return path;
};
function heuristic(node, endNode) {
// Use Manhattan distance as heuristic
return Math.abs(node.x - endNode.x) + Math.abs(node.y - endNode.y);
}
function getNeighbors(node) {
// Get all valid neighbors (up, down, left, right)
var neighbors = [];
var directions = [{
x: -1,
y: 0
}, {
x: 1,
y: 0
}, {
x: 0,
y: -1
}, {
x: 0,
y: 1
}];
directions.forEach(function (dir) {
var newX = node.x + dir.x;
var newY = node.y + dir.y;
if (newX >= 0 && newX < self.cells.length && newY >= 0 && newY < self.cells[0].length) {
neighbors.push({
x: newX,
y: newY
});
}
});
return neighbors;
}
self.lastInputPosition = null;
self.handleDrag = function (input) {
// Clamp the view center to the map boundaries
/*var targetX = Math.max(11, Math.min(self.currentViewCenter.x + input.x, mapXSize - 4));
var targetY = Math.max(14, Math.min(self.currentViewCenter.y + input.y, mapYSize - 9));
self.currentViewCenter.x = Math.round(self.currentViewCenter.x + (targetX - self.currentViewCenter.x) * dragSpeed);
self.currentViewCenter.y = Math.round(self.currentViewCenter.y + (targetY - self.currentViewCenter.y) * dragSpeed);
*/
/*
viewPort.wX = Math.max(0, Math.min(mapXSize - viewPort.cellW, viewPort.wX + input.x));
viewPort.wY = Math.max(0, Math.min(mapYSize - viewPort.cellH, viewPort.wY + input.y));
viewPort.wCellX = Math.max(0, Math.min(mapXSize - viewPort.cellW, viewPort.wX + input.x));
viewPort.wCellY = Math.max(0, Math.min(mapYSize - viewPort.cellH, viewPort.wY + input.y));
*/
viewPort.wCellX = Math.max(0, Math.min(mapXSize - viewPort.cellW, viewPort.wCellX + input.x));
viewPort.wCellY = Math.max(0, Math.min(mapYSize - viewPort.cellH, viewPort.wCellY + input.y));
viewPort.wX = viewPort.wCellX * tileSize;
viewPort.wY = viewPort.wCellY * tileSize;
console.log("handling drag...", input, input.x, input.y);
// Update the Text2 object with the new coordinates
self.viewCenterText.setText(self.currentViewCenter.x + ', ' + self.currentViewCenter.y + '\r\n' + viewPort.wCellX + ',' + viewPort.wCellY);
//selectionMarker.setOnElement(currentSelection);
};
self.checkCollisions = function () {
// Handle collisions between units and obstacles
};
self.serialize = function () {
// Serialize map data to a file
};
self.load = function (data) {
// Load map data from a file
};
});
var Player = Container.expand(function (playerId, tint) {
var self = Container.call(this);
self.playerId = playerId;
self.resources = 0;
self.tint = 0xFFFFFF;
self.spice = 1000; // Initialize spice property with 1000
self.energy = 0; // Initialize spice property with 1000
// Initialize player-specific properties here
self.buildings = []; // Array to store all the player's buildings
self.units = []; // Array to store all the player's units
// ...
self.addUnit = function (unit) {
// Add the unit to the player's units array
self.units.push(unit);
// Update any unit-related properties or behaviors
// ...
};
self.addBuilding = function (building) {
// Add the building to the player's buildings array
self.buildings.push(building);
// Update the energy production based on the new building
self.updateEnergy();
// If the building can produce or store resources, update those as well
// ... (additional resource management code can be added here)
};
self.updateEnergy = function () {
var counter = 0;
// Iterate through all buildings owned by the player
self.buildings.forEach(function (building) {
// Sum the energy provided by the building
var buildingInfo = buildableRepository.getBuildableInfo(building.type);
console.log("Count energy of " + buildingInfo.name);
var buildingInfo = buildableRepository.getBuildableInfo(building.type);
counter = Math.min(Math.max(counter + buildingInfo.energy, 0), 100);
});
self.energy = counter;
console.log("Player " + self.playerId + " energy updated: " + self.energy);
};
return self;
});
var Rock = Container.expand(function (x, y) {
var self = Container.call(this);
self.asset = LK.getAsset('rock', {
x: x * 100,
y: y * 100
}); // Pre-create the asset for this cell
return self.asset;
});
var Sand = Container.expand(function (x, y) {
var self = Container.call(this);
self.asset = LK.getAsset('sand', {
x: x * 100,
y: y * 100
}); // Pre-create the asset for this cell
return self.asset;
});
var SelectionMarker = Container.expand(function () {
var self = Container.call(this);
self.selectionCross = self.attachAsset('selectionCross', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 1
});
self.selectionCircle = self.attachAsset('selectionCircle', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0
});
self.alpha = 0.5;
self.visible = false;
// Initially, we display the selectionCross
self.addChild(self.selectionCross);
self.currentElement = null;
self.setOnElement = function (element) {
//console.log('SelectionMarker setOnElement:', element);
self.currentElement = element;
if (!element) {
self.visible = false;
return;
}
var elementDeltaX = 0;
var elementDeltaY = 0;
if (element.isBuilding) {
elementDeltaX = element.cellW / 2 * tileSize;
elementDeltaY = element.cellH / 2 * tileSize;
self.selectionCross.alpha = 1;
self.selectionCircle.alpha = 0;
}
if (element.isUnit) {
elementDeltaX = 0;
elementDeltaY = 500;
self.selectionCross.alpha = 0;
self.selectionCircle.alpha = 0.9;
}
var centerDeltaX = (gameMap.currentViewCenter.x - 15) * 100;
var centerDeltaY = (gameMap.currentViewCenter.y - 15) * 100;
//var cellElt = screenCoordToWorldCell(element.x, element.y);
var cellElt = worldCoordToScreenCell(element.x, element.y);
console.log("element at : " + element.x + ',' + element.y);
//self.x = element.x - centerDeltaX + elementDeltaX;
//self.y = element.y - centerDeltaY + elementDeltaY;
self.x = cellElt.cellX * tileSize + elementDeltaX;
self.y = cellElt.cellY * tileSize + elementDeltaY;
console.log("SelectionMarker at : " + cellElt.wCellX + ',' + cellElt.wCellY + ' => ' + self.x + ',' + self.y);
self.visible = true;
};
self.hide = function () {
console.log('SelectionMarker hidden');
self.visible = false;
};
return self;
});
var TargetMoveCursor = Container.expand(function () {
var self = Container.call(this);
self.asset = self.attachAsset('targetMoveCursor', {
anchorX: 0.5,
anchorY: 0.5
});
self.updatePosition = function (position) {
//console.log("moving at : " + position.x + ',' + position.y);
self.x = position.x;
self.y = position.y;
};
game.on('move', function (obj) {
if (currentUserActionState != UserActionState.SET_ORDER_TARGET) {
return;
}
//console.log("moving cursor");
var pos = obj.event.getLocalPosition(game);
if (pos.y > game.height * 0.80) {
self.visible = false;
} else {
self.visible = true;
self.updatePosition(pos);
}
});
/*game.on('up', function () {
self.destroy();
});*/
return self;
});
var Unit = Container.expand(function (cellX, cellY, playerId, type) {
var self = Container.call(this);
self.moveAlongPath = function (path, callback) {
console.log("moveAlongPath", path, callback);
self.path = path;
self.pathIndex = 0;
self.isMoving = true;
self.onArrivedCallback = callback;
};
self.updateMovement = function (delta) {
//console.log("updateMovement", delta);
if (!self.isMoving) {
//console.log("updateMovement not moving ", self.path, self.pathIndex, self.onArrivedCallback);
return;
}
if (!self.path || self.pathIndex >= self.path.length) {
console.log("updateMovement will stop ", self.path, self.pathIndex, self.onArrivedCallback);
self.isMoving = false;
if (self.onArrivedCallback) {
console.log("updateMovement call onArrivedCallback 1");
self.onArrivedCallback();
self.onArrivedCallback = null;
}
return;
}
var targetPathStep = self.path[self.pathIndex];
var targetCell = {
cellX: self.cellX + targetPathStep.cellX,
cellY: self.cellY + targetPathStep.cellY
};
var fixedX = Math.floor((self.x - (gameMap.currentViewCenter.x + viewSize) * 100) / 100);
var fixedY = Math.floor((self.y - (gameMap.currentViewCenter.y + viewSize) * 100) / 100);
var coords = getCoordsForUnit(self);
//console.log("self.x/y", self.x, self.y);
//console.log("asset.x/y", self.asset.x, self.asset.y);
//console.log("parent.x/y", self.parent.x, self.parent.y);
//console.log("coords", coords.x, coords.y);
//console.log("moving...", {
// x: self.cellX,
// y: self.cellY
//}, ' to ', targetCell, ' fixed :' + fixedX + ',' + fixedY);
//var targetCoords = getCoordsForUnit(targetCell);
var targetCoords = worldCellToScreenCoord(targetCell.cellX, targetCell.cellY);
console.log("targetCoords", targetCoords.x, targetCoords.y);
var dx = targetCoords.x + tileSize / 2 - self.x;
var dy = targetCoords.y + tileSize / 2 - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
//console.log("distance", distance, ' / dx,dy=' + dx, ',', dy);
var step = self.speed * delta;
if (distance < step) {
//console.log("reached step", distance);
self.x = targetCoords.x + tileSize / 2;
self.y = targetCoords.y + tileSize / 2;
// Update map
gameMap.cells[self.cellX][self.cellY].unit = null;
self.cellX = targetCell.cellX;
self.cellY = targetCell.cellY; // Update map
gameMap.cells[self.cellX][self.cellY].unit = self;
self.pathIndex++;
if (self.pathIndex >= self.path.length) {
self.isMoving = false;
if (self.onArrivedCallback) {
console.log("updateMovement call onArrivedCallback 2");
self.onArrivedCallback();
self.onArrivedCallback = null;
}
}
} else {
//console.log("advance by ", dx / distance * step);
var angle = Math.atan2(dy, dx);
self.asset.rotation = angle - Math.PI / 2;
self.x += Math.cos(angle) * step;
self.y += Math.sin(angle) * step;
}
if (selectionMarker.currentElement == self) {
//console.log("current selection moving...");
selectionMarker.setOnElement(self);
}
};
self.playerId = playerId;
var unitInfo = unitRepository.getUnitInfo(type);
self.name = unitInfo.name;
self.type = type;
self.isUnit = true;
self.actions = unitInfo.actions;
self.asset = self.attachAsset(type, {
anchorX: 0.5,
anchorY: 0.5,
tint: getPlayerTint(playerId)
});
self.speed = 200; // Set the unit speed
self.cellX = cellX;
self.cellY = cellY;
self.x = cellX * tileSize;
self.y = cellY * tileSize;
self.cellW = 1;
self.cellH = 1;
/*
var targetCoords = getCoordsForUnit(self);
self.x = targetCoords.x;
self.y = targetCoords.y;
*/
console.log("New unit " + self.name + ' at ', self.x, ',', self.y, ' [' + self.cellX + ',' + self.cellY + ']');
self.asset.on('down', function () {
console.log("Unit selected");
currentSelection = self;
selectionMarker.setOnElement(currentSelection);
currentUserActionState = UserActionState.GIVING_ORDERS;
updateActionBoard();
});
self.onArrivedCallback = null;
return self;
});
var UnitHarvester = Unit.expand(function (x, y, playerId) {
var self = Unit.call(this, x, y, playerId, 'unitHarvester');
self.harvestedSpiceCapacity = 600;
self.harvestedSpiceOnTripCounter = 0;
self.harvestedSpiceOnCellCounter = 0;
self.harvestingMode = 0; // 0 : Idle / 1 : harvesting / 2 : unload
self.harvestSpeed = 2; // TEMP DEBUG !!!TEMP DEBUG !!!TEMP DEBUG !!! 0.25; // Adjust this value to control the speed of harvesting
self.unloadSpeed = 1; // TEMP DEBUG !!!TEMP DEBUG !!!TEMP DEBUG !!! 0.25; // Adjust this value to control the speed of harvesting
self.startHarvesting = function () {
console.log("startHarvesting...");
var closestSpiceSpot = findClosestSpiceSpot(self.cellX, self.cellY);
if (closestSpiceSpot) {
console.log("closestSpiceSpot :", closestSpiceSpot);
var path = gameMap.findPath({
x: self.cellX,
y: self.cellY
}, {
x: closestSpiceSpot.x,
y: closestSpiceSpot.y
});
console.log("path :", path);
self.moveAlongPath(path);
self.harvestingMode = 1;
}
};
self.startUnloading = function () {
self.harvestingMode = 2;
console.log("Unloading spice...");
};
self.update = function () {
if (self.harvestingMode == 1 && self.harvestedSpiceOnCellCounter < 200 && gameMap.cells[self.cellX][self.cellY].spice) {
self.harvestedSpiceOnTripCounter += self.harvestSpeed;
self.harvestedSpiceOnCellCounter += self.harvestSpeed;
//console.log('Harvested Spice Counter:', self.harvestedSpiceOnCellCounter); //, ' cell ' + self.cellX + ',' + self.cellY, ' of map ', gameMap.cells[self.cellX][self.cellY]);
if (self.harvestedSpiceOnCellCounter >= 200) {
self.asset.tint = 0xFFFFFF;
gameMap.clearCellSpice(self.cellX, self.cellY);
if (self.harvestedSpiceOnTripCounter >= self.harvestedSpiceCapacity) {
self.harvestedSpiceOnCellCounter = 0;
var closestRefinery = findClosestRefinery(self);
if (closestRefinery) {
var path = gameMap.findPath({
x: self.cellX,
y: self.cellY
}, {
x: closestRefinery.cellX,
y: closestRefinery.cellY
}, closestRefinery);
if (path.length > 0) {
console.log("Returning to Refiniery...");
self.moveAlongPath(path, self.startUnloading);
} else {
console.warn("No path to Refinery !");
}
}
} else {
self.harvestedSpiceOnCellCounter = 0;
self.startHarvesting();
}
} else {
// Make the unit blink in orange more smoothly
var blinkPhase = Math.sin(Date.now() * 0.01) * 0.5 + 0.5;
self.asset.tint = blinkPhase < 0.5 ? 0xFFA500 : 0xFFFFFF;
self.asset.rotation += 45 / 400 * (Math.PI / 180);
}
}
if (self.harvestingMode == 2) {
self.harvestedSpiceOnTripCounter -= self.unloadSpeed;
// Add the unloaded spice to the player's spice counter
player1.spice += self.unloadSpeed; // TODO : update for Player 2
updateBaseInfo();
// Make the unit blink in green to indicate unloading
var blinkPhase = Math.sin(Date.now() * 0.01) * 0.5 + 0.5;
self.asset.tint = blinkPhase < 0.5 ? 0x00FFA5 : 0xFFFFFF;
if (self.harvestedSpiceOnTripCounter <= 0) {
console.log("Unloading finished...");
self.asset.tint = 0xFFFFFF;
self.harvestedSpiceOnTripCounter = 0;
self.harvestingMode = 0; // Reset harvesting mode
self.startHarvesting(); // Start a new harvesting cycle
}
}
};
// Additional properties and methods for UnitHarvester can be added here
return self;
});
//{15.1}
var UnitRepository = Container.expand(function () {
var self = Container.call(this);
self.units = {
'unitHarvester': {
'name': 'Spice Harvester',
'cost': 400,
'energy': 0,
'constructionTime': 5,
'className': 'UnitHarvester',
'actions': ['harvest', 'move', 'return']
}
// Add more units as needed
};
self.getUnitInfo = function (type) {
return self.units[type];
};
return self;
});
/****
* Initialize Game
****/
// Event listeners
// Instantiate and initialize the Map
var game = new LK.Game({
backgroundColor: 0x000000 // Init game with black background
});
/****
* Game Code
****/
// Global function to find the closest refinery to a given unit
function findClosestRefinery(unit) {
var closestRefinery = null;
var minDistance = Number.MAX_VALUE;
var playerBuildings = unit.playerId === player1.playerId ? player1.buildings : player2.buildings;
console.log("Player has " + playerBuildings.length + " buildings");
playerBuildings.forEach(function (building) {
if (building instanceof SpiceRefinery) {
console.log("Found Refinery at " + building.cellX + "," + building.cellY);
var dx = unit.cellX - building.cellX;
var dy = unit.cellY - building.cellY;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < minDistance) {
closestRefinery = building;
minDistance = distance;
}
}
});
console.log("OK result ", closestRefinery);
return closestRefinery ? {
cellX: closestRefinery.cellX,
cellY: closestRefinery.cellY
} : null;
}
function spawnUnit(unitType, x, y, playerId) {
var unitInfo = unitRepository.getUnitInfo(unitType);
var unit;
switch (unitInfo.className) {
case 'UnitHarvester':
unit = new UnitHarvester(x, y, playerId);
// Find the first available place around the refinery
var path = findAvailablePositionAroundRefinery(x, y);
if (path.length > 0) {
unit.moveAlongPath(path, function () {
harvestActionLogic(unit);
});
}
break;
// Add additional cases for other unit classes as needed
default:
throw new Error('Unknown unit class: ' + unitInfo.className);
}
gameMap.cells[x][y].unit = unit;
if (playerId === player1.playerId) {
player1.addUnit(unit);
} else if (playerId === player2.playerId) {
player2.addUnit(unit);
}
game.addChild(unit);
return unit;
}
function findAvailablePositionAroundRefinery(refineryX, refineryY) {
var directions = [{
x: -1,
y: 0
}, {
x: 1,
y: 0
}, {
x: 0,
y: -1
}, {
x: 0,
y: 1
}];
for (var i = 0; i < directions.length; i++) {
var checkX = refineryX + directions[i].x;
var checkY = refineryY + directions[i].y;
if (gameMap.cells[checkX] && gameMap.cells[checkX][checkY] && !gameMap.cells[checkX][checkY].unit && !gameMap.cells[checkX][checkY].building) {
return [{
cellX: directions[i].x,
cellY: directions[i].y
}]; // Return relative move to the first available cell
}
}
return []; // No available position found
}
function _typeof(o) {
"@babel/helpers - typeof";
return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) {
return typeof o;
} : function (o) {
return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
}, _typeof(o);
}
function moveActionLogic(targetUnit, destinationX, destinationY) {
console.log("MoveActionLogic...", destinationX, ',', destinationY);
if (targetUnit && targetUnit.isUnit) {
var path = gameMap.findPath({
x: targetUnit.cellX,
y: targetUnit.cellY
}, {
x: destinationX,
y: destinationY
});
targetUnit.moveAlongPath(path);
}
}
function harvestActionLogic(targetUnit, destinationX, destinationY) {
console.log("HarvestActionLogic...", targetUnit, ' pos=', destinationX, ',', destinationY);
if (targetUnit && targetUnit.isUnit && targetUnit.type === "unitHarvester") {
var path = [];
if (destinationX && destinationY) {
path = gameMap.findPath({
x: targetUnit.cellX,
y: targetUnit.cellY
}, {
x: destinationX,
y: destinationY
});
}
if (path.length > 0) {
console.log("Valid harvesting, path:", path);
targetUnit.moveAlongPath(path, targetUnit.startHarvesting);
} else {
console.log("No path, direct harvesting ");
targetUnit.startHarvesting();
}
}
}
function highlightBorder(borderX) {
var iconBorders = game.children.filter(function (child) {
return child instanceof IconBorder;
});
for (var i = 0; i < iconBorders.length; i++) {
var iconAsset = iconBorders[i].asset;
iconAsset.tint = iconAsset.x === borderX ? 0xffAAAA : 0xFFFFFF;
}
}
function getEnergyColor(energy) {
if (energy < 25) {
return '#ff1100'; // Red color for low energy
} else if (energy < 75) {
return '#d26600'; // Orange color for medium energy
} else {
return '#037d50'; // Original green color for high energy
}
}
function checkBuildingPlacement(newBuilding, cellX, cellY) {
if (newBuilding && 'cellW' in newBuilding) {
for (var w = 0; w < newBuilding.cellW; w++) {
for (var h = 0; h < newBuilding.cellH; h++) {
if (!gameMap.cells[cellX + w] || !gameMap.cells[cellX + w][cellY + h] || gameMap.cells[cellX + w][cellY + h].terrain !== 'rock' || gameMap.cells[cellX + w][cellY + h].building) {
return false;
}
}
}
}
return true;
}
function enqueueBuildable(selectedBuildable, progressDisplay) {
console.log("enqueueBuildable...", selectedBuildable);
if (!currentSelection || !currentSelection.buildable.includes(selectedBuildable.type)) {
console.log("Cannot build this item here.");
return;
}
var buildableInfo = buildableRepository.getBuildableInfo(selectedBuildable.type);
if (player1.spice < buildableInfo.cost) {
console.log("Not enough resources to build.");
return;
}
updateBaseInfo();
var constructionTime = buildableInfo.constructionTime;
var building;
switch (buildableInfo.className) {
case 'ConstructionYard':
building = new ConstructionYard(0, 0, player1.playerId);
break;
case 'WindTrap':
building = new WindTrap(0, 0, player1.playerId);
break;
case 'SpiceRefinery':
building = new SpiceRefinery(0, 0, player1.playerId);
break;
// Add cases for other buildings as needed
}
building.constructionProgress = 0;
building.constructionTimer = LK.setInterval(function () {
building.constructionProgress += 0.1;
var progressFraction = building.constructionProgress / constructionTime;
building.progressDisplay.setProgress(progressFraction);
// Deduct spice progressively based on construction progress
var costPerTick = buildableInfo.cost * 0.1 / constructionTime;
player1.spice -= costPerTick;
updateBaseInfo();
if (building.constructionProgress >= constructionTime) {
LK.clearInterval(building.constructionTimer);
console.log(selectedBuildable.type + " construction completed.");
building.constructionTimer = null;
building.progressDisplay.hide();
if (progressDisplay.parentIcon && typeof progressDisplay.parentIcon.setLabelToPlace === 'function') {
progressDisplay.parentIcon.setLabelToPlace(); // Change label text to 'Place'
}
console.log("Building Ready for placement ", building);
currentBuildingForPlacement = building;
game.children.forEach(function (child) {
if (child instanceof BuildableItemIcon) {
child.asset.interactive = true;
child.alpha = 1.0;
}
});
}
}, 100);
building.progressDisplay = progressDisplay;
currentSelection.buildingQueue.push(building);
game.children.forEach(function (child) {
if (child instanceof BuildableItemIcon) {
child.asset.interactive = false;
}
});
// Instantiate and display the CancelActionButton on the command panel
cancelActionBtn = new CancelActionButton(commandPanel.x + commandPanel.width - 200, commandPanel.y + 200);
game.addChild(cancelActionBtn);
}
var applyCellOccupation = function applyCellOccupation(cellX, cellY) {
var building = gameMap.cells[cellX][cellY].building;
if (building) {
for (var w = 0; w < building.cellW; w++) {
for (var h = 0; h < building.cellH; h++) {
if (cellX + w < gameMap.cells.length && cellY + h < gameMap.cells[0].length) {
console.log("applyCellOccupation", cellX, cellY, " to ", cellX + w, cellY + h);
gameMap.cells[cellX + w][cellY + h].building = building;
}
}
}
}
};
var getPlayerTint = function getPlayerTint(id) {
return player1.playerId === id ? player1.tint : player2.tint;
};
var gameIsRunning = false;
var mapXSize = 20 * 2;
var mapYSize = 21 * 2;
var tileSize = 100;
var mapHeight = game.height * 0.80;
var viewSize = Math.ceil(Math.max(game.width, game.height) / 2 / 100);
var viewPort = {
wX: 0,
wY: 0,
wCellX: 0,
wCellY: 0,
cellW: Math.floor(game.width / tileSize),
// ~20
cellH: Math.floor(mapHeight / tileSize) // ~21
};
// Init view port
viewPort.wCellX = Math.max(0, Math.min(mapXSize - viewPort.cellW, viewPort.wCellX)); // + game.width/2));
viewPort.wCellY = Math.max(0, Math.min(mapYSize - viewPort.cellH, viewPort.wCellY)); // + game.height/2));
viewPort.wX = viewPort.wCellX * tileSize;
viewPort.wY = viewPort.wCellY * tileSize;
var dragSpeed = 0.15;
var gameMap = new Map();
var buildableRepository = new BuildableRepository();
var unitRepository = new UnitRepository();
var actionRepository = new ActionRepository();
// Define user action states
var UserActionState = {
NAVIGATING: 'navigating',
BUILDING: 'building',
PLACING_BUILDINGS: 'placing_buildings',
GIVING_ORDERS: 'giving_orders',
SET_ORDER_TARGET: 'set_order_target'
};
// Current state of user action
var currentUserActionState = UserActionState.NAVIGATING;
var globalTerrain = null;
var player1 = null;
var player2 = null;
var spiceSpots = [];
// Global variable to keep track of the previous energy level
var previousEnergyLevel = 0;
var currentSelection = null;
var currentBuildingForPlacement = null;
var selectionMarker = null;
var tickCounter = 0;
var fps = 0;
// Gui
var commandPanel = null;
var player1SpiceText = null;
var player1EnergyText = null;
var energyOffsetSufix = '% ';
var currentSelectionText = null;
var fpsText = null;
var targetMoveCursor = null;
var cancelActionBtn = null;
var rockIlot1Center = {
x: 0,
y: 0
};
// Prepare the map
function prepareMap() {
globalTerrain = new Array(mapXSize).fill(0).map(function () {
return new Array(mapYSize).fill(0);
});
gameMap = new Map();
gameMap.init(mapXSize, mapYSize); // Initialize with a 20x20 grid
// Define a fixed rock ilot near the center left of the map
rockIlot1Center = {
x: Math.floor(mapXSize * 0.15),
y: Math.floor(mapYSize * 0.25)
};
console.log("rockIlot1Center : ", rockIlot1Center);
var rockIlot1Radius = 4;
for (var x = rockIlot1Center.x - rockIlot1Radius; x <= rockIlot1Center.x + rockIlot1Radius; x++) {
for (var y = rockIlot1Center.y - rockIlot1Radius; y <= rockIlot1Center.y + rockIlot1Radius; y++) {
if (x >= 0 && x < mapXSize && y >= 0 && y < mapYSize) {
globalTerrain[x][y] = 1;
}
}
}
console.log("rockIlot1Center at " + rockIlot1Center.x + ',' + rockIlot1Center.y);
var initialConstructionYard = new ConstructionYard(rockIlot1Center.x, rockIlot1Center.y, 1);
gameMap.cells[rockIlot1Center.x][rockIlot1Center.y].building = initialConstructionYard;
applyCellOccupation(rockIlot1Center.x, rockIlot1Center.y);
player1.addBuilding(initialConstructionYard);
// Add a new harvester to player 1
//spawnUnit('unitHarvester', rockIlot1Center.x, rockIlot1Center.y - 2, player1.playerId);
// Define a fixed rock ilot near the center right of the map
var rockIlot2Center = {
x: Math.floor(mapXSize * 0.85),
y: Math.floor(mapYSize * 0.5)
};
var rockIlot2Radius = 4;
for (var x = rockIlot2Center.x - rockIlot2Radius; x <= rockIlot2Center.x + rockIlot2Radius; x++) {
for (var y = rockIlot2Center.y - rockIlot2Radius; y <= rockIlot2Center.y + rockIlot2Radius; y++) {
if (x >= 0 && x < mapXSize && y >= 0 && y < mapYSize) {
globalTerrain[x][y] = 1;
}
}
}
console.log("rockIlot2Center at " + rockIlot2Center.x + ',' + rockIlot2Center.y);
var initialConstructionYard2 = new ConstructionYard(rockIlot2Center.x, rockIlot2Center.y, 2);
gameMap.cells[rockIlot2Center.x][rockIlot2Center.y].building = initialConstructionYard2;
applyCellOccupation(rockIlot2Center.x, rockIlot2Center.y);
player2.addBuilding(initialConstructionYard2);
gameMap.initTerrain(mapXSize, mapYSize); // Initialize with a 20x20 grid
initSpiceSpots();
console.log('ConstructionYard1 cell :', gameMap.cells[rockIlot1Center.x][rockIlot1Center.y]);
selectionMarker = new SelectionMarker();
// Add the map to the game
game.addChild(gameMap);
game.addChild(selectionMarker);
}
function initSpiceSpots() {
var quarterWidth = Math.floor(mapXSize / 2);
var quarterHeight = Math.floor(mapYSize / 2);
for (var i = 0; i < 4; i++) {
var startX = i % 2 * quarterWidth;
var startY = Math.floor(i / 2) * quarterHeight;
var ilotCenterX = startX + Math.floor(Math.random() * quarterWidth);
var ilotCenterY = startY + Math.floor(Math.random() * quarterHeight);
var ilotRadius = 2 + Math.floor(Math.random() * 3); // Radius between 2 and 4
for (var x = ilotCenterX - ilotRadius; x <= ilotCenterX + ilotRadius; x++) {
for (var y = ilotCenterY - ilotRadius; y <= ilotCenterY + ilotRadius; y++) {
if (x >= 0 && x < mapXSize && y >= 0 && y < mapYSize && globalTerrain[x][y] === 0) {
globalTerrain[x][y] = 2; // Mark as spice
spiceSpots.push({
x: x,
y: y
});
gameMap.cells[x][y].spice = true;
gameMap.cells[x][y].spiceAsset = LK.getAsset('terrainSpice', {
x: x * 100,
y: y * 100
});
}
}
}
}
}
//#region Event listeners
var dragStart = null;
var dragDelta = 0;
function handleDragStart(obj) {
console.log("Drag start...");
dragStart = obj.event.getLocalPosition(game);
}
function handleDragMove(obj) {
var currentPos = obj.event.getLocalPosition(game);
var input = {
x: currentPos.x,
y: currentPos.y
};
updateMouseCoords(input.x, input.y);
if (currentUserActionState === UserActionState.PLACING_BUILDINGS) {
//console.log("User is moving building..." + Math.floor(input.x) + ',' + Math.floor(input.y), currentBuildingForPlacement);
var cellCoord = screenCoordToWorldCell(input.x, input.y); //getCellForPlacement(input.x, input.y, currentBuildingForPlacement);
var cellX = cellCoord.wCellX;
var cellY = cellCoord.wCellY;
var isValidPlacement = checkBuildingPlacement(currentBuildingForPlacement, cellX, cellY);
//console.log("Verif coords : " + cellX + ',' + cellY);
if (currentBuildingForPlacement && currentBuildingForPlacement.asset) {
currentBuildingForPlacement.asset.tint = isValidPlacement ? 0x00FF00 : 0xFF0000;
currentBuildingForPlacement.visible = input.y + currentBuildingForPlacement.cellH * tileSize < mapHeight;
}
//var cursorCellCoord = getCursorCellForMovement(input, currentBuildingForPlacement);
currentBuildingForPlacement.x = (cellX + currentBuildingForPlacement.cellW / 2) * tileSize; //cursorCellCoord.cellX;
currentBuildingForPlacement.y = (cellY + currentBuildingForPlacement.cellH / 2) * tileSize; //cursorCellCoord.cellY;
//console.log("Follow coords : " + currentBuildingForPlacement.x + ',' + currentBuildingForPlacement.y);
} else if (dragStart) {
//console.log("Drag move...");
var deltaX = currentPos.x - dragStart.x;
var deltaY = currentPos.y - dragStart.y;
var inputPosition = {
x: Math.round(-deltaX / tileSize),
y: Math.round(-deltaY / tileSize)
};
var allUnits = player1.units.concat(player2.units);
allUnits.forEach(function (unit) {
var targetX = Math.max(11, Math.min(gameMap.currentViewCenter.x + inputPosition.x, mapXSize - 4));
var targetY = Math.max(14, Math.min(gameMap.currentViewCenter.y + inputPosition.y, mapYSize - 9));
var newCenterX = Math.round(gameMap.currentViewCenter.x + (targetX - gameMap.currentViewCenter.x) * dragSpeed);
var newCenterY = Math.round(gameMap.currentViewCenter.y + (targetY - gameMap.currentViewCenter.y) * dragSpeed);
var deltaX = gameMap.currentViewCenter.x - newCenterX;
var deltaY = gameMap.currentViewCenter.y - newCenterY;
console.log("unit coords : " + unit.x + ',' + unit.y);
//console.log("target coords : " + targetX + ',' + targetY);
//console.log("center coords : " + gameMap.currentViewCenter.x + ',' + gameMap.currentViewCenter.y);
//console.log("input coords : " + inputPosition.x + ',' + inputPosition.y);
console.log("delta coords : " + deltaX + ',' + deltaY);
unit.x += deltaX * tileSize;
unit.y += deltaY * tileSize;
});
gameMap.handleDrag(inputPosition);
dragDelta = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
selectionMarker.setOnElement(currentSelection);
}
}
function handleDragEnd(obj) {
var currentPos = obj.event.getLocalPosition(game);
var input = {
x: currentPos.x,
y: currentPos.y
};
console.log("Clicked at " + input.x + ',' + input.y);
if (input.y > game.height * 0.80) {
console.log("Clicked on board at " + input.x + ',' + input.y);
dragStart = null;
dragDelta = 0;
return;
}
if (currentUserActionState === UserActionState.PLACING_BUILDINGS) {
var cellCoord = screenCoordToWorldCell(input.x, input.y); //getCellForPlacement(input.x, input.y, currentBuildingForPlacement);
var cellX = cellCoord.wCellX;
var cellY = cellCoord.wCellY;
/*
var cellCoord = getCellForPlacement(input.x, input.y, currentBuildingForPlacement);
var cellX = cellCoord.cellX;
var cellY = cellCoord.cellY;
*/
var isValidPlacement = checkBuildingPlacement(currentBuildingForPlacement, cellX, cellY);
if (!isValidPlacement) {
return;
}
console.log("Placing building ", currentBuildingForPlacement, " at " + cellX + ',' + cellY);
handleBuildingPlacement(currentBuildingForPlacement, cellX, cellY);
currentUserActionState = UserActionState.NAVIGATING;
dragStart = null;
dragDelta = 0;
} else if (currentUserActionState === UserActionState.SET_ORDER_TARGET) {
if (currentSelection && currentSelection.isUnit) {
var cellCoord = convertCoordsToCell(input.x, input.y);
currentSelection.destinationTarget = {
x: cellCoord.cellX,
y: cellCoord.cellY
};
console.log(currentSelection.name + ' received new destination target: ' + cellCoord.cellX + ',' + cellCoord.cellY);
// Call the action handler with the target position
if (currentSelection.actions && currentSelection.selectedAction) {
console.log(currentSelection.selectedAction + ' received ');
var actionInfo = actionRepository.getActionInfo(currentSelection.selectedAction);
if (actionInfo && actionInfo.handler) {
console.log('Call action handler : ', actionInfo);
actionInfo.handler(currentSelection, cellCoord.cellX, cellCoord.cellY);
}
}
if (targetMoveCursor) {
console.log('hiding move cursor ...');
targetMoveCursor.visible = false;
}
}
highlightBorder();
currentUserActionState = UserActionState.NAVIGATING;
dragStart = null;
dragDelta = 0;
} else {
// Normal click
var clickCell = screenCoordToWorldCell(input.x, input.y);
var cellX = clickCell.wCellX;
var cellY = clickCell.wCellY;
console.log("Click at cell " + cellX + ',' + cellY);
var deltaToSelection = 99;
if (currentSelection && currentSelection.isUnit) {
var selCell = getCellForUnit(currentSelection);
console.log("currentSelection = " + currentSelection.name + " at " + selCell.cellX + ',' + selCell.cellY);
deltaToSelection = Math.sqrt(Math.pow(Math.abs(selCell.cellX - cellX), 2) + Math.pow(Math.abs(selCell.cellY - cellY), 2));
}
if (cellX >= 0 && cellX < gameMap.cells.length && cellY >= 0 && cellY < gameMap.cells[cellX].length) {
var cell = gameMap.cells[cellX][cellY];
if (!cell.building && !cell.unit && deltaToSelection > 1) {
if (dragDelta < tileSize * 0.25) {
currentSelection = null;
selectionMarker.setOnElement();
selectionMarker.hide();
console.log("Nothing selected at " + cellX + ',' + cellY, " deltaToSelection=" + deltaToSelection, " dragDelta=", dragDelta);
updateActionBoard();
}
} else if (cell.building) {
console.log("Selected building at " + cellX + ',' + cellY);
currentSelection = cell.building;
selectionMarker.setOnElement(currentSelection);
updateActionBoard();
} else if (cell.unit) {
console.log("Selected cell with unit at " + cellX + ',' + cellY);
console.log("unit at " + cell.unit.x + ',' + cell.unit.y);
}
}
dragStart = null;
dragDelta = 0;
}
}
game.on('down', handleDragStart);
game.on('move', handleDragMove);
game.on('up', handleDragEnd);
//#endregion Event listeners
// Global function to handle building placement
var handleBuildingPlacement = function handleBuildingPlacement(building, cellX, cellY) {
console.log("handle " + building.name + " Placement at " + cellX + ',' + cellY);
if (!gameMap.cells[cellX] || !gameMap.cells[cellX][cellY]) {
console.log('Invalid cell for building placement.');
return;
}
var cell = gameMap.cells[cellX][cellY];
if (cell.building) {
console.log('Cell is already occupied.');
return;
}
// Place the building on the map
cell.building = building;
building.cellX = cellX;
building.cellY = cellY;
building.x = cellX * tileSize;
building.y = cellY * tileSize;
building.asset.tint = 0xFFFFFF;
gameMap.addChild(building);
// Call addBuilding for the player who owns the building
if (building.playerId === player1.playerId) {
player1.addBuilding(building);
} else if (building.playerId === player2.playerId) {
player2.addBuilding(building);
}
applyCellOccupation(cellX, cellY);
console.log(building.name + ' placed at ' + cellX + ',' + cellY);
if (player1.playerId === building.playerId) {
player1.updateEnergy();
updateBaseInfo();
}
if (building instanceof SpiceRefinery) {
spawnUnit('unitHarvester', cellX, cellY, building.playerId);
}
currentUserActionState = UserActionState.NAVIGATING;
currentBuildingForPlacement = null;
if (cancelActionBtn) {
cancelActionBtn.visible = false;
}
updateActionBoard();
};
// Screen <-> World Coordinates
var screenCoordToWorldCell = function screenCoordToWorldCell(x, y) {
var wCellX = Math.floor(x / tileSize) + viewPort.wCellX;
var wCellY = Math.floor(y / tileSize) + viewPort.wCellY;
return {
wCellX: wCellX,
wCellY: wCellY
};
};
var screenCoordToWorldCoord = function screenCoordToWorldCoord(x, y) {
var wX = x + viewPort.wX;
var wY = y + viewPort.wY;
return {
wX: wX,
wY: wY
};
};
var screenCellToWorldCell = function screenCellToWorldCell(cellX, cellY) {
var wCellX = cellX + viewPort.wCellX;
var wCellY = cellY + viewPort.wCellY;
return {
wCellX: wCellX,
wCellY: wCellY
};
};
var screenCellToWorldCoord = function screenCellToWorldCoord(cellX, cellY) {
var wX = cellX * tileSize + viewPort.wX;
var wY = cellY * tileSize + viewPort.wY;
return {
wX: wX,
wY: wY
};
};
// World <-> Screen Coordinates
var worldCoordToScreenCell = function worldCoordToScreenCell(wX, wY) {
var cellX = Math.floor(wX / tileSize) - viewPort.wCellX;
var cellY = Math.floor(wY / tileSize) - viewPort.wCellY;
return {
cellX: cellX,
cellY: cellY
};
};
var worldCoordToScreenCoord = function worldCoordToScreenCoord(wX, wY) {
var x = wX - viewPort.wX;
var y = wY - viewPort.wY;
return {
x: x,
y: y
};
};
var worldCellToScreenCell = function worldCellToScreenCell(wCellX, wCellY) {
var cellX = wCellX - viewPort.wCellX;
var cellY = wCellY - viewPort.wCellY;
return {
cellX: cellX,
cellY: cellY
};
};
var worldCellToScreenCoord = function worldCellToScreenCoord(wCellX, wCellY) {
var x = wCellX * tileSize - viewPort.wX;
var y = wCellY * tileSize - viewPort.wY;
return {
x: x,
y: y
};
};
var getScreenToWorldCell = function getScreenToWorldCell(x, y) {
var wCellX = Math.floor(x / tileSize) + viewPort.wX;
var wCellY = Math.floor(y / tileSize) + viewPort.wY;
return {
wCellX: wCellX,
wCellY: wCellY
};
};
var getScreenToWorldCoord = function getScreenToWorldCoord(x, y) {
var wX = x + viewPort.wX * tileSize;
var wY = y + viewPort.wY * tileSize;
return {
wX: wX,
wY: wY
};
};
var convertCoordsToCell = function convertCoordsToCell(x, y) {
return {
cellX: Math.floor(x / 100) + gameMap.currentViewCenter.x - Math.ceil(game.width / 2 / 100) - 3,
cellY: Math.floor(y / 100) + gameMap.currentViewCenter.y - Math.ceil(game.height / 2 / 100)
};
};
var getCellForPlacement = function getCellForPlacement(x, y, building) {
var cX = Math.floor(x / 100) + gameMap.currentViewCenter.x - Math.ceil(game.width / 2 / 100) - 4;
var cY = Math.floor(y / 100) + gameMap.currentViewCenter.y - Math.ceil(game.height / 2 / 100) - 1;
if (building && building.cellW && building.cellH) {
return {
cellX: cX + Math.floor(building.cellW / 2),
cellY: cY + Math.floor(building.cellH / 2)
};
} else {
return {
cellX: cX,
cellY: cY
};
}
};
var getCellForUnit = function getCellForUnit(unit) {
var centerDeltaX = gameMap.currentViewCenter.x - Math.ceil(game.width / 2 / 100);
var centerDeltaY = gameMap.currentViewCenter.y - Math.ceil(game.height / 2 / 100);
var cX = Math.floor(unit.x / 100) + centerDeltaX + unit.cellW / 2 + Math.floor(unit.cellW / 2) - 5;
var cY = Math.floor(unit.y / 100) + centerDeltaY + Math.floor(unit.cellH / 2) + unit.cellH / 2 - 7;
return {
cellX: cX,
cellY: cY
};
};
var getCoordsForUnit = function getCoordsForCell(cell) {
//console.log("getCoordsForUnit :", cell.cellX, ',', cell.cellY);
//console.log("currentViewCenter :", gameMap.currentViewCenter.x, ',', gameMap.currentViewCenter.y);
var centerDeltaX = -1;
var centerDeltaY = -6;
var x = (cell.cellX + centerDeltaX) * 100 + 50;
var y = (cell.cellY + centerDeltaY) * 100 + 50;
/*
var centerDeltaX = gameMap.currentViewCenter.x - Math.ceil(game.width / 2 / 100) - 4;
var centerDeltaY = gameMap.currentViewCenter.y - Math.ceil(game.height / 2 / 100) - 6;
var x = (cell.cellX + centerDeltaX) * 100;
var y = (cell.cellY + centerDeltaY) * 100;
*/
//console.log("=> :", x, ',', y);
return {
x: x,
y: y
};
};
var getCursorCellForMovement = function getCursorCellForMovement(input, building) {
var centerDeltaX = gameMap.currentViewCenter.x - Math.ceil(game.width / 2 / 100);
var centerDeltaY = gameMap.currentViewCenter.y - Math.ceil(game.height / 2 / 100);
var cX = (Math.floor(input.x / 100) + centerDeltaX + building.cellW / 2 + Math.floor(building.cellW / 2) - 5) * 100;
var cY = (Math.floor(input.y / 100) + centerDeltaY + Math.floor(building.cellH / 2) + building.cellH / 2 - 7) * 100;
return {
cellX: cX,
cellY: cY
};
};
// Global function to find the closest spice spot to a given position
var findClosestSpiceSpot = function findClosestSpiceSpot(x, y) {
var closestSpot = null;
var minDistance = Number.MAX_VALUE;
spiceSpots.forEach(function (spot) {
var dx = x - spot.x;
var dy = y - spot.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < minDistance) {
closestSpot = spot;
minDistance = distance;
}
});
return closestSpot;
};
// Global function to handle action board updates
var updateActionBoard = function updateActionBoard() {
console.log('updateActionBoard...' + (currentSelection ? currentSelection.name : 'No selection'));
currentSelectionText.setText(currentSelection ? currentSelection.name : '');
clearIconBorders();
displayBuildableItems(); // Call displayBuildableItems to show items that can be built
displayActionItems(); // Call displayActionItems to show action items
};
function clearIconBorders() {
var iconBorders = game.children.filter(function (child) {
return child instanceof IconBorder;
});
iconBorders.forEach(function (border) {
border.destroy();
});
}
function displayBuildableItems() {
console.log('updateActionBoard...', currentSelection);
var buildableItemIcons = game.children.filter(function (child) {
return child instanceof BuildableItemIcon;
});
buildableItemIcons.forEach(function (icon) {
//console.log('removing...', icon.type);
icon.destroy();
});
if (currentSelection && currentSelection.playerId === player1.playerId && currentSelection.buildable && currentSelection.buildable.length) {
var iconX = commandPanel.x + 200; // Starting X position for the first icon
var iconY = commandPanel.y + 220; // Y position for all icons
currentSelection.buildable.forEach(function (itemType) {
//console.log('Add build button for ' + itemType);
var border = new IconBorder(iconX, iconY);
game.addChild(border);
var icon = new BuildableItemIcon(itemType, iconX, iconY);
game.addChild(icon);
iconX += 300; // Increment X position for the next icon
});
}
}
// Global function to display action items
var displayActionItems = function displayActionItems() {
console.log('displayActionItems...', currentSelection);
var actionItemIcons = game.children.filter(function (child) {
return child instanceof ActionItemIcon;
});
actionItemIcons.forEach(function (icon) {
console.log('removing...', icon.action.name);
icon.destroy();
});
if (currentSelection && currentSelection.isUnit && currentSelection.actions && currentSelection.actions.length) {
var iconX = commandPanel.x + 200; // Starting X position for the first icon
var iconY = commandPanel.y + 220; // Y position for all icons
currentSelection.actions.forEach(function (actionType) {
console.log('Add action button for ', actionType);
var actionInfo = actionRepository.getActionInfo(actionType);
if (actionInfo) {
console.log('ok Action found => display', actionInfo);
var border = new IconBorder(iconX, iconY);
game.addChild(border);
var icon = new ActionItemIcon(actionInfo, iconX, iconY);
game.addChild(icon);
iconX += 300; // Increment X position for the next icon
} else {
console.log('Action not found', actionType);
}
});
}
};
// Global function to update mouse coordinates text
var updateMouseCoords = function updateMouseCoords(x, y) {
/*var cellCoord = convertCoordsToCell(x, y);
if (game.mouseCoordsText) {
game.mouseCoordsText.setText(Math.floor(x) + ',' + Math.floor(y) + '\r\n' + cellCoord.cellX + ',' + cellCoord.cellY);
}*/
/*
var wCellCoords = getScreenToWorldCell(x, y);
var wCoordCoords = getScreenToWorldCoord(x, y);
if (game.mouseCoordsText) {
game.mouseCoordsText.setText("S:" + Math.floor(x) + ',' + Math.floor(y)
+ '\r\n' + Math.floor(x / tileSize) + ',' + Math.floor(y / tileSize) + '\r\nW:' + Math.floor(wCellCoords.wCellX) + ',' + Math.floor(wCellCoords.wCellY) + '\r\n' + Math.floor(wCoordCoords.wX) + ',' + Math.floor(wCoordCoords.wY));
}
*/
var wCell = screenCoordToWorldCell(x, y);
if (game.mouseCoordsText) {
game.mouseCoordsText.setText("S:" + Math.floor(x) + ',' + Math.floor(y) + '\r\n' + Math.floor(x / tileSize) + ',' + Math.floor(y / tileSize) + '\r\nW:' + Math.floor(wCell.wCellX) + ',' + Math.floor(wCell.wCellY));
}
gameMap.viewCenterText.setText(gameMap.currentViewCenter.x + ', ' + gameMap.currentViewCenter.y + '\r\n' + viewPort.wCellX + ',' + viewPort.wCellY);
};
// Global function to update base info text
var updateBaseInfo = function updateBaseInfo() {
player1SpiceText.setText('| ' + player1.spice.toString());
// Animate the change of the energy value
if (previousEnergyLevel !== player1.energy) {
var energyDifference = player1.energy - previousEnergyLevel;
var duration = 2000; // Duration of the animation in milliseconds
var steps = duration / (1000 / 60); // Number of steps based on 60FPS
var stepValue = energyDifference / steps;
var currentStep = 0;
var animateEnergyChange = function animateEnergyChange() {
var energyColor = getEnergyColor(previousEnergyLevel);
player1EnergyText.setStyle({
fill: energyColor
});
if (currentStep < steps) {
previousEnergyLevel += stepValue;
player1EnergyText.setText(previousEnergyLevel.toFixed(0).toString() + energyOffsetSufix);
currentStep++;
LK.setTimeout(animateEnergyChange, 1000 / 60);
} else {
// Ensure the final value is set correctly
player1EnergyText.setText(player1.energy.toString() + energyOffsetSufix);
previousEnergyLevel = player1.energy; // Update the previous energy level
}
};
animateEnergyChange();
} else {
player1EnergyText.setText(player1.energy.toString() + energyOffsetSufix);
}
};
var startFpsCounter = function startFpsCounter() {
var fpsInterval = LK.setInterval(function () {
// Set the FPS value to the tick counter
fps = tickCounter;
// Reset the tick counter
tickCounter = 0;
// Update the FPS text on the screen
fpsText.setText('FPS: ' + fps);
}, 1000); // 1000 milliseconds = 1 second
};
function initGame() {
// Create players
player1 = new Player(1, 0x5e86ff);
player2 = new Player(2, 0xffAAAA);
// Prepare the map
prepareMap();
// Instantiate CommandPanel
commandPanel = game.addChild(new CommandPanel());
// Create a Text2 object for current selection
currentSelectionText = new Text2('', {
size: 50,
fill: '#000000',
font: "'GillSans-Bold',Impact,'Arial Black',Tahoma"
});
currentSelectionText.anchor.set(0.5, 6.8);
LK.gui.bottom.addChild(currentSelectionText);
// Create a Text2 object to display mouse coordinates
if (!game.mouseCoordsText) {
game.mouseCoordsText = new Text2('0,0\r\n0,0', {
size: 50,
fill: '#ffffff',
font: "'GillSans-Bold',Impact,'Arial Black',Tahoma"
});
game.mouseCoordsText.anchor.set(0, 0);
LK.gui.topLeft.addChild(game.mouseCoordsText);
}
// Create a Text2 object to display player1's spice level
player1SpiceText = new Text2('| ' + player1.spice.toString(), {
size: 50,
fill: '#000000',
font: "'GillSans-Bold',Impact,'Arial Black',Tahoma"
});
player1SpiceText.anchor.set(1.0, 0.25);
LK.gui.topRight.addChild(player1SpiceText);
// Create a Text2 object to display player1's energy level
player1EnergyText = new Text2(player1.energy.toString() + energyOffsetSufix, {
size: 50,
fill: '#000000',
font: "'GillSans-Bold',Impact,'Arial Black',Tahoma"
});
player1EnergyText.anchor.set(1.0, 0.25);
LK.gui.topRight.addChild(player1EnergyText);
// Create a Text2 object to display the FPS in the bottom right corner
fpsText = new Text2('', {
size: 50,
fill: '#000000',
font: "'GillSans-Bold',Impact,'Arial Black',Tahoma"
});
fpsText.anchor.set(1.5, 1.0);
LK.gui.bottomRight.addChild(fpsText);
gameIsRunning = true;
startFpsCounter();
}
// Game tick
LK.on('tick', function () {
// Render the map and update unit movement each tick
if (gameIsRunning) {
gameMap.render();
/*if (currentSelection && currentSelection.isUnit) {
currentSelection.updateMovement(1 / 60); // Assuming tick operates at 60FPS
}*/
//game.addChild(newHarvester.asset); // TEMP DEBUG
var allUnits = player1.units.concat(player2.units);
allUnits.forEach(function (unit) {
//console.log("render unit " + unit.name, unit.x, unit.y);
// Ensure the unit is added to the game container, not 'self' which is not defined in this context
//console.log(" unit parent ", unit.asset.parent.parent.parent);
/*if (!unit.asset.parent.parent.parent) {
console.log("First add unit !", unit.asset.parent.parent.parent);
game.addChild(unit.asset);
} else { }*/
unit.updateMovement(1 / 60); // Assuming tick operates at 60FPS
if (unit.update) {
unit.update();
}
game.addChild(unit);
/*var screenX = (unit.cellX - 2 - gameMap.currentViewCenter.x + viewSize) * unit.asset.width;
var screenY = (unit.cellY - 3 - gameMap.currentViewCenter.y + viewSize) * unit.asset.height;
unit.x = screenX;
unit.y = screenY;*/
});
}
tickCounter++;
});
// Start the game with Player 1 construction yard preselected
LK.setTimeout(function () {
initGame();
currentSelection = gameMap.cells[rockIlot1Center.x][rockIlot1Center.y].building;
selectionMarker.setOnElement(currentSelection);
updateActionBoard();
}, 100);
a tileable sand terrain tile.
A square tileable rock terrain tile WITHOUT BBORDER. Single Game Texture. In-Game asset. 2d. No shadows. No Border
Zenith view of Dune's Wind Trap power facility square fence. Ressembles a bit to Sydney's Opera. Zenith view Directly from above.
grey cancel icon. UI
thin white circle empty.
0x5e86ff
Zenith view of a white rectangular Harvester shape of a garbage truck with a triangular head. Harvesting on sand, with flowing spice in the back. inside a square fence. Zenith view. Directly overhead. Plumb view.
Minimal Ui icon of an right sign aside with an icon of a target. sand background
Minimal icon of a home with direction icon pointing to the home. sand background
3 white flat isometric concentric circles like a target.
Remove background
Gray background
Minimal Ui icon of target sign on a fire icon.. sand background
top view of an explosion effect.
Simple heavy army tank factory buiding a tank with a crane. Square fence... Zenith view Directly overhead. Plumb view.
an empty black popup UI. UI