forked from 0ad/0ad
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:
parent
c236e8a877
commit
e4774066e2
@ -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] = [];
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user