Code edit (1 edits merged)
Please save this source code
Code edit (8 edits merged)
Please save this source code
User prompt
Please fix the bug: 'ReferenceError: unit is not defined' in or related to this line: 'switch (unit.type) {' Line Number: 2176
Code edit (1 edits merged)
Please save this source code
Code edit (14 edits merged)
Please save this source code
User prompt
Please fix the bug: 'ReferenceError: rockIlot2Center is not defined' in or related to this line: 'baseBuilding = {' Line Number: 1740
Code edit (1 edits merged)
Please save this source code
Code edit (5 edits merged)
Please save this source code
User prompt
Please fix the bug: 'TypeError: LK.getTime is not a function' in or related to this line: 'self.lastHitTime = LK.getTime();' Line Number: 1099
Code edit (2 edits merged)
Please save this source code
User prompt
could you implement findFactoryForUnit
Code edit (1 edits merged)
Please save this source code
User prompt
add a new function findEmplacementForBuilding(building, cellX, cellY) that scans the map around the given cellX,cellY to find a free area of rocks that fits the given building size
Code edit (5 edits merged)
Please save this source code
User prompt
Please fix the bug: 'Timeout.tick error: buildable.placeBuilding is not a function' in or related to this line: 'buildable.placeBuilding(placeX, placeY);' Line Number: 2117
Code edit (1 edits merged)
Please save this source code
Code edit (6 edits merged)
Please save this source code
User prompt
in handleDragEnd, don't select buildings if they are under fog
User prompt
don't select ennemy units and building if they are under fog
User prompt
in updateFogOfWar remove the fog in a radius shape instead of a square
Code edit (2 edits merged)
Please save this source code
User prompt
in building growExplosion, remove building from player list of buildings
User prompt
in checkGameEnd, check if player1 of player2 have no more buildings game over if so
Code edit (1 edits merged)
Please save this source code
Code edit (1 edits merged)
Please save this source code
===================================================================
--- original.js
+++ change.js
@@ -155,18 +155,20 @@
'name': 'Spice Refinery',
'cost': 600,
'energy': -50,
'health': 75,
- 'constructionTime': 15,
+ 'constructionTime': 2,
+ //15, TEMP DEBUG !!!TEMP DEBUG !!!TEMP DEBUG !!!
'className': 'SpiceRefinery',
'buildable': []
},
'lightFactory': {
'name': 'Light Factory',
'cost': 400,
'energy': -30,
'health': 60,
- 'constructionTime': 15,
+ 'constructionTime': 2,
+ //15, TEMP DEBUG !!!TEMP DEBUG !!!TEMP DEBUG !!!
'className': 'LightFactory',
'buildable': ['unitQuad'],
'requires': 'spiceRefinery'
},
@@ -174,9 +176,10 @@
'name': 'Heavy Factory',
'cost': 600,
'energy': -50,
'health': 80,
- 'constructionTime': 30,
+ 'constructionTime': 2,
+ // 30, TEMP DEBUG !!!TEMP DEBUG !!!TEMP DEBUG !!!
'className': 'HeavyFactory',
'buildable': ['unitLightTank', 'unitHeavyTank', 'unitHarvester'],
'requires': 'lightFactory'
},
@@ -199,17 +202,19 @@
'unitHeavyTank': {
'name': 'Heavy Tank',
'cost': 600,
'energy': 0,
- 'constructionTime': 15,
+ 'constructionTime': 2,
+ //15,TEMP DEBUG !!!TEMP DEBUG !!!TEMP DEBUG !!!
'className': 'UnitHeavyTank',
'buildable': []
},
'unitHarvester': {
'name': 'Harvester',
'cost': 500,
'energy': 0,
- 'constructionTime': 12,
+ 'constructionTime': 2,
+ //12,TEMP DEBUG !!!TEMP DEBUG !!!TEMP DEBUG !!!
'className': 'UnitHarvester',
'buildable': []
}
// Add more buildables as needed
@@ -244,19 +249,22 @@
self.asset.y = self.y;
self.buildingQueue = [];
self.lastAttackTime = 0;
self.lastHitTime = 0;
+ self.lastAttaker = null;
self.defenders = [];
- self.damage = function (points) {
- console.log("Building " + self.name + " hit! " + points);
- self.health -= points;
+ self.damage = function (attacker) {
+ console.log("Building " + self.name + " hit! " + attacker.attackDamage);
+ self.lastAttaker = attacker;
+ self.health -= attacker.attackDamage;
self.lastHitTime = Date.now();
self.asset.tint = 0xff0000;
LK.setTimeout(function () {
self.asset.tint = 0xFFFFFF;
}, 500);
if (self.health <= 0) {
console.log("Building " + self.name + " destroyed");
+ self.clean();
self.assetEffect = self.attachAsset('buildingExplosion', {
anchorX: 0.5,
anchorY: 0.5,
x: self.x + self.cellW / 2 * tileSize,
@@ -302,9 +310,23 @@
}
};
growExplosion(1);
}
+ LK.setTimeout(function () {
+ if (self.health > 0 && Date.now() - self.lastHitTime > aiUnderAttackDelayMs) {
+ // Not under attack anymore
+ self.lastAttaker = null;
+ self.defenders = [];
+ }
+ }, aiUnderAttackDelayMs * 1.1);
};
+ self.clean = function () {
+ self.buildingQueue = [];
+ self.lastAttackTime = 0;
+ self.lastHitTime = 0;
+ self.lastAttaker = null;
+ self.defenders = [];
+ };
return self;
});
var WindTrap = Building.expand(function (x, y, playerId) {
var self = Building.call(this, x, y, 'windTrap', 'Wind Trap', playerId, 2, 2);
@@ -725,9 +747,9 @@
var self = Container.call(this);
self.playerId = playerId;
self.resources = 0;
self.tint = tint;
- self.spice = 2000; // Initialize spice property with 1000
+ self.spice = 9999; //2000; // 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
@@ -876,8 +898,9 @@
self.attackSpeed = unitInfo.attackSpeed; // Speed of attack (time between attacks)
self.attackMode = 0; // 0 = not attacking, 1 = attacking, 2 = moving to target
self.lastAttackTime = 0;
self.lastHitTime = 0;
+ self.lastAttaker = null;
self.defenders = [];
self.actions = unitInfo.actions;
self.asset = self.attachAsset(type, {
anchorX: 0.5,
@@ -898,13 +921,13 @@
self.asset.on('down', function () {
if (currentUserActionState === UserActionState.NAVIGATING || currentUserActionState === UserActionState.GIVING_ORDERS) {
console.log("Unit selected");
currentSelection = self;
+ // Update map to fix unselectable units
+ gameMap.cells[self.cellX][self.cellY].unit = self;
selectionMarker.setOnElement(currentSelection);
currentUserActionState = UserActionState.GIVING_ORDERS;
updateActionBoard();
- // Update map to fix unselectable units
- gameMap.cells[self.cellX][self.cellY].unit = self;
} else {
console.log("Not Navigating don't select unit...", currentUserActionState);
}
});
@@ -1029,24 +1052,28 @@
self.lastAttackTime = Date.now();
// Check if target is in range
var distanceToTarget = calculateDistance(self, self.attackTarget);
if (distanceToTarget <= self.attackRange) {
+ console.log("Target at range => fire");
// Rotate towards the target
var angleToTarget = calculateAngle(self, self.attackTarget);
self.asset.rotation = angleToTarget;
// Fire at the target
self.fire();
} else {
+ console.log("Target too far => move to target");
self.attackMode = 2;
// Move towards the target if it's out of range
var path = gameMap.findPath({
x: self.cellX,
y: self.cellY
}, {
x: self.attackTarget.cellX,
y: self.attackTarget.cellY
- });
+ }, self.attackRange);
+ console.log("Path to target:", path);
self.moveAlongPath(path, function () {
+ console.log("Reached to target !");
self.attackMode = 1;
});
}
} else if (!self.isMoving) {
@@ -1057,26 +1084,28 @@
// Code to perform firing action
console.log("Firing at target!", self.attackTarget);
if (self.attackTarget && self.health > 0) {
// Reduce target's health
- self.attackTarget.damage(self.attackDamage);
+ self.attackTarget.damage(self);
if (!self.attackTarget || self.attackTarget.health <= 0) {
self.attackMode = 0;
self.attackTarget = null;
}
}
};
- self.damage = function (points) {
- console.log("Unit " + self.name + " hit! " + points);
+ self.damage = function (attacker) {
+ console.log("Unit " + self.name + " hit! ", attacker);
self.asset.tint = 0xff0000;
+ self.lastAttaker = attacker;
self.lastHitTime = Date.now();
LK.setTimeout(function () {
self.asset.tint = getPlayerTint(self.playerId);
}, 300);
- self.health -= points;
+ self.health -= attacker.attackDamage;
if (self.health <= 0 && !self.isDestroying) {
self.isDestroying = true;
console.log("Unit " + self.name + " destroyed");
+ self.clean();
self.assetEffect = self.attachAsset('buildingExplosion', {
anchorX: 0.5,
anchorY: 0.5,
x: self.x,
@@ -1119,8 +1148,15 @@
}
};
growExplosion(1);
}
+ LK.setTimeout(function () {
+ if (self.health > 0 && Date.now() - self.lastHitTime > aiUnderAttackDelayMs) {
+ // Not under attack anymore
+ self.lastAttaker = null;
+ self.defenders = [];
+ }
+ }, aiUnderAttackDelayMs * 1.1);
};
self.stopAttack = function () {
self.attackMode = false;
self.attackTarget = null;
@@ -1128,8 +1164,14 @@
self.stopOtherActions = function () {
console.log("Unit stopOtherActions :");
self.attackMode = false; // Stop attacking
};
+ self.clean = function () {
+ self.lastAttackTime = 0;
+ self.lastHitTime = 0;
+ self.lastAttaker = null;
+ self.defenders = [];
+ };
return self;
});
var UnitQuad = Unit.expand(function (x, y, playerId) {
var self = Unit.call(this, x, y, playerId, 'unitQuad');
@@ -1178,9 +1220,9 @@
x: closestSpiceSpot.x,
y: closestSpiceSpot.y
});
if (!path || path.length == 0) {
- console.warn("No path to spot! retry later");
+ console.warn("No path to spot! ", closestSpiceSpot, ". Retry later");
LK.setTimeout(function () {
self.startHarvesting(true);
}, 1000);
return;
@@ -1333,9 +1375,10 @@
'className': 'UnitHeavyTank',
'actions': ['move', 'attack', 'return'],
'health': 60,
'sightRange': 8,
- 'attackRange': 6,
+ 'attackRange': 2,
+ //6, TEMP DEBUG !!!TEMP DEBUG !!!TEMP DEBUG !!!
'attackSpeed': 5,
'attackDamage': 6
}
// Add more units as needed
@@ -1865,17 +1908,25 @@
var getNextId = function getNextId() {
return nextId++;
};
var getAllUnitsPerDistance = function getAllUnitsPerDistance(position, unitList) {
- var distanceList = {};
+ var orderedUnitList = [];
+ // Calculer la distance de chaque unité par rapport à la position donnée
unitList.forEach(function (unit) {
- distanceList[unit.id] = Math.sqrt(Math.pow(position.x - unit.x, 2) + Math.pow(position.y - unit.y, 2));
+ var distance = Math.sqrt(Math.pow(position.cellX - unit.cellX, 2) + Math.pow(position.cellY - unit.cellY, 2));
+ // Ajouter l'unité à la liste
+ orderedUnitList.push({
+ unit: unit,
+ distance: distance
+ });
+ console.log("unit", unit.id, " ", unit.type, " Pos:", unit.cellX, unit.cellY, " distance", distance);
});
- // Order by distance
- var orderedDistanceList = Object.keys(distanceList).sort(function (a, b) {
- return distanceList[a] - distanceList[b];
+ // Trier les unités en fonction de leurs distances
+ orderedUnitList.sort(function (a, b) {
+ return a.distance - b.distance;
});
- return orderedDistanceList;
+ console.log("orderedUnitList", orderedUnitList);
+ return orderedUnitList;
};
/* ******************************************** GLOBAL GAME VARIABLES ******************************************** */
/* ******************************************** GLOBAL GAME VARIABLES ******************************************** */
/* ******************************************** GLOBAL GAME VARIABLES ******************************************** */
@@ -1944,17 +1995,17 @@
/* ********************************************* AI FUNCTIONS ****************************************** */
/* ***************************************************************************************************** */
var AI_LEVEL = {
EASY: {
- acttingDelay: 500,
+ actingDelay: 500,
thinkingDelay: 500
},
NORMAL: {
- acttingDelay: 300,
+ actingDelay: 300,
thinkingDelay: 600
},
HARD: {
- acttingDelay: 100,
+ actingDelay: 100,
thinkingDelay: 200
}
};
var aiCurrentLevel = AI_LEVEL.EASY;
@@ -1974,8 +2025,10 @@
var aiCurrentBuildingConstruction = null;
var aiNeededBuildingList = null;
var aiNeededUnitsList = null;
var aiBuildingsUnderAttackList = null;
+var aiUnitsUnderAttackList = null;
+var aiUnderAttackDelayMs = aiCurrentLevel.thinkingDelay * 10;
// Think of what AI must do
function aiThinking() {
if (LK.ticks % aiCurrentLevel.thinkingDelay !== 0) {
return;
@@ -1987,8 +2040,9 @@
aiNeededUnitsList = checkUnitRequirements();
// Check buildings defense needs
aiBuildingsUnderAttackList = checkBuildingUnderAttack();
// Check units defense needs
+ aiUnitsUnderAttackList = checkUnitsUnderAttack();
// Check attack opportunities
}
function checkBuildingRequirements() {
console.log("checkBuildingRequirements...");
@@ -2018,15 +2072,27 @@
console.log("checkBuildingUnderAttack...");
// Check delay since lastHitTime of all AI buildings
var tempUnderAttackBuildingArray = [];
player2.buildings.forEach(function (building) {
- if (Date.now() - building.lastHitTime < 10000) {
+ if (Date.now() - building.lastHitTime < aiUnderAttackDelayMs) {
// Building is under attack
tempUnderAttackBuildingArray.push(building);
}
});
return tempUnderAttackBuildingArray;
}
+function checkUnitsUnderAttack() {
+ console.log("checkUnitsUnderAttack...");
+ // Check delay since lastHitTime of all AI units
+ var tempUnderAttackUnitsArray = [];
+ player2.units.forEach(function (unit) {
+ if (Date.now() - unit.lastHitTime < aiUnderAttackDelayMs) {
+ // Unit is under attack
+ tempUnderAttackUnitsArray.push(unit);
+ }
+ });
+ return tempUnderAttackUnitsArray;
+}
function checkUnitRequirements() {
console.log("checkUnitRequirements...");
console.log("player2 units:", player2.units);
// 1) Count currently owned units
@@ -2051,9 +2117,9 @@
return tempNeededUnitList;
}
// Do what AI thought about
function aiActing() {
- if (LK.ticks % aiCurrentLevel.acttingDelay !== 0) {
+ if (LK.ticks % aiCurrentLevel.actingDelay !== 0) {
return;
}
console.log("aiActing...");
// 1) Meet buildings requirements
@@ -2078,8 +2144,15 @@
aiBuildingsUnderAttackList.forEach(function (building) {
aiHandleBuildingUnderAttack(building);
});
}
+ // 4) Meet unit defense needs
+ console.log("aiUnitsUnderAttackList:", aiUnitsUnderAttackList);
+ if (aiUnitsUnderAttackList.length > 0) {
+ aiUnitsUnderAttackList.forEach(function (unit) {
+ aiHandleUnitUnderAttack(unit);
+ });
+ }
}
function aiHandleBuildingConstruction(buildingToBuild) {
console.log("aiHandleBuildingConstruction...", buildingToBuild);
if (player2.isCurrentlyBuilding) {
@@ -2114,12 +2187,58 @@
if (buildingToDefend.defenders.length > 1) {
console.log("already have defenders...", buildingToDefend.defenders);
return;
}
- // List all units per distance to building
+ // List all units per distance to building [] = { unit: unit, distance: distance }
var potentialDefenders = getAllUnitsPerDistance(buildingToDefend, player2.units);
+ // Browse potentialDefenders and add as defenders the ones that can attack & are idle
+ potentialDefenders.forEach(function (defenderEntry) {
+ var defender = defenderEntry.unit;
+ console.log("potential defender ", defender.id, " attackDamage:", defender.attackDamage, " / moving:", defender.isMoving, " / attackMode:", defender.attackMode);
+ if (buildingToDefend.defenders.length < 2 && defender.attackDamage && !defender.isMoving && defender.attackMode == 0) {
+ buildingToDefend.defenders.push(defender);
+ }
+ });
+ if (buildingToDefend.defenders.length > 0) {
+ console.log(buildingToDefend.defenders.length + " defenders found");
+ // Start attacking the first enemy spotted
+ buildingToDefend.defenders.forEach(function (defender) {
+ console.log("defender ", defender.id, " ", defender.type, " Will attack:", buildingToDefend.lastAttaker);
+ defender.startAttack(buildingToDefend.lastAttaker);
+ });
+ } else {
+ console.log("No defenders found");
+ }
console.warn("potentialDefenders:", potentialDefenders);
}
+function aiHandleUnitUnderAttack(unitToDefend) {
+ console.log("aiHandleUnitUnderAttack...", unitToDefend);
+ // Check if already have defenders
+ if (unitToDefend.defenders.length > 1) {
+ console.log("unit already have defenders...", unitToDefend.defenders);
+ return;
+ }
+ // List all units per distance to building [] = { unit: unit, distance: distance }
+ var potentialDefenders = getAllUnitsPerDistance(unitToDefend, player2.units);
+ // Browse potentialDefenders and add as defenders the ones that can attack & are idle
+ potentialDefenders.forEach(function (defenderEntry) {
+ var defender = defenderEntry.unit;
+ console.log("potential defender ", defender.id, " attackDamage:", defender.attackDamage, " / moving:", defender.isMoving, " / attackMode:", defender.attackMode);
+ if (unitToDefend.defenders.length < 2 && defender.attackDamage && !defender.isMoving && defender.attackMode == 0) {
+ unitToDefend.defenders.push(defender);
+ }
+ });
+ if (unitToDefend.defenders.length > 0) {
+ console.log(unitToDefend.defenders.length + " defenders found");
+ // Start attacking the first enemy spotted
+ unitToDefend.defenders.forEach(function (defender) {
+ console.log("defender ", defender.id, " ", defender.type, " Will attack:", unitToDefend.lastAttaker);
+ defender.startAttack(unitToDefend.lastAttaker);
+ });
+ } else {
+ console.log("No defenders found");
+ }
+}
function aiHandleUnitConstruction(unitToBuild, sourceFactory) {
console.log("aiHandleUnitConstruction...", unitToBuild, sourceFactory);
if (player2.isCurrentlyBuildingUnit) {
console.log("Already building unit...");
@@ -2167,10 +2286,10 @@
game.addChild(p1Quad2);
// Player 2 base
// Define a fixed rock ilot near the center right of the map
var rockIlot2Center = {
- x: 30,
- y: 30
+ x: mapXSize - 8,
+ y: mapYSize - 10
};
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++) {
@@ -2423,13 +2542,17 @@
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();
+ if (currentSelection && currentSelection.isUnit && currentSelection.cellX == cellX && currentSelection.cellY == cellY) {
+ console.log("Already selected unit at " + cellX + ',' + cellY);
+ } else {
+ currentSelection = null;
+ selectionMarker.setOnElement();
+ selectionMarker.hide();
+ //console.log("Nothing selected at " + cellX + ',' + cellY, " deltaToSelection=" + deltaToSelection, " dragDelta=", dragDelta);
+ updateActionBoard();
+ }
}
} else if (cell.building && !cell.fog) {
//console.log("Selected building at " + cellX + ',' + cellY);
currentSelection = cell.building;
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