complete the support of saved games by Petra. It is playable now, but still needs cleaning and bug fixes.

This was SVN commit r15950.
This commit is contained in:
mimo 2014-11-10 18:35:52 +00:00
parent c236e8a877
commit e4774066e2
10 changed files with 173 additions and 153 deletions

View File

@ -68,6 +68,8 @@ m.PetraBot.prototype.CustomInit = function(gameState, sharedScript)
this.isDeserialized = false;
this.data = undefined;
this.HQ.start(gameState, true);
this.queueManager.printQueues(gameState);
}
else
@ -99,6 +101,8 @@ m.PetraBot.prototype.OnUpdate = function(sharedScript)
for (var i in this.events)
{
if (i == "AIMetadata") // not used inside petra
continue;
if(this.savedEvents[i] !== undefined)
this.savedEvents[i] = this.savedEvents[i].concat(this.events[i]);
else
@ -123,12 +127,6 @@ m.PetraBot.prototype.OnUpdate = function(sharedScript)
this.queueManager.update(this.gameState);
// Generate some entropy in the random numbers (against humans) until the engine gets random initialised numbers
// TODO: remove this when the engine gives a random seed
var n = this.savedEvents["Create"].length % 29;
for (var i = 0; i < n; i++)
Math.random();
for (var i in this.savedEvents)
this.savedEvents[i] = [];

View File

@ -15,34 +15,34 @@ m.AttackManager = function(Config)
this.upcomingAttacks = { "Rush": [], "Raid": [], "Attack": [], "HugeAttack": [] };
this.startedAttacks = { "Rush": [], "Raid": [], "Attack": [], "HugeAttack": [] };
this.debugTime = 0;
this.maxRushes = 0;
this.rushSize = [];
};
// More initialisation for stuff that needs the gameState
m.AttackManager.prototype.init = function(gameState, allowRush)
m.AttackManager.prototype.init = function(gameState)
{
this.outOfPlan = gameState.getOwnUnits().filter(API3.Filters.byMetadata(PlayerID, "plan", -1));
this.outOfPlan.allowQuickIter();
this.outOfPlan.registerUpdates();
};
this.maxRushes = 0;
this.rushSize = [];
if (allowRush)
m.AttackManager.prototype.setRushes = function()
{
if (this.Config.personality.aggressive > 0.8)
{
if (this.Config.personality.aggressive > 0.8)
{
this.maxRushes = 3
this.rushSize = [ 16, 22, 28 ];
}
else if (this.Config.personality.aggressive > 0.6)
{
this.maxRushes = 2;
this.rushSize = [ 18, 28 ];
}
else if (this.Config.personality.aggressive > 0.3)
{
this.maxRushes = 1;
this.rushSize = [ 24 ];
}
this.maxRushes = 3
this.rushSize = [ 16, 22, 28 ];
}
else if (this.Config.personality.aggressive > 0.6)
{
this.maxRushes = 2;
this.rushSize = [ 18, 28 ];
}
else if (this.Config.personality.aggressive > 0.3)
{
this.maxRushes = 1;
this.rushSize = [ 24 ];
}
};
@ -272,21 +272,6 @@ m.AttackManager.prototype.unpauseAllPlans = function()
attack.setPaused(false);
};
m.AttackManager.prototype.Serialize = function()
{
// TODO the attackPlans have still to be serialized
return {
"maxRushes": this.maxRushes,
"rushSize": this.rushSize
};
};
m.AttackManager.prototype.Deserialize = function(data)
{
for (let key in data)
this[key] = data[key];
};
m.AttackManager.prototype.Serialize = function()
{
let properties = {
@ -321,7 +306,7 @@ m.AttackManager.prototype.Serialize = function()
m.AttackManager.prototype.Deserialize = function(gameState, data)
{
for (let key in data.properties)
this[key] = data[key];
this[key] = data.properties[key];
this.upcomingAttacks = {};
for (let key in data.upcomingAttacks)

View File

@ -950,7 +950,8 @@ m.BaseManager.prototype.Serialize = function()
"accessIndex": this.accessIndex,
"maxDistResourceSquare": this.maxDistResourceSquare,
"constructing": this.constructing,
"gatherers": this.gatherers
"gatherers": this.gatherers,
"territoryIndices": this.territoryIndices
};
};

View File

@ -166,7 +166,7 @@ m.Config.prototype.Serialize = function()
{
var data = {};
for (let key in this)
if (this.hasOwnProperty(key))
if (this.hasOwnProperty(key) && key != "debug")
data[key] = this[key];
return data;
};

View File

@ -325,12 +325,27 @@ m.HQ.prototype.init = function(gameState, queues, deserialization)
}
}
var allowRushes = (startingWood > 8500 && this.canBuildUnits);
this.attackManager.init(gameState, queues, allowRushes);
this.navalManager.init(gameState, queues);
this.attackManager.init(gameState);
if (startingWood > 8500 && this.canBuildUnits && !deserialization)
this.attackManager.setRushes();
this.navalManager.init(gameState);
this.tradeManager.init(gameState);
};
m.HQ.prototype.start = function(gameState, deserialization)
{
if (deserialization)
{
var self = this;
gameState.getOwnEntities().forEach( function (ent) {
if (!ent.resourceDropsiteTypes() || ent.hasClass("Elephant"))
return;
let base = self.baseManagers[ent.getMetadata(PlayerID, "base")];
base.assignResourceToDropsite(gameState, ent);
});
}
};
// returns the sea index linking regions 1 and region 2 (supposed to be different land region)
// otherwise return undefined
// for the moment, only the case land-sea-land is supported
@ -1727,6 +1742,20 @@ m.HQ.prototype.canBuild = function(gameState, structure)
return true;
};
m.HQ.prototype.stopBuild = function(gameState, structure)
{
let type = gameState.applyCiv(structure);
if (this.stopBuilding.indexOf(type) == -1)
this.stopBuilding.push(type);
};
m.HQ.prototype.restartBuild = function(gameState, structure)
{
let index = this.stopBuilding.indexOf(gameState.applyCiv(structure));
if (index != -1)
this.stopBuilding.splice(index, 1);
};
m.HQ.prototype.updateTerritories = function(gameState)
{
// TODO may-be update also when territory decreases. For the moment, only increases are taking into account
@ -1960,89 +1989,6 @@ m.HQ.prototype.update = function(gameState, queues, events)
Engine.ProfileStop();
};
m.HQ.prototype.Serialize = function()
{
let properties = {
"targetNumBuilders": this.targetNumBuilders,
"econState": this.econState,
"phaseStarted": this.phaseStarted,
"wantedRates": this.wantedRates,
"currentRates": this.currentRates,
"lastFailedGather": this.lastFailedGather,
"femaleRatio": this.femaleRatio,
"lastTerritoryUpdate": this.lastTerritoryUpdate,
"stopBuilding": this.stopBuilding,
"towerStartTime": this.towerStartTime,
"towerLapseTime": this.towerLapseTime,
"fortressStartTime": this.fortressStartTime,
"fortressLapseTime": this.fortressLapseTime,
"targetNumWorkers": this.targetNumWorkers,
"bBase": this.bBase,
"bAdvanced": this.bAdvanced,
"saveResources": this.saveResources,
"canBuildUnits": this.canBuildUnits
};
let baseManagers = {};
for (let base in this.baseManagers)
baseManagers[base] = this.baseManagers[base].Serialize();
if (this.Config.debug == -100)
API3.warn(" HQ serialization: properties >> " + uneval(properties));
return {
"properties": properties,
"baseManagers": baseManagers,
"attackManager": this.attackManager.Serialize(),
"defenseManager": this.defenseManager.Serialize(),
"tradeManager": this.tradeManager.Serialize(),
"navalManager": this.navalManager.Serialize(),
"researchManager": this.researchManager.Serialize(),
"diplomacyManager": this.diplomacyManager.Serialize(),
"garrisonManager": this.garrisonManager.Serialize(),
};
};
m.HQ.prototype.Deserialize = function(gameState, data)
{
for (let key in data.properties)
this[key] = data.properties[key];
this.baseManagers = {};
for (let base in data.baseManagers)
{
// the first call to deserialize set the ID base needed by entitycollections
this.baseManagers[base] = new m.BaseManager(gameState, this.Config);
this.baseManagers[base].Deserialize(gameState, data.baseManagers[base]);
this.baseManagers[base].init(gameState);
this.baseManagers[base].Deserialize(gameState, data.baseManagers[base]);
}
this.attackManager = new m.AttackManager(this.Config);
this.attackManager.Deserialize(data.attackManager);
this.defenseManager = new m.DefenseManager(this.Config);
this.defenseManager.Deserialize(data.defenseManager);
this.tradeManager = new m.TradeManager(this.Config);
this.tradeManager.init(gameState);
this.tradeManager.Deserialize(data.tradeManager);
this.navalManager = new m.NavalManager(this.Config);
this.navalManager.init(gameState);
this.navalManager.Deserialize(data.navalManager);
this.researchManager = new m.ResearchManager(this.Config);
this.garrisonManager.Deserialize(data.researchManager);
this.diplomacyManager = new m.DiplomacyManager(this.Config);
this.diplomacyManager.Deserialize(data.diplomacyManager);
this.garrisonManager = new m.GarrisonManager();
this.garrisonManager.Deserialize(data.garrisonManager);
};
m.HQ.prototype.Serialize = function()
{
let properties = {
@ -2127,10 +2073,10 @@ m.HQ.prototype.Deserialize = function(gameState, data)
this.navalManager = new m.NavalManager(this.Config);
this.navalManager.init(gameState);
this.navalManager.Deserialize(data.navalManager);
this.navalManager.Deserialize(gameState, data.navalManager);
this.researchManager = new m.ResearchManager(this.Config);
this.garrisonManager.Deserialize(data.researchManager);
this.researchManager.Deserialize(data.researchManager);
this.diplomacyManager = new m.DiplomacyManager(this.Config);
this.diplomacyManager.Deserialize(data.diplomacyManager);

View File

@ -348,6 +348,7 @@ m.NavalManager.prototype.requireTransport = function(gameState, entity, startInd
API3.warn(">>>> transport plan aborted <<<<");
return false;
}
plan.init(gameState);
this.transportPlans.push(plan);
return true;
};
@ -364,6 +365,7 @@ m.NavalManager.prototype.splitTransport = function(gameState, plan)
API3.warn(">>>> split of transport plan aborted <<<<");
return false;
}
newplan.init();
var nbUnits = 0;
plan.units.forEach(function (ent) {
@ -680,21 +682,26 @@ m.NavalManager.prototype.Serialize = function()
"landingZones": this.landingZones
};
let transport = {};
let transports = {};
for (let plan in this.transportPlans)
transport[plan] = this.transportPlans[plan].Serialize();
transports[plan] = this.transportPlans[plan].Serialize();
return { "properties": properties, "transport": transport };
return { "properties": properties, "transports": transports };
};
m.NavalManager.prototype.Deserialize = function(data)
m.NavalManager.prototype.Deserialize = function(gameState, data)
{
for (let property in data.properties)
this[property] = data.properties[property];
for (let key in data.properties)
this[key] = data.properties[key];
this.transportPlans = [];
// for (let plan in data.transport)
// this.transportPlans[plan] = new m.TransportPlan(gameState, [entity], startIndex, endIndex, endPos)
for (let dataPlan in data.transports)
{
let plan = new m.TransportPlan(gameState, [], dataPlan.startIndex, dataPlan.endIndex, dataPlan.endPos);
plan.Deserialize(dataPlan);
plan.init(gameState);
this.transportPlans[plan].push(plan);
}
};

