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);
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