mirror of
https://gitea.wildfiregames.com/0ad/0ad
synced 2026-07-04 05:55:47 -07:00
petra: continue splitting of attack function in smaller functions, + some cleanup
This was SVN commit r18273.
This commit is contained in:
parent
246c758085
commit
7060ca888c
7 changed files with 244 additions and 232 deletions
|
|
@ -209,7 +209,7 @@ m.Army.prototype.removeOwn = function (gameState, id, Entity)
|
|||
|
||||
if (this.assignedTo[id] !== 0)
|
||||
{
|
||||
var temp = this.assignedAgainst[this.assignedTo[id]];
|
||||
let temp = this.assignedAgainst[this.assignedTo[id]];
|
||||
if (temp)
|
||||
temp.splice(temp.indexOf(id), 1);
|
||||
}
|
||||
|
|
@ -235,13 +235,13 @@ m.Army.prototype.removeOwn = function (gameState, id, Entity)
|
|||
// TODO be sure that all units in the transport need the cancelation
|
||||
/* if (!ent.position()) // this unit must still be in a transport plan ... try to cancel it
|
||||
{
|
||||
var planID = ent.getMetadata(PlayerID, "transport");
|
||||
let planID = ent.getMetadata(PlayerID, "transport");
|
||||
// no plans must mean that the unit was in a ship which was destroyed, so do nothing
|
||||
if (planID)
|
||||
{
|
||||
if (gameState.ai.Config.debug > 0)
|
||||
warn("ent from army still in transport plan: plan " + planID + " canceled");
|
||||
var plan = gameState.ai.HQ.navalManager.getPlan(planID);
|
||||
let plan = gameState.ai.HQ.navalManager.getPlan(planID);
|
||||
if (plan && !plan.canceled)
|
||||
plan.cancelTransport(gameState);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ m.AttackPlan = function(gameState, Config, uniqueID, type, data)
|
|||
this.maxCompletingTime = 0;
|
||||
|
||||
// priority of the queues we'll create.
|
||||
var priority = 70;
|
||||
let priority = 70;
|
||||
|
||||
// unitStat priority is relative. If all are 0, the only relevant criteria is "currentsize/targetsize".
|
||||
// if not, this is a "bonus". The higher the priority, the faster this unit will get built.
|
||||
|
|
@ -158,7 +158,7 @@ m.AttackPlan = function(gameState, Config, uniqueID, type, data)
|
|||
}
|
||||
|
||||
// Put some randomness on the attack size
|
||||
var variation = 0.8 + 0.4*Math.random();
|
||||
let variation = 0.8 + 0.4*Math.random();
|
||||
// and lower priority and smaller sizes for easier difficulty levels
|
||||
if (this.Config.difficulty < 2)
|
||||
{
|
||||
|
|
@ -311,7 +311,7 @@ m.AttackPlan.prototype.forceStart = function()
|
|||
}
|
||||
};
|
||||
|
||||
/** Adds a build order. If resetQueue is true, this will reset the queue.*/
|
||||
/** Adds a build order. If resetQueue is true, this will reset the queue. */
|
||||
m.AttackPlan.prototype.addBuildOrder = function(gameState, name, unitStats, resetQueue)
|
||||
{
|
||||
if (!this.isStarted())
|
||||
|
|
@ -349,7 +349,7 @@ m.AttackPlan.prototype.addSiegeUnits = function(gameState)
|
|||
return true;
|
||||
};
|
||||
|
||||
/** Three returns possible: 1 is "keep going", 0 is "failed plan", 2 is "start" */
|
||||
/** Three returns possible: 1 is "keep going", 0 is "failed plan", 2 is "start". */
|
||||
m.AttackPlan.prototype.updatePreparation = function(gameState)
|
||||
{
|
||||
// the completing step is used to return resources and regroup the units
|
||||
|
|
@ -466,8 +466,8 @@ m.AttackPlan.prototype.updatePreparation = function(gameState)
|
|||
Engine.PostCommand(PlayerID, {"type": "attack-request", "source": PlayerID, "target": this.targetPlayer});
|
||||
}
|
||||
|
||||
var rallyPoint = this.rallyPoint;
|
||||
var rallyIndex = gameState.ai.accessibility.getAccessValue(rallyPoint);
|
||||
let rallyPoint = this.rallyPoint;
|
||||
let rallyIndex = gameState.ai.accessibility.getAccessValue(rallyPoint);
|
||||
for (let ent of this.unitCollection.values())
|
||||
{
|
||||
// For the time being, if occupied in a transport, remove the unit from this plan TODO improve that
|
||||
|
|
@ -585,8 +585,8 @@ m.AttackPlan.prototype.trainMoreUnits = function(gameState)
|
|||
|
||||
m.AttackPlan.prototype.assignUnits = function(gameState)
|
||||
{
|
||||
var plan = this.name;
|
||||
var added = false;
|
||||
let plan = this.name;
|
||||
let added = false;
|
||||
// If we can not build units, assign all available except those affected to allied defense to the current attack
|
||||
if (!this.canBuildUnits)
|
||||
{
|
||||
|
|
@ -695,7 +695,7 @@ m.AttackPlan.prototype.assignUnits = function(gameState)
|
|||
return added;
|
||||
};
|
||||
|
||||
/** Reassign one (at each turn) Cav unit to fasten raid preparation */
|
||||
/** Reassign one (at each turn) Cav unit to fasten raid preparation. */
|
||||
m.AttackPlan.prototype.reassignCavUnit = function(gameState)
|
||||
{
|
||||
let found;
|
||||
|
|
@ -1176,16 +1176,15 @@ m.AttackPlan.prototype.update = function(gameState, events)
|
|||
Engine.ProfileStart("Update Attack");
|
||||
|
||||
this.position = this.unitCollection.getCentrePosition();
|
||||
var IDs = this.unitCollection.toIdArray();
|
||||
|
||||
var self = this;
|
||||
let self = this;
|
||||
|
||||
// we are transporting our units, let's wait
|
||||
// TODO instead of state "arrived", made a state "walking" with a new path
|
||||
if (this.state === "transporting")
|
||||
this.UpdateTransporting(gameState, events, IDs);
|
||||
this.UpdateTransporting(gameState, events);
|
||||
|
||||
if (this.state === "walking" && !this.UpdateWalking(gameState, events, IDs))
|
||||
if (this.state === "walking" && !this.UpdateWalking(gameState, events))
|
||||
{
|
||||
Engine.ProfileStop();
|
||||
return 0;
|
||||
|
|
@ -1214,95 +1213,22 @@ m.AttackPlan.prototype.update = function(gameState, events)
|
|||
// basic state of attacking.
|
||||
if (this.state === "")
|
||||
{
|
||||
// First update the target position in case it's a unit (and check if it has garrisoned)
|
||||
if (this.target && this.target.hasClass("Unit"))
|
||||
// First update the target and/or its position if needed
|
||||
if (!this.UpdateTarget(gameState, events))
|
||||
{
|
||||
this.targetPos = this.target.position();
|
||||
if (!this.targetPos)
|
||||
{
|
||||
let holder = m.getHolder(gameState, this.target);
|
||||
if (holder && gameState.isPlayerEnemy(holder.owner()))
|
||||
{
|
||||
this.target = holder;
|
||||
this.targetPos = holder.position();
|
||||
}
|
||||
else
|
||||
this.target = undefined;
|
||||
}
|
||||
}
|
||||
// Then update the target if needed:
|
||||
if (this.targetPlayer === undefined)
|
||||
{
|
||||
this.targetPlayer = gameState.ai.HQ.attackManager.getEnemyPlayer(gameState, this);
|
||||
if (this.targetPlayer === undefined)
|
||||
{
|
||||
Engine.ProfileStop();
|
||||
return false;
|
||||
}
|
||||
if (this.target && this.target.owner() !== this.targetPlayer)
|
||||
this.target = undefined;
|
||||
}
|
||||
if (this.target && this.target.owner() === 0 && this.targetPlayer !== 0) // this enemy has resigned
|
||||
this.target = undefined;
|
||||
if (!this.target || !gameState.getEntityById(this.target.id()))
|
||||
{
|
||||
if (this.Config.debug > 1)
|
||||
API3.warn("Seems like our target has been destroyed. Switching.");
|
||||
this.target = this.getNearestTarget(gameState, this.position, true);
|
||||
if (!this.target)
|
||||
{
|
||||
// Check if we could help any current attack
|
||||
let attackManager = gameState.ai.HQ.attackManager;
|
||||
let accessIndex = gameState.ai.accessibility.getAccessValue(this.position);
|
||||
for (let attackType in attackManager.startedAttacks)
|
||||
{
|
||||
if (this.target)
|
||||
break;
|
||||
for (let attack of attackManager.startedAttacks[attackType])
|
||||
{
|
||||
if (attack.name === this.name)
|
||||
continue;
|
||||
if (!attack.target || !gameState.getEntityById(attack.target.id()))
|
||||
continue;
|
||||
if (accessIndex !== gameState.ai.accessibility.getAccessValue(attack.targetPos))
|
||||
continue;
|
||||
if (attack.target.owner() === 0 && attack.targetPlayer !== 0) // looks like it has resigned
|
||||
continue;
|
||||
this.target = attack.target;
|
||||
this.targetPlayer = attack.targetPlayer;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If not, let's look for another enemy
|
||||
if (!this.target)
|
||||
{
|
||||
this.targetPlayer = gameState.ai.HQ.attackManager.getEnemyPlayer(gameState, this);
|
||||
if (this.targetPlayer !== undefined)
|
||||
this.target = this.getNearestTarget(gameState, this.position, true);
|
||||
if (!this.target)
|
||||
{
|
||||
if (this.Config.debug > 1)
|
||||
API3.warn("No new target found. Remaining units " + this.unitCollection.length);
|
||||
Engine.ProfileStop();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (this.Config.debug > 1)
|
||||
API3.warn("We will help one of our other attacks");
|
||||
}
|
||||
this.targetPos = this.target.position();
|
||||
Engine.ProfileStop();
|
||||
return false;
|
||||
}
|
||||
|
||||
var time = gameState.ai.elapsedTime;
|
||||
let time = gameState.ai.elapsedTime;
|
||||
for (let evt of events.Attacked)
|
||||
{
|
||||
if (IDs.indexOf(evt.target) == -1)
|
||||
if (!this.unitCollection.hasEntId(evt.target))
|
||||
continue;
|
||||
let attacker = gameState.getEntityById(evt.attacker);
|
||||
if (!attacker || !attacker.position() || !attacker.hasClass("Unit"))
|
||||
continue;
|
||||
var ourUnit = gameState.getEntityById(evt.target);
|
||||
let ourUnit = gameState.getEntityById(evt.target);
|
||||
if (this.isSiegeUnit(gameState, ourUnit))
|
||||
{ // if our siege units are attacked, we'll send some units to deal with enemies.
|
||||
let collec = this.unitCollection.filter(API3.Filters.not(API3.Filters.byClass("Siege"))).filterNearest(ourUnit.position(), 5);
|
||||
|
|
@ -1358,8 +1284,8 @@ m.AttackPlan.prototype.update = function(gameState, events)
|
|||
}
|
||||
}
|
||||
|
||||
var enemyUnits = gameState.getEnemyUnits(this.targetPlayer);
|
||||
var enemyStructures = gameState.getEnemyStructures(this.targetPlayer);
|
||||
let enemyUnits = gameState.getEnemyUnits(this.targetPlayer);
|
||||
let enemyStructures = gameState.getEnemyStructures(this.targetPlayer);
|
||||
|
||||
// Count the number of times an enemy is targeted, to prevent all units to follow the same target
|
||||
let unitTargets = {};
|
||||
|
|
@ -1390,8 +1316,8 @@ m.AttackPlan.prototype.update = function(gameState, events)
|
|||
if (unitTargets[target] > 0)
|
||||
veto[target] = true;
|
||||
|
||||
var targetClassesUnit;
|
||||
var targetClassesSiege;
|
||||
let targetClassesUnit;
|
||||
let targetClassesSiege;
|
||||
if (this.type === "Rush")
|
||||
targetClassesUnit = {"attack": ["Unit", "Structure"], "avoid": ["Palisade", "StoneWall", "Tower", "Fortress"], "vetoEntities": veto};
|
||||
else
|
||||
|
|
@ -1419,7 +1345,7 @@ m.AttackPlan.prototype.update = function(gameState, events)
|
|||
this.unitCollUpdateArray = this.unitCollection.toIdArray();
|
||||
|
||||
// Let's check a few units each time we update (currently 10) except when attack starts
|
||||
var lgth = (this.unitCollUpdateArray.length < 15 || this.startingAttack) ? this.unitCollUpdateArray.length : 10;
|
||||
let lgth = (this.unitCollUpdateArray.length < 15 || this.startingAttack) ? this.unitCollUpdateArray.length : 10;
|
||||
for (let check = 0; check < lgth; check++)
|
||||
{
|
||||
let ent = gameState.getEntityById(this.unitCollUpdateArray[check]);
|
||||
|
|
@ -1687,7 +1613,7 @@ m.AttackPlan.prototype.update = function(gameState, events)
|
|||
return this.unitCollection.length;
|
||||
};
|
||||
|
||||
m.AttackPlan.prototype.UpdateTransporting = function(gameState, events, IDs)
|
||||
m.AttackPlan.prototype.UpdateTransporting = function(gameState, events)
|
||||
{
|
||||
let done = true;
|
||||
for (let ent of this.unitCollection.values())
|
||||
|
|
@ -1711,7 +1637,7 @@ m.AttackPlan.prototype.UpdateTransporting = function(gameState, events, IDs)
|
|||
// if we are attacked while waiting the rest of the army, retaliate
|
||||
for (let evt of events.Attacked)
|
||||
{
|
||||
if (IDs.indexOf(evt.target) == -1)
|
||||
if (!this.unitCollection.hasEntId(evt.target))
|
||||
continue;
|
||||
let attacker = gameState.getEntityById(evt.attacker);
|
||||
if (!attacker || !gameState.getEntityById(evt.target))
|
||||
|
|
@ -1728,7 +1654,7 @@ m.AttackPlan.prototype.UpdateTransporting = function(gameState, events, IDs)
|
|||
}
|
||||
};
|
||||
|
||||
m.AttackPlan.prototype.UpdateWalking = function(gameState, events, IDs)
|
||||
m.AttackPlan.prototype.UpdateWalking = function(gameState, events)
|
||||
{
|
||||
// we're marching towards the target
|
||||
// Let's check if any of our unit has been attacked.
|
||||
|
|
@ -1738,7 +1664,7 @@ m.AttackPlan.prototype.UpdateWalking = function(gameState, events, IDs)
|
|||
let attackedUnitNB = 0;
|
||||
for (let evt of events.Attacked)
|
||||
{
|
||||
if (IDs.indexOf(evt.target) === -1)
|
||||
if (!this.unitCollection.hasEntId(evt.target))
|
||||
continue;
|
||||
let attacker = gameState.getEntityById(evt.attacker);
|
||||
if (attacker && (attacker.owner() !== 0 || this.targetPlayer === 0))
|
||||
|
|
@ -1803,9 +1729,9 @@ m.AttackPlan.prototype.UpdateWalking = function(gameState, events, IDs)
|
|||
API3.warn("Attack Plan " + this.type + " " + this.name + " has met walls and gives up.");
|
||||
return false;
|
||||
}
|
||||
else
|
||||
//this.unitCollection.move(this.path[0][0], this.path[0][1]);
|
||||
this.unitCollection.moveIndiv(this.path[0][0], this.path[0][1]);
|
||||
|
||||
//this.unitCollection.move(this.path[0][0], this.path[0][1]);
|
||||
this.unitCollection.moveIndiv(this.path[0][0], this.path[0][1]);
|
||||
}
|
||||
|
||||
// check if our units are close enough from the next waypoint.
|
||||
|
|
@ -1833,6 +1759,87 @@ m.AttackPlan.prototype.UpdateWalking = function(gameState, events, IDs)
|
|||
return true;
|
||||
};
|
||||
|
||||
m.AttackPlan.prototype.UpdateTarget = function(gameState, events)
|
||||
{
|
||||
// First update the target position in case it's a unit (and check if it has garrisoned)
|
||||
if (this.target && this.target.hasClass("Unit"))
|
||||
{
|
||||
this.targetPos = this.target.position();
|
||||
if (!this.targetPos)
|
||||
{
|
||||
let holder = m.getHolder(gameState, this.target);
|
||||
if (holder && gameState.isPlayerEnemy(holder.owner()))
|
||||
{
|
||||
this.target = holder;
|
||||
this.targetPos = holder.position();
|
||||
}
|
||||
else
|
||||
this.target = undefined;
|
||||
}
|
||||
}
|
||||
// Then update the target if needed:
|
||||
if (this.targetPlayer === undefined)
|
||||
{
|
||||
this.targetPlayer = gameState.ai.HQ.attackManager.getEnemyPlayer(gameState, this);
|
||||
if (this.targetPlayer === undefined)
|
||||
return false;
|
||||
|
||||
if (this.target && this.target.owner() !== this.targetPlayer)
|
||||
this.target = undefined;
|
||||
}
|
||||
if (this.target && this.target.owner() === 0 && this.targetPlayer !== 0) // this enemy has resigned
|
||||
this.target = undefined;
|
||||
|
||||
if (!this.target || !gameState.getEntityById(this.target.id()))
|
||||
{
|
||||
if (this.Config.debug > 1)
|
||||
API3.warn("Seems like our target has been destroyed. Switching.");
|
||||
this.target = this.getNearestTarget(gameState, this.position, true);
|
||||
if (!this.target)
|
||||
{
|
||||
// Check if we could help any current attack
|
||||
let attackManager = gameState.ai.HQ.attackManager;
|
||||
let accessIndex = gameState.ai.accessibility.getAccessValue(this.position);
|
||||
for (let attackType in attackManager.startedAttacks)
|
||||
{
|
||||
for (let attack of attackManager.startedAttacks[attackType])
|
||||
{
|
||||
if (attack.name === this.name)
|
||||
continue;
|
||||
if (!attack.target || !gameState.getEntityById(attack.target.id()))
|
||||
continue;
|
||||
if (accessIndex !== gameState.ai.accessibility.getAccessValue(attack.targetPos))
|
||||
continue;
|
||||
if (attack.target.owner() === 0 && attack.targetPlayer !== 0) // looks like it has resigned
|
||||
continue;
|
||||
this.target = attack.target;
|
||||
this.targetPlayer = attack.targetPlayer;
|
||||
this.targetPos = this.target.position();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// If not, let's look for another enemy
|
||||
if (!this.target)
|
||||
{
|
||||
this.targetPlayer = gameState.ai.HQ.attackManager.getEnemyPlayer(gameState, this);
|
||||
if (this.targetPlayer !== undefined)
|
||||
this.target = this.getNearestTarget(gameState, this.position, true);
|
||||
if (!this.target)
|
||||
{
|
||||
if (this.Config.debug > 1)
|
||||
API3.warn("No new target found. Remaining units " + this.unitCollection.length);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (this.Config.debug > 1)
|
||||
API3.warn("We will help one of our other attacks");
|
||||
}
|
||||
this.targetPos = this.target.position();
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
/** reset any units */
|
||||
m.AttackPlan.prototype.Abort = function(gameState)
|
||||
{
|
||||
|
|
@ -1885,7 +1892,7 @@ m.AttackPlan.prototype.checkEvents = function(gameState, events)
|
|||
|
||||
for (let evt of events.OwnershipChanged) // capture event
|
||||
if (this.target && this.target.id() == evt.entity && gameState.isPlayerAlly(evt.to))
|
||||
this.target = undefined;
|
||||
this.target = undefined;
|
||||
|
||||
for (let evt of events.PlayerDefeated)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -77,7 +77,6 @@ m.DefenseManager.prototype.getArmy = function(partOfArmy)
|
|||
return undefined;
|
||||
};
|
||||
|
||||
// TODO: this algorithm needs to be improved, sorta.
|
||||
m.DefenseManager.prototype.isDangerous = function(gameState, entity)
|
||||
{
|
||||
if (!entity.position())
|
||||
|
|
@ -165,11 +164,10 @@ m.DefenseManager.prototype.isDangerous = function(gameState, entity)
|
|||
return false;
|
||||
};
|
||||
|
||||
|
||||
m.DefenseManager.prototype.checkEnemyUnits = function(gameState)
|
||||
{
|
||||
const nbPlayers = gameState.sharedScript.playersData.length;
|
||||
var i = gameState.ai.playedTurn % nbPlayers;
|
||||
let i = gameState.ai.playedTurn % nbPlayers;
|
||||
this.attackingUnits[i] = undefined;
|
||||
|
||||
if (i === PlayerID)
|
||||
|
|
@ -346,9 +344,8 @@ m.DefenseManager.prototype.assignDefenders = function(gameState)
|
|||
if (this.armies.length === 0)
|
||||
return;
|
||||
|
||||
var armiesNeeding = [];
|
||||
// Okay, let's add defenders
|
||||
// TODO: this is dumb.
|
||||
let armiesNeeding = [];
|
||||
// let's add defenders
|
||||
for (let army of this.armies)
|
||||
{
|
||||
let needsDef = army.needsDefenders(gameState);
|
||||
|
|
@ -364,7 +361,7 @@ m.DefenseManager.prototype.assignDefenders = function(gameState)
|
|||
return;
|
||||
|
||||
// let's get our potential units
|
||||
var potentialDefenders = [];
|
||||
let potentialDefenders = [];
|
||||
gameState.getOwnUnits().forEach(function(ent) {
|
||||
if (!ent.position())
|
||||
return;
|
||||
|
|
@ -380,7 +377,7 @@ m.DefenseManager.prototype.assignDefenders = function(gameState)
|
|||
return;
|
||||
if (ent.getMetadata(PlayerID, "plan") !== undefined && ent.getMetadata(PlayerID, "plan") !== -1)
|
||||
{
|
||||
var subrole = ent.getMetadata(PlayerID, "subrole");
|
||||
let subrole = ent.getMetadata(PlayerID, "subrole");
|
||||
if (subrole && (subrole === "completing" || subrole === "walking" || subrole === "attacking"))
|
||||
return;
|
||||
}
|
||||
|
|
@ -423,7 +420,7 @@ m.DefenseManager.prototype.assignDefenders = function(gameState)
|
|||
if (!armiesNeeding.length)
|
||||
return;
|
||||
// If shortage of defenders, produce infantry garrisoned in nearest civil centre
|
||||
var armiesPos = [];
|
||||
let armiesPos = [];
|
||||
for (let a = 0; a < armiesNeeding.length; ++a)
|
||||
armiesPos.push(armiesNeeding[a].army.foePosition);
|
||||
gameState.ai.HQ.trainEmergencyUnits(gameState, armiesPos);
|
||||
|
|
@ -441,9 +438,11 @@ m.DefenseManager.prototype.abortArmy = function(gameState, army)
|
|||
}
|
||||
};
|
||||
|
||||
// If our defense structures are attacked, garrison soldiers inside when possible
|
||||
// and if a support unit is attacked and has less than 55% health, garrison it inside the nearest healing structure
|
||||
// and if a ranged siege unit (not used for defense) is attacked, garrison it in the nearest fortress
|
||||
/**
|
||||
* If our defense structures are attacked, garrison soldiers inside when possible
|
||||
* and if a support unit is attacked and has less than 55% health, garrison it inside the nearest healing structure
|
||||
* and if a ranged siege unit (not used for defense) is attacked, garrison it in the nearest fortress
|
||||
*/
|
||||
m.DefenseManager.prototype.checkEvents = function(gameState, events)
|
||||
{
|
||||
// must be called every turn for all armies
|
||||
|
|
@ -553,10 +552,10 @@ m.DefenseManager.prototype.garrisonRangedUnitsInside = function(gameState, targe
|
|||
if (dist >= range*range)
|
||||
return;
|
||||
}
|
||||
var index = gameState.ai.accessibility.getAccessValue(target.position());
|
||||
var garrisonManager = gameState.ai.HQ.garrisonManager;
|
||||
var garrisonArrowClasses = target.getGarrisonArrowClasses();
|
||||
var units = gameState.getOwnUnits().filter(function (ent) { return MatchesClassList(garrisonArrowClasses, ent.classes()); }).filterNearest(target.position());
|
||||
let index = gameState.ai.accessibility.getAccessValue(target.position());
|
||||
let garrisonManager = gameState.ai.HQ.garrisonManager;
|
||||
let garrisonArrowClasses = target.getGarrisonArrowClasses();
|
||||
let units = gameState.getOwnUnits().filter(ent => MatchesClassList(garrisonArrowClasses, ent.classes())).filterNearest(target.position());
|
||||
for (let ent of units.values())
|
||||
{
|
||||
if (garrisonManager.numberOfGarrisonedUnits(target) >= minGarrison)
|
||||
|
|
@ -569,7 +568,7 @@ m.DefenseManager.prototype.garrisonRangedUnitsInside = function(gameState, targe
|
|||
continue;
|
||||
if (ent.getMetadata(PlayerID, "plan") !== undefined && ent.getMetadata(PlayerID, "plan") !== -1)
|
||||
{
|
||||
var subrole = ent.getMetadata(PlayerID, "subrole");
|
||||
let subrole = ent.getMetadata(PlayerID, "subrole");
|
||||
if (subrole && (subrole === "completing" || subrole === "walking" || subrole === "attacking"))
|
||||
continue;
|
||||
}
|
||||
|
|
@ -579,7 +578,7 @@ m.DefenseManager.prototype.garrisonRangedUnitsInside = function(gameState, targe
|
|||
}
|
||||
};
|
||||
|
||||
// garrison a attacked siege ranged unit inside the nearest fortress
|
||||
/** garrison a attacked siege ranged unit inside the nearest fortress */
|
||||
m.DefenseManager.prototype.garrisonSiegeUnit = function(gameState, unit)
|
||||
{
|
||||
let distmin = Math.min();
|
||||
|
|
@ -593,7 +592,7 @@ m.DefenseManager.prototype.garrisonSiegeUnit = function(gameState, unit)
|
|||
return;
|
||||
if (ent.hitpoints() < ent.garrisonEjectHealth() * ent.maxHitpoints())
|
||||
return;
|
||||
var entAccess = ent.getMetadata(PlayerID, "access");
|
||||
let entAccess = ent.getMetadata(PlayerID, "access");
|
||||
if (!entAccess)
|
||||
{
|
||||
entAccess = gameState.ai.accessibility.getAccessValue(ent.position());
|
||||
|
|
@ -611,7 +610,7 @@ m.DefenseManager.prototype.garrisonSiegeUnit = function(gameState, unit)
|
|||
garrisonManager.garrison(gameState, unit, nearest, "protection");
|
||||
};
|
||||
|
||||
// garrison a hurt unit inside the nearest healing structure
|
||||
/** garrison a hurt unit inside the nearest healing structure */
|
||||
m.DefenseManager.prototype.garrisonUnitForHealing = function(gameState, unit)
|
||||
{
|
||||
let distmin = Math.min();
|
||||
|
|
|
|||
|
|
@ -15,14 +15,16 @@ m.DiplomacyManager = function(Config)
|
|||
this.nextTributeRequest.set("all", 240);
|
||||
};
|
||||
|
||||
// Check if any allied needs help (tribute) and sent it if we have enough resource
|
||||
// or ask for a tribute if we are in need and one ally can help
|
||||
/**
|
||||
* Check if any allied needs help (tribute) and sent it if we have enough resource
|
||||
* or ask for a tribute if we are in need and one ally can help
|
||||
*/
|
||||
m.DiplomacyManager.prototype.tributes = function(gameState)
|
||||
{
|
||||
this.nextTributeUpdate = gameState.ai.elapsedTime + 30;
|
||||
var totalResources = gameState.getResources();
|
||||
var availableResources = gameState.ai.queueManager.getAvailableResources(gameState);
|
||||
var mostNeeded;
|
||||
let totalResources = gameState.getResources();
|
||||
let availableResources = gameState.ai.queueManager.getAvailableResources(gameState);
|
||||
let mostNeeded;
|
||||
for (let i = 1; i < gameState.sharedScript.playersData.length; ++i)
|
||||
{
|
||||
if (i === PlayerID || !gameState.isPlayerAlly(i) || gameState.ai.HQ.attackManager.defeated[i])
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
var PETRA = function(m)
|
||||
{
|
||||
|
||||
// returns some sort of DPS * health factor. If you specify a class, it'll use the modifiers against that class too.
|
||||
/** returns some sort of DPS * health factor. If you specify a class, it'll use the modifiers against that class too. */
|
||||
m.getMaxStrength = function(ent, againstClass)
|
||||
{
|
||||
var strength = 0.0;
|
||||
var attackTypes = ent.attackTypes();
|
||||
let strength = 0;
|
||||
let attackTypes = ent.attackTypes();
|
||||
if (!attackTypes)
|
||||
return strength;
|
||||
|
||||
|
|
@ -58,7 +58,7 @@ m.getMaxStrength = function(ent, againstClass)
|
|||
}
|
||||
}
|
||||
|
||||
var armourStrength = ent.armourStrengths();
|
||||
let armourStrength = ent.armourStrengths();
|
||||
for (let str in armourStrength)
|
||||
{
|
||||
let val = parseFloat(armourStrength[str]);
|
||||
|
|
@ -81,24 +81,24 @@ m.getMaxStrength = function(ent, againstClass)
|
|||
return strength * ent.maxHitpoints() / 100.0;
|
||||
};
|
||||
|
||||
// Decide if we should try to capture or destroy
|
||||
/** Decide if we should try to capture or destroy */
|
||||
m.allowCapture = function(ent, target)
|
||||
{
|
||||
return !target.hasClass("Siege") || !ent.hasClass("Melee") ||
|
||||
!target.isGarrisonHolder() || !target.garrisoned().length;
|
||||
};
|
||||
|
||||
// Makes the worker deposit the currently carried resources at the closest accessible dropsite
|
||||
/** Makes the worker deposit the currently carried resources at the closest accessible dropsite */
|
||||
m.returnResources = function(gameState, ent)
|
||||
{
|
||||
if (!ent.resourceCarrying() || !ent.resourceCarrying().length || !ent.position())
|
||||
return false;
|
||||
|
||||
var resource = ent.resourceCarrying()[0].type;
|
||||
let resource = ent.resourceCarrying()[0].type;
|
||||
|
||||
var closestDropsite;
|
||||
var distmin = Math.min();
|
||||
var access = gameState.ai.accessibility.getAccessValue(ent.position());
|
||||
let closestDropsite;
|
||||
let distmin = Math.min();
|
||||
let access = gameState.ai.accessibility.getAccessValue(ent.position());
|
||||
gameState.getOwnDropsites(resource).forEach(function(dropsite) {
|
||||
if (!dropsite.position() || dropsite.getMetadata(PlayerID, "access") !== access)
|
||||
return;
|
||||
|
|
@ -115,13 +115,13 @@ m.returnResources = function(gameState, ent)
|
|||
return true;
|
||||
};
|
||||
|
||||
// is supply full taking into account gatherers affected during this turn
|
||||
/** is supply full taking into account gatherers affected during this turn */
|
||||
m.IsSupplyFull = function(gameState, ent)
|
||||
{
|
||||
if (ent.isFull() === true)
|
||||
return true;
|
||||
var turnCache = gameState.ai.HQ.turnCache;
|
||||
var count = ent.resourceSupplyNumGatherers();
|
||||
let turnCache = gameState.ai.HQ.turnCache;
|
||||
let count = ent.resourceSupplyNumGatherers();
|
||||
if (turnCache.resourceGatherer && turnCache.resourceGatherer[ent.id()])
|
||||
count += turnCache.resourceGatherer[ent.id()];
|
||||
if (count >= ent.maxGatherers())
|
||||
|
|
@ -134,7 +134,7 @@ m.IsSupplyFull = function(gameState, ent)
|
|||
*/
|
||||
m.getBestBase = function(gameState, ent)
|
||||
{
|
||||
var pos = ent.position();
|
||||
let pos = ent.position();
|
||||
if (!pos)
|
||||
{
|
||||
let holder = m.getHolder(gameState, ent);
|
||||
|
|
@ -146,9 +146,9 @@ m.getBestBase = function(gameState, ent)
|
|||
}
|
||||
pos = holder.position();
|
||||
}
|
||||
var distmin = Math.min();
|
||||
var bestbase;
|
||||
var accessIndex = gameState.ai.accessibility.getAccessValue(pos);
|
||||
let distmin = Math.min();
|
||||
let bestbase;
|
||||
let accessIndex = gameState.ai.accessibility.getAccessValue(pos);
|
||||
for (let base of gameState.ai.HQ.baseManagers)
|
||||
{
|
||||
if (!base.anchor)
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ m.HQ.prototype.gameAnalysis = function(gameState)
|
|||
nobase.init(gameState);
|
||||
nobase.accessIndex = 0;
|
||||
this.baseManagers.push(nobase); // baseManagers[0] will deal with unit/structure without base
|
||||
var ccEnts = gameState.getOwnStructures().filter(API3.Filters.byClass("CivCentre"));
|
||||
let ccEnts = gameState.getOwnStructures().filter(API3.Filters.byClass("CivCentre"));
|
||||
for (let cc of ccEnts.values())
|
||||
{
|
||||
let newbase = new m.BaseManager(gameState, this.Config);
|
||||
|
|
@ -133,10 +133,10 @@ m.HQ.prototype.assignStartingEntities = function(gameState)
|
|||
*/
|
||||
m.HQ.prototype.regionAnalysis = function(gameState)
|
||||
{
|
||||
var accessibility = gameState.ai.accessibility;
|
||||
let accessibility = gameState.ai.accessibility;
|
||||
let landIndex;
|
||||
let seaIndex;
|
||||
var ccEnts = gameState.getOwnStructures().filter(API3.Filters.byClass("CivCentre"));
|
||||
let ccEnts = gameState.getOwnStructures().filter(API3.Filters.byClass("CivCentre"));
|
||||
for (let cc of ccEnts.values())
|
||||
{
|
||||
let land = accessibility.getAccessValue(cc.position());
|
||||
|
|
@ -170,11 +170,11 @@ m.HQ.prototype.regionAnalysis = function(gameState)
|
|||
return false;
|
||||
}
|
||||
|
||||
var passabilityMap = gameState.getMap();
|
||||
var totalSize = passabilityMap.width * passabilityMap.width;
|
||||
var minLandSize = Math.floor(0.1*totalSize);
|
||||
var minWaterSize = Math.floor(0.2*totalSize);
|
||||
var cellArea = passabilityMap.cellSize * passabilityMap.cellSize;
|
||||
let passabilityMap = gameState.getMap();
|
||||
let totalSize = passabilityMap.width * passabilityMap.width;
|
||||
let minLandSize = Math.floor(0.1*totalSize);
|
||||
let minWaterSize = Math.floor(0.2*totalSize);
|
||||
let cellArea = passabilityMap.cellSize * passabilityMap.cellSize;
|
||||
for (let i = 0; i < accessibility.regionSize.length; ++i)
|
||||
{
|
||||
if (landIndex && i == landIndex)
|
||||
|
|
@ -227,8 +227,8 @@ m.HQ.prototype.regionAnalysis = function(gameState)
|
|||
*/
|
||||
m.HQ.prototype.structureAnalysis = function(gameState)
|
||||
{
|
||||
var civref = gameState.playerData.civ;
|
||||
var civ = civref in this.Config.buildings.base ? civref : 'default';
|
||||
let civref = gameState.playerData.civ;
|
||||
let civ = civref in this.Config.buildings.base ? civref : 'default';
|
||||
this.bBase = [];
|
||||
for (let base of this.Config.buildings.base[civ])
|
||||
this.bBase.push(gameState.applyCiv(base));
|
||||
|
|
@ -246,13 +246,13 @@ m.HQ.prototype.structureAnalysis = function(gameState)
|
|||
*/
|
||||
m.HQ.prototype.buildFirstBase = function(gameState)
|
||||
{
|
||||
var total = gameState.getResources();
|
||||
var template = gameState.applyCiv("structures/{civ}_civil_centre");
|
||||
let total = gameState.getResources();
|
||||
let template = gameState.applyCiv("structures/{civ}_civil_centre");
|
||||
if (gameState.isDisabledTemplates(template))
|
||||
return;
|
||||
template = gameState.getTemplate(template);
|
||||
var goal = "civil_centre";
|
||||
var docks = gameState.getOwnStructures().filter(API3.Filters.byClass("Dock"));
|
||||
let goal = "civil_centre";
|
||||
let docks = gameState.getOwnStructures().filter(API3.Filters.byClass("Dock"));
|
||||
if (!total.canAfford(new API3.Resources(template.cost())) && !docks.hasEntities())
|
||||
{
|
||||
// not enough resource to build a cc, try with a dock to accumulate resources if none yet
|
||||
|
|
@ -325,22 +325,22 @@ m.HQ.prototype.buildFirstBase = function(gameState)
|
|||
*/
|
||||
m.HQ.prototype.dispatchUnits = function(gameState)
|
||||
{
|
||||
var allycc = gameState.getExclusiveAllyEntities().filter(API3.Filters.byClass("CivCentre")).toEntityArray();
|
||||
let allycc = gameState.getExclusiveAllyEntities().filter(API3.Filters.byClass("CivCentre")).toEntityArray();
|
||||
if (allycc.length)
|
||||
{
|
||||
if (this.Config.debug > 1)
|
||||
API3.warn(" We have allied cc " + allycc.length + " and " + gameState.getOwnUnits().length + " units ");
|
||||
var units = gameState.getOwnUnits();
|
||||
var num = Math.max(Math.min(Math.round(0.08*(1+this.Config.personality.cooperative)*units.length), 20), 5);
|
||||
var num1 = Math.floor(num / 2);
|
||||
var num2 = num1;
|
||||
let units = gameState.getOwnUnits();
|
||||
let num = Math.max(Math.min(Math.round(0.08*(1+this.Config.personality.cooperative)*units.length), 20), 5);
|
||||
let num1 = Math.floor(num / 2);
|
||||
let num2 = num1;
|
||||
// first pass to affect ranged infantry
|
||||
units.filter(API3.Filters.byClassesAnd(["Infantry", "Ranged"])).forEach(function (ent) {
|
||||
if (!num || !num1)
|
||||
return;
|
||||
if (ent.getMetadata(PlayerID, "allied"))
|
||||
return;
|
||||
var access = gameState.ai.accessibility.getAccessValue(ent.position());
|
||||
let access = gameState.ai.accessibility.getAccessValue(ent.position());
|
||||
for (let cc of allycc)
|
||||
{
|
||||
if (!cc.position())
|
||||
|
|
@ -410,8 +410,8 @@ m.HQ.prototype.configFirstBase = function(gameState)
|
|||
if (this.baseManagers.length < 2)
|
||||
return;
|
||||
|
||||
var startingSize = 0;
|
||||
var startingLand = [];
|
||||
let startingSize = 0;
|
||||
let startingLand = [];
|
||||
for (let region in this.landRegions)
|
||||
{
|
||||
for (let base of this.baseManagers)
|
||||
|
|
@ -423,7 +423,7 @@ m.HQ.prototype.configFirstBase = function(gameState)
|
|||
break;
|
||||
}
|
||||
}
|
||||
var cell = gameState.getMap().cellSize;
|
||||
let cell = gameState.getMap().cellSize;
|
||||
startingSize = startingSize * cell * cell;
|
||||
if (this.Config.debug > 1)
|
||||
API3.warn("starting size " + startingSize + "(cut at 24000 for fish pushing)");
|
||||
|
|
@ -441,8 +441,8 @@ m.HQ.prototype.configFirstBase = function(gameState)
|
|||
}
|
||||
|
||||
// - count the available wood resource, and react accordingly
|
||||
var startingFood = gameState.getResources().food;
|
||||
var check = {};
|
||||
let startingFood = gameState.getResources().food;
|
||||
let check = {};
|
||||
for (let proxim of ["nearby", "medium", "faraway"])
|
||||
{
|
||||
for (let base of this.baseManagers)
|
||||
|
|
@ -467,7 +467,7 @@ m.HQ.prototype.configFirstBase = function(gameState)
|
|||
this.needFarm = true;
|
||||
}
|
||||
// - count the available wood resource, and allow rushes only if enough (we should otherwise favor expansion)
|
||||
var startingWood = gameState.getResources().wood;
|
||||
let startingWood = gameState.getResources().wood;
|
||||
check = {};
|
||||
for (let proxim of ["nearby", "medium", "faraway"])
|
||||
{
|
||||
|
|
@ -501,7 +501,7 @@ m.HQ.prototype.configFirstBase = function(gameState)
|
|||
}
|
||||
|
||||
// immediatly build a wood dropsite if possible.
|
||||
var template = gameState.applyCiv("structures/{civ}_storehouse");
|
||||
let template = gameState.applyCiv("structures/{civ}_storehouse");
|
||||
if (!gameState.getOwnEntitiesByClass("Storehouse", true).hasEntities() && this.canBuild(gameState, template))
|
||||
{
|
||||
let newDP = this.baseManagers[1].findBestDropsiteLocation(gameState, "wood");
|
||||
|
|
|
|||
|
|
@ -33,26 +33,26 @@ m.TradeManager.prototype.assignTrader = function(ent)
|
|||
this.traders.updateEnt(ent);
|
||||
};
|
||||
|
||||
// TODO take trader ships into account
|
||||
m.TradeManager.prototype.trainMoreTraders = function(gameState, queues)
|
||||
{
|
||||
if (!this.tradeRoute || queues.trader.hasQueuedUnits())
|
||||
return;
|
||||
|
||||
var numTraders = this.traders.length;
|
||||
var numSeaTraders = this.traders.filter(API3.Filters.byClass("Ship")).length;
|
||||
var numLandTraders = numTraders - numSeaTraders;
|
||||
let numTraders = this.traders.length;
|
||||
let numSeaTraders = this.traders.filter(API3.Filters.byClass("Ship")).length;
|
||||
let numLandTraders = numTraders - numSeaTraders;
|
||||
// add traders already in training
|
||||
gameState.getOwnTrainingFacilities().forEach(function(ent) {
|
||||
ent.trainingQueue().forEach(function(item) {
|
||||
for (let item of ent.trainingQueue())
|
||||
{
|
||||
if (!item.metadata || !item.metadata.role || item.metadata.role !== "trader")
|
||||
return;
|
||||
continue;
|
||||
numTraders += item.count;
|
||||
if (item.metadata.sea !== undefined)
|
||||
numSeaTraders += item.count;
|
||||
else
|
||||
numLandTraders += item.count;
|
||||
});
|
||||
}
|
||||
});
|
||||
if (numTraders >= this.targetNumTraders &&
|
||||
((!this.tradeRoute.sea && numLandTraders >= Math.floor(this.targetNumTraders/2)) ||
|
||||
|
|
@ -118,8 +118,8 @@ m.TradeManager.prototype.updateTrader = function(gameState, ent)
|
|||
return;
|
||||
|
||||
Engine.ProfileStart("Trade Manager");
|
||||
var access = ent.hasClass("Ship") ? ent.getMetadata(PlayerID, "sea") : gameState.ai.accessibility.getAccessValue(ent.position());
|
||||
var route = this.checkRoutes(gameState, access);
|
||||
let access = ent.hasClass("Ship") ? ent.getMetadata(PlayerID, "sea") : gameState.ai.accessibility.getAccessValue(ent.position());
|
||||
let route = this.checkRoutes(gameState, access);
|
||||
if (!route)
|
||||
{
|
||||
// TODO try to garrison land trader inside merchant ship when only sea routes available
|
||||
|
|
@ -129,7 +129,7 @@ m.TradeManager.prototype.updateTrader = function(gameState, ent)
|
|||
return;
|
||||
}
|
||||
|
||||
var nearerSource = true;
|
||||
let nearerSource = true;
|
||||
if (API3.SquareVectorDistance(route.target.position(), ent.position()) < API3.SquareVectorDistance(route.source.position(), ent.position()))
|
||||
nearerSource = false;
|
||||
|
||||
|
|
@ -153,13 +153,13 @@ m.TradeManager.prototype.updateTrader = function(gameState, ent)
|
|||
|
||||
m.TradeManager.prototype.setTradingGoods = function(gameState)
|
||||
{
|
||||
var tradingGoods = { "food": 0, "wood": 0, "stone": 0, "metal": 0 };
|
||||
let tradingGoods = { "food": 0, "wood": 0, "stone": 0, "metal": 0 };
|
||||
// first, try to anticipate future needs
|
||||
var stocks = gameState.ai.HQ.getTotalResourceLevel(gameState);
|
||||
var mostNeeded = gameState.ai.HQ.pickMostNeededResources(gameState);
|
||||
var remaining = 100;
|
||||
var targetNum = this.Config.Economy.targetNumTraders;
|
||||
for (var type in stocks)
|
||||
let stocks = gameState.ai.HQ.getTotalResourceLevel(gameState);
|
||||
let mostNeeded = gameState.ai.HQ.pickMostNeededResources(gameState);
|
||||
let remaining = 100;
|
||||
let targetNum = this.Config.Economy.targetNumTraders;
|
||||
for (let type in stocks)
|
||||
{
|
||||
if (type == "food")
|
||||
continue;
|
||||
|
|
@ -185,8 +185,8 @@ m.TradeManager.prototype.setTradingGoods = function(gameState)
|
|||
|
||||
|
||||
// then add what is needed now
|
||||
var mainNeed = Math.floor(remaining * 70 / 100);
|
||||
var nextNeed = remaining - mainNeed;
|
||||
let mainNeed = Math.floor(remaining * 70 / 100);
|
||||
let nextNeed = remaining - mainNeed;
|
||||
|
||||
tradingGoods[mostNeeded[0].type] += mainNeed;
|
||||
if (mostNeeded[1].wanted > 0)
|
||||
|
|
@ -198,33 +198,35 @@ m.TradeManager.prototype.setTradingGoods = function(gameState)
|
|||
API3.warn(" trading goods set to " + uneval(tradingGoods));
|
||||
};
|
||||
|
||||
// Try to barter unneeded resources for needed resources.
|
||||
// only once per turn because the info doesn't update between a turn and fixing isn't worth it.
|
||||
/**
|
||||
* Try to barter unneeded resources for needed resources.
|
||||
* only once per turn because the info is not updated within a turn
|
||||
*/
|
||||
m.TradeManager.prototype.performBarter = function(gameState)
|
||||
{
|
||||
var barterers = gameState.getOwnEntitiesByClass("BarterMarket", true).filter(API3.Filters.isBuilt()).toEntityArray();
|
||||
let barterers = gameState.getOwnEntitiesByClass("BarterMarket", true).filter(API3.Filters.isBuilt()).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);
|
||||
let available = gameState.ai.queueManager.getAvailableResources(gameState);
|
||||
let needs = gameState.ai.queueManager.currentNeeds(gameState);
|
||||
|
||||
var rates = gameState.ai.HQ.GetCurrentGatherRates(gameState);
|
||||
let rates = gameState.ai.HQ.GetCurrentGatherRates(gameState);
|
||||
|
||||
var prices = gameState.getBarterPrices();
|
||||
let prices = gameState.getBarterPrices();
|
||||
// calculates conversion rates
|
||||
var getBarterRate = function (prices,buy,sell) { return Math.round(100 * prices.sell[sell] / prices.buy[buy]); };
|
||||
let getBarterRate = function (prices,buy,sell) { return Math.round(100 * prices.sell[sell] / prices.buy[buy]); };
|
||||
|
||||
// loop through each missing resource checking if we could barter and help finishing a queue quickly.
|
||||
for (var buy of needs.types)
|
||||
for (let buy of needs.types)
|
||||
{
|
||||
if (needs[buy] === 0 || needs[buy] < rates[buy]*30) // check if our rate allows to gather it fast enough
|
||||
continue;
|
||||
|
||||
// pick the best resource to barter.
|
||||
var bestToSell = undefined;
|
||||
var bestRate = 0;
|
||||
let bestToSell = undefined;
|
||||
let bestRate = 0;
|
||||
for (let sell of needs.types)
|
||||
{
|
||||
if (sell === buy)
|
||||
|
|
@ -273,8 +275,8 @@ m.TradeManager.prototype.performBarter = function(gameState)
|
|||
// now do contingency bartering, selling food to buy finite resources (and annoy our ennemies by increasing prices)
|
||||
if (available.food < 1000 || needs.food > 0)
|
||||
return false;
|
||||
var bestToBuy;
|
||||
var bestChoice = 0;
|
||||
let bestToBuy;
|
||||
let bestChoice = 0;
|
||||
for (let buy of needs.types)
|
||||
{
|
||||
if (buy === "food")
|
||||
|
|
@ -371,12 +373,14 @@ m.TradeManager.prototype.checkEvents = function(gameState, events)
|
|||
return false;
|
||||
};
|
||||
|
||||
// fills the best trade route in this.tradeRoute and the best potential route in this.potentialTradeRoute
|
||||
// If an index is given, it returns the best route with this index or the best land route if index is a land index
|
||||
/**
|
||||
* fills the best trade route in this.tradeRoute and the best potential route in this.potentialTradeRoute
|
||||
* If an index is given, it returns the best route with this index or the best land route if index is a land index
|
||||
*/
|
||||
m.TradeManager.prototype.checkRoutes = function(gameState, accessIndex)
|
||||
{
|
||||
var market1 = gameState.updatingCollection("OwnMarkets", API3.Filters.byClass("Market"), gameState.getOwnStructures()).toEntityArray();
|
||||
var market2 = gameState.updatingCollection("ExclusiveAllyMarkets", API3.Filters.byClass("Market"), gameState.getExclusiveAllyEntities()).toEntityArray();
|
||||
let market1 = gameState.updatingCollection("OwnMarkets", API3.Filters.byClass("Market"), gameState.getOwnStructures()).toEntityArray();
|
||||
let market2 = gameState.updatingCollection("ExclusiveAllyMarkets", API3.Filters.byClass("Market"), gameState.getExclusiveAllyEntities()).toEntityArray();
|
||||
if (market1.length + market2.length < 2) // We have to wait ... markets will be built soon
|
||||
{
|
||||
this.tradeRoute = undefined;
|
||||
|
|
@ -386,29 +390,29 @@ m.TradeManager.prototype.checkRoutes = function(gameState, accessIndex)
|
|||
|
||||
if (!market2.length)
|
||||
market2 = market1;
|
||||
var candidate = { "gain": 0 };
|
||||
var potential = { "gain": 0 };
|
||||
var bestIndex = { "gain": 0 };
|
||||
var bestLand = { "gain": 0 };
|
||||
let candidate = { "gain": 0 };
|
||||
let potential = { "gain": 0 };
|
||||
let bestIndex = { "gain": 0 };
|
||||
let bestLand = { "gain": 0 };
|
||||
|
||||
let traderTemplatesGains = gameState.getTraderTemplatesGains();
|
||||
|
||||
for (var m1 of market1)
|
||||
for (let m1 of market1)
|
||||
{
|
||||
if (!m1.position())
|
||||
continue;
|
||||
var access1 = gameState.ai.accessibility.getAccessValue(m1.position());
|
||||
var sea1 = m1.hasClass("NavalMarket") ? gameState.ai.HQ.navalManager.getDockIndex(gameState, m1, true) : undefined;
|
||||
for (var m2 of market2)
|
||||
let access1 = gameState.ai.accessibility.getAccessValue(m1.position());
|
||||
let sea1 = m1.hasClass("NavalMarket") ? gameState.ai.HQ.navalManager.getDockIndex(gameState, m1, true) : undefined;
|
||||
for (let m2 of market2)
|
||||
{
|
||||
if (m1.id() === m2.id())
|
||||
continue;
|
||||
if (!m2.position())
|
||||
continue;
|
||||
var access2 = gameState.ai.accessibility.getAccessValue(m2.position());
|
||||
var sea2 = m2.hasClass("NavalMarket") ? gameState.ai.HQ.navalManager.getDockIndex(gameState, m2, true) : undefined;
|
||||
var land = access1 == access2 ? access1 : undefined;
|
||||
var sea = (sea1 && sea1 == sea2) ? sea1 : undefined;
|
||||
let access2 = gameState.ai.accessibility.getAccessValue(m2.position());
|
||||
let sea2 = m2.hasClass("NavalMarket") ? gameState.ai.HQ.navalManager.getDockIndex(gameState, m2, true) : undefined;
|
||||
let land = access1 == access2 ? access1 : undefined;
|
||||
let sea = (sea1 && sea1 == sea2) ? sea1 : undefined;
|
||||
if (!land && !sea)
|
||||
continue;
|
||||
let gainMultiplier;
|
||||
|
|
@ -499,10 +503,10 @@ m.TradeManager.prototype.checkRoutes = function(gameState, accessIndex)
|
|||
return true;
|
||||
};
|
||||
|
||||
// Called when a market was built or destroyed, and checks if trader orders should be changed
|
||||
/** Called when a market was built or destroyed, and checks if trader orders should be changed */
|
||||
m.TradeManager.prototype.checkTrader = function(gameState, ent)
|
||||
{
|
||||
var presentRoute = ent.getMetadata(PlayerID, "route");
|
||||
let presentRoute = ent.getMetadata(PlayerID, "route");
|
||||
if (!presentRoute)
|
||||
return;
|
||||
|
||||
|
|
@ -513,8 +517,8 @@ m.TradeManager.prototype.checkTrader = function(gameState, ent)
|
|||
return;
|
||||
}
|
||||
|
||||
var access = ent.hasClass("Ship") ? ent.getMetadata(PlayerID, "sea") : gameState.ai.accessibility.getAccessValue(ent.position());
|
||||
var possibleRoute = this.checkRoutes(gameState, access);
|
||||
let access = ent.hasClass("Ship") ? ent.getMetadata(PlayerID, "sea") : gameState.ai.accessibility.getAccessValue(ent.position());
|
||||
let possibleRoute = this.checkRoutes(gameState, access);
|
||||
// Warning: presentRoute is from metadata, so contains entity ids
|
||||
if (!possibleRoute ||
|
||||
(possibleRoute.source.id() != presentRoute.source && possibleRoute.source.id() != presentRoute.target) ||
|
||||
|
|
@ -535,11 +539,11 @@ m.TradeManager.prototype.prospectForNewMarket = function(gameState, queues)
|
|||
if (!gameState.updatingCollection("OwnMarkets", API3.Filters.byClass("Market"), gameState.getOwnStructures()).length &&
|
||||
!gameState.updatingCollection("ExclusiveAllyMarkets", API3.Filters.byClass("Market"), gameState.getExclusiveAllyEntities()).length)
|
||||
return;
|
||||
var template = gameState.getTemplate(gameState.applyCiv("structures/{civ}_market"));
|
||||
let template = gameState.getTemplate(gameState.applyCiv("structures/{civ}_market"));
|
||||
if (!template)
|
||||
return;
|
||||
this.checkRoutes(gameState);
|
||||
var marketPos = gameState.ai.HQ.findMarketLocation(gameState, template);
|
||||
let marketPos = gameState.ai.HQ.findMarketLocation(gameState, template);
|
||||
if (!marketPos || marketPos[3] === 0) // marketPos[3] is the expected gain
|
||||
{ // no position found
|
||||
gameState.ai.HQ.stopBuild(gameState, "structures/{civ}_market");
|
||||
|
|
@ -582,7 +586,7 @@ m.TradeManager.prototype.update = function(gameState, events, queues)
|
|||
if (this.routeProspection)
|
||||
this.prospectForNewMarket(gameState, queues);
|
||||
|
||||
var self = this;
|
||||
let self = this;
|
||||
|
||||
if (this.checkEvents(gameState, events)) // true if one market was built or destroyed
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in a new issue