View File

@ -49,7 +49,7 @@ m.ConstructionPlan.prototype.start = function(gameState)
var pos = this.findGoodPosition(gameState);
if (!pos)
{
gameState.ai.HQ.stopBuilding.push(this.type);
gameState.ai.HQ.stopBuild(gameState, this.type);
Engine.ProfileStop();
return;
}
@ -474,6 +474,43 @@ m.ConstructionPlan.prototype.Deserialize = function(gameState, data)
let cost = new API3.Resources();
cost.Deserialize(data.cost);
this.cost = cost;
// TODO find a way to properly serialize functions. For the time being, they are manually added
if (this.type == "structures/{civ}_house")
{
var difficulty = gameState.ai.Config.difficulty;
// change the starting condition according to the situation.
this.isGo = function (gameState) {
if (!self.canBuild(gameState, "structures/{civ}_house"))
return false;
if (gameState.getPopulationMax() <= gameState.getPopulationLimit())
return false;
var HouseNb = gameState.countEntitiesByType(gameState.applyCiv("foundation|structures/{civ}_house"), true);
var freeSlots = 0;
// TODO how to modify with tech
var popBonus = gameState.getTemplate(gameState.applyCiv("structures/{civ}_house")).getPopulationBonus();
freeSlots = gameState.getPopulationLimit() + HouseNb*popBonus - gameState.getPopulation();
if (gameState.ai.HQ.saveResources)
return (freeSlots <= 10);
else if (gameState.getPopulation() > 55 && difficulty > 1)
return (freeSlots <= 21);
else if (gameState.getPopulation() >= 30 && difficulty > 0)
return (freeSlots <= 15);
else
return (freeSlots <= 10);
};
}
else if (this.type == "structures/{civ}_market")
{
let priority = gameState.ai.Config.priorities.economicBuilding;
this.onStart = function(gameState) { gameState.ai.queueManager.changePriority("economicBuilding", priority); };
}
else if (this.type == "structures/{civ}_barracks")
{
let priority = gameState.ai.Config.priorities.militaryBuilding;
this.onStart = function(gameState) { gameState.ai.queueManager.changePriority("militaryBuilding", priority); };
}
};
return m;

