forked from 0ad/0ad
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
|
||||
m.Config = function() {
|
||||
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 = {
|
||||
"towerLapseTime" : 90, // Time to wait between building 2 towers
|
||||
@ -69,7 +69,7 @@ m.Config = function() {
|
||||
|
||||
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,
|
||||
"trader" : 50,
|
||||
"ships" : 70,
|
||||
@ -81,7 +81,8 @@ m.Config = function() {
|
||||
"defenseBuilding" : 70,
|
||||
"civilCentre" : 950,
|
||||
"majorTech" : 700,
|
||||
"minorTech" : 40
|
||||
"minorTech" : 40,
|
||||
"emergency" : 1000 // used only in emergency situations, should be the highest one
|
||||
};
|
||||
|
||||
this.personality =
|
||||
|
@ -316,11 +316,13 @@ m.DefenseManager.prototype.assignDefenders = function(gameState, events)
|
||||
break;
|
||||
}
|
||||
|
||||
// If shortage of defenders: increase the priority of soldiers queues
|
||||
if (armiesNeeding.length !== 0)
|
||||
gameState.ai.HQ.boostSoldiers(gameState);
|
||||
else
|
||||
gameState.ai.HQ.unboostSoldiers(gameState);
|
||||
if (armiesNeeding.length === 0)
|
||||
return;
|
||||
// If shortage of defenders, produce ranged infantry garrisoned in nearest civil centre
|
||||
var armiesPos = [];
|
||||
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
|
||||
|
@ -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
|
||||
* 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().
|
||||
* 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()
|
||||
@ -27,7 +27,7 @@ m.GarrisonManager.prototype.update = function(gameState, queues)
|
||||
for each (var entId in this.holders[id])
|
||||
{
|
||||
var ent = gameState.getEntityById(entId);
|
||||
if (ent && ent.getMetadata(PlayerID, "garrison-holder") === id)
|
||||
if (ent && ent.getMetadata(PlayerID, "garrisonHolder") === id)
|
||||
this.leaveGarrison(ent);
|
||||
}
|
||||
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
|
||||
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"))
|
||||
var range = holder.attackRange("Ranged").max;
|
||||
@ -68,7 +69,7 @@ m.GarrisonManager.prototype.update = function(gameState, queues)
|
||||
|
||||
var healer = holder.buffHeal();
|
||||
|
||||
for each (var entId in holder._entity.garrisoned)
|
||||
for (var entId of holder._entity.garrisoned)
|
||||
{
|
||||
var ent = gameState.getEntityById(entId);
|
||||
if (!this.keepGarrisoned(ent, holder, enemiesAround))
|
||||
@ -79,7 +80,7 @@ m.GarrisonManager.prototype.update = function(gameState, queues)
|
||||
var ent = gameState.getEntityById(list[j]);
|
||||
if (this.keepGarrisoned(ent, holder, enemiesAround))
|
||||
continue;
|
||||
if (ent.getMetadata(PlayerID, "garrison-holder") === id)
|
||||
if (ent.getMetadata(PlayerID, "garrisonHolder") === id)
|
||||
this.leaveGarrison(ent);
|
||||
list.splice(j--, 1);
|
||||
}
|
||||
@ -126,8 +127,8 @@ m.GarrisonManager.prototype.garrison = function(gameState, ent, holder, type)
|
||||
else
|
||||
ent.setMetadata(PlayerID, "plan", -3);
|
||||
ent.setMetadata(PlayerID, "subrole", "garrisoning");
|
||||
ent.setMetadata(PlayerID, "garrison-holder", holder.id());
|
||||
ent.setMetadata(PlayerID, "garrison-type", type);
|
||||
ent.setMetadata(PlayerID, "garrisonHolder", holder.id());
|
||||
ent.setMetadata(PlayerID, "garrisonType", type);
|
||||
ent.garrison(holder);
|
||||
};
|
||||
|
||||
@ -140,12 +141,12 @@ m.GarrisonManager.prototype.leaveGarrison = function(ent)
|
||||
ent.setMetadata(PlayerID, "plan", -1);
|
||||
else
|
||||
ent.setMetadata(PlayerID, "plan", undefined);
|
||||
ent.setMetadata(PlayerID, "garrison-holder", undefined);
|
||||
ent.setMetadata(PlayerID, "garrisonHolder", undefined);
|
||||
};
|
||||
|
||||
m.GarrisonManager.prototype.keepGarrisoned = function(ent, holder, enemiesAround)
|
||||
{
|
||||
switch (ent.getMetadata(PlayerID, "garrison-type"))
|
||||
switch (ent.getMetadata(PlayerID, "garrisonType"))
|
||||
{
|
||||
case 'force': // force the ungarrisoning
|
||||
return false;
|
||||
@ -161,7 +162,7 @@ m.GarrisonManager.prototype.keepGarrisoned = function(ent, holder, enemiesAround
|
||||
default:
|
||||
if (ent.getMetadata(PlayerID, "onBoard") === "onBoard") // transport is not (yet ?) managed by garrisonManager
|
||||
return true;
|
||||
warn("unknown type in garrisonManager " + ent.getMetadata(PlayerID, "garrison-type"));
|
||||
warn("unknown type in garrisonManager " + ent.getMetadata(PlayerID, "garrisonType"));
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
@ -47,8 +47,6 @@ m.HQ = function(Config)
|
||||
this.navalManager = new m.NavalManager(this.Config);
|
||||
this.researchManager = new m.ResearchManager(this.Config);
|
||||
this.garrisonManager = new m.GarrisonManager();
|
||||
|
||||
this.boostedSoldiers = undefined;
|
||||
};
|
||||
|
||||
// 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)
|
||||
{
|
||||
// TODO: probably check stuffs like a base destruction.
|
||||
var CreateEvents = events["Create"];
|
||||
var ConstructionEvents = events["ConstructionFinished"];
|
||||
for (var i in CreateEvents)
|
||||
for (var evt of CreateEvents)
|
||||
{
|
||||
var evt = CreateEvents[i];
|
||||
// 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);
|
||||
|
||||
if (ent === undefined)
|
||||
continue; // happens when this message is right before a "Destroy" one for the same entity.
|
||||
|
||||
if (ent.isOwn(PlayerID) && ent.getMetadata(PlayerID, "base") === -1)
|
||||
// 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);
|
||||
|
||||
// Let's get a few units out there to build this.
|
||||
var builders = this.bulkPickWorkers(gameState, bID, 10);
|
||||
if (builders !== false)
|
||||
{
|
||||
// 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);
|
||||
|
||||
// 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());
|
||||
});
|
||||
}
|
||||
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.
|
||||
// TODO: move to the base manager.
|
||||
if (evt.newentity)
|
||||
{
|
||||
var ent = gameState.getEntityById(evt.newentity);
|
||||
if (!ent || !ent.isOwn(PlayerID))
|
||||
continue;
|
||||
|
||||
if (ent === undefined)
|
||||
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)
|
||||
{
|
||||
if (ent.getMetadata(PlayerID, "baseAnchor") == true)
|
||||
{
|
||||
var base = ent.getMetadata(PlayerID, "base");
|
||||
if (this.baseManagers[base].constructing)
|
||||
this.baseManagers[base].constructing = false;
|
||||
this.baseManagers[base].anchor = ent;
|
||||
this.baseManagers[base].buildings.updateEnt(ent);
|
||||
this.updateTerritories(gameState);
|
||||
// let us hope this new base will fix our resource shortage
|
||||
// TODO check it really does so
|
||||
this.saveResources = undefined;
|
||||
}
|
||||
else if (ent.hasTerritoryInfluence())
|
||||
this.updateTerritories(gameState);
|
||||
var base = ent.getMetadata(PlayerID, "base");
|
||||
if (this.baseManagers[base].constructing)
|
||||
this.baseManagers[base].constructing = false;
|
||||
this.baseManagers[base].anchor = ent;
|
||||
this.baseManagers[base].buildings.updateEnt(ent);
|
||||
this.updateTerritories(gameState);
|
||||
// let us hope this new base will fix our resource shortage
|
||||
// TODO check it really does so
|
||||
this.saveResources = undefined;
|
||||
}
|
||||
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.
|
||||
m.HQ.prototype.trainMoreWorkers = function(gameState, queues)
|
||||
{
|
||||
// Get some data.
|
||||
// Count the workers in the world and in progress
|
||||
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 numTotal = numWorkers + numQueued;
|
||||
|
||||
// If we have too few, train more
|
||||
if (!this.boostedSoldiers)
|
||||
{
|
||||
if (this.saveResources && numTotal > this.Config.Economy.popForTown + 10)
|
||||
return;
|
||||
if (numTotal > this.targetNumWorkers || (numTotal >= this.Config.Economy.popForTown
|
||||
&& gameState.currentPhase() === 1 && !gameState.isResearching(gameState.townPhase())))
|
||||
return;
|
||||
}
|
||||
if (this.saveResources && numTotal > this.Config.Economy.popForTown + 10)
|
||||
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)
|
||||
return;
|
||||
|
||||
@ -1365,24 +1395,116 @@ m.HQ.prototype.findBestBaseForMilitary = function(gameState)
|
||||
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)
|
||||
return;
|
||||
this.boostedSoldiers = true;
|
||||
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();
|
||||
};
|
||||
var available = gameState.ai.queueManager.getAvailableResources(gameState, false);
|
||||
var total = gameState.ai.queueManager.getAvailableResources(gameState, true);
|
||||
var distcut = 20000;
|
||||
|
||||
m.HQ.prototype.unboostSoldiers = function(gameState)
|
||||
{
|
||||
if (!this.boostedSoldiers)
|
||||
var nearestAnchor = undefined;
|
||||
var templateAnchor = undefined;
|
||||
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;
|
||||
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)
|
||||
|
@ -165,7 +165,7 @@ m.createFrontierMap = function(gameState, borderMap)
|
||||
continue;
|
||||
var ix = 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]);
|
||||
if (jx < 0 || jx >= width)
|
||||
|
@ -260,7 +260,7 @@ m.QueueManager.prototype.update = function(gameState)
|
||||
if (ress === "population")
|
||||
continue;
|
||||
|
||||
if (availableRes[ress] > 1)
|
||||
if (availableRes[ress] > 0)
|
||||
{
|
||||
var totalPriority = 0;
|
||||
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"
|
||||
// But we'll sometimes allow less if that would overflow.
|
||||
var available = availableRes[ress];
|
||||
var missing = false;
|
||||
for (var j in tempPrio)
|
||||
{
|
||||
// we'll add at much what can be allowed to this queue.
|
||||
var toAdd = Math.floor(availableRes[ress] * tempPrio[j]/totalPriority);
|
||||
var maxAdd = Math.min(maxNeed[j], toAdd);
|
||||
this.accounts[j][ress] += maxAdd;
|
||||
if (toAdd >= maxNeed[j])
|
||||
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
|
||||
{
|
||||
|
@ -37,6 +37,19 @@ m.TrainingPlan.prototype.canStart = 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)
|
||||
var trainers = gameState.findTrainers(this.type).filter(API3.Filters.byMetadata(PlayerID, "sea", this.metadata.sea)).toEntityArray();
|
||||
else if (this.metadata && this.metadata.base)
|
||||
|
Loading…
Reference in New Issue
Block a user