Code edit (17 edits merged)
Please save this source code
User prompt
Please fix the bug: 'Timeout.tick error: screenCoordsToWorldCell is not defined' in or related to this line: 'var cellElt = screenCoordsToWorldCell(element.x, element.y);' Line Number: 645
Code edit (1 edits merged)
Please save this source code
Code edit (2 edits merged)
Please save this source code
User prompt
Please fix the bug: 'ReferenceError: getScreenToWorldCoord is not defined' in or related to this line: 'var wCoordCoords = getScreenToWorldCoord(x, y);' Line Number: 1657
Code edit (1 edits merged)
Please save this source code
User prompt
Please fix the bug: 'ReferenceError: getScreenToWorldCell is not defined' in or related to this line: 'var wCellCoords = getScreenToWorldCell(x, y);' Line Number: 1650
Code edit (1 edits merged)
Please save this source code
Code edit (4 edits merged)
Please save this source code
User prompt
update the Map.render function to use the viewPort and world coordinates
Code edit (10 edits merged)
Please save this source code
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'setText')' in or related to this line: 'Map.viewCenterText.setText(Map.currentViewCenter.x + ', ' + Map.currentViewCenter.y);' Line Number: 1619
Code edit (4 edits merged)
Please save this source code
User prompt
Please fix the bug: 'ReferenceError: newCoords is not defined' in or related to this line: 'game.mouseCoordsText.setText("S:" + Math.floor(x) + ',' + Math.floor(y) + '\r\n' + newCoords.wCellX + ',' + newCoords.wCellY + '\r\nW:' + wCellCoords.wCellX + ',' + wCellCoords.wCellY + '\r\n' + wCoordCoords.wX + ',' + wCoordCoords.wY);' Line Number: 1615
Code edit (2 edits merged)
Please save this source code
User prompt
in findAvailablePositionAroundRefinery, return relative values, instead of aboslute cell coordinates
Code edit (1 edits merged)
Please save this source code
User prompt
For a move from [9,11 to 8,11 find Path returned a path [{8,11}], instead of [{-1,0}]. Fix that
User prompt
now that findPath returns relative values, update the instruction var targetCell = { cellX: targetPathStep.x, cellY: targetPathStep.y }; in Unit.updateMovement accordingly
User prompt
in Map.findPath(), instead of returning and array of targetCells, return an array of relative moves. ie: instead of : [{cellX: 5, cellY: 5}, {cellX: 6, cellY: 5}, {cellX: 6, cellY: 6}] return : [{cellX: +1, cellY: 0}, {cellX: 0, cellY: +1}]
Code edit (16 edits merged)
Please save this source code
User prompt
in UnitHarvester, in update function, implement the case of spice unloading (self.harvestingMode == 2) In this mode, harvestedSpiceOnTripCounter is decremented by self.unloadSpeed. during this decrement, unit blinks in green. Each spice decremented is added to the player spice counter. When harvestedSpiceOnTripCounter reaches 0, the units starts a new harvesting cycle (self.startHarvesting()).
Code edit (1 edits merged)
Please save this source code
Code edit (1 edits merged)
Please save this source code
User prompt
Please fix the bug: 'TypeError: Cannot read properties of null (reading 'name')' in or related to this line: 'return node.x === neighbor.x && node.y === neighbor.y;' Line Number: 441
/**** * 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 * 100; self.y = y * 100; 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 for (var x = self.currentViewCenter.x - viewSize - 1; x <= self.currentViewCenter.x + viewSize; x++) { for (var y = self.currentViewCenter.y - viewSize - 1; y <= self.currentViewCenter.y + viewSize; 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 screenX = (x - self.currentViewCenter.x + viewSize) * asset.width; var screenY = (y - self.currentViewCenter.y + viewSize) * asset.height; 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) { building.asset.x = screenX - (building.cellW - 2) / 2 * 100; building.asset.y = screenY - (building.cellH - 2) / 2 * 100; 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) { // Convert absolute path to relative moves var prev = curr.parent; if (prev) { path.push({ cellX: curr.x - prev.x, cellY: curr.y - prev.y }); } curr = curr.parent; } path.reverse(); 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; } } } 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); //console.log("handling drag...", input, self.currentViewCenter.x, self.currentViewCenter.y); // Update the Text2 object with the new coordinates self.viewCenterText.setText(self.currentViewCenter.x + ', ' + self.currentViewCenter.y); //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) / 2 * 100; elementDeltaY = (element.cellH - 2) / 2 * 100; 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; self.x = element.x - centerDeltaX + elementDeltaX; self.y = element.y - centerDeltaY + elementDeltaY; 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 (x, y, 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); //console.log("targetCoords", targetCoords.x, targetCoords.y); var dx = targetCoords.x - self.x; var dy = targetCoords.y - 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; self.y = targetCoords.y; // 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 = x; self.cellY = y; 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) { var path = gameMap.findPath({ x: self.cellX, y: self.cellY }, { x: closestSpiceSpot.x, y: closestSpiceSpot.y }); 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 [{ x: checkX, y: checkY }]; // Return path with one step 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) { 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 = 50; var mapYSize = 30; var viewSize = Math.ceil(Math.max(game.width, game.height) / 2 / 100); 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.5) }; 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; 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 = getCellForPlacement(input.x, input.y, currentBuildingForPlacement); var cellX = cellCoord.cellX; var cellY = cellCoord.cellY; var isValidPlacement = checkBuildingPlacement(currentBuildingForPlacement, cellX, cellY); //console.log("Verif coords : " + cellX + ',' + cellY); if (currentBuildingForPlacement && currentBuildingForPlacement.asset) { currentBuildingForPlacement.asset.tint = isValidPlacement ? 0x00FF00 : 0xFF0000; } var cursorCellCoord = getCursorCellForMovement(input, currentBuildingForPlacement); currentBuildingForPlacement.x = cursorCellCoord.cellX; currentBuildingForPlacement.y = 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 / 100), y: Math.round(-deltaY / 100) }; 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 * 100; unit.y += deltaY * 100; }); gameMap.handleDrag(inputPosition); } } 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; return; } if (currentUserActionState === UserActionState.PLACING_BUILDINGS) { 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; } 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; } else { // Existing code for handling drag end without a building placement var cellX = Math.floor(input.x / 100) + gameMap.currentViewCenter.x - Math.ceil(game.width / 2 / 100) - 3; var cellY = Math.floor(input.y / 100) + gameMap.currentViewCenter.y - Math.ceil(game.height / 2 / 100); 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) { currentSelection = null; selectionMarker.setOnElement(); selectionMarker.hide(); console.log("Nothing selected at " + cellX + ',' + cellY, " deltaToSelection=" + deltaToSelection); 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; } } 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 * 100; building.y = cellY * 100; 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(); }; 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); } }; // 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);
===================================================================
--- original.js
+++ change.js
@@ -657,10 +657,10 @@
return;
}
var targetPathStep = self.path[self.pathIndex];
var targetCell = {
- cellX: targetPathStep.x,
- cellY: targetPathStep.y
+ 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);
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