Petra: bugfixes + improved attack/defense behaviour
This was SVN commit r15376.
This commit is contained in:
parent
013ab4bda7
commit
d11e48cd85
@ -74,7 +74,7 @@ m.AttackManager.prototype.update = function(gameState, queues, events)
|
||||
// okay so we'll get the support plan
|
||||
if (!attack.isStarted())
|
||||
{
|
||||
var updateStep = attack.updatePreparation(gameState, this,events);
|
||||
var updateStep = attack.updatePreparation(gameState, events);
|
||||
|
||||
// now we're gonna check if the preparation time is over
|
||||
if (updateStep === 1 || attack.isPaused() )
|
||||
@ -146,7 +146,7 @@ m.AttackManager.prototype.update = function(gameState, queues, events)
|
||||
// okay so then we'll update the attack.
|
||||
if (attack.isPaused())
|
||||
continue;
|
||||
var remaining = attack.update(gameState,this, events);
|
||||
var remaining = attack.update(gameState, events);
|
||||
if (!remaining)
|
||||
{
|
||||
if (this.Config.debug > 0)
|
||||
|
@ -1130,27 +1130,31 @@ m.AttackPlan.prototype.update = function(gameState, events)
|
||||
// basic state of attacking.
|
||||
if (this.state === "")
|
||||
{
|
||||
var timeElapsed = gameState.getTimeElapsed();
|
||||
|
||||
var attackedEvents = events["Attacked"];
|
||||
for (var key in attackedEvents)
|
||||
for (var evt of attackedEvents)
|
||||
{
|
||||
var e = attackedEvents[key];
|
||||
if (IDs.indexOf(e.target) === -1)
|
||||
if (IDs.indexOf(evt.target) === -1)
|
||||
continue;
|
||||
var attacker = gameState.getEntityById(e.attacker);
|
||||
var attacker = gameState.getEntityById(evt.attacker);
|
||||
if (!attacker || !attacker.position() || !attacker.hasClass("Unit"))
|
||||
continue;
|
||||
var ourUnit = gameState.getEntityById(e.target);
|
||||
var ourUnit = gameState.getEntityById(evt.target);
|
||||
if (this.isSiegeUnit(gameState, ourUnit))
|
||||
{
|
||||
// if siege units are attacked, we'll send some units to deal with enemies.
|
||||
var collec = this.unitCollection.filter(API3.Filters.not(API3.Filters.byClass("Siege"))).filterNearest(ourUnit.position(), 5).toEntityArray();
|
||||
for (var ent of collec)
|
||||
if (!this.isSiegeUnit(gameState, ent))
|
||||
{
|
||||
ent.attack(attacker.id());
|
||||
ent.setMetadata(PlayerID, "lastAttackPlanUpdateTime", timeElapsed);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// if other units are attacked, abandon their target (if it was a structure or a support) and retaliate
|
||||
// if units are attacked, abandon their target (if it was a structure or a support) and retaliate
|
||||
var orderData = ourUnit.unitAIOrderData();
|
||||
if (orderData.length !== 0 && orderData[0]["target"])
|
||||
{
|
||||
@ -1159,6 +1163,7 @@ m.AttackPlan.prototype.update = function(gameState, events)
|
||||
continue;
|
||||
}
|
||||
ourUnit.attack(attacker.id());
|
||||
ourUnit.setMetadata(PlayerID, "lastAttackPlanUpdateTime", timeElapsed);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1168,8 +1173,6 @@ m.AttackPlan.prototype.update = function(gameState, events)
|
||||
if (this.unitCollUpdateArray === undefined || this.unitCollUpdateArray.length === 0)
|
||||
this.unitCollUpdateArray = this.unitCollection.toIdArray();
|
||||
|
||||
var timeElapsed = gameState.getTimeElapsed();
|
||||
|
||||
// Let's check a few units each time we update (currently 10) except when attack starts
|
||||
if (this.unitCollUpdateArray.length < 15 || this.startingAttack)
|
||||
var lgth = this.unitCollUpdateArray.length;
|
||||
@ -1202,12 +1205,15 @@ m.AttackPlan.prototype.update = function(gameState, events)
|
||||
else if(!target.hasClass("Structure"))
|
||||
maybeUpdate = true;
|
||||
}
|
||||
else if (!ent.hasClass("Cavalry") && !ent.hasClass("Ranged") && orderData && orderData["target"])
|
||||
else if(orderData && orderData["target"])
|
||||
{
|
||||
var target = gameState.getEntityById(orderData["target"]);
|
||||
if (!target)
|
||||
needsUpdate = true;
|
||||
else if (target.hasClass("Female") && target.unitAIState().split(".")[1] == "FLEEING")
|
||||
else if(target.hasClass("Structure"))
|
||||
maybeUpdate = true;
|
||||
else if (!ent.hasClass("Cavalry") && !ent.hasClass("Ranged")
|
||||
&& target.hasClass("Female") && target.unitAIState().split(".")[1] == "FLEEING")
|
||||
maybeUpdate = true;
|
||||
}
|
||||
|
||||
|
@ -331,17 +331,16 @@ m.DefenseManager.prototype.checkDefenseStructures = function(gameState, events)
|
||||
{
|
||||
var self = this;
|
||||
var attackedEvents = events["Attacked"];
|
||||
for (var key in attackedEvents)
|
||||
for (var evt of attackedEvents)
|
||||
{
|
||||
var e = attackedEvents[key];
|
||||
var target = gameState.getEntityById(e.target);
|
||||
var target = gameState.getEntityById(evt.target);
|
||||
if (!target || !gameState.isEntityOwn(target) || !target.getArrowMultiplier())
|
||||
continue;
|
||||
if (!target.isGarrisonHolder() || gameState.ai.HQ.garrisonManager.numberOfGarrisonedUnits(target) >= target.garrisonMax())
|
||||
continue;
|
||||
if (target.hasClass("Ship")) // TODO integrate ships later need to be sure it is accessible
|
||||
continue;
|
||||
var attacker = gameState.getEntityById(e.attacker);
|
||||
var attacker = gameState.getEntityById(evt.attacker);
|
||||
if (!attacker)
|
||||
continue;
|
||||
var attackTypes = target.attackTypes();
|
||||
@ -359,11 +358,6 @@ m.DefenseManager.prototype.checkDefenseStructures = function(gameState, events)
|
||||
|
||||
if (!ent.position())
|
||||
return;
|
||||
var army = ent.getMetadata(PlayerID, "PartOfArmy");
|
||||
if (army !== undefined)
|
||||
army = self.getArmy(army);
|
||||
if (army !== undefined)
|
||||
army.removeOwn(gameState, ent.id(), ent);
|
||||
if (ent.getMetadata(PlayerID, "transport") !== undefined)
|
||||
return;
|
||||
if (ent.getMetadata(PlayerID, "plan") === -2 || ent.getMetadata(PlayerID, "plan") === -3)
|
||||
@ -376,6 +370,13 @@ m.DefenseManager.prototype.checkDefenseStructures = function(gameState, events)
|
||||
}
|
||||
if (gameState.ai.accessibility.getAccessValue(target.position()) !== index)
|
||||
return;
|
||||
var army = ent.getMetadata(PlayerID, "PartOfArmy");
|
||||
if (army !== undefined)
|
||||
{
|
||||
army = self.getArmy(army);
|
||||
if (army !== undefined)
|
||||
army.removeOwn(gameState, ent.id(), ent);
|
||||
}
|
||||
garrisonManager.garrison(gameState, ent, target, "protection");
|
||||
});
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ m.GarrisonManager.prototype.update = function(gameState, queues)
|
||||
var holder = gameState.getEntityById(id);
|
||||
if (!holder) // this holder was certainly destroyed. Let's remove it
|
||||
{
|
||||
for each (var entId in this.holders[id])
|
||||
for (var entId of this.holders[id])
|
||||
{
|
||||
var ent = gameState.getEntityById(entId);
|
||||
if (ent && ent.getMetadata(PlayerID, "garrisonHolder") === id)
|
||||
@ -51,8 +51,7 @@ m.GarrisonManager.prototype.update = function(gameState, queues)
|
||||
if (!holder.position()) // could happen with siege unit inside a ship
|
||||
continue;
|
||||
|
||||
if (holder.getMetadata(PlayerID, "lastUpdate") === undefined
|
||||
|| gameState.ai.playedTurn - holder.getMetadata(PlayerID, "lastUpdate") > 5)
|
||||
if (gameState.ai.playedTurn - holder.getMetadata(PlayerID, "holderUpdate") > 5)
|
||||
{
|
||||
if (holder.attackRange("Ranged"))
|
||||
var range = holder.attackRange("Ranged").max;
|
||||
@ -87,7 +86,7 @@ m.GarrisonManager.prototype.update = function(gameState, queues)
|
||||
if (this.numberOfGarrisonedUnits(holder) === 0)
|
||||
this.holders[id] = undefined;
|
||||
else
|
||||
holder.setMetadata(PlayerID, "lastUpdate", gameState.ai.playedTurn);
|
||||
holder.setMetadata(PlayerID, "holderUpdate", gameState.ai.playedTurn);
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -107,13 +106,8 @@ m.GarrisonManager.prototype.garrison = function(gameState, ent, holder, type)
|
||||
if (this.numberOfGarrisonedUnits(holder) >= holder.garrisonMax())
|
||||
return;
|
||||
|
||||
if (!this.holders[holder.id()])
|
||||
{
|
||||
this.holders[holder.id()] = [ent.id()];
|
||||
holder.setMetadata(PlayerID, "lastUpdate", gameState.ai.playedTurn);
|
||||
}
|
||||
else
|
||||
this.holders[holder.id()].push(ent.id());
|
||||
this.registerHolder(gameState, holder);
|
||||
this.holders[holder.id()].push(ent.id());
|
||||
|
||||
if (gameState.ai.HQ.Config.debug > 1)
|
||||
{
|
||||
@ -167,5 +161,14 @@ m.GarrisonManager.prototype.keepGarrisoned = function(ent, holder, enemiesAround
|
||||
}
|
||||
};
|
||||
|
||||
// Add this holder in the list managed by the garrisonManager
|
||||
m.GarrisonManager.prototype.registerHolder = function(gameState, holder)
|
||||
{
|
||||
if (this.holders[holder.id()]) // already registered
|
||||
return;
|
||||
this.holders[holder.id()] = [];
|
||||
holder.setMetadata(PlayerID, "holderUpdate", gameState.ai.playedTurn);
|
||||
};
|
||||
|
||||
return m;
|
||||
}(PETRA);
|
||||
|
@ -332,11 +332,7 @@ m.HQ.prototype.checkEvents = function (gameState, events, queues)
|
||||
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();
|
||||
}
|
||||
@ -354,8 +350,9 @@ m.HQ.prototype.checkEvents = function (gameState, events, queues)
|
||||
{
|
||||
// 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] = [];
|
||||
var holder = gameState.getEntityById(holderId);
|
||||
if (holder)
|
||||
this.garrisonManager.registerHolder(gameState, holder);
|
||||
}
|
||||
else if (ent.getMetadata(PlayerID, "garrisonType"))
|
||||
{
|
||||
@ -406,6 +403,18 @@ m.HQ.prototype.trainMoreWorkers = function(gameState, queues)
|
||||
numInTraining += item.count;
|
||||
});
|
||||
});
|
||||
|
||||
// Adapt the batch size of the first queued workers and females to the present population
|
||||
// to ease a possible recovery if our population was drastically reduced by an attack
|
||||
if (numWorkers < 12)
|
||||
var size = 1;
|
||||
else
|
||||
var size = Math.min(5, Math.ceil(numWorkers / 10));
|
||||
if (queues.villager.queue[0])
|
||||
queues.villager.queue[0].number = Math.min(queues.villager.queue[0].number, size);
|
||||
if (queues.citizenSoldier.queue[0])
|
||||
queues.citizenSoldier.queue[0].number = Math.min(queues.citizenSoldier.queue[0].number, size);
|
||||
|
||||
var numQueuedF = queues.villager.countQueuedUnits();
|
||||
var numQueuedS = queues.citizenSoldier.countQueuedUnits();
|
||||
var numQueued = numQueuedS + numQueuedF;
|
||||
@ -419,11 +428,13 @@ m.HQ.prototype.trainMoreWorkers = function(gameState, queues)
|
||||
if (numQueued > 50 || (numQueuedF > 20 && numQueuedS > 20) || numInTraining > 15)
|
||||
return;
|
||||
|
||||
// default template and size
|
||||
// default template
|
||||
var template = gameState.applyCiv("units/{civ}_support_female_citizen");
|
||||
var size = Math.min(5, Math.ceil(numTotal / 10));
|
||||
// anticipate the optimal batch size when this queue will start
|
||||
if (numTotal < 12)
|
||||
size = 1;
|
||||
var size = 1;
|
||||
else
|
||||
var size = Math.min(5, Math.ceil(numTotal / 10));
|
||||
|
||||
// Choose whether we want soldiers instead.
|
||||
if ((numFemales+numQueuedF) > 8 && (numFemales+numQueuedF)/numTotal > this.femaleRatio)
|
||||
@ -436,8 +447,6 @@ m.HQ.prototype.trainMoreWorkers = function(gameState, queues)
|
||||
template = gameState.applyCiv("units/{civ}_support_female_citizen");
|
||||
}
|
||||
|
||||
// TODO: perhaps assign them a default resource and check the base according to that.
|
||||
|
||||
// base "0" means "auto"
|
||||
if (template === gameState.applyCiv("units/{civ}_support_female_citizen"))
|
||||
queues.villager.addItem(new m.TrainingPlan(gameState, template, { "role": "worker", "base": 0 }, size, size));
|
||||
@ -1408,16 +1417,20 @@ m.HQ.prototype.trainEmergencyUnits = function(gameState, positions)
|
||||
var nearestAnchor = undefined;
|
||||
var templateAnchor = undefined;
|
||||
var distmin = undefined;
|
||||
var rangedUnit = false;
|
||||
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)
|
||||
for each (var base in this.baseManagers)
|
||||
{
|
||||
if (!base.anchor || !base.anchor.position())
|
||||
continue;
|
||||
if (base.anchor.getMetadata(PlayerID, "access") !== access)
|
||||
continue;
|
||||
var trainables = base.anchor.trainableEntities();
|
||||
if (!trainables) // base still in construction
|
||||
continue;
|
||||
var queue = base.anchor._entity.trainingQueue
|
||||
if (queue)
|
||||
{
|
||||
@ -1428,18 +1441,30 @@ m.HQ.prototype.trainEmergencyUnits = function(gameState, positions)
|
||||
if (time/1000 > 5)
|
||||
continue;
|
||||
}
|
||||
var trainable = base.anchor.trainableEntities();
|
||||
var templateFound = undefined;
|
||||
for (var i in trainable)
|
||||
for (var trainable of trainables)
|
||||
{
|
||||
var template = gameState.getTemplate(trainable[i]);
|
||||
var template = gameState.getTemplate(trainable);
|
||||
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 (rangedUnit)
|
||||
continue;
|
||||
// if we still have no ranged units, but can afford a melee unit, let's try it
|
||||
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;
|
||||
}
|
||||
else
|
||||
rangedUnit = true;
|
||||
templateFound = [trainable, template];
|
||||
if (rangedUnit)
|
||||
break;
|
||||
}
|
||||
if (!templateFound)
|
||||
continue;
|
||||
@ -1454,7 +1479,7 @@ m.HQ.prototype.trainEmergencyUnits = function(gameState, positions)
|
||||
if (!nearestAnchor || distmin > distcut)
|
||||
return;
|
||||
|
||||
var autogarrison = true;
|
||||
var autogarrison = rangedUnit;
|
||||
var numGarrisoned = this.garrisonManager.numberOfGarrisonedUnits(nearestAnchor);
|
||||
if (nearestAnchor._entity.trainingQueue)
|
||||
{
|
||||
@ -1466,9 +1491,9 @@ m.HQ.prototype.trainEmergencyUnits = function(gameState, positions)
|
||||
nearestAnchor.stopProduction(item.id);
|
||||
}
|
||||
}
|
||||
if (numGarrisoned >= nearestAnchor.garrisonMax())
|
||||
if (rangedUnit && numGarrisoned >= nearestAnchor.garrisonMax())
|
||||
{
|
||||
// No more room to garrison ... favor a melee unit
|
||||
// No ranged more room to garrison ... favor a melee unit
|
||||
autogarrison = false;
|
||||
var trainables = nearestAnchor.trainableEntities();
|
||||
for (var trainable of trainables)
|
||||
|
Loading…
Reference in New Issue
Block a user