Fix an issue that caused a crash on serialization. Prepare the AI manager a little more for serialization.
Fix bugs with tests. Fix some other issues in the AI (attack plans deal with walls better, choose better paths, target selection is better. Dock building won't be tried hundreds of times if it fails.) Changes the Oasis random map to only put a path in the middle 50% of the time. This was SVN commit r13230.
This commit is contained in:
parent
f0db42e34e
commit
a45a926aeb
@ -265,7 +265,7 @@ terrainPainter = new LayeredPainter( [pOasisForestLight,tShoreBlend, tWater, tWa
|
||||
var elevationPainter = new SmoothElevationPainter(ELEVATION_SET, -3, 15 );
|
||||
createArea(placer, [terrainPainter, elevationPainter, paintClass(clWater)], null);
|
||||
RMS.SetProgress(50);
|
||||
if(mapSize > 150) {
|
||||
if(mapSize > 150 && randInt(0,1)) {
|
||||
log ("creating path through");
|
||||
var pAngle = randFloat(0, TWO_PI);
|
||||
var px = round(fx) + round(fractionToTiles(0.13 * cos(pAngle)));
|
||||
|
@ -266,6 +266,21 @@ var EntityTemplate = Class({
|
||||
return 1;
|
||||
},
|
||||
|
||||
// returns true if the entity can attack the given class
|
||||
canAttackClass: function(saidClass) {
|
||||
if (!this._template.Attack)
|
||||
return false;
|
||||
|
||||
for (i in this._template.Attack) {
|
||||
if (!this._template.Attack[i].RestrictedClasses)
|
||||
continue;
|
||||
var cannotAttack = this._template.Attack[i].RestrictedClasses._string.split(" ");
|
||||
if (cannotAttack.indexOf(saidClass) !== -1)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
buildableEntities: function() {
|
||||
if (!this._template.Builder || !this._template.Builder.Entities._string)
|
||||
return undefined;
|
||||
|
@ -113,6 +113,13 @@ var Filters = {
|
||||
},
|
||||
"dynamicProperties": ['unitAIOrderData']};
|
||||
},
|
||||
|
||||
byCanAttack: function(saidClass){
|
||||
return {"func" : function(ent){
|
||||
return ent.canAttackClass(saidClass);
|
||||
},
|
||||
"dynamicProperties": []};
|
||||
},
|
||||
|
||||
isSoldier: function(){
|
||||
return {"func" : function(ent){
|
||||
|
@ -216,7 +216,7 @@ aStarPath.prototype.continuePath = function(gamestate)
|
||||
this.openList.push(index);
|
||||
}
|
||||
this.isOpened[index] = true;
|
||||
if (SquareVectorDistance( [this.currentSquare%w, Math.floor(this.currentSquare/w)] , target) <= this.Sampling*this.Sampling) {
|
||||
if (SquareVectorDistance( [this.currentSquare%w, Math.floor(this.currentSquare/w)] , target) <= this.Sampling*this.Sampling+1) {
|
||||
if (this.e != this.currentSquare)
|
||||
this.parentSquare[this.e] = this.currentSquare;
|
||||
found = true;
|
||||
|
@ -236,6 +236,7 @@ TerrainAnalysis.prototype.updateMapWithEvents = function(sharedAI) {
|
||||
* it can also determine if any point is "probably" reachable, assuming the unit can get close enough
|
||||
* for optimizations it's called after the TerrainAnalyser has finished initializing his map
|
||||
* so this can use the land regions already.
|
||||
|
||||
*/
|
||||
function Accessibility(rawState, terrainAnalyser){
|
||||
var self = this;
|
||||
@ -245,8 +246,11 @@ function Accessibility(rawState, terrainAnalyser){
|
||||
|
||||
this.regionSize = [];
|
||||
this.regionSize.push(0);
|
||||
// initialized to 0, so start to 1 for optimization
|
||||
this.regionID = 1;
|
||||
|
||||
// initialized to 0, it's more optimized to start at 1 (I'm checking that if it's not 0, then it's already aprt of a region, don't touch);
|
||||
// However I actually store all unpassable as region 1 (because if I don't, on some maps the toal nb of region is over 256, and it crashes as the mapis 8bit.)
|
||||
// So start at 2.
|
||||
this.regionID = 2;
|
||||
for (var i = 0; i < this.passMap.length; ++i) {
|
||||
if (this.passMap[i] === 0 && this.map[i] !== 0) { // any non-painted, non-inacessible area.
|
||||
this.regionSize.push(0); // updated
|
||||
|
@ -20,6 +20,8 @@ function CityAttack(gameState, militaryManager, uniqueID, targetEnemy, type , ta
|
||||
max = enemyCount[i];
|
||||
}
|
||||
}
|
||||
if (this.targetPlayer === undefined)
|
||||
return false;
|
||||
debug ("Target = " +this.targetPlayer);
|
||||
this.targetFinder = targetFinder || this.defaultTargetFinder;
|
||||
this.type = type || "normal";
|
||||
@ -184,6 +186,7 @@ function CityAttack(gameState, militaryManager, uniqueID, targetEnemy, type , ta
|
||||
|
||||
//debug ("after");
|
||||
//Engine.DumpHeap();
|
||||
return true;
|
||||
};
|
||||
|
||||
CityAttack.prototype.getName = function(){
|
||||
@ -266,7 +269,7 @@ CityAttack.prototype.updatePreparation = function(gameState, militaryManager,eve
|
||||
}
|
||||
}
|
||||
// when we have a target, we path to it.
|
||||
this.path = this.pathFinder.getPath(this.rallyPoint,this.targetPos, 2, 2);//,300000,gameState);
|
||||
this.path = this.pathFinder.getPath(this.rallyPoint,this.targetPos, 4, 4,300000,gameState);
|
||||
|
||||
if (this.path === undefined) {
|
||||
delete this.pathFinder;
|
||||
@ -560,6 +563,9 @@ CityAttack.prototype.update = function(gameState, militaryManager, events){
|
||||
var bool_attacked = false;
|
||||
// raids don't care about attacks much
|
||||
|
||||
if (this.unitCollection.length === 0)
|
||||
return 0;
|
||||
|
||||
this.position = this.unitCollection.getCentrePosition();
|
||||
|
||||
var IDs = this.unitCollection.toIdArray();
|
||||
@ -673,32 +679,60 @@ CityAttack.prototype.update = function(gameState, militaryManager, events){
|
||||
|
||||
this.position = this.unitCollection.filter(Filters.not(Filters.byClass("Warship"))).getCentrePosition();
|
||||
|
||||
// probably not too good.
|
||||
if (!this.position)
|
||||
return undefined; // should spawn an error.
|
||||
|
||||
if (SquareVectorDistance(this.position, this.lastPosition) < 20 && this.path.length > 0) {
|
||||
this.unitCollection.filter(Filters.not(Filters.byClass("Warship"))).moveIndiv(this.path[0][0][0], this.path[0][0][1]);
|
||||
// We're stuck, presumably. Check if there are no walls just close to us. If so, we're arrived, and we're gonna tear down some serious stone.
|
||||
var walls = gameState.getEnemyEntities().filter(Filters.and(Filters.byOwner(this.targetPlayer), Filters.byClass("StoneWall")));
|
||||
var nexttoWalls = false;
|
||||
walls.forEach( function (ent) {
|
||||
if (!nexttoWalls && SquareVectorDistance(self.position, ent.position()) < 800)
|
||||
nexttoWalls = true;
|
||||
});
|
||||
// there are walls but we can attack
|
||||
if (nexttoWalls && this.unitCollection.filter(Filters.byCanAttack("StoneWall")).length !== 0)
|
||||
{
|
||||
debug ("Attack Plan " +this.type +" " +this.name +" has met walls and is not happy.");
|
||||
this.state = "arrived";
|
||||
} else if (nexttoWalls) {
|
||||
// abort plan.
|
||||
debug ("Attack Plan " +this.type +" " +this.name +" has met walls and gives up.");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// check if our land units are close enough from the next waypoint.
|
||||
if (SquareVectorDistance(this.unitCollection.filter(Filters.not(Filters.byClass("Warship"))).getCentrePosition(), this.path[0][0]) < 600) {
|
||||
// okay so here basically two cases. The first one is "we need a boat at this point".
|
||||
// the second one is "we need to unload at this point". The third is "normal".
|
||||
if (this.path[0][1] !== true)
|
||||
if (this.unitCollection.filter(Filters.byClass("Siege")).length !== 0
|
||||
&& SquareVectorDistance(this.unitCollection.filter(Filters.byClass("Siege")).getCentrePosition(), this.path[0][0]) > 600)
|
||||
{
|
||||
this.path.shift();
|
||||
if (this.path.length > 0){
|
||||
this.unitCollection.filter(Filters.not(Filters.byClass("Warship"))).moveIndiv(this.path[0][0][0], this.path[0][0][1]);
|
||||
} else {
|
||||
debug ("Attack Plan " +this.type +" " +this.name +" has arrived to destination.");
|
||||
// we must assume we've arrived at the end of the trail.
|
||||
this.state = "arrived";
|
||||
}
|
||||
} else if (this.path[0][1] === true)
|
||||
{
|
||||
// okay we must load our units.
|
||||
// check if we have some kind of ships.
|
||||
var ships = this.unitCollection.filter(Filters.byClass("Warship"));
|
||||
if (ships.length === 0)
|
||||
return 0; // abort
|
||||
} else {
|
||||
// okay so here basically two cases. The first one is "we need a boat at this point".
|
||||
// the second one is "we need to unload at this point". The third is "normal".
|
||||
if (this.path[0][1] !== true)
|
||||
{
|
||||
this.path.shift();
|
||||
if (this.path.length > 0){
|
||||
this.unitCollection.filter(Filters.not(Filters.byClass("Warship"))).moveIndiv(this.path[0][0][0], this.path[0][0][1]);
|
||||
} else {
|
||||
debug ("Attack Plan " +this.type +" " +this.name +" has arrived to destination.");
|
||||
// we must assume we've arrived at the end of the trail.
|
||||
this.state = "arrived";
|
||||
}
|
||||
} else if (this.path[0][1] === true)
|
||||
{
|
||||
// okay we must load our units.
|
||||
// check if we have some kind of ships.
|
||||
var ships = this.unitCollection.filter(Filters.byClass("Warship"));
|
||||
if (ships.length === 0)
|
||||
return 0; // abort
|
||||
|
||||
debug ("switch to boarding");
|
||||
this.state = "boarding";
|
||||
debug ("switch to boarding");
|
||||
this.state = "boarding";
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (this.state === "shipping") {
|
||||
@ -854,7 +888,7 @@ CityAttack.prototype.update = function(gameState, militaryManager, events){
|
||||
this.unitCollection.forEach( function (ent) { //}) {
|
||||
if (ent.isIdle()) {
|
||||
var mStruct = enemyStructures.filter(function (enemy) {// }){
|
||||
if (!enemy.position()) {
|
||||
if (!enemy.position() || (enemy.hasClass("StoneWall") && ent.canAttackClass("StoneWall"))) {
|
||||
return false;
|
||||
}
|
||||
if (SquareVectorDistance(enemy.position(),ent.position()) > ent.visionRange()*ent.visionRange() + 300) {
|
||||
@ -871,32 +905,54 @@ CityAttack.prototype.update = function(gameState, militaryManager, events){
|
||||
}
|
||||
return true;
|
||||
});
|
||||
var isGate = false;
|
||||
mUnit = mUnit.toEntityArray();
|
||||
mStruct = mStruct.toEntityArray();
|
||||
mStruct.sort(function (struct) {
|
||||
if (struct.hasClass("ConquestCritical"))
|
||||
return 100 + struct.costSum();
|
||||
else
|
||||
return struct.costSum();
|
||||
})
|
||||
mStruct.sort(function (structa,structb) {
|
||||
var vala = structa.costSum();
|
||||
if (structa.hasClass("Gates") && ent.canAttackClass("StoneWall")) // we hate gates
|
||||
{
|
||||
isGate = true;
|
||||
vala += 10000;
|
||||
} else if (structa.hasClass("ConquestCritical"))
|
||||
vala = 100;
|
||||
var valb = structb.costSum();
|
||||
if (structb.hasClass("Gates") && ent.canAttackClass("StoneWall")) // we hate gates
|
||||
{
|
||||
isGate = true;
|
||||
valb += 10000;
|
||||
} else if (structb.hasClass("ConquestCritical"))
|
||||
valb = 100;
|
||||
return (valb - vala);
|
||||
});
|
||||
if (ent.hasClass("Siege")) {
|
||||
if (mStruct.length !== 0) {
|
||||
var rand = Math.floor(Math.random() * mStruct.length*0.2);
|
||||
ent.attack(mStruct[+rand].id());
|
||||
//debug ("Siege units attacking a structure from " +mStruct[+rand].owner() + " , " +mStruct[+rand].templateName());
|
||||
if (isGate)
|
||||
ent.attack(mStruct[0].id());
|
||||
else
|
||||
{
|
||||
var rand = Math.floor(Math.random() * mStruct.length*0.2);
|
||||
ent.attack(mStruct[+rand].id());
|
||||
//debug ("Siege units attacking a structure from " +mStruct[+rand].owner() + " , " +mStruct[+rand].templateName());
|
||||
}
|
||||
} else if (SquareVectorDistance(self.targetPos, ent.position()) > 900 ){
|
||||
//debug ("Siege units moving to " + uneval(self.targetPos));
|
||||
ent.move((self.targetPos[0] + ent.position()[0])/2,(self.targetPos[1] + ent.position()[1])/2);
|
||||
}
|
||||
} else {
|
||||
if (mUnit.length !== 0) {
|
||||
if (mUnit.length !== 0 && !isGate) {
|
||||
var rand = Math.floor(Math.random() * mUnit.length*0.99);
|
||||
ent.attack(mUnit[(+rand)].id());
|
||||
//debug ("Units attacking a unit from " +mUnit[+rand].owner() + " , " +mUnit[+rand].templateName());
|
||||
} else if (mStruct.length !== 0) {
|
||||
var rand = Math.floor(Math.random() * mStruct.length*0.99);
|
||||
ent.attack(mStruct[+rand].id());
|
||||
//debug ("Units attacking a structure from " +mStruct[+rand].owner() + " , " +mStruct[+rand].templateName());
|
||||
if (isGate)
|
||||
ent.attack(mStruct[0].id());
|
||||
else
|
||||
{
|
||||
var rand = Math.floor(Math.random() * mStruct.length*0.2);
|
||||
ent.attack(mStruct[+rand].id());
|
||||
//debug ("Units attacking a structure from " +mStruct[+rand].owner() + " , " +mStruct[+rand].templateName());
|
||||
}
|
||||
} else if (SquareVectorDistance(self.targetPos, ent.position()) > 900 ){
|
||||
//debug ("Units moving to " + uneval(self.targetPos));
|
||||
ent.move((self.targetPos[0] + ent.position()[0])/2,(self.targetPos[1] + ent.position()[1])/2);
|
||||
|
@ -1,9 +1,9 @@
|
||||
// Baseconfig is the highest difficulty.
|
||||
var baseConfig = {
|
||||
"Military" : {
|
||||
"fortressStartTime" : 840, // Time to wait before building one fortress.
|
||||
"fortressStartTime" : 780, // Time to wait before building one fortress.
|
||||
"fortressLapseTime" : 300, // Time to wait between building 2 fortresses (minimal)
|
||||
"defenceBuildingTime" : 300, // Time to wait before building towers or fortresses
|
||||
"defenceBuildingTime" : 600, // Time to wait before building towers or fortresses
|
||||
"advancedMilitaryStartTime" : 720, // Time to wait before building advanced military buildings. Also limited by phase 2.
|
||||
"attackPlansStartTime" : 0 // time to wait before attacking. Start as soon as possible (first barracks)
|
||||
},
|
||||
@ -11,7 +11,7 @@ var baseConfig = {
|
||||
"townPhase" : 180, // time to start trying to reach town phase (might be a while after. Still need the requirements + ress )
|
||||
"cityPhase" : 540, // time to start trying to reach city phase
|
||||
"farmsteadStartTime" : 240, // Time to wait before building a farmstead.
|
||||
"marketStartTime" : 620, // Time to wait before building the market.
|
||||
"marketStartTime" : 480, // Time to wait before building the market.
|
||||
"dockStartTime" : 240, // Time to wait before building the dock
|
||||
"techStartTime" : 600, // time to wait before teching.
|
||||
"targetNumBuilders" : 1.5, // Base number of builders per foundation. Later updated, but this remains a multiplier.
|
||||
@ -58,7 +58,7 @@ var baseConfig = {
|
||||
"villager" : 60,
|
||||
"economicBuilding" : 80,
|
||||
"dropsites" : 180,
|
||||
"field" : 500,
|
||||
"field" : 1000,
|
||||
"militaryBuilding" : 120,
|
||||
"defenceBuilding" : 17,
|
||||
"majorTech" : 100,
|
||||
@ -83,7 +83,7 @@ if (Config.difficulty === 1)
|
||||
Config["Military"] = {
|
||||
"fortressStartTime" : 1000,
|
||||
"fortressLapseTime" : 400,
|
||||
"defenceBuildingTime" : 350,
|
||||
"defenceBuildingTime" : 720,
|
||||
"advancedMilitaryStartTime" : 1000,
|
||||
"attackPlansStartTime" : 600
|
||||
};
|
||||
@ -106,7 +106,7 @@ if (Config.difficulty === 1)
|
||||
Config["Military"] = {
|
||||
"fortressStartTime" : 1500,
|
||||
"fortressLapseTime" : 1000000,
|
||||
"defenceBuildingTime" : 500,
|
||||
"defenceBuildingTime" : 900,
|
||||
"advancedMilitaryStartTime" : 1300,
|
||||
"attackPlansStartTime" : 1200 // 20 minutes ought to give enough times for beginners
|
||||
};
|
||||
|
@ -23,6 +23,8 @@ var EconomyManager = function() {
|
||||
this.farmsteadStartTime = Config.Economy.farmsteadStartTime * 1000;
|
||||
this.techStartTime = Config.Economy.techStartTime * 1000;
|
||||
|
||||
this.dockFailed = false; // sanity check
|
||||
|
||||
this.resourceMaps = {}; // Contains maps showing the density of wood, stone and metal
|
||||
this.CCResourceMaps = {}; // Contains maps showing the density of wood, stone and metal, optimized for CC placement.
|
||||
|
||||
@ -844,7 +846,7 @@ EconomyManager.prototype.buildFarmstead = function(gameState, queues){
|
||||
};
|
||||
|
||||
EconomyManager.prototype.buildDock = function(gameState, queues){
|
||||
if (!gameState.ai.waterMap)
|
||||
if (!gameState.ai.waterMap || this.dockFailed)
|
||||
return;
|
||||
if (gameState.getTimeElapsed() > this.dockStartTime) {
|
||||
if (queues.economicBuilding.countTotalQueuedUnitsWithClass("NavalMarket") === 0 &&
|
||||
|
@ -379,7 +379,7 @@ MilitaryAttackManager.prototype.buildDefences = function(gameState, queues){
|
||||
+ queues.defenceBuilding.totalLength() < gameState.getEntityLimits()["DefenseTower"]
|
||||
&& gameState.currentPhase() > 1) {
|
||||
gameState.getOwnEntities().forEach(function(dropsiteEnt) {
|
||||
if (dropsiteEnt.resourceDropsiteTypes() && dropsiteEnt.getMetadata(PlayerID, "defenseTower") !== true){
|
||||
if (dropsiteEnt.resourceDropsiteTypes() && dropsiteEnt.getMetadata(PlayerID, "defenseTower") !== true && !dropsiteEnt.hasClass("CivCentre")){
|
||||
var position = dropsiteEnt.position();
|
||||
if (position){
|
||||
queues.defenceBuilding.addItem(new BuildingConstructionPlan(gameState, 'structures/{civ}_defense_tower', position));
|
||||
@ -574,14 +574,24 @@ MilitaryAttackManager.prototype.update = function(gameState, queues, events) {
|
||||
&& gameState.getTimeElapsed() > this.attackPlansStartTime) {
|
||||
if (this.upcomingAttacks["CityAttack"].length == 0 && (gameState.getTimeElapsed() < 25*60000 || Config.difficulty < 2)) {
|
||||
var Lalala = new CityAttack(gameState, this,this.TotalAttackNumber, -1);
|
||||
debug ("Military Manager: Creating the plan " +this.TotalAttackNumber);
|
||||
this.TotalAttackNumber++;
|
||||
this.upcomingAttacks["CityAttack"].push(Lalala);
|
||||
if (!Lalala)
|
||||
{
|
||||
this.attackPlansEncounteredWater = true; // hack
|
||||
} else {
|
||||
debug ("Military Manager: Creating the plan " +this.TotalAttackNumber);
|
||||
this.TotalAttackNumber++;
|
||||
this.upcomingAttacks["CityAttack"].push(Lalala);
|
||||
}
|
||||
} else if (this.upcomingAttacks["CityAttack"].length == 0 && Config.difficulty !== 0) {
|
||||
var Lalala = new CityAttack(gameState, this,this.TotalAttackNumber, -1, "superSized");
|
||||
debug ("Military Manager: Creating the super sized plan " +this.TotalAttackNumber);
|
||||
this.TotalAttackNumber++;
|
||||
this.upcomingAttacks["CityAttack"].push(Lalala);
|
||||
if (!Lalala)
|
||||
{
|
||||
this.attackPlansEncounteredWater = true; // hack
|
||||
} else {
|
||||
debug ("Military Manager: Creating the super sized plan " +this.TotalAttackNumber);
|
||||
this.TotalAttackNumber++;
|
||||
this.upcomingAttacks["CityAttack"].push(Lalala);
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
|
@ -38,6 +38,8 @@ BuildingConstructionPlan.prototype.execute = function(gameState) {
|
||||
|
||||
var pos = this.findGoodPosition(gameState);
|
||||
if (!pos){
|
||||
if (this.template.hasClass("Naval"))
|
||||
gameState.ai.modules.economy.dockFailed = true;
|
||||
debug("No room to place " + this.type);
|
||||
return;
|
||||
}
|
||||
|
@ -65,9 +65,12 @@ QBotAI.prototype.InitShared = function(gameState, sharedScript) {
|
||||
this.pathsToMe = [];
|
||||
this.pathInfo = { "angle" : 0, "needboat" : true, "mkeyPos" : myKeyEntities.toEntityArray()[0].position(), "ekeyPos" : enemyKeyEntities.toEntityArray()[0].position() };
|
||||
|
||||
var pos = [this.pathInfo.mkeyPos[0] + 140*Math.cos(this.pathInfo.angle),this.pathInfo.mkeyPos[1] + 140*Math.sin(this.pathInfo.angle)];
|
||||
// First path has a sampling of 3, which ensures we'll get at least one path even on Acropolis. The others are 6 so might fail.
|
||||
var pos = [this.pathInfo.mkeyPos[0] + 180*Math.cos(this.pathInfo.angle),this.pathInfo.mkeyPos[1] + 180*Math.sin(this.pathInfo.angle)];
|
||||
var path = this.pathFinder.getPath(this.pathInfo.ekeyPos, pos, 3, 3);// uncomment for debug:*/, 300000, gameState);
|
||||
|
||||
//Engine.DumpImage("initialPath" + PlayerID + ".png", this.pathFinder.TotorMap.map, this.pathFinder.TotorMap.width,this.pathFinder.TotorMap.height,255);
|
||||
|
||||
if (path !== undefined && path[1] !== undefined && path[1] == false) {
|
||||
// path is viable and doesn't require boating.
|
||||
// blackzone the last two waypoints.
|
||||
@ -171,7 +174,7 @@ QBotAI.prototype.OnUpdate = function(sharedScript) {
|
||||
|
||||
if (this.pathInfo !== undefined)
|
||||
{
|
||||
var pos = [this.pathInfo.mkeyPos[0] + 140*Math.cos(this.pathInfo.angle),this.pathInfo.mkeyPos[1] + 140*Math.sin(this.pathInfo.angle)];
|
||||
var pos = [this.pathInfo.mkeyPos[0] + 180*Math.cos(this.pathInfo.angle),this.pathInfo.mkeyPos[1] + 180*Math.sin(this.pathInfo.angle)];
|
||||
var path = this.pathFinder.getPath(this.pathInfo.ekeyPos, pos, 6, 6);// uncomment for debug:*/, 300000, gameState);
|
||||
if (path !== undefined && path[1] !== undefined && path[1] == false) {
|
||||
// path is viable and doesn't require boating.
|
||||
|
@ -128,10 +128,48 @@ AddMock(101, IID_EntityLimits, {
|
||||
GetCounts: function() { return {"Bar": 0}; },
|
||||
});
|
||||
|
||||
AddMock(101, IID_TechnologyManager, {
|
||||
AddMock(100, IID_TechnologyManager, {
|
||||
IsTechnologyResearched: function(tech) { if (tech == "phase_village") return true; else return false; },
|
||||
GetQueuedResearch: function() { return {}; },
|
||||
GetStartedResearch: function() { return {}; },
|
||||
GetResearchedTechs: function() { return {}; },
|
||||
GetClassCounts: function() { return {}; },
|
||||
GetTypeCountsByClass: function() { return {}; },
|
||||
GetTechModifications: function() { return {}; },
|
||||
});
|
||||
AddMock(100, IID_StatisticsTracker, {
|
||||
GetStatistics: function() {
|
||||
return {
|
||||
"unitsTrained": 10,
|
||||
"unitsLost": 9,
|
||||
"buildingsConstructed": 5,
|
||||
"buildingsLost": 4,
|
||||
"civCentresBuilt": 1,
|
||||
"resourcesGathered": {
|
||||
"food": 100,
|
||||
"wood": 0,
|
||||
"metal": 0,
|
||||
"stone": 0,
|
||||
"vegetarianFood": 0,
|
||||
},
|
||||
"treasuresCollected": 0,
|
||||
"percentMapExplored": 10,
|
||||
};
|
||||
},
|
||||
IncreaseTrainedUnitsCounter: function() { return 1; },
|
||||
IncreaseConstructedBuildingsCounter: function() { return 1; },
|
||||
IncreaseBuiltCivCentresCounter: function() { return 1; },
|
||||
});
|
||||
|
||||
AddMock(101, IID_TechnologyManager, {
|
||||
IsTechnologyResearched: function(tech) { if (tech == "phase_village") return true; else return false; },
|
||||
GetQueuedResearch: function() { return {}; },
|
||||
GetStartedResearch: function() { return {}; },
|
||||
GetResearchedTechs: function() { return {}; },
|
||||
GetClassCounts: function() { return {}; },
|
||||
GetTypeCountsByClass: function() { return {}; },
|
||||
GetTechModifications: function() { return {}; },
|
||||
});
|
||||
|
||||
AddMock(101, IID_StatisticsTracker, {
|
||||
GetStatistics: function() {
|
||||
@ -174,13 +212,18 @@ TS_ASSERT_UNEVAL_EQUALS(cmp.GetSimulationState(), {
|
||||
state: "active",
|
||||
team: -1,
|
||||
teamsLocked: false,
|
||||
phase: "",
|
||||
phase: "village",
|
||||
isAlly: [false, false],
|
||||
isNeutral: [false, false],
|
||||
isEnemy: [true, true],
|
||||
entityLimits: {"Foo": 10},
|
||||
entityCounts: {"Foo": 5},
|
||||
techModifications: {},
|
||||
researchQueued: {},
|
||||
researchStarted: {},
|
||||
researchedTechs: {},
|
||||
classCounts: {},
|
||||
typeCountsByClass: {},
|
||||
},
|
||||
{
|
||||
name: "Player 2",
|
||||
@ -201,6 +244,11 @@ TS_ASSERT_UNEVAL_EQUALS(cmp.GetSimulationState(), {
|
||||
entityLimits: {"Bar": 20},
|
||||
entityCounts: {"Bar": 0},
|
||||
techModifications: {},
|
||||
researchQueued: {},
|
||||
researchStarted: {},
|
||||
researchedTechs: {},
|
||||
classCounts: {},
|
||||
typeCountsByClass: {},
|
||||
}
|
||||
],
|
||||
circularMap: false,
|
||||
@ -221,13 +269,18 @@ TS_ASSERT_UNEVAL_EQUALS(cmp.GetExtendedSimulationState(), {
|
||||
state: "active",
|
||||
team: -1,
|
||||
teamsLocked: false,
|
||||
phase: "",
|
||||
phase: "village",
|
||||
isAlly: [false, false],
|
||||
isNeutral: [false, false],
|
||||
isEnemy: [true, true],
|
||||
entityLimits: {"Foo": 10},
|
||||
entityCounts: {"Foo": 5},
|
||||
techModifications: {},
|
||||
researchQueued: {},
|
||||
researchStarted: {},
|
||||
researchedTechs: {},
|
||||
classCounts: {},
|
||||
typeCountsByClass: {},
|
||||
statistics: {
|
||||
unitsTrained: 10,
|
||||
unitsLost: 9,
|
||||
@ -264,6 +317,11 @@ TS_ASSERT_UNEVAL_EQUALS(cmp.GetExtendedSimulationState(), {
|
||||
entityLimits: {"Bar": 20},
|
||||
entityCounts: {"Bar": 0},
|
||||
techModifications: {},
|
||||
researchQueued: {},
|
||||
researchStarted: {},
|
||||
researchedTechs: {},
|
||||
classCounts: {},
|
||||
typeCountsByClass: {},
|
||||
statistics: {
|
||||
unitsTrained: 10,
|
||||
unitsLost: 9,
|
||||
|
@ -359,7 +359,7 @@ public:
|
||||
JS_GC(self->m_ScriptInterface.GetContext());
|
||||
}
|
||||
|
||||
bool TryLoadSharedComponent(bool callConstructor)
|
||||
bool TryLoadSharedComponent(bool hasTechs)
|
||||
{
|
||||
// only load if there are AI players.
|
||||
if (m_Players.size() == 0)
|
||||
@ -370,7 +370,7 @@ public:
|
||||
|
||||
// reset the value so it can be used to determine if we actually initialized it.
|
||||
m_HasSharedComponent = false;
|
||||
|
||||
|
||||
VfsPaths sharedPathnames;
|
||||
// Check for "shared" module.
|
||||
vfs::GetPathnames(g_VFS, L"simulation/ai/common-api-v3/", L"*.js", sharedPathnames);
|
||||
@ -423,10 +423,27 @@ public:
|
||||
}
|
||||
else
|
||||
{
|
||||
// For deserialization, we want to create the object with the correct prototype
|
||||
// but don't want to actually run the constructor again
|
||||
// XXX: actually we don't currently use this path for deserialization - maybe delete it?
|
||||
m_SharedAIObj = CScriptValRooted(m_ScriptInterface.GetContext(),m_ScriptInterface.NewObjectFromConstructor(ctor.get()));
|
||||
// won't get the tech templates directly.
|
||||
// Set up the data to pass as the constructor argument
|
||||
CScriptVal settings;
|
||||
m_ScriptInterface.Eval(L"({})", settings);
|
||||
CScriptVal playersID;
|
||||
m_ScriptInterface.Eval(L"({})", playersID);
|
||||
for (size_t i = 0; i < m_Players.size(); ++i)
|
||||
{
|
||||
jsval val = m_ScriptInterface.ToJSVal(m_ScriptInterface.GetContext(), m_Players[i]->m_Player);
|
||||
m_ScriptInterface.SetPropertyInt(playersID.get(), i, CScriptVal(val), true);
|
||||
}
|
||||
|
||||
m_ScriptInterface.SetProperty(settings.get(), "players", playersID);
|
||||
|
||||
CScriptVal m_fakeTech;
|
||||
m_ScriptInterface.Eval("({})", m_fakeTech);
|
||||
m_ScriptInterface.SetProperty(settings.get(), "techTemplates", m_fakeTech, false);
|
||||
|
||||
ENSURE(m_HasLoadedEntityTemplates);
|
||||
m_ScriptInterface.SetProperty(settings.get(), "templates", m_EntityTemplates, false);
|
||||
m_SharedAIObj = CScriptValRooted(m_ScriptInterface.GetContext(),m_ScriptInterface.CallConstructor(ctor.get(), settings.get()));
|
||||
}
|
||||
|
||||
if (m_SharedAIObj.undefined())
|
||||
@ -640,6 +657,7 @@ public:
|
||||
if (!m_ScriptInterface.CallFunctionVoid(m_Players.back()->m_Obj.get(), "Deserialize", scriptData))
|
||||
LOGERROR(L"AI script Deserialize call failed");
|
||||
}
|
||||
TryLoadSharedComponent(false);
|
||||
}
|
||||
|
||||
int getPlayerSize()
|
||||
@ -774,17 +792,6 @@ public:
|
||||
m_TerritoriesDirtyID = 0;
|
||||
|
||||
StartLoadEntityTemplates();
|
||||
|
||||
// loading the technology template
|
||||
ScriptInterface& scriptInterface = GetSimContext().GetScriptInterface();
|
||||
|
||||
CmpPtr<ICmpTechnologyTemplateManager> cmpTechTemplateManager(GetSimContext(), SYSTEM_ENTITY);
|
||||
ENSURE(cmpTechTemplateManager);
|
||||
|
||||
// Get the game state from AIInterface
|
||||
CScriptVal techTemplates = cmpTechTemplateManager->GetAllTechs();
|
||||
|
||||
m_Worker.RegisterTechTemplates(scriptInterface.WriteStructuredClone(techTemplates.get()));
|
||||
}
|
||||
|
||||
virtual void Deinit()
|
||||
@ -847,6 +854,15 @@ public:
|
||||
|
||||
virtual void TryLoadSharedComponent()
|
||||
{
|
||||
ScriptInterface& scriptInterface = GetSimContext().GetScriptInterface();
|
||||
// load the technology templates
|
||||
CmpPtr<ICmpTechnologyTemplateManager> cmpTechTemplateManager(GetSimContext(), SYSTEM_ENTITY);
|
||||
ENSURE(cmpTechTemplateManager);
|
||||
|
||||
// Get the game state from AIInterface
|
||||
CScriptVal techTemplates = cmpTechTemplateManager->GetAllTechs();
|
||||
|
||||
m_Worker.RegisterTechTemplates(scriptInterface.WriteStructuredClone(techTemplates.get()));
|
||||
m_Worker.TryLoadSharedComponent(true);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user