Changeset View
Changeset View
Standalone View
Standalone View
ps/trunk/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
Show First 20 Lines • Show All 164 Lines • ▼ Show 20 Lines | else | ||||
this.unitStat.FastMoving = { "priority": 1, "minSize": 2, "targetSize": 6, "batchSize": 2, "classes": ["FastMoving+CitizenSoldier"], | this.unitStat.FastMoving = { "priority": 1, "minSize": 2, "targetSize": 6, "batchSize": 2, "classes": ["FastMoving+CitizenSoldier"], | ||||
"interests": [["strength", 1]] }; | "interests": [["strength", 1]] }; | ||||
this.neededShips = 3; | this.neededShips = 3; | ||||
} | } | ||||
// Put some randomness on the attack size | // Put some randomness on the attack size | ||||
let variation = randFloat(0.8, 1.2); | let variation = randFloat(0.8, 1.2); | ||||
// and lower priority and smaller sizes for easier difficulty levels | // and lower priority and smaller sizes for easier difficulty levels | ||||
if (this.Config.difficulty < 2) | if (this.Config.difficulty < PETRA.DIFFICULTY_EASY) | ||||
{ | { | ||||
priority *= 0.4; | priority *= 0.4; | ||||
variation *= 0.2; | variation *= 0.2; | ||||
} | } | ||||
else if (this.Config.difficulty < 3) | else if (this.Config.difficulty < PETRA.DIFFICULTY_MEDIUM) | ||||
{ | { | ||||
priority *= 0.8; | priority *= 0.8; | ||||
variation *= 0.6; | variation *= 0.6; | ||||
} | } | ||||
if (this.Config.difficulty < 2) | if (this.Config.difficulty < PETRA.DIFFICULTY_EASY) | ||||
{ | { | ||||
for (const cat in this.unitStat) | for (const cat in this.unitStat) | ||||
{ | { | ||||
this.unitStat[cat].targetSize = Math.ceil(variation * this.unitStat[cat].targetSize); | this.unitStat[cat].targetSize = Math.ceil(variation * this.unitStat[cat].targetSize); | ||||
this.unitStat[cat].minSize = Math.min(this.unitStat[cat].targetSize, Math.min(this.unitStat[cat].minSize, 2)); | this.unitStat[cat].minSize = Math.min(this.unitStat[cat].targetSize, Math.min(this.unitStat[cat].minSize, 2)); | ||||
this.unitStat[cat].batchSize = this.unitStat[cat].minSize; | this.unitStat[cat].batchSize = this.unitStat[cat].minSize; | ||||
} | } | ||||
} | } | ||||
▲ Show 20 Lines • Show All 224 Lines • ▼ Show 20 Lines | PETRA.AttackPlan.prototype.addSiegeUnits = function(gameState) | ||||
{ | { | ||||
if (hasTrainer[i]) | if (hasTrainer[i]) | ||||
break; | break; | ||||
i = ++i % classes.length; | i = ++i % classes.length; | ||||
} | } | ||||
this.siegeState = PETRA.AttackPlan.SIEGE_ADDED; | this.siegeState = PETRA.AttackPlan.SIEGE_ADDED; | ||||
let targetSize; | let targetSize; | ||||
if (this.Config.difficulty < 3) | if (this.Config.difficulty < PETRA.DIFFICULTY_MEDIUM) | ||||
targetSize = this.type === PETRA.AttackPlan.TYPE_HUGE_ATTACK ? Math.max(this.Config.difficulty, 1) : Math.max(this.Config.difficulty - 1, 0); | targetSize = this.type === PETRA.AttackPlan.TYPE_HUGE_ATTACK ? Math.max(this.Config.difficulty, 1) : Math.max(this.Config.difficulty - 1, 0); | ||||
else | else | ||||
targetSize = this.type === PETRA.AttackPlan.TYPE_HUGE_ATTACK ? this.Config.difficulty + 1 : this.Config.difficulty - 1; | targetSize = this.type === PETRA.AttackPlan.TYPE_HUGE_ATTACK ? this.Config.difficulty + 1 : this.Config.difficulty - 1; | ||||
targetSize = Math.max(Math.round(this.Config.popScaling * targetSize), this.type === PETRA.AttackPlan.TYPE_HUGE_ATTACK ? 1 : 0); | targetSize = Math.max(Math.round(this.Config.popScaling * targetSize), this.type === PETRA.AttackPlan.TYPE_HUGE_ATTACK ? 1 : 0); | ||||
if (!targetSize) | if (!targetSize) | ||||
return true; | return true; | ||||
// no minsize as we don't want the plan to fail at the last minute though. | // no minsize as we don't want the plan to fail at the last minute though. | ||||
let stat = { "priority": 1, "minSize": 0, "targetSize": targetSize, "batchSize": Math.min(targetSize, 2), | let stat = { "priority": 1, "minSize": 0, "targetSize": targetSize, "batchSize": Math.min(targetSize, 2), | ||||
▲ Show 20 Lines • Show All 147 Lines • ▼ Show 20 Lines | PETRA.AttackPlan.prototype.updatePreparation = function(gameState) | ||||
for (let ent of this.unitCollection.values()) | 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 | // For the time being, if occupied in a transport, remove the unit from this plan TODO improve that | ||||
if (ent.getMetadata(PlayerID, "transport") !== undefined || ent.getMetadata(PlayerID, "transporter") !== undefined) | if (ent.getMetadata(PlayerID, "transport") !== undefined || ent.getMetadata(PlayerID, "transporter") !== undefined) | ||||
{ | { | ||||
ent.setMetadata(PlayerID, "plan", -1); | ent.setMetadata(PlayerID, "plan", -1); | ||||
continue; | continue; | ||||
} | } | ||||
ent.setMetadata(PlayerID, "role", "attack"); | ent.setMetadata(PlayerID, "role", PETRA.Worker.ROLE_ATTACK); | ||||
ent.setMetadata(PlayerID, "subrole", "completing"); | ent.setMetadata(PlayerID, "subrole", PETRA.Worker.SUBROLE_COMPLETING); | ||||
let queued = false; | let queued = false; | ||||
if (ent.resourceCarrying() && ent.resourceCarrying().length) | if (ent.resourceCarrying() && ent.resourceCarrying().length) | ||||
queued = PETRA.returnResources(gameState, ent); | queued = PETRA.returnResources(gameState, ent); | ||||
let index = PETRA.getLandAccess(gameState, ent); | let index = PETRA.getLandAccess(gameState, ent); | ||||
if (index == rallyIndex) | if (index == rallyIndex) | ||||
ent.moveToRange(rallyPoint[0], rallyPoint[1], 0, 15, queued); | ent.moveToRange(rallyPoint[0], rallyPoint[1], 0, 15, queued); | ||||
else | else | ||||
gameState.ai.HQ.navalManager.requireTransport(gameState, ent, index, rallyIndex, rallyPoint); | gameState.ai.HQ.navalManager.requireTransport(gameState, ent, index, rallyIndex, rallyPoint); | ||||
▲ Show 20 Lines • Show All 71 Lines • ▼ Show 20 Lines | if (queue.length() <= 5) | ||||
} | } | ||||
else | else | ||||
{ | { | ||||
if (this.Config.debug > 2) | if (this.Config.debug > 2) | ||||
API3.warn("attack template " + template + " added for plan " + this.name); | API3.warn("attack template " + template + " added for plan " + this.name); | ||||
let max = firstOrder[3].batchSize; | let max = firstOrder[3].batchSize; | ||||
let specialData = "Plan_" + this.name + "_" + firstOrder[4]; | let specialData = "Plan_" + this.name + "_" + firstOrder[4]; | ||||
let data = { "plan": this.name, "special": specialData, "base": 0 }; | let data = { "plan": this.name, "special": specialData, "base": 0 }; | ||||
data.role = gameState.getTemplate(template).hasClass("CitizenSoldier") ? "worker" : "attack"; | data.role = gameState.getTemplate(template).hasClass("CitizenSoldier") ? PETRA.Worker.ROLE_WORKER : PETRA.Worker.ROLE_ATTACK; | ||||
let trainingPlan = new PETRA.TrainingPlan(gameState, template, data, max, max); | let trainingPlan = new PETRA.TrainingPlan(gameState, template, data, max, max); | ||||
if (trainingPlan.template) | if (trainingPlan.template) | ||||
queue.addPlan(trainingPlan); | queue.addPlan(trainingPlan); | ||||
else if (this.Config.debug > 1) | else if (this.Config.debug > 1) | ||||
API3.warn("training plan canceled because no template for " + template + " build1 " + uneval(firstOrder[1]) + | API3.warn("training plan canceled because no template for " + template + " build1 " + uneval(firstOrder[1]) + | ||||
" build3 " + uneval(firstOrder[3].interests)); | " build3 " + uneval(firstOrder[3].interests)); | ||||
} | } | ||||
} | } | ||||
▲ Show 20 Lines • Show All 54 Lines • ▼ Show 20 Lines | for (let ent of gameState.ai.HQ.attackManager.outOfPlan.values()) | ||||
ent.setMetadata(PlayerID, "plan", plan); | ent.setMetadata(PlayerID, "plan", plan); | ||||
this.unitCollection.updateEnt(ent); | this.unitCollection.updateEnt(ent); | ||||
added = true; | added = true; | ||||
} | } | ||||
// Finally add also some workers for the higher difficulties, | // Finally add also some workers for the higher difficulties, | ||||
// If Rush, assign all kind of workers, keeping only a minimum number of defenders | // If Rush, assign all kind of workers, keeping only a minimum number of defenders | ||||
// Otherwise, assign only some idle workers if too much of them | // Otherwise, assign only some idle workers if too much of them | ||||
if (this.Config.difficulty <= 2) | if (this.Config.difficulty <= PETRA.DIFFICULTY_EASY) | ||||
return added; | return added; | ||||
let num = 0; | let num = 0; | ||||
const numbase = {}; | const numbase = {}; | ||||
let keep = this.type !== PETRA.AttackPlan.TYPE_RUSH ? | let keep = this.type !== PETRA.AttackPlan.TYPE_RUSH ? | ||||
6 + 4 * gameState.getNumPlayerEnemies() + 8 * this.Config.personality.defensive : 8; | 6 + 4 * gameState.getNumPlayerEnemies() + 8 * this.Config.personality.defensive : 8; | ||||
keep = Math.round(this.Config.popScaling * keep); | keep = Math.round(this.Config.popScaling * keep); | ||||
for (const ent of gameState.getOwnEntitiesByRole("worker", true).values()) | for (const ent of gameState.getOwnEntitiesByRole(PETRA.Worker.ROLE_WORKER, true).values()) | ||||
{ | { | ||||
if (!ent.hasClass("CitizenSoldier") || !this.isAvailableUnit(gameState, ent)) | if (!ent.hasClass("CitizenSoldier") || !this.isAvailableUnit(gameState, ent)) | ||||
continue; | continue; | ||||
const baseID = ent.getMetadata(PlayerID, "base"); | const baseID = ent.getMetadata(PlayerID, "base"); | ||||
if (baseID) | if (baseID) | ||||
numbase[baseID] = numbase[baseID] ? ++numbase[baseID] : 1; | numbase[baseID] = numbase[baseID] ? ++numbase[baseID] : 1; | ||||
else | else | ||||
{ | { | ||||
API3.warn("Petra problem ent without base "); | API3.warn("Petra problem ent without base "); | ||||
PETRA.dumpEntity(ent); | PETRA.dumpEntity(ent); | ||||
continue; | continue; | ||||
} | } | ||||
if (num++ < keep || numbase[baseID] < 5) | if (num++ < keep || numbase[baseID] < 5) | ||||
continue; | continue; | ||||
if (this.type !== PETRA.AttackPlan.TYPE_RUSH && ent.getMetadata(PlayerID, "subrole") != "idle") | if (this.type !== PETRA.AttackPlan.TYPE_RUSH && ent.getMetadata(PlayerID, "subrole") !== PETRA.Worker.SUBROLE_IDLE) | ||||
continue; | continue; | ||||
ent.setMetadata(PlayerID, "plan", plan); | ent.setMetadata(PlayerID, "plan", plan); | ||||
this.unitCollection.updateEnt(ent); | this.unitCollection.updateEnt(ent); | ||||
added = true; | added = true; | ||||
} | } | ||||
return added; | return added; | ||||
}; | }; | ||||
▲ Show 20 Lines • Show All 470 Lines • ▼ Show 20 Lines | if ((this.targetPlayer === undefined || !this.target || !gameState.getEntityById(this.target.id())) && | ||||
!this.chooseTarget(gameState)) | !this.chooseTarget(gameState)) | ||||
return false; | return false; | ||||
// erase our queue. This will stop any leftover unit from being trained. | // erase our queue. This will stop any leftover unit from being trained. | ||||
this.removeQueues(gameState); | this.removeQueues(gameState); | ||||
for (let ent of this.unitCollection.values()) | for (let ent of this.unitCollection.values()) | ||||
{ | { | ||||
ent.setMetadata(PlayerID, "subrole", "walking"); | ent.setMetadata(PlayerID, "subrole", PETRA.Worker.SUBROLE_WALKING); | ||||
let stance = ent.isPackable() ? "standground" : "aggressive"; | let stance = ent.isPackable() ? "standground" : "aggressive"; | ||||
if (ent.getStance() != stance) | if (ent.getStance() != stance) | ||||
ent.setStance(stance); | ent.setStance(stance); | ||||
} | } | ||||
let rallyAccess = gameState.ai.accessibility.getAccessValue(this.rallyPoint); | let rallyAccess = gameState.ai.accessibility.getAccessValue(this.rallyPoint); | ||||
let targetAccess = PETRA.getLandAccess(gameState, this.target); | let targetAccess = PETRA.getLandAccess(gameState, this.target); | ||||
if (rallyAccess == targetAccess) | if (rallyAccess == targetAccess) | ||||
▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | PETRA.AttackPlan.prototype.update = function(gameState, events) | ||||
if (this.state === PETRA.AttackPlan.STATE_ARRIVED) | if (this.state === PETRA.AttackPlan.STATE_ARRIVED) | ||||
{ | { | ||||
// let's proceed on with whatever happens now. | // let's proceed on with whatever happens now. | ||||
this.state = ""; | this.state = ""; | ||||
this.startingAttack = true; | this.startingAttack = true; | ||||
this.unitCollection.forEach(ent => { | this.unitCollection.forEach(ent => { | ||||
ent.stopMoving(); | ent.stopMoving(); | ||||
ent.setMetadata(PlayerID, "subrole", "attacking"); | ent.setMetadata(PlayerID, "subrole", PETRA.Worker.SUBROLE_ATTACKING); | ||||
}); | }); | ||||
if (this.type === PETRA.AttackPlan.TYPE_RUSH) // try to find a better target for rush | if (this.type === PETRA.AttackPlan.TYPE_RUSH) // try to find a better target for rush | ||||
{ | { | ||||
let newtarget = this.getNearestTarget(gameState, this.position); | let newtarget = this.getNearestTarget(gameState, this.position); | ||||
if (newtarget) | if (newtarget) | ||||
{ | { | ||||
this.target = newtarget; | this.target = newtarget; | ||||
this.targetPos = this.target.position(); | this.targetPos = this.target.position(); | ||||
▲ Show 20 Lines • Show All 708 Lines • ▼ Show 20 Lines | if (this.isStarted()) | ||||
continue; | continue; | ||||
dist = newdist; | dist = newdist; | ||||
rallyPoint = base.anchor.position(); | rallyPoint = base.anchor.position(); | ||||
} | } | ||||
} | } | ||||
for (let ent of this.unitCollection.values()) | for (let ent of this.unitCollection.values()) | ||||
{ | { | ||||
if (ent.getMetadata(PlayerID, "role") == "attack") | if (ent.getMetadata(PlayerID, "role") === PETRA.Worker.ROLE_ATTACK) | ||||
ent.stopMoving(); | ent.stopMoving(); | ||||
if (rallyPoint) | if (rallyPoint) | ||||
ent.moveToRange(rallyPoint[0], rallyPoint[1], 0, 15); | ent.moveToRange(rallyPoint[0], rallyPoint[1], 0, 15); | ||||
this.removeUnit(ent); | this.removeUnit(ent); | ||||
} | } | ||||
} | } | ||||
for (let unitCat in this.unitStat) | for (let unitCat in this.unitStat) | ||||
this.unit[unitCat].unregister(); | this.unit[unitCat].unregister(); | ||||
this.removeQueues(gameState); | this.removeQueues(gameState); | ||||
}; | }; | ||||
PETRA.AttackPlan.prototype.removeUnit = function(ent, update) | PETRA.AttackPlan.prototype.removeUnit = function(ent, update) | ||||
{ | { | ||||
if (ent.getMetadata(PlayerID, "role") == "attack") | if (ent.getMetadata(PlayerID, "role") === PETRA.Worker.ROLE_ATTACK) | ||||
{ | { | ||||
if (ent.hasClass("CitizenSoldier")) | if (ent.hasClass("CitizenSoldier")) | ||||
ent.setMetadata(PlayerID, "role", "worker"); | ent.setMetadata(PlayerID, "role", PETRA.Worker.ROLE_WORKER); | ||||
else | else | ||||
ent.setMetadata(PlayerID, "role", undefined); | ent.setMetadata(PlayerID, "role", undefined); | ||||
ent.setMetadata(PlayerID, "subrole", undefined); | ent.setMetadata(PlayerID, "subrole", undefined); | ||||
} | } | ||||
ent.setMetadata(PlayerID, "plan", -1); | ent.setMetadata(PlayerID, "plan", -1); | ||||
if (update) | if (update) | ||||
this.unitCollection.updateEnt(ent); | this.unitCollection.updateEnt(ent); | ||||
}; | }; | ||||
▲ Show 20 Lines • Show All 141 Lines • Show Last 20 Lines |
Wildfire Games · Phabricator