View File

@ -71,6 +71,30 @@ m.ResearchPlan.prototype.Deserialize = function(gameState, data)
let cost = new API3.Resources();
cost.Deserialize(data.cost);
this.cost = cost;
// TODO find a way to properly serialize functions. For the time being, they are manually added
if (this.type == gameState.townPhase())
{
this.onStart = function (gameState) {
gameState.ai.HQ.econState = "growth";
gameState.ai.HQ.OnTownPhase(gameState)
};
this.isGo = function (gameState) {
var ret = gameState.getPopulation() >= gameState.ai.Config.Economy.popForTown;
if (ret && !this.lastIsGo)
this.onGo(gameState);
else if (!ret && this.lastIsGo)
this.onNotGo(gameState);
this.lastIsGo = ret;
return ret;
};
this.onGo = function (gameState) { gameState.ai.HQ.econState = "townPhasing"; };
this.onNotGo = function (gameState) { gameState.ai.HQ.econState = "growth"; };
}
else if (this.type == gameState.cityPhase())
{
plan.onStart = function (gameState) { gameState.ai.HQ.OnCityPhase(gameState) };
}
};
return m;

View File

@ -311,6 +311,8 @@ m.TradeManager.prototype.checkEvents = function(gameState, events)
else
API3.warn("one market (or foundation) has been destroyed ... checking routes");
}
gameState.ai.HQ.restartBuild(gameState, "structures/{civ}_market");
gameState.ai.HQ.restartBuild(gameState, "structures/{civ}_dock");
return true;
}
@ -473,7 +475,10 @@ m.TradeManager.prototype.prospectForNewMarket = function(gameState, queues)
this.checkRoutes(gameState);
var marketPos = gameState.ai.HQ.findMarketLocation(gameState, template);
if (!marketPos || marketPos[3] === 0) // marketPos[3] is the expected gain
{
gameState.ai.HQ.stopBuild(gameState, "structures/{civ}_market");
return;
}
if (this.potentialTradeRoute && marketPos[3] < 2*this.potentialTradeRoute.gain
&& marketPos[3] < this.potentialTradeRoute.gain + 20)
return;

