Okay, lots of changes here. Houses are now built on demand, there's a lot of restructuring to workers, instead of a static defence force citizen soliders are drafted to a militia as needed (this needs some work still but is mostly done). Any citizen infantry given at the start of a game are used in the workforce properly now, too.

This was SVN commit r10310.
This commit is contained in:
James Baillie 2011-09-24 15:26:11 +00:00
parent 17076f2561
commit b9fc207437
3 changed files with 265 additions and 197 deletions

View File

@ -6,6 +6,8 @@ var EconomyManager = Class({
this.targetNumWorkers = 55; // minimum number of workers we want
this.targetNumBuilders = 6; // number of workers we want working on construction
this.changetimeRegBui = 180*1000;
this.changetimeWorkers = 60*1000;
this.worknumbers = 1.5;
// (This is a stupid design where we just construct certain numbers
// of certain buildings in sequence)
// Greek building list
@ -27,11 +29,6 @@ var EconomyManager = Class({
"priority": 500,
"count": 1,
},
{
"template": "structures/{civ}_house",
"priority": 110,
"count": 2,
},
{
"template": "structures/{civ}_scout_tower",
"priority": 105,
@ -47,11 +44,6 @@ var EconomyManager = Class({
"priority": 101,
"count": 1,
},
{
"template": "structures/{civ}_house",
"priority": 100,
"count": 5,
},
{
"template": "structures/{civ}_scout_tower",
"priority": 90,
@ -72,31 +64,16 @@ var EconomyManager = Class({
"priority": 60,
"count": 1,
},
{
"template": "structures/{civ}_house",
"priority": 55,
"count": 10,
},
{
"template": "structures/{civ}_scout_tower",
"priority": 50,
"count": 5,
},
{
"template": "structures/{civ}_house",
"priority": 45,
"count": 15,
},
{
"template": "structures/{civ}_field",
"priority": 40,
"count": 3,
},
{
"template": "structures/{civ}_house",
"priority": 30,
"count": 20,
},
];
}
// Celt building list
@ -106,16 +83,11 @@ var EconomyManager = Class({
"template": "structures/{civ}_civil_centre",
"priority": 500,
"count": 1,
},
{
"template": "structures/{civ}_house",
"priority": 110,
"count": 6,
},
{
"template": "structures/{civ}_field",
"priority": 100,
"count": 2,
"count": 1,
},
{
"template": "structures/{civ}_barracks",
@ -132,21 +104,11 @@ var EconomyManager = Class({
"priority": 60,
"count": 3,
},
{
"template": "structures/{civ}_house",
"priority": 55,
"count": 15,
},
{
"template": "structures/{civ}_field",
"priority": 40,
"count": 3,
},
{
"template": "structures/{civ}_house",
"priority": 30,
"count": 25,
},
];
}
// Carthage building list
@ -156,16 +118,11 @@ var EconomyManager = Class({
"template": "structures/{civ}_civil_centre",
"priority": 500,
"count": 1,
},
{
"template": "structures/{civ}_house",
"priority": 110,
"count": 6,
},
{
"template": "structures/{civ}_field",
"priority": 100,
"count": 2,
"count": 1,
},
{
"template": "structures/{civ}_barracks",
@ -187,11 +144,6 @@ var EconomyManager = Class({
"priority": 70,
"count": 3,
},
{
"template": "structures/{civ}_house",
"priority": 55,
"count": 15,
},
{
"template": "structures/cart_embassy_celtic",
"priority": 50,
@ -212,11 +164,6 @@ var EconomyManager = Class({
"priority": 40,
"count": 3,
},
{
"template": "structures/{civ}_house",
"priority": 30,
"count": 25,
},
];
}
// Celt building list
@ -226,16 +173,11 @@ var EconomyManager = Class({
"template": "structures/{civ}_civil_centre",
"priority": 500,
"count": 1,
},
{
"template": "structures/{civ}_house",
"priority": 110,
"count": 6,
},
{
"template": "structures/{civ}_field",
"priority": 100,
"count": 2,
"count": 1,
},
{
"template": "structures/{civ}_barracks",
@ -252,21 +194,11 @@ var EconomyManager = Class({
"priority": 70,
"count": 3,
},
{
"template": "structures/{civ}_house",
"priority": 55,
"count": 15,
},
{
"template": "structures/{civ}_field",
"priority": 40,
"count": 3,
},
{
"template": "structures/{civ}_house",
"priority": 30,
"count": 25,
},
];
}
@ -278,20 +210,10 @@ var EconomyManager = Class({
"priority": 500,
"count": 1,
},
{
"template": "structures/{civ}_house",
"priority": 110,
"count": 2,
},
{
"template": "structures/{civ}_scout_tower",
"priority": 105,
"count": 1,
},
{
"template": "structures/{civ}_house",
"priority": 100,
"count": 5,
},
{
"template": "structures/{civ}_field",
@ -303,31 +225,16 @@ var EconomyManager = Class({
"priority": 99,
"count": 1,
},
{
"template": "structures/{civ}_house",
"priority": 98,
"count": 7,
},
{
"template": "structures/{civ}_scout_tower",
"priority": 60,
"count": 4,
},
{
"template": "structures/{civ}_house",
"priority": 55,
"count": 15,
},
{
"template": "structures/{civ}_field",
"priority": 40,
"count": 5,
},
{
"template": "structures/{civ}_house",
"priority": 30,
"count": 20,
},
];
}
},
@ -336,9 +243,22 @@ var EconomyManager = Class({
buildMoreBuildings: function(gameState, planGroups)
{
// Limit ourselves to constructing two buildings at a time
if (gameState.findFoundations().length > 1)
if (gameState.findFoundations().length > 0)
return;
var pop = gameState.getPopulation();
var poplim = gameState.getPopulationLimit();
var space = poplim - pop;
if (space < 9) {
planGroups.economyConstruction.addPlan(160,
new BuildingConstructionPlan(gameState, "structures/{civ}_house", 1)
);
}
if (gameState.findFoundations().length > 0)
return;
for each (var building in this.targetBuildings)
{
var numBuildings = gameState.countEntitiesAndQueuedWithType(gameState.applyCiv(building.template));
@ -355,87 +275,98 @@ var EconomyManager = Class({
trainMoreWorkers: function(gameState, planGroups)
{
if (gameState.getTimeElapsed() > this.changetime){
this.worknumbers = Math.random()*2;
this.changetimeWorkers = this.changetime + (30*1000);
}
// Count the workers in the world and in progress
var numWorkers = gameState.countEntitiesAndQueuedWithRole("worker");
var numWorkers = gameState.countEntitiesAndQueuedWithRoles("worker", "militia");
var workNumMod = this.worknumbers;
var miliNo = gameState.countEntitiesAndQueuedWithRole("militia");
var workNo = gameState.countEntitiesAndQueuedWithRole("worker");
if (miliNo > workNo){
workNumMod = workNumMod - 0.6;
}
// If we have too few, train another
// print("Want "+this.targetNumWorkers+" workers; got "+numWorkers+"\n");
if (numWorkers < this.baseNumWorkers)
{
var menorwomen = Math.random()*2;
if (gameState.displayCiv() == "hele" || gameState.displayCiv() == "celt"){
if (menorwomen < 1.5){
planGroups.economyPersonnel.addPlan(120,
new UnitTrainingPlan(gameState,
"units/{civ}_support_female_citizen", 2, { "role": "worker" })
);
}
else if (menorwomen > 1.82) {
planGroups.economyPersonnel.addPlan(120,
new UnitTrainingPlan(gameState,
"units/{civ}_infantry_spearman_b", 2, { "role": "worker" })
);
}
else {
planGroups.economyPersonnel.addPlan(120,
new UnitTrainingPlan(gameState,
"units/{civ}_infantry_javelinist_b", 2, { "role": "worker" })
);
}
}
else {
if (menorwomen < 1.5){
planGroups.economyPersonnel.addPlan(120,
new UnitTrainingPlan(gameState,
"units/{civ}_support_female_citizen", 2, { "role": "worker" })
);
}
else {
planGroups.economyPersonnel.addPlan(120,
new UnitTrainingPlan(gameState,
"units/{civ}_infantry_swordsman_b", 2, { "role": "worker" })
);
}
}
var priority = 180;
}
else if (numWorkers < this.targetNumWorkers)
{
var menorwomen = Math.random()*2;
if (gameState.displayCiv() == "hele" || gameState.displayCiv() == "celt"){
if (menorwomen < 1.5){
planGroups.economyPersonnel.addPlan(90,
var priority = 140;
}
if (gameState.displayCiv() == "hele" || gameState.displayCiv() == "celt"){
if (workNumMod < 0.95){
planGroups.economyPersonnel.addPlan(priority,
new UnitTrainingPlan(gameState,
"units/{civ}_support_female_citizen", 2, { "role": "worker" })
);
}
else if (menorwomen > 1.82) {
planGroups.economyPersonnel.addPlan(90,
else if (workNumMod > 1.6) {
planGroups.economyPersonnel.addPlan(priority,
new UnitTrainingPlan(gameState,
"units/{civ}_infantry_spearman_b", 2, { "role": "worker" })
"units/{civ}_infantry_spearman_b", 2, { "role": "militia" })
);
}
else {
planGroups.economyPersonnel.addPlan(90,
planGroups.economyPersonnel.addPlan(priority,
new UnitTrainingPlan(gameState,
"units/{civ}_infantry_javelinist_b", 2, { "role": "worker" })
"units/{civ}_infantry_javelinist_b", 2, { "role": "militia" })
);
}
}
else {
if (menorwomen < 1.5){
planGroups.economyPersonnel.addPlan(90,
new UnitTrainingPlan(gameState,
"units/{civ}_support_female_citizen", 2, { "role": "worker" })
);
}
else {
planGroups.economyPersonnel.addPlan(90,
new UnitTrainingPlan(gameState,
"units/{civ}_infantry_swordsman_b", 2, { "role": "worker" })
);
}
}
}
else if (gameState.displayCiv() == "cart"){
if (workNumMod < 0.95){
planGroups.economyPersonnel.addPlan(priority,
new UnitTrainingPlan(gameState,
"units/{civ}_support_female_citizen", 2, { "role": "worker" })
);
}
else if (workNumMod > 1.6) {
planGroups.economyPersonnel.addPlan(priority,
new UnitTrainingPlan(gameState,
"units/{civ}_infantry_spearman_b", 2, { "role": "militia" })
);
}
else {
planGroups.economyPersonnel.addPlan(priority,
new UnitTrainingPlan(gameState,
"units/{civ}_infantry_archer_b", 2, { "role": "militia" })
);
}
}
else if (gameState.displayCiv() == "iber"){
if (workNumMod < 0.95){
planGroups.economyPersonnel.addPlan(priority,
new UnitTrainingPlan(gameState,
"units/{civ}_support_female_citizen", 2, { "role": "worker" })
);
}
else if (workNumMod > 1.6) {
planGroups.economyPersonnel.addPlan(priority,
new UnitTrainingPlan(gameState,
"units/{civ}_infantry_swordsman_b", 2, { "role": "militia" })
);
}
else {
planGroups.economyPersonnel.addPlan(priority,
new UnitTrainingPlan(gameState,
"units/{civ}_infantry_javelinist_b", 2, { "role": "militia" })
);
}
}
else {
planGroups.economyPersonnel.addPlan(priority,
new UnitTrainingPlan(gameState,
"units/{civ}_support_female_citizen", 2, { "role": "worker" })
);
}
},
pickMostNeededResources: function(gameState)
@ -451,6 +382,10 @@ var EconomyManager = Class({
if (ent.getMetadata("subrole") === "gatherer")
numGatherers[ent.getMetadata("gather-type")] += 1;
});
gameState.getOwnEntitiesWithRole("militia").forEach(function(ent) {
if (ent.getMetadata("subrole") === "gatherer")
numGatherers[ent.getMetadata("gather-type")] += 1;
});
var types = Object.keys(this.gatherWeights);
types.sort(function(a, b) {
@ -467,11 +402,46 @@ var EconomyManager = Class({
{
var roleless = gameState.getOwnEntitiesWithRole(undefined);
roleless.forEach(function(ent) {
if (ent.hasClass("Worker"))
if (ent.hasClass("Worker")){
ent.setMetadata("role", "worker");
else
}
else if (ent.hasClass("CitizenSoldier") && ent.hasClass("Infantry")){
var currentPosition = ent.position();
var targets = gameState.entities.filter(function(enten) {
var foeposition = enten.position();
if (foeposition){
var dist = VectorDistance(foeposition, currentPosition);
return (enten.isEnemy() && enten.owner()!= 0 && dist < 50);
}
else {
return false;
}
});
if (targets.length == 0){
// If we're clear go back to work
ent.setMetadata("role", "militia");
}
else {
// If not, go home!
var targets = gameState.entities.filter(function(squeak) {
return (!squeak.isEnemy() && squeak.hasClass("Village"));
});
// If we have a target, move to it
if (targets.length)
{
var targetrandomiser = Math.floor(Math.random()*targets.length);
var target = targets.toEntityArray()[targetrandomiser];
var targetPos = target.position();
// TODO: this should be an attack-move command
ent.move(targetPos[0], targetPos[1]);
}
}
}
else {
ent.setMetadata("role", "randomcannonfodder");
}
});
},
@ -484,7 +454,7 @@ var EconomyManager = Class({
// later we could add some timer that redistributes workers based on
// resource demand.
var idleWorkers = gameState.getOwnEntitiesWithRole("worker").filter(function(ent) {
var idleWorkers = gameState.getOwnEntitiesWithTwoRoles("worker", "militia").filter(function(ent) {
return ent.isIdle();
});
@ -621,7 +591,7 @@ var EconomyManager = Class({
if (!foundations.length)
return;
var workers = gameState.getOwnEntitiesWithRole("worker");
var workers = gameState.getOwnEntitiesWithTwoRoles("worker", "militia");
var builderWorkers = workers.filter(function(ent) {
return (ent.getMetadata("subrole") === "builder");
@ -653,7 +623,7 @@ var EconomyManager = Class({
buildRegroup: function(gameState, planGroups)
{
if (gameState.getTimeElapsed() > this.changetimeRegBui){
var buildregroupers = gameState.getOwnEntitiesWithRole("worker");
var buildregroupers = gameState.getOwnEntitiesWithTwoRoles("worker", "militia");
buildregroupers.forEach(function(shirk) {
if (shirk.getMetadata("subrole") == "builder"){
var targets = gameState.entities.filter(function(ent) {

View File

@ -78,6 +78,32 @@ var GameState = Class({
});
}),
getOwnEntitiesWithTwoRoles: Memoize('getOwnEntitiesWithRole', function(role, role2)
{
var metas = this.ai._entityMetadata;
if (role === undefined)
return this.getOwnEntities().filter_raw(function(ent) {
var metadata = metas[ent.id];
if (!metadata || !('role' in metadata))
return true;
return (metadata.role === undefined);
});
else if (role2 === undefined)
return this.getOwnEntities().filter_raw(function(ent) {
var metadata = metas[ent.id];
if (!metadata || !('role' in metadata))
return true;
return (metadata.role === undefined);
});
else
return this.getOwnEntities().filter_raw(function(ent) {
var metadata = metas[ent.id];
if (!metadata || !('role' in metadata))
return false;
return (metadata.role === role || metadata.role === role2);
});
}),
countEntitiesWithType: function(type)
{
var count = 0;
@ -131,6 +157,30 @@ var GameState = Class({
return count;
},
countEntitiesAndQueuedWithRoles: function(role, role2)
{
var count = 0;
this.getOwnEntities().forEach(function(ent) {
if (ent.getMetadata("role") == role)
++count;
else if (ent.getMetadata("role") == role2)
++count;
var queue = ent.trainingQueue();
if (queue)
{
queue.forEach(function(item) {
if (item.metadata && item.metadata.role == role)
count += item.count;
else if (item.metadata && item.metadata.role == role2)
count += item.count;
});
}
});
return count;
},
/**
* Find buildings that are capable of training the given unit type,
* and aren't already too busy.
@ -207,4 +257,14 @@ var GameState = Class({
});
return supplies;
},
getPopulationLimit: function()
{
return this.playerData.popLimit;
},
getPopulation: function()
{
return this.playerData.popCount;
}
});

View File

@ -12,12 +12,12 @@ var MilitaryAttackManager = Class({
{
this.baserate = 11;
this.defsquad = 10;
this.defsquadmin = 2;
this.defsquadmin = 5;
this.findatype = 1;
this.killstrat = 0;
this.changetime = 60*1000;
this.changetimeReg = 60*5000;
this.changetimeRegDef = 60*5000;
this.changetimeRegDef = 60*1000;
this.changetimeRegWaiting = 60*4000;
this.attacknumbers = 0.4
this.squadTypes = [
@ -222,24 +222,69 @@ var MilitaryAttackManager = Class({
}
});
},
combatcheck_militia: function(gameState, planGroups, assaultgroup)
{
var regroupneeded = gameState.getOwnEntitiesWithRole(assaultgroup);
regroupneeded.forEach(function(troop) {
var currentPosition = troop.position();
// Find nearby enemies
var targets = gameState.entities.filter(function(ent) {
var foeposition = ent.position();
if (foeposition){
var dist = VectorDistance(foeposition, currentPosition);
return (ent.isEnemy() && ent.owner()!= 0 && dist < 50);
}
else {
return false;
}
});
// Check that some of our own buildings are nearby
var ownbuildings = gameState.getOwnEntities.filter(function(ent) {
var foeposition = ent.position();
if (foeposition){
var dist = VectorDistance(foeposition, currentPosition);
return (dist < 50 && ent.hasClass("Village"));
}
else {
return false;
}
});
if (targets.length >= 5 && ownbuildings.length > 0){
regroupneeded.forEach(function(person) {
var targetrandomiser = Math.floor(Math.random()*targets.length);
var target = targets.toEntityArray()[targetrandomiser];
var targetPos = target.position();
// TODO: this should be an attack-move command
person.move(targetPos[0], targetPos[1]);
person.setMetadata("role", "militiafighter");
});
}
});
},
defenseregroup: function(gameState, planGroups)
{
if (gameState.getTimeElapsed() > this.changetimeRegDef){
var defenseregroupers = gameState.getOwnEntitiesWithRole("defenders");
//Find a friendsly CC
var targets = gameState.entities.filter(function(ent) {
return (!ent.isEnemy() && ent.hasClass("CivCentre"));
// Send them home
var targets = gameState.entities.filter(function(squeak) {
return (!squeak.isEnemy() && squeak.hasClass("Village"));
});
if (targets.length){
var target = targets.toEntityArray()[0];
if (targets.length)
{
var targetrandomiser = Math.floor(Math.random()*targets.length);
var target = targets.toEntityArray()[targetrandomiser];
var targetPos = target.position();
// TODO: this should be an attack-move command
defenseregroupers.move(targetPos[0], targetPos[1]);
}
// Wait 4 mins to do this again.
this.changetimeRegDef = this.changetimeRegDef + (60*1500);
// Change 'em back to militia
var defenseregroupers = gameState.getOwnEntitiesWithRole("militiafighter");
defenseregroupers.forEach(function(ent) {
// If we have a target to go home to, move to it
ent.move(targetPos[0], targetPos[1]);
ent.setMetadata("role", "militia");
});
// Wait 45 secs to do this again.
this.changetimeRegDef = this.changetimeRegDef + (30*1000);
}
},
@ -314,27 +359,27 @@ var MilitaryAttackManager = Class({
var pendingdefense = gameState.getOwnEntitiesWithRole("defenders");
//JuBotAI.prototype.chat("Number of defenders is" + pendingdefense.length);
if (pendingdefense.length < this.defsquadmin && gameState.displayCiv() == "iber"){
planGroups.economyPersonnel.addPlan(122,
planGroups.economyPersonnel.addPlan(500,
new UnitTrainingPlan(gameState,
"units/{civ}_infantry_swordsman_b", 3, { "role": "defenders" })
);
}
else if (pendingdefense.length < this.defsquadmin){
planGroups.economyPersonnel.addPlan(122,
planGroups.economyPersonnel.addPlan(500,
new UnitTrainingPlan(gameState,
"units/{civ}_infantry_spearman_b", 3, { "role": "defenders" })
);
//JuBotAI.prototype.chat("Training defenders");
}
else if (pendingdefense.length < this.defsquad && gameState.displayCiv() == "iber"){
planGroups.economyPersonnel.addPlan(110,
planGroups.economyPersonnel.addPlan(150,
new UnitTrainingPlan(gameState,
"units/{civ}_infantry_swordsman_b", 3, { "role": "defenders" })
);
//JuBotAI.prototype.chat("Training defenders");
}
else if (pendingdefense.length < this.defsquad){
planGroups.economyPersonnel.addPlan(110,
planGroups.economyPersonnel.addPlan(150,
new UnitTrainingPlan(gameState,
"units/{civ}_infantry_spearman_b", 3, { "role": "defenders" })
);
@ -346,7 +391,7 @@ var MilitaryAttackManager = Class({
{
var trainers = gameState.findTrainers(gameState.applyCiv(type));
if (trainers.length != 0){
planGroups.economyPersonnel.addPlan(100,
planGroups.economyPersonnel.addPlan(150,
new UnitTrainingPlan(gameState,
type, 3, { "role": "attack-pending" })
);
@ -360,7 +405,7 @@ var MilitaryAttackManager = Class({
{
var trainers = gameState.findTrainers(gameState.applyCiv(type));
if (trainers.length != 0){
planGroups.economyPersonnel.addPlan(100,
planGroups.economyPersonnel.addPlan(150,
new UnitTrainingPlan(gameState,
type, 1, { "role": "attack-pending" })
);
@ -375,19 +420,19 @@ var MilitaryAttackManager = Class({
var trainers = gameState.findTrainers(gameState.applyCiv(type));
var section = Math.random();
if (trainers.length != 0 && section < 0.3){
planGroups.economyPersonnel.addPlan(100,
planGroups.economyPersonnel.addPlan(150,
new UnitTrainingPlan(gameState,
type, 3, { "role": "attack-pending_3p1" })
);
}
else if (trainers.length != 0 && section < 0.6){
planGroups.economyPersonnel.addPlan(100,
planGroups.economyPersonnel.addPlan(150,
new UnitTrainingPlan(gameState,
type, 3, { "role": "attack-pending_3p2" })
);
}
else if (trainers.length != 0){
planGroups.economyPersonnel.addPlan(100,
planGroups.economyPersonnel.addPlan(150,
new UnitTrainingPlan(gameState,
type, 3, { "role": "attack-pending_3p3" })
);
@ -656,7 +701,8 @@ var MilitaryAttackManager = Class({
this.combatcheck(gameState, planGroups, "attack_3p1");
this.combatcheck(gameState, planGroups, "attack_3p2");
this.combatcheck(gameState, planGroups, "attack_3p3");
this.trainDefenderSquad(gameState, planGroups);
this.combatcheck(gameState, planGroups, "militia");
//this.trainDefenderSquad(gameState, planGroups);
this.trainAttackSquad(gameState, planGroups);
this.regroup(gameState, planGroups);
this.defenseregroup(gameState, planGroups);
@ -815,25 +861,17 @@ var MilitaryAttackManager = Class({
if (whatnext > 0.8){
this.killstrat = 0;
// Regular "train a few guys and go kill stuff" type attack.
//JuBotAI.prototype.chat("Regular attack (" + gameState.displayCiv() + ")");
//JuBotAI.prototype.chat(whatnext);
}
else if (whatnext > 0.5) {
this.killstrat = 2;
//JuBotAI.prototype.chat("Cavalry raid (" + gameState.displayCiv() + ")");
//JuBotAI.prototype.chat(whatnext);
// Cavalry raid
}
else if (whatnext > 0.4) {
this.killstrat = 3;
//JuBotAI.prototype.chat("3 pronged assault (" + gameState.displayCiv() + ")");
//JuBotAI.prototype.chat(whatnext);
// 3 prong
}
else {
this.killstrat = 1;
//JuBotAI.prototype.chat("Full assault (" + gameState.displayCiv() + ")");
//JuBotAI.prototype.chat(whatnext);
//Full Assault!
}
}