Petra: make better use of garrisoning when attacked
This was SVN commit r15364.
This commit is contained in:
parent
9a743d65fe
commit
b17ffaeb7e
@ -4,7 +4,7 @@ var PETRA = function(m)
|
|||||||
// this defines the medium difficulty
|
// this defines the medium difficulty
|
||||||
m.Config = function() {
|
m.Config = function() {
|
||||||
this.difficulty = 2; // 0 is sandbox, 1 is easy, 2 is medium, 3 is hard, 4 is very hard.
|
this.difficulty = 2; // 0 is sandbox, 1 is easy, 2 is medium, 3 is hard, 4 is very hard.
|
||||||
this.debug = 0;
|
this.debug = 1;
|
||||||
|
|
||||||
this.Military = {
|
this.Military = {
|
||||||
"towerLapseTime" : 90, // Time to wait between building 2 towers
|
"towerLapseTime" : 90, // Time to wait between building 2 towers
|
||||||
@ -69,7 +69,7 @@ m.Config = function() {
|
|||||||
|
|
||||||
this.priorities =
|
this.priorities =
|
||||||
{
|
{
|
||||||
"villager" : 30, // should be slightly lower than the citizen soldier one because otherwise they get all the food
|
"villager" : 30, // should be slightly lower than the citizen soldier one to not get all the food
|
||||||
"citizenSoldier" : 60,
|
"citizenSoldier" : 60,
|
||||||
"trader" : 50,
|
"trader" : 50,
|
||||||
"ships" : 70,
|
"ships" : 70,
|
||||||
@ -81,7 +81,8 @@ m.Config = function() {
|
|||||||
"defenseBuilding" : 70,
|
"defenseBuilding" : 70,
|
||||||
"civilCentre" : 950,
|
"civilCentre" : 950,
|
||||||
"majorTech" : 700,
|
"majorTech" : 700,
|
||||||
"minorTech" : 40
|
"minorTech" : 40,
|
||||||
|
"emergency" : 1000 // used only in emergency situations, should be the highest one
|
||||||
};
|
};
|
||||||
|
|
||||||
this.personality =
|
this.personality =
|
||||||
|
@ -316,11 +316,13 @@ m.DefenseManager.prototype.assignDefenders = function(gameState, events)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If shortage of defenders: increase the priority of soldiers queues
|
if (armiesNeeding.length === 0)
|
||||||
if (armiesNeeding.length !== 0)
|
return;
|
||||||
gameState.ai.HQ.boostSoldiers(gameState);
|
// If shortage of defenders, produce ranged infantry garrisoned in nearest civil centre
|
||||||
else
|
var armiesPos = [];
|
||||||
gameState.ai.HQ.unboostSoldiers(gameState);
|
for (var a = 0; a < armiesNeeding.length; ++a)
|
||||||
|
armiesPos.push(armiesNeeding[a]["army"].foePosition);
|
||||||
|
gameState.ai.HQ.trainEmergencyUnits(gameState, armiesPos);
|
||||||
};
|
};
|
||||||
|
|
||||||
// If our defense structures are attacked, garrison soldiers inside when possible
|
// If our defense structures are attacked, garrison soldiers inside when possible
|
||||||
|
@ -6,7 +6,7 @@ var PETRA = function(m)
|
|||||||
* When a unit is ordered to garrison, it must be done through this.garrison() function so that
|
* When a unit is ordered to garrison, it must be done through this.garrison() function so that
|
||||||
* an object in this.holders is created. This object contains an array with the entities
|
* an object in this.holders is created. This object contains an array with the entities
|
||||||
* in the process of being garrisoned. To have all garrisoned units, we must add those in holder.garrisoned().
|
* in the process of being garrisoned. To have all garrisoned units, we must add those in holder.garrisoned().
|
||||||
* Futhermore garrison units have a metadata garrison describing its reason (protection, transport, ...)
|
* Futhermore garrison units have a metadata garrisonType describing its reason (protection, transport, ...)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
m.GarrisonManager = function()
|
m.GarrisonManager = function()
|
||||||
@ -27,7 +27,7 @@ m.GarrisonManager.prototype.update = function(gameState, queues)
|
|||||||
for each (var entId in this.holders[id])
|
for each (var entId in this.holders[id])
|
||||||
{
|
{
|
||||||
var ent = gameState.getEntityById(entId);
|
var ent = gameState.getEntityById(entId);
|
||||||
if (ent && ent.getMetadata(PlayerID, "garrison-holder") === id)
|
if (ent && ent.getMetadata(PlayerID, "garrisonHolder") === id)
|
||||||
this.leaveGarrison(ent);
|
this.leaveGarrison(ent);
|
||||||
}
|
}
|
||||||
this.holders[id] = undefined;
|
this.holders[id] = undefined;
|
||||||
@ -51,7 +51,8 @@ m.GarrisonManager.prototype.update = function(gameState, queues)
|
|||||||
if (!holder.position()) // could happen with siege unit inside a ship
|
if (!holder.position()) // could happen with siege unit inside a ship
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (gameState.ai.playedTurn - holder.getMetadata(PlayerID, "lastUpdate") > 5)
|
if (holder.getMetadata(PlayerID, "lastUpdate") === undefined
|
||||||
|
|| gameState.ai.playedTurn - holder.getMetadata(PlayerID, "lastUpdate") > 5)
|
||||||
{
|
{
|
||||||
if (holder.attackRange("Ranged"))
|
if (holder.attackRange("Ranged"))
|
||||||
var range = holder.attackRange("Ranged").max;
|
var range = holder.attackRange("Ranged").max;
|
||||||
@ -68,7 +69,7 @@ m.GarrisonManager.prototype.update = function(gameState, queues)
|
|||||||
|
|
||||||
var healer = holder.buffHeal();
|
var healer = holder.buffHeal();
|
||||||
|
|
||||||
for each (var entId in holder._entity.garrisoned)
|
for (var entId of holder._entity.garrisoned)
|
||||||
{
|
{
|
||||||
var ent = gameState.getEntityById(entId);
|
var ent = gameState.getEntityById(entId);
|
||||||
if (!this.keepGarrisoned(ent, holder, enemiesAround))
|
if (!this.keepGarrisoned(ent, holder, enemiesAround))
|
||||||
@ -79,7 +80,7 @@ m.GarrisonManager.prototype.update = function(gameState, queues)
|
|||||||
var ent = gameState.getEntityById(list[j]);
|
var ent = gameState.getEntityById(list[j]);
|
||||||
if (this.keepGarrisoned(ent, holder, enemiesAround))
|
if (this.keepGarrisoned(ent, holder, enemiesAround))
|
||||||
continue;
|
continue;
|
||||||
if (ent.getMetadata(PlayerID, "garrison-holder") === id)
|
if (ent.getMetadata(PlayerID, "garrisonHolder") === id)
|
||||||
this.leaveGarrison(ent);
|
this.leaveGarrison(ent);
|
||||||
list.splice(j--, 1);
|
list.splice(j--, 1);
|
||||||
}
|
}
|
||||||
@ -126,8 +127,8 @@ m.GarrisonManager.prototype.garrison = function(gameState, ent, holder, type)
|
|||||||
else
|
else
|
||||||
ent.setMetadata(PlayerID, "plan", -3);
|
ent.setMetadata(PlayerID, "plan", -3);
|
||||||
ent.setMetadata(PlayerID, "subrole", "garrisoning");
|
ent.setMetadata(PlayerID, "subrole", "garrisoning");
|
||||||
ent.setMetadata(PlayerID, "garrison-holder", holder.id());
|
ent.setMetadata(PlayerID, "garrisonHolder", holder.id());
|
||||||
ent.setMetadata(PlayerID, "garrison-type", type);
|
ent.setMetadata(PlayerID, "garrisonType", type);
|
||||||
ent.garrison(holder);
|
ent.garrison(holder);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -140,12 +141,12 @@ m.GarrisonManager.prototype.leaveGarrison = function(ent)
|
|||||||
ent.setMetadata(PlayerID, "plan", -1);
|
ent.setMetadata(PlayerID, "plan", -1);
|
||||||
else
|
else
|
||||||
ent.setMetadata(PlayerID, "plan", undefined);
|
ent.setMetadata(PlayerID, "plan", undefined);
|
||||||
ent.setMetadata(PlayerID, "garrison-holder", undefined);
|
ent.setMetadata(PlayerID, "garrisonHolder", undefined);
|
||||||
};
|
};
|
||||||
|
|
||||||
m.GarrisonManager.prototype.keepGarrisoned = function(ent, holder, enemiesAround)
|
m.GarrisonManager.prototype.keepGarrisoned = function(ent, holder, enemiesAround)
|
||||||
{
|
{
|
||||||
switch (ent.getMetadata(PlayerID, "garrison-type"))
|
switch (ent.getMetadata(PlayerID, "garrisonType"))
|
||||||
{
|
{
|
||||||
case 'force': // force the ungarrisoning
|
case 'force': // force the ungarrisoning
|
||||||
return false;
|
return false;
|
||||||
@ -161,7 +162,7 @@ m.GarrisonManager.prototype.keepGarrisoned = function(ent, holder, enemiesAround
|
|||||||
default:
|
default:
|
||||||
if (ent.getMetadata(PlayerID, "onBoard") === "onBoard") // transport is not (yet ?) managed by garrisonManager
|
if (ent.getMetadata(PlayerID, "onBoard") === "onBoard") // transport is not (yet ?) managed by garrisonManager
|
||||||
return true;
|
return true;
|
||||||
warn("unknown type in garrisonManager " + ent.getMetadata(PlayerID, "garrison-type"));
|
warn("unknown type in garrisonManager " + ent.getMetadata(PlayerID, "garrisonType"));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -47,8 +47,6 @@ m.HQ = function(Config)
|
|||||||
this.navalManager = new m.NavalManager(this.Config);
|
this.navalManager = new m.NavalManager(this.Config);
|
||||||
this.researchManager = new m.ResearchManager(this.Config);
|
this.researchManager = new m.ResearchManager(this.Config);
|
||||||
this.garrisonManager = new m.GarrisonManager();
|
this.garrisonManager = new m.GarrisonManager();
|
||||||
|
|
||||||
this.boostedSoldiers = undefined;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// More initialisation for stuff that needs the gameState
|
// More initialisation for stuff that needs the gameState
|
||||||
@ -263,69 +261,106 @@ m.HQ.prototype.getSeaIndex = function (gameState, index1, index2)
|
|||||||
|
|
||||||
m.HQ.prototype.checkEvents = function (gameState, events, queues)
|
m.HQ.prototype.checkEvents = function (gameState, events, queues)
|
||||||
{
|
{
|
||||||
// TODO: probably check stuffs like a base destruction.
|
|
||||||
var CreateEvents = events["Create"];
|
var CreateEvents = events["Create"];
|
||||||
var ConstructionEvents = events["ConstructionFinished"];
|
for (var evt of CreateEvents)
|
||||||
for (var i in CreateEvents)
|
|
||||||
{
|
{
|
||||||
var evt = CreateEvents[i];
|
|
||||||
// Let's check if we have a building set to create a new base.
|
// Let's check if we have a building set to create a new base.
|
||||||
if (evt && evt.entity)
|
var ent = gameState.getEntityById(evt.entity);
|
||||||
|
if (!ent || !ent.isOwn(PlayerID))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (ent.getMetadata(PlayerID, "base") === -1)
|
||||||
{
|
{
|
||||||
var ent = gameState.getEntityById(evt.entity);
|
// Okay so let's try to create a new base around this.
|
||||||
|
var bID = m.playerGlobals[PlayerID].uniqueIDBases;
|
||||||
|
this.baseManagers[bID] = new m.BaseManager(this.Config);
|
||||||
|
this.baseManagers[bID].init(gameState, true);
|
||||||
|
this.baseManagers[bID].setAnchor(gameState, ent);
|
||||||
|
|
||||||
if (ent === undefined)
|
// Let's get a few units out there to build this.
|
||||||
continue; // happens when this message is right before a "Destroy" one for the same entity.
|
var builders = this.bulkPickWorkers(gameState, bID, 10);
|
||||||
|
if (builders !== false)
|
||||||
if (ent.isOwn(PlayerID) && ent.getMetadata(PlayerID, "base") === -1)
|
|
||||||
{
|
{
|
||||||
// Okay so let's try to create a new base around this.
|
builders.forEach(function (worker) {
|
||||||
var bID = m.playerGlobals[PlayerID].uniqueIDBases;
|
worker.setMetadata(PlayerID, "base", bID);
|
||||||
this.baseManagers[bID] = new m.BaseManager(this.Config);
|
worker.setMetadata(PlayerID, "subrole", "builder");
|
||||||
this.baseManagers[bID].init(gameState, true);
|
worker.setMetadata(PlayerID, "target-foundation", ent.id());
|
||||||
this.baseManagers[bID].setAnchor(gameState, ent);
|
});
|
||||||
|
|
||||||
// Let's get a few units out there to build this.
|
|
||||||
var builders = this.bulkPickWorkers(gameState, bID, 10);
|
|
||||||
if (builders !== false)
|
|
||||||
{
|
|
||||||
builders.forEach(function (worker) {
|
|
||||||
worker.setMetadata(PlayerID, "base", bID);
|
|
||||||
worker.setMetadata(PlayerID, "subrole", "builder");
|
|
||||||
worker.setMetadata(PlayerID, "target-foundation", ent.id());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (var i in ConstructionEvents)
|
|
||||||
|
var ConstructionEvents = events["ConstructionFinished"];
|
||||||
|
for (var evt of ConstructionEvents)
|
||||||
{
|
{
|
||||||
var evt = ConstructionEvents[i];
|
|
||||||
// Let's check if we have a building set to create a new base.
|
// Let's check if we have a building set to create a new base.
|
||||||
// TODO: move to the base manager.
|
// TODO: move to the base manager.
|
||||||
if (evt.newentity)
|
if (evt.newentity)
|
||||||
{
|
{
|
||||||
var ent = gameState.getEntityById(evt.newentity);
|
var ent = gameState.getEntityById(evt.newentity);
|
||||||
|
if (!ent || !ent.isOwn(PlayerID))
|
||||||
|
continue;
|
||||||
|
|
||||||
if (ent === undefined)
|
if (ent.getMetadata(PlayerID, "baseAnchor") == true)
|
||||||
continue; // happens when this message is right before a "Destroy" one for the same entity.
|
|
||||||
|
|
||||||
if (ent.isOwn(PlayerID))
|
|
||||||
{
|
{
|
||||||
if (ent.getMetadata(PlayerID, "baseAnchor") == true)
|
var base = ent.getMetadata(PlayerID, "base");
|
||||||
{
|
if (this.baseManagers[base].constructing)
|
||||||
var base = ent.getMetadata(PlayerID, "base");
|
this.baseManagers[base].constructing = false;
|
||||||
if (this.baseManagers[base].constructing)
|
this.baseManagers[base].anchor = ent;
|
||||||
this.baseManagers[base].constructing = false;
|
this.baseManagers[base].buildings.updateEnt(ent);
|
||||||
this.baseManagers[base].anchor = ent;
|
this.updateTerritories(gameState);
|
||||||
this.baseManagers[base].buildings.updateEnt(ent);
|
// let us hope this new base will fix our resource shortage
|
||||||
this.updateTerritories(gameState);
|
// TODO check it really does so
|
||||||
// let us hope this new base will fix our resource shortage
|
this.saveResources = undefined;
|
||||||
// TODO check it really does so
|
}
|
||||||
this.saveResources = undefined;
|
else if (ent.hasTerritoryInfluence())
|
||||||
}
|
this.updateTerritories(gameState);
|
||||||
else if (ent.hasTerritoryInfluence())
|
}
|
||||||
this.updateTerritories(gameState);
|
}
|
||||||
|
|
||||||
|
// deal with the different rally points of training units: the rally point is set when the training starts
|
||||||
|
// for the time being, only autogarrison is used
|
||||||
|
|
||||||
|
var TrainingEvents = events["TrainingStarted"];
|
||||||
|
for (var evt of TrainingEvents)
|
||||||
|
{
|
||||||
|
var ent = gameState.getEntityById(evt.entity);
|
||||||
|
if (!ent || !ent.isOwn(PlayerID))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!ent._entity.trainingQueue || !ent._entity.trainingQueue.length)
|
||||||
|
continue;
|
||||||
|
var metadata = ent._entity.trainingQueue[0].metadata;
|
||||||
|
if (metadata.garrisonType)
|
||||||
|
{
|
||||||
|
ent.setRallyPoint(ent, "garrison"); // trained units will autogarrison
|
||||||
|
if (!this.garrisonManager.holders[evt.entity])
|
||||||
|
this.garrisonManager.holders[evt.entity] = [];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ent.unsetRallyPoint();
|
||||||
|
}
|
||||||
|
|
||||||
|
var TrainingEvents = events["TrainingFinished"];
|
||||||
|
for (var evt of TrainingEvents)
|
||||||
|
{
|
||||||
|
for (var entId of evt.entities)
|
||||||
|
{
|
||||||
|
var ent = gameState.getEntityById(entId);
|
||||||
|
if (!ent || !ent.isOwn(PlayerID))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!ent.position())
|
||||||
|
{
|
||||||
|
// we are autogarrisoned, check that the holder is registered in the garrisonManager
|
||||||
|
var holderId = ent.unitAIOrderData()[0]["target"];
|
||||||
|
if (!this.garrisonManager.holders[holderId])
|
||||||
|
this.garrisonManager.holders[holderId] = [];
|
||||||
|
}
|
||||||
|
else if (ent.getMetadata(PlayerID, "garrisonType"))
|
||||||
|
{
|
||||||
|
// we were supposed to be autogarrisoned, but this has failed (may-be full)
|
||||||
|
ent.getMetadata(PlayerID, "garrisonType", undefined);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -354,7 +389,6 @@ m.HQ.prototype.OnCityPhase = function(gameState)
|
|||||||
// TODO: also there are several things that could be greatly improved here.
|
// TODO: also there are several things that could be greatly improved here.
|
||||||
m.HQ.prototype.trainMoreWorkers = function(gameState, queues)
|
m.HQ.prototype.trainMoreWorkers = function(gameState, queues)
|
||||||
{
|
{
|
||||||
// Get some data.
|
|
||||||
// Count the workers in the world and in progress
|
// Count the workers in the world and in progress
|
||||||
var numFemales = gameState.countEntitiesAndQueuedByType(gameState.applyCiv("units/{civ}_support_female_citizen"), true);
|
var numFemales = gameState.countEntitiesAndQueuedByType(gameState.applyCiv("units/{civ}_support_female_citizen"), true);
|
||||||
|
|
||||||
@ -377,15 +411,11 @@ m.HQ.prototype.trainMoreWorkers = function(gameState, queues)
|
|||||||
var numQueued = numQueuedS + numQueuedF;
|
var numQueued = numQueuedS + numQueuedF;
|
||||||
var numTotal = numWorkers + numQueued;
|
var numTotal = numWorkers + numQueued;
|
||||||
|
|
||||||
// If we have too few, train more
|
if (this.saveResources && numTotal > this.Config.Economy.popForTown + 10)
|
||||||
if (!this.boostedSoldiers)
|
return;
|
||||||
{
|
if (numTotal > this.targetNumWorkers || (numTotal >= this.Config.Economy.popForTown
|
||||||
if (this.saveResources && numTotal > this.Config.Economy.popForTown + 10)
|
&& gameState.currentPhase() === 1 && !gameState.isResearching(gameState.townPhase())))
|
||||||
return;
|
return;
|
||||||
if (numTotal > this.targetNumWorkers || (numTotal >= this.Config.Economy.popForTown
|
|
||||||
&& gameState.currentPhase() === 1 && !gameState.isResearching(gameState.townPhase())))
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (numQueued > 50 || (numQueuedF > 20 && numQueuedS > 20) || numInTraining > 15)
|
if (numQueued > 50 || (numQueuedF > 20 && numQueuedS > 20) || numInTraining > 15)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -1365,24 +1395,116 @@ m.HQ.prototype.findBestBaseForMilitary = function(gameState)
|
|||||||
return bestBase;
|
return bestBase;
|
||||||
};
|
};
|
||||||
|
|
||||||
m.HQ.prototype.boostSoldiers = function(gameState)
|
/**
|
||||||
|
* train with highest priority ranged infantry in the nearest civil centre from a given set of positions
|
||||||
|
* and garrison them there for defense
|
||||||
|
*/
|
||||||
|
m.HQ.prototype.trainEmergencyUnits = function(gameState, positions)
|
||||||
{
|
{
|
||||||
if (this.boostedSoldiers)
|
var available = gameState.ai.queueManager.getAvailableResources(gameState, false);
|
||||||
return;
|
var total = gameState.ai.queueManager.getAvailableResources(gameState, true);
|
||||||
this.boostedSoldiers = true;
|
var distcut = 20000;
|
||||||
gameState.ai.queueManager.changePriority("citizenSoldier", 5*this.Config.priorities.citizenSoldier);
|
|
||||||
// Reset accounts from all other queues
|
|
||||||
for (var p in gameState.ai.queueManager.queues)
|
|
||||||
if (p != "citizenSoldier")
|
|
||||||
gameState.ai.queueManager.accounts[p].reset();
|
|
||||||
};
|
|
||||||
|
|
||||||
m.HQ.prototype.unboostSoldiers = function(gameState)
|
var nearestAnchor = undefined;
|
||||||
{
|
var templateAnchor = undefined;
|
||||||
if (!this.boostedSoldiers)
|
var distmin = undefined;
|
||||||
|
for (var pos of positions)
|
||||||
|
{
|
||||||
|
var access = gameState.ai.accessibility.getAccessValue(pos);
|
||||||
|
// check nearest base anchor
|
||||||
|
for each (var base in gameState.ai.HQ.baseManagers)
|
||||||
|
{
|
||||||
|
if (!base.anchor || !base.anchor.position())
|
||||||
|
continue;
|
||||||
|
if (base.anchor.getMetadata(PlayerID, "access") !== access)
|
||||||
|
continue;
|
||||||
|
var queue = base.anchor._entity.trainingQueue
|
||||||
|
if (queue)
|
||||||
|
{
|
||||||
|
var time = 0;
|
||||||
|
for (var item of queue)
|
||||||
|
if (item.progress > 0 || (item.metadata && item.metadata.trainer))
|
||||||
|
time += item.timeRemaining;
|
||||||
|
if (time/1000 > 5)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
var trainable = base.anchor.trainableEntities();
|
||||||
|
var templateFound = undefined;
|
||||||
|
for (var i in trainable)
|
||||||
|
{
|
||||||
|
var template = gameState.getTemplate(trainable[i]);
|
||||||
|
if (!template.hasClass("Infantry") || !template.hasClass("Ranged")
|
||||||
|
|| !template.hasClass("CitizenSoldier"))
|
||||||
|
continue;
|
||||||
|
if (!total.canAfford(new API3.Resources(template.cost())))
|
||||||
|
continue;
|
||||||
|
templateFound = [trainable[i], template];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!templateFound)
|
||||||
|
continue;
|
||||||
|
var dist = API3.SquareVectorDistance(base.anchor.position(), pos);
|
||||||
|
if (nearestAnchor && dist > distmin)
|
||||||
|
continue;
|
||||||
|
distmin = dist;
|
||||||
|
nearestAnchor = base.anchor;
|
||||||
|
templateAnchor = templateFound;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!nearestAnchor || distmin > distcut)
|
||||||
return;
|
return;
|
||||||
gameState.ai.queueManager.changePriority("citizenSoldier", this.Config.priorities.citizenSoldier);
|
|
||||||
this.boostedSoldiers = undefined;
|
var autogarrison = true;
|
||||||
|
var numGarrisoned = this.garrisonManager.numberOfGarrisonedUnits(nearestAnchor);
|
||||||
|
if (nearestAnchor._entity.trainingQueue)
|
||||||
|
{
|
||||||
|
for (var item of nearestAnchor._entity.trainingQueue)
|
||||||
|
{
|
||||||
|
if (item.metadata && item.metadata["garrisonType"])
|
||||||
|
numGarrisoned += item.count;
|
||||||
|
else if (!item.progress || !item.metadata || !item.metadata.trainer)
|
||||||
|
nearestAnchor.stopProduction(item.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (numGarrisoned >= nearestAnchor.garrisonMax())
|
||||||
|
{
|
||||||
|
// No more room to garrison ... favor a melee unit
|
||||||
|
autogarrison = false;
|
||||||
|
var trainables = nearestAnchor.trainableEntities();
|
||||||
|
for (var trainable of trainables)
|
||||||
|
{
|
||||||
|
var template = gameState.getTemplate(trainable);
|
||||||
|
if (!template.hasClass("Infantry") || !template.hasClass("Melee")
|
||||||
|
|| !template.hasClass("CitizenSoldier"))
|
||||||
|
continue;
|
||||||
|
if (!total.canAfford(new API3.Resources(template.cost())))
|
||||||
|
continue;
|
||||||
|
templateFound = [trainable, template];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Check first if we can afford it without touching other the accounts
|
||||||
|
// and if not, take some of ther accounted resources
|
||||||
|
// TODO substract only what is needed instead of reset
|
||||||
|
// TODO sort the queues
|
||||||
|
var cost = new API3.Resources(templateFound[1].cost());
|
||||||
|
if (!available.canAfford(cost))
|
||||||
|
{
|
||||||
|
for (var p in gameState.ai.queueManager.queues)
|
||||||
|
{
|
||||||
|
// TODO substract only what is needed instead of reseting
|
||||||
|
// and do a better sorting of queues
|
||||||
|
available.add(gameState.ai.queueManager.accounts[p]);
|
||||||
|
gameState.ai.queueManager.accounts[p].reset();
|
||||||
|
if (available.canAfford(cost))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gameState.ai.queueManager.accounts["emergency"].add(cost);
|
||||||
|
var metadata = { "role": "worker", "base": nearestAnchor.getMetadata(PlayerID, "base"), "trainer": nearestAnchor.id() };
|
||||||
|
if (autogarrison)
|
||||||
|
metadata.garrisonType = "protection";
|
||||||
|
gameState.ai.queues.emergency.addItem(new m.TrainingPlan(gameState, templateFound[0], metadata, 1, 1));
|
||||||
};
|
};
|
||||||
|
|
||||||
m.HQ.prototype.canBuild = function(gameState, structure)
|
m.HQ.prototype.canBuild = function(gameState, structure)
|
||||||
|
@ -165,7 +165,7 @@ m.createFrontierMap = function(gameState, borderMap)
|
|||||||
continue;
|
continue;
|
||||||
var ix = j%width;
|
var ix = j%width;
|
||||||
var iz = Math.floor(j/width);
|
var iz = Math.floor(j/width);
|
||||||
for each (var a in around)
|
for (var a of around)
|
||||||
{
|
{
|
||||||
var jx = ix + Math.round(insideSmall*a[0]);
|
var jx = ix + Math.round(insideSmall*a[0]);
|
||||||
if (jx < 0 || jx >= width)
|
if (jx < 0 || jx >= width)
|
||||||
|
@ -260,7 +260,7 @@ m.QueueManager.prototype.update = function(gameState)
|
|||||||
if (ress === "population")
|
if (ress === "population")
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (availableRes[ress] > 1)
|
if (availableRes[ress] > 0)
|
||||||
{
|
{
|
||||||
var totalPriority = 0;
|
var totalPriority = 0;
|
||||||
var tempPrio = {};
|
var tempPrio = {};
|
||||||
@ -295,13 +295,33 @@ m.QueueManager.prototype.update = function(gameState)
|
|||||||
}
|
}
|
||||||
// Now we allow resources to the accounts. We can at most allow "TempPriority/totalpriority*available"
|
// Now we allow resources to the accounts. We can at most allow "TempPriority/totalpriority*available"
|
||||||
// But we'll sometimes allow less if that would overflow.
|
// But we'll sometimes allow less if that would overflow.
|
||||||
|
var available = availableRes[ress];
|
||||||
|
var missing = false;
|
||||||
for (var j in tempPrio)
|
for (var j in tempPrio)
|
||||||
{
|
{
|
||||||
// we'll add at much what can be allowed to this queue.
|
// we'll add at much what can be allowed to this queue.
|
||||||
var toAdd = Math.floor(availableRes[ress] * tempPrio[j]/totalPriority);
|
var toAdd = Math.floor(availableRes[ress] * tempPrio[j]/totalPriority);
|
||||||
var maxAdd = Math.min(maxNeed[j], toAdd);
|
if (toAdd >= maxNeed[j])
|
||||||
this.accounts[j][ress] += maxAdd;
|
toAdd = maxNeed[j];
|
||||||
|
else
|
||||||
|
missing = true;
|
||||||
|
this.accounts[j][ress] += toAdd;
|
||||||
|
maxNeed[j] -= toAdd;
|
||||||
|
available -= toAdd;
|
||||||
}
|
}
|
||||||
|
if (missing && available > 0) // distribute the rest (due to floor) in any queue
|
||||||
|
{
|
||||||
|
for (var j in tempPrio)
|
||||||
|
{
|
||||||
|
var toAdd = Math.min(maxNeed[j], available);
|
||||||
|
this.accounts[j][ress] += toAdd;
|
||||||
|
available -= toAdd;
|
||||||
|
if (available <= 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (available < 0)
|
||||||
|
warn("Petra: problem with remaining " + ress + " in queueManager " + available);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -37,6 +37,19 @@ m.TrainingPlan.prototype.canStart = function(gameState)
|
|||||||
|
|
||||||
m.TrainingPlan.prototype.start = function(gameState)
|
m.TrainingPlan.prototype.start = function(gameState)
|
||||||
{
|
{
|
||||||
|
if (this.metadata && this.metadata.trainer)
|
||||||
|
{
|
||||||
|
var metadata = {};
|
||||||
|
for (var key in this.metadata)
|
||||||
|
if (key !== "trainer")
|
||||||
|
metadata[key] = this.metadata[key];
|
||||||
|
var trainer = gameState.getEntityById(this.metadata.trainer);
|
||||||
|
if (trainer)
|
||||||
|
trainer.train(this.type, this.number, metadata);
|
||||||
|
this.onStart(gameState);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (this.metadata && this.metadata.sea)
|
if (this.metadata && this.metadata.sea)
|
||||||
var trainers = gameState.findTrainers(this.type).filter(API3.Filters.byMetadata(PlayerID, "sea", this.metadata.sea)).toEntityArray();
|
var trainers = gameState.findTrainers(this.type).filter(API3.Filters.byMetadata(PlayerID, "sea", this.metadata.sea)).toEntityArray();
|
||||||
else if (this.metadata && this.metadata.base)
|
else if (this.metadata && this.metadata.base)
|
||||||
|
Loading…
Reference in New Issue
Block a user