View File

@ -43,27 +43,16 @@ m.TransportPlan = function(gameState, units, startIndex, endIndex, endPos)
return false;
}
this.units = gameState.getOwnUnits().filter(API3.Filters.byMetadata(PlayerID, "transport", this.ID));
this.units.registerUpdates();
for (var ent of units)
{
ent.setMetadata(PlayerID, "transport", this.ID);
ent.setMetadata(PlayerID, "endPos", endPos);
this.units.updateEnt(ent);
}
if (this.debug > 1)
API3.warn("Starting a new transport plan with ID " + this.ID + " to index " + endIndex
+ " with units length " + units.length);
this.ships = gameState.ai.HQ.navalManager.ships.filter(API3.Filters.byMetadata(PlayerID, "transporter", this.ID));
// note: those two can overlap (some transport ships are warships too and vice-versa).
this.transportShips = gameState.ai.HQ.navalManager.transportShips.filter(API3.Filters.byMetadata(PlayerID, "transporter", this.ID));
this.ships.registerUpdates();
this.transportShips.registerUpdates();
this.state = "boarding";
this.boardingPos = {};
this.needTransportShips = true;
@ -71,6 +60,17 @@ m.TransportPlan = function(gameState, units, startIndex, endIndex, endPos)
return true;
};
m.TransportPlan.prototype.init = function(gameState)
{
this.units = gameState.getOwnUnits().filter(API3.Filters.byMetadata(PlayerID, "transport", this.ID));
this.ships = gameState.ai.HQ.navalManager.ships.filter(API3.Filters.byMetadata(PlayerID, "transporter", this.ID));
this.transportShips = gameState.ai.HQ.navalManager.transportShips.filter(API3.Filters.byMetadata(PlayerID, "transporter", this.ID));
this.units.registerUpdates();
this.ships.registerUpdates();
this.transportShips.registerUpdates();
};
// count available slots
m.TransportPlan.prototype.countFreeSlots = function()
{
@ -578,12 +578,29 @@ m.TransportPlan.prototype.resetUnit = function(gameState, ent)
m.TransportPlan.prototype.Serialize = function()
{
// TODO transport plans have still to be serialized
return {};
return {
"ID": this.ID,
"flotilla": this.flotilla,
"endPos": this.endPos,
"endIndex": this.endIndex,
"startIndex": this.startIndex,
"sea": this.sea,
"state": this.state,
"boardingPos": this.boardingPos,
"needTransportShips": this.needTransportShips,
"nTry": this.nTry,
"canceled": this.canceled,
"unloaded": this.unloaded,
"recovered": this.recovered
};
};
m.TransportPlan.prototype.Deserialize = function(data)
{
for (let key in data)
this[key] = data[key];
this.failed = false;
};
return m;