mirror of
https://gitea.wildfiregames.com/0ad/0ad
synced 2026-08-15 14:43:32 -07:00
petra: various (small) changes in attack and economic management + cleanings
This was SVN commit r15408.
This commit is contained in:
parent
8f0772034e
commit
67d81996f6
13 changed files with 131 additions and 160 deletions
|
|
@ -13,6 +13,7 @@ m.PetraBot = function PetraBot(settings)
|
|||
|
||||
this.turn = 0;
|
||||
this.playedTurn = 0;
|
||||
this.elapsedTime = 0;
|
||||
|
||||
this.Config = new m.Config();
|
||||
this.Config.updateDifficulty(settings.difficulty);
|
||||
|
|
@ -51,7 +52,7 @@ m.PetraBot.prototype.CustomInit = function(gameState, sharedScript)
|
|||
|
||||
this.myIndex = this.accessibility.getAccessValue(myKeyEntities.toEntityArray()[0].position());
|
||||
|
||||
this.HQ.init(gameState,this.queues);
|
||||
this.HQ.init(gameState, this.queues);
|
||||
};
|
||||
|
||||
m.PetraBot.prototype.OnUpdate = function(sharedScript)
|
||||
|
|
@ -68,6 +69,7 @@ m.PetraBot.prototype.OnUpdate = function(sharedScript)
|
|||
}
|
||||
|
||||
// Run the update every n turns, offset depending on player ID to balance the load
|
||||
this.elapsedTime = this.gameState.getTimeElapsed() / 1000;
|
||||
if ((this.turn + this.player) % 8 == 5)
|
||||
{
|
||||
Engine.ProfileStart("PetraBot bot (player " + this.player +")");
|
||||
|
|
@ -83,39 +85,6 @@ m.PetraBot.prototype.OnUpdate = function(sharedScript)
|
|||
this.HQ.update(this.gameState, this.queues, this.savedEvents);
|
||||
|
||||
this.queueManager.update(this.gameState);
|
||||
|
||||
/*
|
||||
// Use this to debug informations about the metadata.
|
||||
if (this.playedTurn % 10 === 0)
|
||||
{
|
||||
// some debug informations about units.
|
||||
var units = this.gameState.getOwnEntities();
|
||||
for (var i in units._entities)
|
||||
{
|
||||
var ent = units._entities[i];
|
||||
if (!ent.isIdle())
|
||||
continue;
|
||||
warn ("Unit " + ent.id() + " is a " + ent._templateName);
|
||||
if (sharedScript._entityMetadata[PlayerID][ent.id()])
|
||||
{
|
||||
var metadata = sharedScript._entityMetadata[PlayerID][ent.id()];
|
||||
for (var j in metadata)
|
||||
{
|
||||
warn ("Metadata " + j);
|
||||
if (typeof(metadata[j]) == "object")
|
||||
warn ("Object");
|
||||
else if (typeof(metadata[j]) == undefined)
|
||||
warn ("Undefined");
|
||||
else
|
||||
warn(uneval(metadata[j]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
|
||||
//if (this.playedTurn % 5 === 0)
|
||||
// this.queueManager.printQueues(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
|
||||
|
|
@ -146,7 +115,6 @@ m.PetraBot.prototype.initPersonality = function()
|
|||
{
|
||||
this.Config.Military.popForBarracks1 = 12;
|
||||
this.Config.Economy.popForTown = 55;
|
||||
this.Config.Economy.cityPhase = 900;
|
||||
this.Config.Economy.popForMarket = 70;
|
||||
this.Config.Economy.femaleRatio = 0.3;
|
||||
this.Config.priorities.defenseBuilding = 60;
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ m.Army = function(gameState, owner, ownEntities, foeEntities)
|
|||
// average
|
||||
this.foePosition = [0,0];
|
||||
this.ownPosition = [0,0];
|
||||
this.positionLastUpdate = gameState.getTimeElapsed();
|
||||
this.positionLastUpdate = gameState.ai.elapsedTime;
|
||||
|
||||
// Some caching
|
||||
// A list of our defenders that were tasked with attacking a particular unit
|
||||
|
|
@ -50,7 +50,7 @@ m.Army = function(gameState, owner, ownEntities, foeEntities)
|
|||
// if not forced, will only recalculate if on a different turn.
|
||||
m.Army.prototype.recalculatePosition = function(gameState, force)
|
||||
{
|
||||
if (!force && this.positionLastUpdate === gameState.getTimeElapsed())
|
||||
if (!force && this.positionLastUpdate === gameState.ai.elapsedTime)
|
||||
return;
|
||||
var pos = [0,0];
|
||||
if (this.foeEntities.length !== 0)
|
||||
|
|
@ -85,7 +85,7 @@ m.Army.prototype.recalculatePosition = function(gameState, force)
|
|||
this.ownPosition[1] = pos[1]/npos;
|
||||
}
|
||||
|
||||
this.positionLastUpdate = gameState.getTimeElapsed();
|
||||
this.positionLastUpdate = gameState.ai.elapsedTime;
|
||||
}
|
||||
|
||||
// helper
|
||||
|
|
@ -240,7 +240,7 @@ m.Army.prototype.removeOwn = function (gameState, ID, Entity)
|
|||
{
|
||||
if (gameState.ai.HQ.Config.debug > 0)
|
||||
warn("ent from army still in transport plan: plan " + planID + " canceled");
|
||||
for each (var plan in gameState.ai.HQ.navalManager.transportPlans)
|
||||
for (var plan of gameState.ai.HQ.navalManager.transportPlans)
|
||||
{
|
||||
if (plan.ID !== planID)
|
||||
continue;
|
||||
|
|
@ -263,7 +263,7 @@ m.Army.prototype.assignUnit = function (gameState, entID)
|
|||
|
||||
// resets the army properly.
|
||||
// assumes we already cleared dead units.
|
||||
m.Army.prototype.clear = function (gameState, events)
|
||||
m.Army.prototype.clear = function (gameState)
|
||||
{
|
||||
while(this.foeEntities.length > 0)
|
||||
this.removeFoe(gameState,this.foeEntities[0]);
|
||||
|
|
@ -316,7 +316,7 @@ m.Army.prototype.checkEvents = function (gameState, events)
|
|||
// Warning the metadata is already cloned in shared.js. Futhermore, changes should be done before destroyEvents
|
||||
// otherwise it would remove the old entity from this army list
|
||||
// TODO we should may-be reevaluate the strength
|
||||
for each (var msg in renameEvents)
|
||||
for (var msg of renameEvents)
|
||||
{
|
||||
if (this.foeEntities.indexOf(msg.entity) !== -1)
|
||||
{
|
||||
|
|
@ -344,7 +344,7 @@ m.Army.prototype.checkEvents = function (gameState, events)
|
|||
}
|
||||
}
|
||||
|
||||
for each (var msg in destroyEvents)
|
||||
for (var msg of destroyEvents)
|
||||
{
|
||||
if (msg.entityObj === undefined)
|
||||
continue;
|
||||
|
|
@ -354,10 +354,10 @@ m.Army.prototype.checkEvents = function (gameState, events)
|
|||
this.removeFoe(gameState, msg.entity, msg.entityObj);
|
||||
}
|
||||
|
||||
for each (var msg in garriEvents)
|
||||
for (var msg of garriEvents)
|
||||
this.removeFoe(gameState, msg.entity);
|
||||
|
||||
for each (var msg in convEvents)
|
||||
for (var msg of convEvents)
|
||||
{
|
||||
if (msg.to === PlayerID)
|
||||
{
|
||||
|
|
@ -378,10 +378,10 @@ m.Army.prototype.onUpdate = function (gameState)
|
|||
// perhaps occasional strength recomputation
|
||||
|
||||
// occasional update or breakaways, positions…
|
||||
if (gameState.getTimeElapsed() - this.positionLastUpdate > 5000)
|
||||
if (gameState.ai.elapsedTime - this.positionLastUpdate > 5)
|
||||
{
|
||||
this.recalculatePosition(gameState);
|
||||
this.positionLastUpdate = gameState.getTimeElapsed();
|
||||
this.positionLastUpdate = gameState.ai.elapsedTime;
|
||||
|
||||
// Check for breakaways.
|
||||
for (var i = 0; i < this.foeEntities.length; ++i)
|
||||
|
|
|
|||
|
|
@ -40,9 +40,9 @@ m.AttackManager.prototype.init = function(gameState, queues, allowRush)
|
|||
// Others once in a while
|
||||
m.AttackManager.prototype.update = function(gameState, queues, events)
|
||||
{
|
||||
if (this.Config.debug == 2 && gameState.getTimeElapsed() > this.debugTime + 60000)
|
||||
if (this.Config.debug == 2 && gameState.ai.elapsedTime > this.debugTime + 60)
|
||||
{
|
||||
this.debugTime = gameState.getTimeElapsed();
|
||||
this.debugTime = gameState.ai.elapsedTime;
|
||||
warn(" upcoming attacks =================");
|
||||
for (var attackType in this.upcomingAttacks)
|
||||
{
|
||||
|
|
@ -69,7 +69,7 @@ m.AttackManager.prototype.update = function(gameState, queues, events)
|
|||
for (var i = 0; i < this.upcomingAttacks[attackType].length; ++i)
|
||||
{
|
||||
var attack = this.upcomingAttacks[attackType][i];
|
||||
attack.checkEvents(gameState, events, queues);
|
||||
attack.checkEvents(gameState, events);
|
||||
|
||||
// okay so we'll get the support plan
|
||||
if (!attack.isStarted())
|
||||
|
|
@ -142,7 +142,7 @@ m.AttackManager.prototype.update = function(gameState, queues, events)
|
|||
for (var i = 0; i < this.startedAttacks[attackType].length; ++i)
|
||||
{
|
||||
var attack = this.startedAttacks[attackType][i];
|
||||
attack.checkEvents(gameState, events, queues);
|
||||
attack.checkEvents(gameState, events);
|
||||
// okay so then we'll update the attack.
|
||||
if (attack.isPaused())
|
||||
continue;
|
||||
|
|
|
|||
|
|
@ -508,9 +508,6 @@ m.AttackPlan.prototype.trainMoreUnits = function(gameState)
|
|||
warn(" >>> " + order[4] + " done " + order[2].length + " training " + inTraining
|
||||
+ " queue " + queue1 + " champ " + queue2 + " siege " + queue3 + " >> need " + order[3].targetSize);
|
||||
}
|
||||
warn("------------------------------------");
|
||||
gameState.ai.queueManager.printQueues(gameState);
|
||||
warn("====================================");
|
||||
warn("====================================");
|
||||
}
|
||||
|
||||
|
|
@ -701,7 +698,7 @@ m.AttackPlan.prototype.rushTargetFinder = function(gameState)
|
|||
if (!defense.hasClass("CivCentre") && !defense.hasClass("Tower") && !defense.hasClass("Fortress"))
|
||||
continue;
|
||||
var dist = API3.SquareVectorDistance(pos, defense.position());
|
||||
if (dist < 4900) // TODO check on defense range rather than this fixed 80*80
|
||||
if (dist < 4900) // TODO check on defense range rather than this fixed 70*70
|
||||
{
|
||||
defended = true;
|
||||
break;
|
||||
|
|
@ -939,13 +936,12 @@ m.AttackPlan.prototype.update = function(gameState, events)
|
|||
{
|
||||
// if we are attacked while waiting the rest of the army, retaliate
|
||||
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 ourUnit = gameState.getEntityById(e.target);
|
||||
var attacker = gameState.getEntityById(evt.attacker);
|
||||
var ourUnit = gameState.getEntityById(evt.target);
|
||||
if (!attacker || !ourUnit)
|
||||
continue;
|
||||
this.unitCollection.forEach(function (entity) {
|
||||
|
|
@ -969,13 +965,12 @@ m.AttackPlan.prototype.update = function(gameState, events)
|
|||
// or if we reached the enemy base. Different plans may react differently.
|
||||
var attackedNB = 0;
|
||||
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 ourUnit = gameState.getEntityById(e.target);
|
||||
var attacker = gameState.getEntityById(evt.attacker);
|
||||
var ourUnit = gameState.getEntityById(evt.target);
|
||||
|
||||
if (attacker && attacker.position() && attacker.hasClass("Unit") && attacker.owner() != 0)
|
||||
attackedNB++;
|
||||
|
|
@ -1094,18 +1089,10 @@ m.AttackPlan.prototype.update = function(gameState, events)
|
|||
}
|
||||
}
|
||||
}
|
||||
/* else if (this.state === "transporting")
|
||||
{
|
||||
// check that we haven't finished transporting, ie the plan
|
||||
if (!gameState.ai.HQ.navalManager.checkActivePlan(this.tpPlanID))
|
||||
this.state = "walking";
|
||||
} */
|
||||
|
||||
|
||||
if (this.state === "arrived")
|
||||
{
|
||||
// let's proceed on with whatever happens now.
|
||||
// There's a ton of TODOs on this part.
|
||||
this.state = "";
|
||||
this.startingAttack = true;
|
||||
this.unitCollection.forEach( function (ent) {
|
||||
|
|
@ -1130,8 +1117,7 @@ m.AttackPlan.prototype.update = function(gameState, events)
|
|||
// basic state of attacking.
|
||||
if (this.state === "")
|
||||
{
|
||||
var timeElapsed = gameState.getTimeElapsed();
|
||||
|
||||
var time = gameState.ai.elapsedTime;
|
||||
var attackedEvents = events["Attacked"];
|
||||
for (var evt of attackedEvents)
|
||||
{
|
||||
|
|
@ -1149,7 +1135,7 @@ m.AttackPlan.prototype.update = function(gameState, events)
|
|||
if (!this.isSiegeUnit(gameState, ent))
|
||||
{
|
||||
ent.attack(attacker.id());
|
||||
ent.setMetadata(PlayerID, "lastAttackPlanUpdateTime", timeElapsed);
|
||||
ent.setMetadata(PlayerID, "lastAttackPlanUpdateTime", time);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -1163,7 +1149,7 @@ m.AttackPlan.prototype.update = function(gameState, events)
|
|||
continue;
|
||||
}
|
||||
ourUnit.attack(attacker.id());
|
||||
ourUnit.setMetadata(PlayerID, "lastAttackPlanUpdateTime", timeElapsed);
|
||||
ourUnit.setMetadata(PlayerID, "lastAttackPlanUpdateTime", time);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1205,12 +1191,12 @@ m.AttackPlan.prototype.update = function(gameState, events)
|
|||
else if(!target.hasClass("Structure"))
|
||||
maybeUpdate = true;
|
||||
}
|
||||
else if(orderData && orderData["target"])
|
||||
else if (orderData && orderData["target"])
|
||||
{
|
||||
var target = gameState.getEntityById(orderData["target"]);
|
||||
if (!target)
|
||||
needsUpdate = true;
|
||||
else if(target.hasClass("Structure"))
|
||||
else if (target.hasClass("Structure"))
|
||||
maybeUpdate = true;
|
||||
else if (!ent.hasClass("Cavalry") && !ent.hasClass("Ranged")
|
||||
&& target.hasClass("Female") && target.unitAIState().split(".")[1] == "FLEEING")
|
||||
|
|
@ -1223,17 +1209,23 @@ m.AttackPlan.prototype.update = function(gameState, events)
|
|||
if (!maybeUpdate)
|
||||
continue;
|
||||
var lastAttackPlanUpdateTime = ent.getMetadata(PlayerID, "lastAttackPlanUpdateTime");
|
||||
if (lastAttackPlanUpdateTime && (timeElapsed - lastAttackPlanUpdateTime) < 5000)
|
||||
if (lastAttackPlanUpdateTime && (time - lastAttackPlanUpdateTime) < 5)
|
||||
continue;
|
||||
}
|
||||
ent.setMetadata(PlayerID, "lastAttackPlanUpdateTime", timeElapsed);
|
||||
|
||||
ent.setMetadata(PlayerID, "lastAttackPlanUpdateTime", time);
|
||||
var range = 60;
|
||||
var attackTypes = ent.attackTypes();
|
||||
if (attackTypes && attackTypes.indexOf("Ranged") !== -1)
|
||||
range = 30 + ent.attackRange("Ranged").max;
|
||||
else if (ent.hasClass("Cavalry"))
|
||||
range += 30;
|
||||
range = range * range;
|
||||
// let's filter targets further based on this unit.
|
||||
var entIndex = gameState.ai.accessibility.getAccessValue(ent.position());
|
||||
var mStruct = enemyStructures.filter(function (enemy) {
|
||||
if (!enemy.position() || (enemy.hasClass("StoneWall") && !ent.canAttackClass("StoneWall")))
|
||||
return false;
|
||||
if (API3.SquareVectorDistance(enemy.position(), ent.position()) > 3000)
|
||||
if (API3.SquareVectorDistance(enemy.position(), ent.position()) > range)
|
||||
return false;
|
||||
if (siegeUnit && enemy.foundationProgress() === 0)
|
||||
return false;
|
||||
|
|
@ -1250,12 +1242,11 @@ m.AttackPlan.prototype.update = function(gameState, events)
|
|||
if (nearby && enemy.hasClass("Female") && enemy.unitAIState().split(".")[1] == "FLEEING")
|
||||
return false;
|
||||
var dist = API3.SquareVectorDistance(enemy.position(), ent.position());
|
||||
if (dist > 10000)
|
||||
return false;
|
||||
if (nearby && dist > 3600)
|
||||
if (dist > range)
|
||||
return false;
|
||||
if (gameState.ai.accessibility.getAccessValue(enemy.position()) !== entIndex)
|
||||
return false;
|
||||
enemy.setMetadata(PlayerID, "distance", Math.sqrt(dist));
|
||||
return true;
|
||||
});
|
||||
// Checking for gates if we're a siege unit.
|
||||
|
|
@ -1270,11 +1261,15 @@ m.AttackPlan.prototype.update = function(gameState, events)
|
|||
var vala = structa.costSum();
|
||||
if (structa.hasClass("Gates") && ent.canAttackClass("StoneWall"))
|
||||
vala += 10000;
|
||||
else if (structa.getDefaultArrow() || structa.getArrowMultiplier())
|
||||
vala += 1000;
|
||||
else if (structa.hasClass("ConquestCritical"))
|
||||
vala += 200;
|
||||
var valb = structb.costSum();
|
||||
if (structb.hasClass("Gates") && ent.canAttackClass("StoneWall"))
|
||||
valb += 10000;
|
||||
else if (structb.getDefaultArrow() || structb.getArrowMultiplier())
|
||||
valb += 1000;
|
||||
else if (structb.hasClass("ConquestCritical"))
|
||||
valb += 200;
|
||||
return (valb - vala);
|
||||
|
|
@ -1301,6 +1296,13 @@ m.AttackPlan.prototype.update = function(gameState, events)
|
|||
var valb = unitB.hasClass("Support") ? 50 : 0;
|
||||
if (ent.countersClasses(unitB.classes()))
|
||||
valb += 100;
|
||||
var distA = unitA.getMetadata(PlayerID, "distance");
|
||||
var distB = unitB.getMetadata(PlayerID, "distance");
|
||||
if( distA && distB)
|
||||
{
|
||||
vala -= distA;
|
||||
valb -= distB;
|
||||
}
|
||||
return valb - vala;
|
||||
});
|
||||
var rand = Math.floor(Math.random() * mUnit.length * 0.1);
|
||||
|
|
@ -1392,15 +1394,14 @@ m.AttackPlan.prototype.Abort = function(gameState)
|
|||
gameState.ai.queueManager.removeQueue("plan_" + this.name + "_siege");
|
||||
};
|
||||
|
||||
m.AttackPlan.prototype.checkEvents = function(gameState, events, queues)
|
||||
m.AttackPlan.prototype.checkEvents = function(gameState, events)
|
||||
{
|
||||
if (this.state === "unexecuted")
|
||||
return;
|
||||
var TrainingEvents = events["TrainingFinished"];
|
||||
for (var i in TrainingEvents)
|
||||
for (var evt of TrainingEvents)
|
||||
{
|
||||
var evt = TrainingEvents[i];
|
||||
for each (var id in evt.entities)
|
||||
for (var id of evt.entities)
|
||||
{
|
||||
var ent = gameState.getEntityById(id);
|
||||
if (!ent || ent.getMetadata(PlayerID, "plan") === undefined)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "Petra Bot",
|
||||
"description": "Based on Aegis, but heavily modified by mimo and expected to be more robust. Support for naval maps is also added. Note that it doesn't support saved games yet. Please report issues to Wildfire Games (see the link in the main menu).",
|
||||
"description": "Based on Aegis bot developped by wratii, but heavily modified by mimo and expected to be more robust. Support for naval maps is also added. Note that it doesn't support saved games yet. Please report issues to Wildfire Games (see the link in the main menu).",
|
||||
"moduleName" : "PETRA",
|
||||
"constructor": "PetraBot",
|
||||
"useShared": true
|
||||
|
|
|
|||
|
|
@ -236,7 +236,7 @@ m.DefenseManager.prototype.checkEnemyArmies = function(gameState, events)
|
|||
}
|
||||
};
|
||||
|
||||
m.DefenseManager.prototype.assignDefenders = function(gameState, events)
|
||||
m.DefenseManager.prototype.assignDefenders = function(gameState)
|
||||
{
|
||||
if (this.armies.length === 0)
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -36,9 +36,9 @@ m.HQ = function(Config)
|
|||
this.stopBuilding = []; // list of buildings to stop (temporarily) production because no room
|
||||
|
||||
this.towerStartTime = 0;
|
||||
this.towerLapseTime = this.Config.Military.towerLapseTime * 1000;
|
||||
this.towerLapseTime = this.Config.Military.towerLapseTime;
|
||||
this.fortressStartTime = 0;
|
||||
this.fortressLapseTime = this.Config.Military.fortressLapseTime * 1000;
|
||||
this.fortressLapseTime = this.Config.Military.fortressLapseTime;
|
||||
|
||||
this.baseManagers = {};
|
||||
this.attackManager = new m.AttackManager(this.Config);
|
||||
|
|
@ -478,7 +478,7 @@ m.HQ.prototype.findBestTrainableUnit = function(gameState, classes, requirements
|
|||
else
|
||||
var costsResource = 0.2;
|
||||
var toAdd = true;
|
||||
for each (var param in parameters)
|
||||
for (var param of parameters)
|
||||
{
|
||||
if (param[0] !== "costsResource" || param[2] !== type)
|
||||
continue;
|
||||
|
|
@ -1268,9 +1268,9 @@ m.HQ.prototype.buildDefenses = function(gameState, queues)
|
|||
else
|
||||
var numFortresses = gameState.countEntitiesAndQueuedByType(gameState.applyCiv("structures/{civ}_fortress_b"), true)
|
||||
+ gameState.countEntitiesAndQueuedByType(gameState.applyCiv("structures/{civ}_fortress_g"), true);
|
||||
if (gameState.getTimeElapsed() > (1 + 0.10*numFortresses)*this.fortressLapseTime + this.fortressStartTime)
|
||||
if (gameState.ai.elapsedTime > (1 + 0.10*numFortresses)*this.fortressLapseTime + this.fortressStartTime)
|
||||
{
|
||||
this.fortressStartTime = gameState.getTimeElapsed();
|
||||
this.fortressStartTime = gameState.ai.elapsedTime;
|
||||
queues.defenseBuilding.addItem(new m.ConstructionPlan(gameState, fortressType));
|
||||
}
|
||||
}
|
||||
|
|
@ -1304,9 +1304,9 @@ m.HQ.prototype.buildDefenses = function(gameState, queues)
|
|||
return;
|
||||
|
||||
var numTowers = gameState.countEntitiesAndQueuedByType(gameState.applyCiv("structures/{civ}_defense_tower"), true);
|
||||
if (gameState.getTimeElapsed() > (1 + 0.10*numTowers)*this.towerLapseTime + this.towerStartTime)
|
||||
if (gameState.ai.elapsedTime > (1 + 0.10*numTowers)*this.towerLapseTime + this.towerStartTime)
|
||||
{
|
||||
this.towerStartTime = gameState.getTimeElapsed();
|
||||
this.towerStartTime = gameState.ai.elapsedTime;
|
||||
queues.defenseBuilding.addItem(new m.ConstructionPlan(gameState, "structures/{civ}_defense_tower"));
|
||||
}
|
||||
// TODO otherwise protect markets and civilcentres
|
||||
|
|
@ -1493,7 +1493,7 @@ m.HQ.prototype.trainEmergencyUnits = function(gameState, positions)
|
|||
}
|
||||
if (rangedUnit && numGarrisoned >= nearestAnchor.garrisonMax())
|
||||
{
|
||||
// No ranged more room to garrison ... favor a melee unit
|
||||
// No more room to garrison ... favor a melee unit
|
||||
autogarrison = false;
|
||||
var trainables = nearestAnchor.trainableEntities();
|
||||
for (var trainable of trainables)
|
||||
|
|
@ -1510,8 +1510,7 @@ m.HQ.prototype.trainEmergencyUnits = function(gameState, positions)
|
|||
}
|
||||
// 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
|
||||
// TODO substract only what is needed instead of reset and sort the queues
|
||||
var cost = new API3.Resources(templateAnchor[1].cost());
|
||||
if (!available.canAfford(cost))
|
||||
{
|
||||
|
|
@ -1692,7 +1691,7 @@ m.HQ.prototype.update = function(gameState, queues, events)
|
|||
}
|
||||
if (gameState.ai.playedTurn - ent.getMetadata(PlayerID, "idleTim") < 50)
|
||||
return;
|
||||
warn(" unit idle since " + (gameState.ai.playedTurn-ent.getMetadata(PlayerID, "lastIdle")) + " turns");
|
||||
warn(" unit idle since " + (gameState.ai.playedTurn-ent.getMetadata(PlayerID, "idleTim")) + " turns");
|
||||
warn(" unitai state " + ent.unitAIState());
|
||||
warn(" >>> base " + ent.getMetadata(PlayerID, "base"));
|
||||
warn(" >>> role " + ent.getMetadata(PlayerID, "role"));
|
||||
|
|
|
|||
|
|
@ -242,9 +242,8 @@ m.NavalManager.prototype.checkEvents = function(gameState, queues, events)
|
|||
{
|
||||
var evts = events["ConstructionFinished"];
|
||||
// TODO: probably check stuffs like a base destruction.
|
||||
for (var i in evts)
|
||||
for (var evt of evts)
|
||||
{
|
||||
var evt = evts[i];
|
||||
if (!evt || !evt.newentity)
|
||||
continue;
|
||||
var entity = gameState.getEntityById(evt.newentity);
|
||||
|
|
@ -253,21 +252,19 @@ m.NavalManager.prototype.checkEvents = function(gameState, queues, events)
|
|||
}
|
||||
|
||||
var evts = events["TrainingFinished"];
|
||||
for (var i in evts)
|
||||
for (var evt of evts)
|
||||
{
|
||||
var evt = evts[i];
|
||||
if (!evt || !evt.entities)
|
||||
continue;
|
||||
for each (var entId in evt.entities)
|
||||
for (var entId of evt.entities)
|
||||
{
|
||||
var entity = gameState.getEntityById(entId);
|
||||
if (entity && entity.hasClass("Ship") && entity.isOwn(PlayerID))
|
||||
{
|
||||
var pos = gameState.ai.accessibility.gamePosToMapPos(entity.position());
|
||||
var index = pos[0] + pos[1]*gameState.ai.accessibility.width;
|
||||
var sea = gameState.ai.accessibility.navalPassMap[index];
|
||||
entity.setMetadata(PlayerID, "sea", sea);
|
||||
}
|
||||
if (!entity || !entity.hasClass("Ship") || !entity.isOwn(PlayerID))
|
||||
continue;
|
||||
var pos = gameState.ai.accessibility.gamePosToMapPos(entity.position());
|
||||
var index = pos[0] + pos[1]*gameState.ai.accessibility.width;
|
||||
var sea = gameState.ai.accessibility.navalPassMap[index];
|
||||
entity.setMetadata(PlayerID, "sea", sea);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -148,7 +148,7 @@ m.QueueManager.prototype.wantedGatherRates = function(gameState)
|
|||
|
||||
m.QueueManager.prototype.printQueues = function(gameState)
|
||||
{
|
||||
warn("QUEUES");
|
||||
warn("---------- QUEUES ------------");
|
||||
for (var i in this.queues)
|
||||
{
|
||||
var qStr = "";
|
||||
|
|
@ -174,6 +174,7 @@ m.QueueManager.prototype.printQueues = function(gameState)
|
|||
warn("Available Resources:" + uneval(this.getAvailableResources(gameState)));
|
||||
warn("Wanted Gather Rates:" + uneval(this.wantedGatherRates(gameState)));
|
||||
warn("Current Gather Rates:" + uneval(gameState.ai.HQ.GetCurrentGatherRates(gameState)));
|
||||
warn("------------------------------------");
|
||||
};
|
||||
|
||||
// nice readable HTML version.
|
||||
|
|
@ -189,7 +190,7 @@ m.QueueManager.prototype.HTMLprintQueues = function(gameState)
|
|||
|
||||
var q = this.queues[i];
|
||||
var str = "<th>" + i + " (" + this.priorities[i] + ")<br><span class=\"ressLevel\">";
|
||||
for each (var k in this.accounts[i].types)
|
||||
for (var k of this.accounts[i].types)
|
||||
if(k != "population")
|
||||
{
|
||||
str += this.accounts[i][k] + k.substr(0,1).toUpperCase() ;
|
||||
|
|
@ -386,6 +387,9 @@ m.QueueManager.prototype.update = function(gameState)
|
|||
queue.switched = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.Config.debug > 0 && gameState.ai.playedTurn%50 === 0)
|
||||
this.printQueues(gameState);
|
||||
|
||||
Engine.ProfileStop();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ m.ConstructionPlan.prototype.start = function(gameState)
|
|||
else
|
||||
this.metadata.access = gameState.ai.accessibility.getAccessValue([pos.x, pos.z]);
|
||||
|
||||
if (gameState.getTemplate(this.type).buildCategory() === "Dock")
|
||||
if (this.template.buildCategory() === "Dock")
|
||||
{
|
||||
// try to place it a bit inside the land if possible
|
||||
for (var d = -10; d <= 2; d += 2)
|
||||
|
|
@ -88,7 +88,7 @@ m.ConstructionPlan.prototype.start = function(gameState)
|
|||
m.ConstructionPlan.prototype.findGoodPosition = function(gameState)
|
||||
{
|
||||
|
||||
var template = gameState.getTemplate(this.type);
|
||||
var template = this.template;
|
||||
|
||||
if (template.buildCategory() === "Dock")
|
||||
return this.findDockPosition(gameState);
|
||||
|
|
@ -300,7 +300,7 @@ m.ConstructionPlan.prototype.findGoodPosition = function(gameState)
|
|||
// TODO for dock, we should allow building them outside territory, and we should check that we are along the right sea
|
||||
m.ConstructionPlan.prototype.findDockPosition = function(gameState)
|
||||
{
|
||||
var template = gameState.getTemplate(this.type);
|
||||
var template = this.template;
|
||||
|
||||
var cellSize = gameState.cellSize; // size of each tile
|
||||
|
||||
|
|
@ -415,7 +415,7 @@ m.ConstructionPlan.prototype.findDockPosition = function(gameState)
|
|||
// for Dock placement, we need to improve the position of the building as the position given here
|
||||
// is only the position on the shore, while the need the position of the center of the building
|
||||
// We also need to find the angle of the building
|
||||
var angle = this.getDockAngle(gameState, template, x, z);
|
||||
var angle = this.getDockAngle(gameState, x, z);
|
||||
if (!angle)
|
||||
return false;
|
||||
if (template.get("Obstruction") && template.get("Obstruction/Static"))
|
||||
|
|
@ -437,9 +437,9 @@ m.ConstructionPlan.prototype.findDockPosition = function(gameState)
|
|||
};
|
||||
|
||||
// Algorithm taken from the function GetDockAngle in helpers/Commands.js
|
||||
m.ConstructionPlan.prototype.getDockAngle = function(gameState, template, x, z)
|
||||
m.ConstructionPlan.prototype.getDockAngle = function(gameState, x, z)
|
||||
{
|
||||
var radius = template.obstructionRadius();
|
||||
var radius = this.template.obstructionRadius();
|
||||
if (!radius)
|
||||
return false;
|
||||
|
||||
|
|
|
|||
|
|
@ -41,8 +41,8 @@ m.ResearchManager.prototype.checkPhase = function(gameState, queues)
|
|||
|
||||
queues.majorTech.addItem(plan);
|
||||
}
|
||||
else if (gameState.canResearch(cityPhase,true) && gameState.getTimeElapsed() > (this.Config.Economy.cityPhase*1000)
|
||||
&& gameState.getOwnEntitiesByRole("worker", true).length > 85
|
||||
else if (gameState.canResearch(cityPhase,true) && gameState.ai.elapsedTime > this.Config.Economy.cityPhase
|
||||
&& gameState.getOwnEntitiesByRole("worker", true).length > 80
|
||||
&& gameState.findResearchers(cityPhase, true).length != 0
|
||||
&& queues.civilCentre.length() === 0)
|
||||
{
|
||||
|
|
@ -105,33 +105,36 @@ m.ResearchManager.prototype.researchWantedTechs = function(gameState, queues)
|
|||
if (!tech[1]._template.modifications)
|
||||
continue;
|
||||
var template = tech[1]._template;
|
||||
if (template.modifications[0].value.indexOf("ResourceGatherer/Capacities") !== -1)
|
||||
for (var i in template.modifications)
|
||||
{
|
||||
techName = tech[0];
|
||||
break;
|
||||
}
|
||||
else if (template.modifications[0].value === "ResourceGatherer/Rates/food.grain")
|
||||
{
|
||||
techName = tech[0];
|
||||
break;
|
||||
}
|
||||
else if (template.modifications[0].value === "Health/RegenRate")
|
||||
{
|
||||
techName = tech[0];
|
||||
break;
|
||||
}
|
||||
else if (template.modifications[0].value === "BuildingAI/DefaultArrowCount" && template.affects.indexOf("Tower"))
|
||||
{
|
||||
techName = tech[0];
|
||||
break;
|
||||
if (template.modifications[i].value.indexOf("ResourceGatherer/Capacities") !== -1)
|
||||
{
|
||||
queues.minorTech.addItem(new m.ResearchPlan(gameState, tech[0]));
|
||||
return;
|
||||
}
|
||||
else if (template.modifications[i].value === "ResourceGatherer/Rates/food.grain")
|
||||
{
|
||||
queues.minorTech.addItem(new m.ResearchPlan(gameState, tech[0]));
|
||||
return;
|
||||
}
|
||||
else if (template.modifications[i].value === "Health/RegenRate")
|
||||
{
|
||||
queues.minorTech.addItem(new m.ResearchPlan(gameState, tech[0]));
|
||||
return;
|
||||
}
|
||||
else if (template.modifications[i].value === "Attack/Ranged/MaxRange")
|
||||
{
|
||||
queues.minorTech.addItem(new m.ResearchPlan(gameState, tech[0]));
|
||||
return;
|
||||
}
|
||||
else if (template.modifications[i].value === "BuildingAI/DefaultArrowCount"
|
||||
&& template.affects.indexOf("Tower"))
|
||||
{
|
||||
queues.minorTech.addItem(new m.ResearchPlan(gameState, tech[0]));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!techName)
|
||||
return;
|
||||
if (this.Config.debug > 0)
|
||||
warn(" ... ok we've found the " + techName + " tech");
|
||||
queues.minorTech.addItem(new m.ResearchPlan(gameState, techName));
|
||||
};
|
||||
|
||||
m.ResearchManager.prototype.update = function(gameState, queues)
|
||||
|
|
|
|||
|
|
@ -219,22 +219,21 @@ m.TradeManager.prototype.setTradingGoods = function(gameState)
|
|||
// only once per turn because the info doesn't update between a turn and fixing isn't worth it.
|
||||
m.TradeManager.prototype.performBarter = function(gameState)
|
||||
{
|
||||
var markets = gameState.getOwnEntitiesByType(gameState.applyCiv("structures/{civ}_market"), true).toEntityArray();
|
||||
|
||||
if (markets.length === 0)
|
||||
var barterers = gameState.getOwnEntities().filter(API3.Filters.byClass("BarterMarket")).toEntityArray();
|
||||
if (barterers.length === 0)
|
||||
return false;
|
||||
|
||||
// Available resources after account substraction
|
||||
var available = gameState.ai.queueManager.getAvailableResources(gameState);
|
||||
var needs = gameState.ai.queueManager.currentNeeds(gameState);
|
||||
|
||||
var rates = gameState.ai.HQ.GetCurrentGatherRates(gameState)
|
||||
var rates = gameState.ai.HQ.GetCurrentGatherRates(gameState);
|
||||
|
||||
var prices = gameState.getBarterPrices();
|
||||
// calculates conversion rates
|
||||
var getBarterRate = function (prices,buy,sell) { return Math.round(100 * prices["sell"][sell] / prices["buy"][buy]); };
|
||||
|
||||
// loop through each queues checking if we could barter and help finishing a queue quickly.
|
||||
// loop through each missing resource checking if we could barter and help finishing a queue quickly.
|
||||
for (var buy of needs.types)
|
||||
{
|
||||
if (needs[buy] == 0 || needs[buy] < rates[buy]*30) // check if our rate allows to gather it fast enough
|
||||
|
|
@ -278,7 +277,7 @@ m.TradeManager.prototype.performBarter = function(gameState)
|
|||
}
|
||||
if (bestToSell !== undefined)
|
||||
{
|
||||
markets[0].barter(buy, bestToSell, 100);
|
||||
barterers[0].barter(buy, bestToSell, 100);
|
||||
if (this.Config.debug > 1)
|
||||
warn("Necessity bartering: sold " + bestToSell +" for " + buy + " >> need sell " + needs[bestToSell]
|
||||
+ " need buy " + needs[buy] + " rate buy " + rates[buy] + " available sell " + available[bestToSell]
|
||||
|
|
@ -311,7 +310,7 @@ m.TradeManager.prototype.performBarter = function(gameState)
|
|||
}
|
||||
if (bestToBuy !== undefined)
|
||||
{
|
||||
markets[0].barter(bestToBuy, "food", 100);
|
||||
barterers[0].barter(bestToBuy, "food", 100);
|
||||
if (this.Config.debug > 1)
|
||||
warn("Contingency bartering: sold food for " + bestToBuy + " available sell " + available["food"]
|
||||
+ " available buy " + available[bestToBuy] + " barterRate " + getBarterRate(prices, bestToBuy, "food"));
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ m.TransportPlan = function(gameState, units, startIndex, endIndex, endPos)
|
|||
this.units = gameState.getOwnUnits().filter(API3.Filters.byMetadata(PlayerID, "transport", this.ID));
|
||||
this.units.registerUpdates();
|
||||
|
||||
for each (var ent in units)
|
||||
for (var ent of units)
|
||||
{
|
||||
ent.setMetadata(PlayerID, "transport", this.ID);
|
||||
ent.setMetadata(PlayerID, "endPos", endPos);
|
||||
|
|
@ -185,7 +185,7 @@ m.TransportPlan.prototype.onBoarding = function(gameState)
|
|||
{
|
||||
var ready = true;
|
||||
var self = this;
|
||||
var time = gameState.getTimeElapsed();
|
||||
var time = gameState.ai.elapsedTime;
|
||||
this.units.forEach(function (ent) {
|
||||
if (!ent.getMetadata(PlayerID, "onBoard"))
|
||||
{
|
||||
|
|
@ -216,7 +216,7 @@ m.TransportPlan.prototype.onBoarding = function(gameState)
|
|||
else
|
||||
{
|
||||
var distShip = API3.SquareVectorDistance(self.boardingPos[shipId], ship.position());
|
||||
if (time - ship.getMetadata(PlayerID, "timeGarrison") > 8000 && distShip > 225)
|
||||
if (time - ship.getMetadata(PlayerID, "timeGarrison") > 8 && distShip > 225)
|
||||
{
|
||||
if (!self.nTry[shipId])
|
||||
self.nTry[shipId] = 1;
|
||||
|
|
@ -232,7 +232,7 @@ m.TransportPlan.prototype.onBoarding = function(gameState)
|
|||
ship.move(self.boardingPos[shipId][0], self.boardingPos[shipId][1]);
|
||||
ship.setMetadata(PlayerID, "timeGarrison", time);
|
||||
}
|
||||
else if (time - ent.getMetadata(PlayerID, "timeGarrison") > 2000)
|
||||
else if (time - ent.getMetadata(PlayerID, "timeGarrison") > 2)
|
||||
{
|
||||
var oldPos = ent.getMetadata(PlayerID, "posGarrison");
|
||||
var newPos = ent.position();
|
||||
|
|
@ -457,7 +457,7 @@ m.TransportPlan.prototype.onSailing = function(gameState)
|
|||
var shipId = ship.id();
|
||||
var dist = API3.SquareVectorDistance(ship.position(), self.boardingPos[shipId]);
|
||||
var remaining = 0;
|
||||
for each (var entId in ship._entity.garrisoned)
|
||||
for (var entId of ship._entity.garrisoned)
|
||||
{
|
||||
var ent = gameState.getEntityById(entId);
|
||||
if (!ent.getMetadata(PlayerID, "transport"))
|
||||
|
|
|
|||
Loading…
Reference in a new issue