2013-12-30 11:04:59 +01:00
var AEGIS = function ( m )
{
2013-09-29 15:32:52 +02:00
/ * H e a d q u a r t e r s
* Deal with high level logic for the AI . Most of the interesting stuff gets done here .
* Some tasks :
- defining RESS needs
- BO decisions .
> training workers
> building stuff ( though we ' ll send that to bases )
> researching
- picking strategy ( specific manager ? )
- diplomacy ( specific manager ? )
- planning attacks
- picking new CC locations .
* /
2013-12-30 11:04:59 +01:00
m . HQ = function ( Config ) {
this . Config = Config ;
2014-01-10 02:46:27 +01:00
2013-12-30 11:04:59 +01:00
this . targetNumBuilders = this . Config . Economy . targetNumBuilders ; // number of workers we want building stuff
2014-01-11 19:51:37 +01:00
this . dockStartTime = this . Config . Economy . dockStartTime * 1000 ;
2013-12-30 11:04:59 +01:00
this . techStartTime = this . Config . Economy . techStartTime * 1000 ;
2013-09-29 15:32:52 +02:00
this . dockFailed = false ; // sanity check
this . waterMap = false ; // set by the aegis.js file.
2014-01-14 20:54:31 +01:00
this . econState = "growth" ; // existing values: growth, townPhasing.
2013-09-29 15:32:52 +02:00
// tell if we can't gather from a resource type for sanity checks.
this . outOf = { "food" : false , "wood" : false , "stone" : false , "metal" : false } ;
this . baseManagers = { } ;
2014-01-14 20:54:31 +01:00
// cache the rates.
this . wantedRates = { "food" : 0 , "wood" : 0 , "stone" : 0 , "metal" : 0 } ;
this . currentRates = { "food" : 0 , "wood" : 0 , "stone" : 0 , "metal" : 0 } ;
this . currentRateLastUpdateTime = 0 ;
2014-01-12 20:12:55 +01:00
2013-09-29 15:32:52 +02:00
// this means we'll have about a big third of women, and thus we can maximize resource gathering rates.
2013-12-30 11:04:59 +01:00
this . femaleRatio = this . Config . Economy . femaleRatio ;
2013-09-29 15:32:52 +02:00
this . fortressStartTime = 0 ;
2013-12-30 11:04:59 +01:00
this . fortressLapseTime = this . Config . Military . fortressLapseTime * 1000 ;
this . defenceBuildingTime = this . Config . Military . defenceBuildingTime * 1000 ;
this . attackPlansStartTime = this . Config . Military . attackPlansStartTime * 1000 ;
2014-01-14 20:54:31 +01:00
2013-12-30 11:04:59 +01:00
this . defenceManager = new m . Defence ( this . Config ) ;
this . navalManager = new m . NavalManager ( ) ;
2013-09-29 15:32:52 +02:00
this . TotalAttackNumber = 0 ;
2014-01-14 20:54:31 +01:00
this . upcomingAttacks = { "CityAttack" : [ ] , "Rush" : [ ] } ;
this . startedAttacks = { "CityAttack" : [ ] , "Rush" : [ ] } ;
2013-09-29 15:32:52 +02:00
} ;
// More initialisation for stuff that needs the gameState
2014-01-12 20:12:55 +01:00
m . HQ . prototype . init = function ( gameState , queues ) {
2013-09-29 15:32:52 +02:00
// initialize base map. Each pixel is a base ID, or 0 if none
2013-12-30 11:04:59 +01:00
this . basesMap = new API3 . Map ( gameState . sharedScript , new Uint8Array ( gameState . getMap ( ) . data . length ) ) ;
2013-09-29 15:32:52 +02:00
this . basesMap . setMaxVal ( 255 ) ;
2013-12-30 11:04:59 +01:00
if ( this . Config . Economy . targetNumWorkers )
this . targetNumWorkers = this . Config . Economy . targetNumWorkers ;
2014-02-01 01:44:12 +01:00
else if ( this . targetNumWorkers === undefined && this . Config . difficulty === 0 )
this . targetNumWorkers = Math . max ( 1 , Math . min ( 40 , Math . floor ( gameState . getPopulationMax ( ) ) ) ) ;
else if ( this . targetNumWorkers === undefined && this . Config . difficulty === 1 )
this . targetNumWorkers = Math . max ( 1 , Math . min ( 60 , Math . floor ( gameState . getPopulationMax ( ) ) ) ) ;
2013-09-29 15:32:52 +02:00
else if ( this . targetNumWorkers === undefined )
2014-02-01 01:44:12 +01:00
this . targetNumWorkers = Math . max ( 1 , Math . min ( 120 , Math . floor ( gameState . getPopulationMax ( ) / 3.0 ) ) ) ;
2013-09-29 15:32:52 +02:00
// Let's get our initial situation here.
// TODO: improve on this.
// TODO: aknowledge bases, assign workers already.
2013-12-30 11:04:59 +01:00
var ents = gameState . getEntities ( ) . filter ( API3 . Filters . byOwner ( PlayerID ) ) ;
2013-09-29 15:32:52 +02:00
var workersNB = 0 ;
var hasScout = false ;
var treasureAmount = { 'food' : 0 , 'wood' : 0 , 'stone' : 0 , 'metal' : 0 } ;
var hasCC = false ;
2013-12-30 11:04:59 +01:00
if ( ents . filter ( API3 . Filters . byClass ( "CivCentre" ) ) . length > 0 )
2013-09-29 15:32:52 +02:00
hasCC = true ;
2013-12-30 11:04:59 +01:00
workersNB = ents . filter ( API3 . Filters . byClass ( "Worker" ) ) . length ;
if ( ents . filter ( API3 . Filters . byClass ( "Cavalry" ) ) . length > 0 )
2013-09-29 15:32:52 +02:00
hasScout = true ;
2014-01-12 02:07:07 +01:00
// TODO: take multiple CCs into account.
2013-09-29 15:32:52 +02:00
if ( hasCC )
{
2013-12-30 11:04:59 +01:00
var CC = ents . filter ( API3 . Filters . byClass ( "CivCentre" ) ) . toEntityArray ( ) [ 0 ] ;
2014-01-06 21:55:22 +01:00
for ( var i in treasureAmount )
2013-09-29 15:32:52 +02:00
gameState . getResourceSupplies ( i ) . forEach ( function ( ent ) {
2013-12-30 11:04:59 +01:00
if ( ent . resourceSupplyType ( ) . generic === "treasure" && API3 . SquareVectorDistance ( ent . position ( ) , CC . position ( ) ) < 5000 )
2013-09-29 15:32:52 +02:00
treasureAmount [ i ] += ent . resourceSupplyMax ( ) ;
} ) ;
2013-12-30 11:04:59 +01:00
this . baseManagers [ 1 ] = new m . BaseManager ( this . Config ) ;
2014-01-12 20:12:55 +01:00
this . baseManagers [ 1 ] . init ( gameState ) ;
2013-09-29 15:32:52 +02:00
this . baseManagers [ 1 ] . setAnchor ( CC ) ;
this . baseManagers [ 1 ] . initTerritory ( this , gameState ) ;
this . baseManagers [ 1 ] . initGatheringFunctions ( this , gameState ) ;
2013-12-30 15:28:30 +01:00
if ( m . DebugEnabled ( ) )
2013-09-29 15:32:52 +02:00
this . basesMap . dumpIm ( "basesMap.png" ) ;
var self = this ;
ents . forEach ( function ( ent ) { //}){
self . baseManagers [ 1 ] . assignEntity ( ent ) ;
} ) ;
}
// we now have enough data to decide on a few things.
// TODO: here would be where we pick our initial strategy.
// immediatly build a wood dropsite if possible.
if ( this . baseManagers [ 1 ] )
{
if ( gameState . ai . queueManager . getAvailableResources ( gameState ) [ "wood" ] >= 250 )
{
var pos = this . baseManagers [ 1 ] . findBestDropsiteLocation ( gameState , "wood" ) ;
if ( pos )
{
2014-01-14 20:54:31 +01:00
queues . dropsites . addItem ( new m . ConstructionPlan ( gameState , "structures/{civ}_storehouse" , { "base" : 1 } , pos ) ) ;
2013-12-30 11:04:59 +01:00
queues . minorTech . addItem ( new m . ResearchPlan ( gameState , "gather_capacity_wheelbarrow" ) ) ;
2013-09-29 15:32:52 +02:00
}
}
}
2013-12-30 11:04:59 +01:00
var map = new API3 . Map ( gameState . sharedScript , gameState . sharedScript . CCResourceMaps [ "wood" ] . map ) ;
2013-12-30 15:28:30 +01:00
if ( m . DebugEnabled ( ) )
2013-09-29 15:32:52 +02:00
map . dumpIm ( "map_CC_Wood.png" ) ;
//this.reassignIdleWorkers(gameState);
2014-01-12 20:12:55 +01:00
this . navalManager . init ( gameState , queues ) ;
2014-01-14 20:54:31 +01:00
this . defenceManager . init ( gameState ) ;
2013-09-29 15:32:52 +02:00
2014-01-12 02:07:07 +01:00
// TODO: change that to something dynamic.
2013-09-29 15:32:52 +02:00
var civ = gameState . playerData . civ ;
// load units and buildings from the config files
2013-12-30 11:04:59 +01:00
if ( civ in this . Config . buildings . moderate ) {
this . bModerate = this . Config . buildings . moderate [ civ ] ;
2013-09-29 15:32:52 +02:00
} else {
2013-12-30 11:04:59 +01:00
this . bModerate = this . Config . buildings . moderate [ 'default' ] ;
2013-09-29 15:32:52 +02:00
}
2013-12-30 11:04:59 +01:00
if ( civ in this . Config . buildings . advanced ) {
this . bAdvanced = this . Config . buildings . advanced [ civ ] ;
2013-09-29 15:32:52 +02:00
} else {
2013-12-30 11:04:59 +01:00
this . bAdvanced = this . Config . buildings . advanced [ 'default' ] ;
2013-09-29 15:32:52 +02:00
}
2013-12-30 11:04:59 +01:00
if ( civ in this . Config . buildings . fort ) {
this . bFort = this . Config . buildings . fort [ civ ] ;
2013-09-29 15:32:52 +02:00
} else {
2013-12-30 11:04:59 +01:00
this . bFort = this . Config . buildings . fort [ 'default' ] ;
2013-09-29 15:32:52 +02:00
}
for ( var i in this . bAdvanced ) {
this . bAdvanced [ i ] = gameState . applyCiv ( this . bAdvanced [ i ] ) ;
}
for ( var i in this . bFort ) {
this . bFort [ i ] = gameState . applyCiv ( this . bFort [ i ] ) ;
}
} ;
2013-12-30 11:04:59 +01:00
m . HQ . prototype . checkEvents = function ( gameState , events , queues ) {
2014-01-10 02:46:27 +01:00
// TODO: probably check stuffs like a base destruction.
var CreateEvents = events [ "Create" ] ;
var ConstructionEvents = events [ "ConstructionFinished" ] ;
2014-01-10 21:04:37 +01:00
for ( var i in CreateEvents )
2013-09-29 15:32:52 +02:00
{
2014-01-10 02:46:27 +01:00
var evt = CreateEvents [ i ] ;
// Let's check if we have a building set to create a new base.
if ( evt && evt . entity )
2013-09-29 15:32:52 +02:00
{
2014-01-10 02:46:27 +01:00
var ent = gameState . getEntityById ( evt . entity ) ;
if ( ent === undefined )
continue ; // happens when this message is right before a "Destroy" one for the same entity.
if ( ent . isOwn ( PlayerID ) && ent . getMetadata ( PlayerID , "base" ) === - 1 )
2013-09-29 15:32:52 +02:00
{
2014-01-10 02:46:27 +01:00
// Okay so let's try to create a new base around this.
var bID = m . playerGlobals [ PlayerID ] . uniqueIDBases ;
this . baseManagers [ bID ] = new m . BaseManager ( this . Config ) ;
this . baseManagers [ bID ] . init ( gameState , events , true ) ;
this . baseManagers [ bID ] . setAnchor ( ent ) ;
this . baseManagers [ bID ] . initTerritory ( this , gameState ) ;
2013-12-09 17:35:06 +01:00
2014-01-10 02:46:27 +01:00
// Let's get a few units out there to build this.
// TODO: select the best base, or use multiple bases.
var builders = this . bulkPickWorkers ( gameState , bID , 10 ) ;
2014-01-14 20:54:31 +01:00
if ( builders !== false )
{
builders . forEach ( function ( worker ) {
worker . setMetadata ( PlayerID , "base" , bID ) ;
worker . setMetadata ( PlayerID , "subrole" , "builder" ) ;
worker . setMetadata ( PlayerID , "target-foundation" , ent . id ( ) ) ;
} ) ;
}
2013-09-29 15:32:52 +02:00
}
2014-01-10 02:46:27 +01:00
}
}
2014-01-10 21:04:37 +01:00
for ( var i in ConstructionEvents )
2014-01-10 02:46:27 +01:00
{
var evt = ConstructionEvents [ i ] ;
// Let's check if we have a building set to create a new base.
// TODO: move to the base manager.
if ( evt . newentity )
2013-09-29 15:32:52 +02:00
{
2014-01-10 02:46:27 +01:00
var ent = gameState . getEntityById ( evt . newentity ) ;
if ( ent === undefined )
continue ; // happens when this message is right before a "Destroy" one for the same entity.
if ( ent . isOwn ( PlayerID ) && ent . getMetadata ( PlayerID , "baseAnchor" ) == true )
2013-09-29 15:32:52 +02:00
{
2014-01-10 02:46:27 +01:00
var base = ent . getMetadata ( PlayerID , "base" ) ;
if ( this . baseManagers [ base ] . constructing )
2013-09-29 15:32:52 +02:00
{
2014-01-10 02:46:27 +01:00
this . baseManagers [ base ] . constructing = false ;
this . baseManagers [ base ] . initGatheringFunctions ( this , gameState ) ;
2013-09-29 15:32:52 +02:00
}
}
}
}
} ;
2014-01-14 20:54:31 +01:00
// Called by the "town phase" research plan once it's started
m . HQ . prototype . OnTownPhase = function ( gameState )
{
if ( this . Config . difficulty >= 2 && this . femaleRatio !== 0.4 )
{
this . femaleRatio = 0.4 ;
gameState . ai . queues [ "villager" ] . empty ( ) ;
gameState . ai . queues [ "citizenSoldier" ] . empty ( ) ;
2014-01-22 21:26:45 +01:00
for ( var i in this . baseManagers )
{
if ( this . baseManagers [ i ] . willGather [ "wood" ] === 2 )
this . baseManagers [ i ] . willGather [ "wood" ] = 1 ; // retry.
if ( this . baseManagers [ i ] . willGather [ "stone" ] === 2 )
this . baseManagers [ i ] . willGather [ "stone" ] = 1 ; // retry.
if ( this . baseManagers [ i ] . willGather [ "metal" ] === 2 )
this . baseManagers [ i ] . willGather [ "metal" ] = 1 ; // retry.
}
2014-01-14 20:54:31 +01:00
}
}
2014-01-12 20:12:55 +01:00
// This code trains females and citizen workers, trying to keep close to a ratio of females/CS
// TODO: this should choose a base depending on which base need workers
// TODO: also there are several things that could be greatly improved here.
2014-01-12 02:07:07 +01:00
m . HQ . prototype . trainMoreWorkers = function ( gameState , queues )
{
// Get some data.
2013-09-29 15:32:52 +02:00
// Count the workers in the world and in progress
2014-01-12 03:40:42 +01:00
var numFemales = gameState . countEntitiesAndQueuedByType ( gameState . applyCiv ( "units/{civ}_support_female_citizen" ) , true ) ;
2013-09-29 15:32:52 +02:00
// counting the workers that aren't part of a plan
var numWorkers = 0 ;
2014-01-12 03:40:42 +01:00
gameState . getOwnUnits ( ) . forEach ( function ( ent ) {
2013-09-29 15:32:52 +02:00
if ( ent . getMetadata ( PlayerID , "role" ) == "worker" && ent . getMetadata ( PlayerID , "plan" ) == undefined )
numWorkers ++ ;
} ) ;
var numInTraining = 0 ;
gameState . getOwnTrainingFacilities ( ) . forEach ( function ( ent ) {
ent . trainingQueue ( ) . forEach ( function ( item ) {
if ( item . metadata && item . metadata . role && item . metadata . role == "worker" && item . metadata . plan == undefined )
numWorkers += item . count ;
numInTraining += item . count ;
} ) ;
} ) ;
2014-01-12 20:12:55 +01:00
var numQueuedF = queues . villager . countQueuedUnits ( ) ;
var numQueuedS = queues . citizenSoldier . countQueuedUnits ( ) ;
var numQueued = numQueuedS + numQueuedF ;
2013-09-29 15:32:52 +02:00
var numTotal = numWorkers + numQueued ;
// If we have too few, train more
// should plan enough to always have females…
// TODO: 15 here should be changed to something more sensible, such as nb of producing buildings.
2014-01-12 20:12:55 +01:00
if ( numTotal > this . targetNumWorkers || numQueued > 50 || ( numQueuedF > 20 && numQueuedS > 20 ) || numInTraining > 15 )
return ;
2014-01-14 20:54:31 +01:00
if ( numTotal >= this . Config . Economy . villagePopCap && gameState . currentPhase ( ) === 1 && ! gameState . isResearching ( gameState . townPhase ( ) ) )
return ;
2014-01-12 20:12:55 +01:00
// default template and size
var template = gameState . applyCiv ( "units/{civ}_support_female_citizen" ) ;
var size = Math . min ( 5 , Math . ceil ( numTotal / 10 ) ) ;
// Choose whether we want soldiers instead.
// TODO: we might want to adjust our female ratio.
if ( ( numFemales + numQueuedF ) / numTotal > this . femaleRatio && numQueuedS < 20 ) {
if ( numTotal < 35 )
template = this . findBestTrainableUnit ( gameState , [ "CitizenSoldier" , "Infantry" ] , [ [ "cost" , 1 ] , [ "speed" , 0.5 ] , [ "costsResource" , 0.5 , "stone" ] , [ "costsResource" , 0.5 , "metal" ] ] ) ;
else
template = this . findBestTrainableUnit ( gameState , [ "CitizenSoldier" , "Infantry" ] , [ [ "strength" , 1 ] ] ) ;
if ( ! template )
template = gameState . applyCiv ( "units/{civ}_support_female_citizen" ) ;
2013-09-29 15:32:52 +02:00
else
2014-01-12 20:12:55 +01:00
size = Math . min ( 5 , Math . ceil ( numTotal / 12 ) ) ;
2013-09-29 15:32:52 +02:00
}
2014-01-12 20:12:55 +01:00
// TODO: improve that logic.
/ *
if ( numFemales / numWorkers > this . femaleRatio && numQueuedS > 0 && numWorkers > 25 )
queues . villager . paused = true ;
else
queues . villager . paused = false ;
* /
// TODO: perhaps assign them a default resource and check the base according to that.
// base "0" means "auto"
if ( template === gameState . applyCiv ( "units/{civ}_support_female_citizen" ) )
2014-01-14 20:54:31 +01:00
queues . villager . addItem ( new m . TrainingPlan ( gameState , template , { "role" : "worker" , "base" : 0 } , size , size ) ) ;
2014-01-12 20:12:55 +01:00
else
2014-01-14 20:54:31 +01:00
queues . citizenSoldier . addItem ( new m . TrainingPlan ( gameState , template , { "role" : "worker" , "base" : 0 } , size , size ) ) ;
2013-09-29 15:32:52 +02:00
} ;
// picks the best template based on parameters and classes
2013-12-30 11:04:59 +01:00
m . HQ . prototype . findBestTrainableUnit = function ( gameState , classes , parameters ) {
2013-09-29 15:32:52 +02:00
var units = gameState . findTrainableUnits ( classes ) ;
if ( units . length === 0 )
return undefined ;
units . sort ( function ( a , b ) { // }) {
var aDivParam = 0 , bDivParam = 0 ;
var aTopParam = 0 , bTopParam = 0 ;
for ( var i in parameters ) {
var param = parameters [ i ] ;
if ( param [ 0 ] == "base" ) {
aTopParam = param [ 1 ] ;
bTopParam = param [ 1 ] ;
}
if ( param [ 0 ] == "strength" ) {
2013-12-30 11:04:59 +01:00
aTopParam += m . getMaxStrength ( a [ 1 ] ) * param [ 1 ] ;
bTopParam += m . getMaxStrength ( b [ 1 ] ) * param [ 1 ] ;
2013-09-29 15:32:52 +02:00
}
2014-01-14 20:54:31 +01:00
if ( param [ 0 ] == "siegeStrength" ) {
aTopParam += m . getMaxStrength ( a [ 1 ] , "Structure" ) * param [ 1 ] ;
bTopParam += m . getMaxStrength ( b [ 1 ] , "Structure" ) * param [ 1 ] ;
}
2013-09-29 15:32:52 +02:00
if ( param [ 0 ] == "speed" ) {
aTopParam += a [ 1 ] . walkSpeed ( ) * param [ 1 ] ;
bTopParam += b [ 1 ] . walkSpeed ( ) * param [ 1 ] ;
}
if ( param [ 0 ] == "cost" ) {
aDivParam += a [ 1 ] . costSum ( ) * param [ 1 ] ;
bDivParam += b [ 1 ] . costSum ( ) * param [ 1 ] ;
}
// requires a third parameter which is the resource
if ( param [ 0 ] == "costsResource" ) {
if ( a [ 1 ] . cost ( ) [ param [ 2 ] ] )
aTopParam *= param [ 1 ] ;
if ( b [ 1 ] . cost ( ) [ param [ 2 ] ] )
bTopParam *= param [ 1 ] ;
}
if ( param [ 0 ] == "canGather" ) {
// checking against wood, could be anything else really.
if ( a [ 1 ] . resourceGatherRates ( ) && a [ 1 ] . resourceGatherRates ( ) [ "wood.tree" ] )
aTopParam *= param [ 1 ] ;
if ( b [ 1 ] . resourceGatherRates ( ) && b [ 1 ] . resourceGatherRates ( ) [ "wood.tree" ] )
bTopParam *= param [ 1 ] ;
}
}
return - ( aTopParam / ( aDivParam + 1 ) ) + ( bTopParam / ( bDivParam + 1 ) ) ;
} ) ;
return units [ 0 ] [ 0 ] ;
} ;
// Tries to research any available tech
// Only one at once. Also does military tech (selection is completely random atm)
// TODO: Lots, lots, lots here.
2013-12-30 11:04:59 +01:00
m . HQ . prototype . tryResearchTechs = function ( gameState , queues ) {
2013-09-29 15:32:52 +02:00
if ( queues . minorTech . length ( ) === 0 )
{
var possibilities = gameState . findAvailableTech ( ) ;
if ( possibilities . length === 0 )
return ;
// randomly pick one. No worries about pairs in that case.
var p = Math . floor ( ( Math . random ( ) * possibilities . length ) ) ;
2013-12-30 11:04:59 +01:00
queues . minorTech . addItem ( new m . ResearchPlan ( gameState , possibilities [ p ] [ 0 ] ) ) ;
2013-09-29 15:32:52 +02:00
}
}
// We're given a worker and a resource type
// We'll assign the worker for the best base for that resource type.
// TODO: improve choice alogrithm
2013-12-30 11:04:59 +01:00
m . HQ . prototype . switchWorkerBase = function ( gameState , worker , type ) {
2013-09-29 15:32:52 +02:00
var bestBase = 0 ;
2014-01-22 21:26:45 +01:00
var bestBaseState = - 1 ;
2013-12-30 11:04:59 +01:00
2013-09-29 15:32:52 +02:00
for ( var i in this . baseManagers )
{
2014-01-22 21:26:45 +01:00
if ( this . baseManagers [ i ] . willGather [ type ] === 1 || ( this . baseManagers [ i ] . willGather [ type ] === 2 && bestBaseState !== 1 ) )
2013-09-29 15:32:52 +02:00
{
if ( this . baseManagers [ i ] . accessIndex === this . baseManagers [ worker . getMetadata ( PlayerID , "base" ) ] . accessIndex
|| this . navalManager . canReach ( gameState , this . baseManagers [ i ] . accessIndex , this . baseManagers [ worker . getMetadata ( PlayerID , "base" ) ] . accessIndex ) )
{
2014-01-22 21:26:45 +01:00
bestBaseState = this . baseManagers [ i ] . willGather [ type ]
2013-09-29 15:32:52 +02:00
bestBase = i ;
break ;
}
}
}
if ( bestBase && bestBase !== worker . getMetadata ( PlayerID , "base" ) )
{
worker . setMetadata ( PlayerID , "base" , bestBase ) ;
return true ;
} else {
return false ;
}
} ;
// returns an entity collection of workers through BaseManager.pickBuilders
// TODO: better the choice algo.
// TODO: also can't get over multiple bases right now.
2013-12-30 11:04:59 +01:00
m . HQ . prototype . bulkPickWorkers = function ( gameState , newBaseID , number ) {
2013-09-29 15:32:52 +02:00
var accessIndex = this . baseManagers [ newBaseID ] . accessIndex ;
if ( ! accessIndex )
return false ;
// sorting bases by whether they are on the same accessindex or not.
2013-12-30 11:04:59 +01:00
var baseBest = m . AssocArraytoArray ( this . baseManagers ) . sort ( function ( a , b ) {
2013-09-29 15:32:52 +02:00
if ( a . accessIndex === accessIndex && b . accessIndex !== accessIndex )
return - 1 ;
else if ( b . accessIndex === accessIndex && a . accessIndex !== accessIndex )
return 1 ;
return 0 ;
} ) ;
2014-01-06 21:55:22 +01:00
for ( var i in baseBest )
2013-09-29 15:32:52 +02:00
{
if ( baseBest [ i ] . workers . length > number )
{
return baseBest [ i ] . pickBuilders ( gameState , number ) ;
}
}
return false ;
}
// returns the current gather rate
// This is not per-se exact, it performs a few adjustments ad-hoc to account for travel distance, stuffs like that.
2013-12-30 11:04:59 +01:00
m . HQ . prototype . GetCurrentGatherRates = function ( gameState ) {
2013-09-29 15:32:52 +02:00
var self = this ;
2014-02-01 01:44:12 +01:00
// if (gameState.getTimeElapsed() - this.currentRateLastUpdateTime < 10000 && this.currentRateLastUpdateTime !== 0 && gameState.ai.playedTurn > 3)
// return this.currentRates;
2014-01-14 20:54:31 +01:00
this . currentRateLastUpdateTime = gameState . getTimeElapsed ( ) ;
2013-09-29 15:32:52 +02:00
for ( var type in this . wantedRates )
2014-01-14 20:54:31 +01:00
this . currentRates [ type ] = 0 ;
2013-09-29 15:32:52 +02:00
2014-01-06 21:55:22 +01:00
for ( var i in this . baseManagers )
2014-01-14 20:54:31 +01:00
this . baseManagers [ i ] . getGatherRates ( gameState , this . currentRates ) ;
2013-09-29 15:32:52 +02:00
2014-01-14 20:54:31 +01:00
return this . currentRates ;
2013-09-29 15:32:52 +02:00
} ;
2014-01-12 20:12:55 +01:00
/ * P i c k t h e r e s o u r c e w h i c h m o s t n e e d s a n o t h e r w o r k e r
* How this works :
* We get the rates we would want to have to be able to deal with our plans
* We get our current rates
* We compare ; we pick the one where the discrepancy is highest .
* Need to balance long - term needs and possible short - term needs .
* /
2013-12-30 11:04:59 +01:00
m . HQ . prototype . pickMostNeededResources = function ( gameState ) {
2013-09-29 15:32:52 +02:00
var self = this ;
this . wantedRates = gameState . ai . queueManager . wantedGatherRates ( gameState ) ;
var currentRates = { } ;
for ( var type in this . wantedRates )
currentRates [ type ] = 0 ;
2014-02-01 01:44:12 +01:00
currentRates = this . GetCurrentGatherRates ( gameState ) ;
2013-09-29 15:32:52 +02:00
// let's get our ideal number.
var types = Object . keys ( this . wantedRates ) ;
types . sort ( function ( a , b ) {
var va = ( Math . max ( 0 , self . wantedRates [ a ] - currentRates [ a ] ) ) / ( currentRates [ a ] + 1 ) ;
var vb = ( Math . max ( 0 , self . wantedRates [ b ] - currentRates [ b ] ) ) / ( currentRates [ b ] + 1 ) ;
2014-01-12 20:12:55 +01:00
// If they happen to be equal (generally this means "0" aka no need), make it fair.
2013-09-29 15:32:52 +02:00
if ( va === vb )
return ( self . wantedRates [ b ] / ( currentRates [ b ] + 1 ) ) - ( self . wantedRates [ a ] / ( currentRates [ a ] + 1 ) ) ;
return vb - va ;
} ) ;
return types ;
} ;
// If all the CC's are destroyed then build a new one
// TODO: rehabilitate.
2013-12-30 11:04:59 +01:00
m . HQ . prototype . buildNewCC = function ( gameState , queues ) {
2014-01-12 03:40:42 +01:00
var numCCs = gameState . countEntitiesAndQueuedByType ( gameState . applyCiv ( "structures/{civ}_civil_centre" ) , true ) ;
2013-09-29 15:32:52 +02:00
numCCs += queues . civilCentre . length ( ) ;
// no use trying to lay foundations that will be destroyed
if ( gameState . defcon ( ) > 2 )
2014-01-06 21:55:22 +01:00
for ( var i = numCCs ; i < 1 ; i ++ ) {
2013-09-29 15:32:52 +02:00
gameState . ai . queueManager . clear ( ) ;
this . baseNeed [ "food" ] = 0 ;
this . baseNeed [ "wood" ] = 50 ;
this . baseNeed [ "stone" ] = 50 ;
this . baseNeed [ "metal" ] = 50 ;
2013-12-30 11:04:59 +01:00
queues . civilCentre . addItem ( new m . ConstructionPlan ( gameState , "structures/{civ}_civil_centre" ) ) ;
2013-09-29 15:32:52 +02:00
}
return ( gameState . countEntitiesByType ( gameState . applyCiv ( "structures/{civ}_civil_centre" ) , true ) == 0 && gameState . currentPhase ( ) > 1 ) ;
} ;
// Returns the best position to build a new Civil Centre
// Whose primary function would be to reach new resources of type "resource".
2013-12-30 11:04:59 +01:00
m . HQ . prototype . findBestEcoCCLocation = function ( gameState , resource ) {
2013-09-29 15:32:52 +02:00
var CCPlate = gameState . getTemplate ( "structures/{civ}_civil_centre" ) ;
// This builds a map. The procedure is fairly simple. It adds the resource maps
// (which are dynamically updated and are made so that they will facilitate DP placement)
// Then checks for a good spot in the territory. If none, and town/city phase, checks outside
// The AI will currently not build a CC if it wouldn't connect with an existing CC.
2013-12-30 11:04:59 +01:00
var territory = m . createTerritoryMap ( gameState ) ;
2013-09-29 15:32:52 +02:00
2013-12-30 11:04:59 +01:00
var obstructions = m . createObstructionMap ( gameState , 0 ) ;
2013-09-29 15:32:52 +02:00
obstructions . expandInfluences ( ) ;
// copy the resource map as initialization.
2013-12-30 11:04:59 +01:00
var friendlyTiles = new API3 . Map ( gameState . sharedScript , gameState . sharedScript . CCResourceMaps [ resource ] . map , true ) ;
2013-09-29 15:32:52 +02:00
friendlyTiles . setMaxVal ( 255 ) ;
2014-01-12 02:07:07 +01:00
var ents = gameState . getOwnStructures ( ) . filter ( API3 . Filters . byClass ( "CivCentre" ) ) . toEntityArray ( ) ;
var eEnts = gameState . getEnemyStructures ( ) . filter ( API3 . Filters . byClass ( "CivCentre" ) ) . toEntityArray ( ) ;
2013-09-29 15:32:52 +02:00
var dps = gameState . getOwnDropsites ( ) . toEntityArray ( ) ;
for ( var j = 0 ; j < friendlyTiles . length ; ++ j )
{
// We check for our other CCs: the distance must not be too big. Anything bigger will result in scrapping.
// This ensures territorial continuity.
// TODO: maybe whenever I get around to implement multi-base support (details below, requires being part of the team. If you're not, ask wraitii directly by PM).
// (see www.wildfiregames.com/forum/index.php?showtopic=16702&#entry255631 )
// TODO: figure out what I was trying to say above.
var canBuild = true ;
var canBuild2 = false ;
2013-12-08 17:24:09 +01:00
var pos = [ j % friendlyTiles . width + 0.5 , Math . floor ( j / friendlyTiles . width ) + 0.5 ] ;
2013-09-29 15:32:52 +02:00
for ( var i in ents )
{
2013-12-08 17:24:09 +01:00
var entPos = ents [ i ] . position ( ) ;
entPos = [ entPos [ 0 ] / 4.0 , entPos [ 1 ] / 4.0 ] ;
2013-12-30 11:04:59 +01:00
var dist = API3 . SquareVectorDistance ( entPos , pos ) ;
2014-01-10 02:46:27 +01:00
if ( dist < 3500 || dist > 7900 )
friendlyTiles . map [ j ] /= 2.0 ;
2013-12-08 10:07:33 +01:00
if ( dist < 2120 )
2013-09-29 15:32:52 +02:00
{
canBuild = false ;
continue ;
2014-01-10 02:46:27 +01:00
} else if ( dist < 9200 || this . waterMap )
2013-09-29 15:32:52 +02:00
canBuild2 = true ;
}
// checking for bases.
if ( this . basesMap . map [ j ] !== 0 )
canBuild = false ;
if ( ! canBuild2 )
canBuild = false ;
if ( canBuild )
{
// Checking for enemy CCs
for ( var i in eEnts )
{
2013-12-08 17:24:09 +01:00
var entPos = eEnts [ i ] . position ( ) ;
entPos = [ entPos [ 0 ] / 4.0 , entPos [ 1 ] / 4.0 ] ;
2013-09-29 15:32:52 +02:00
// 7100 works well as a limit.
2013-12-30 11:04:59 +01:00
if ( API3 . SquareVectorDistance ( entPos , pos ) < 2500 )
2013-09-29 15:32:52 +02:00
{
canBuild = false ;
continue ;
}
}
}
if ( ! canBuild )
{
friendlyTiles . map [ j ] = 0 ;
continue ;
}
for ( var i in dps )
{
var dpPos = dps [ i ] . position ( ) ;
2013-12-08 17:24:09 +01:00
if ( dpPos === undefined )
{
// Probably a mauryan elephant, skip
continue ;
}
dpPos = [ dpPos [ 0 ] / 4.0 , dpPos [ 1 ] / 4.0 ] ;
2014-01-10 02:46:27 +01:00
var dist = API3 . SquareVectorDistance ( dpPos , pos ) ;
if ( dist < 600 )
2013-09-29 15:32:52 +02:00
{
friendlyTiles . map [ j ] = 0 ;
continue ;
2014-01-10 02:46:27 +01:00
} else if ( dist < 1500 )
friendlyTiles . map [ j ] /= 2.0 ;
2013-09-29 15:32:52 +02:00
}
friendlyTiles . map [ j ] *= 1.5 ;
for ( var i in gameState . sharedScript . CCResourceMaps )
if ( friendlyTiles . map [ j ] !== 0 && i !== "food" )
{
var val = friendlyTiles . map [ j ] + gameState . sharedScript . CCResourceMaps [ i ] . map [ j ] ;
if ( val < 255 )
friendlyTiles . map [ j ] = val ;
else
friendlyTiles . map [ j ] = 255 ;
}
}
2013-12-08 17:24:09 +01:00
var best = friendlyTiles . findBestTile ( 6 , obstructions ) ;
2013-09-29 15:32:52 +02:00
var bestIdx = best [ 0 ] ;
2013-12-30 15:28:30 +01:00
if ( m . DebugEnabled ( ) )
2013-09-29 15:32:52 +02:00
{
2013-12-08 17:24:09 +01:00
friendlyTiles . map [ bestIdx ] = 270 ;
friendlyTiles . dumpIm ( "cc_placement_base_" + gameState . getTimeElapsed ( ) + "_" + resource + "_" + best [ 1 ] + ".png" , 301 ) ;
//obstructions.dumpIm("cc_placement_base_" + gameState.getTimeElapsed() + "_" + resource + "_" + best[1] + "_obs.png", 20);
2013-09-29 15:32:52 +02:00
}
// not good enough.
if ( best [ 1 ] < 60 )
return false ;
var x = ( ( bestIdx % friendlyTiles . width ) + 0.5 ) * gameState . cellSize ;
var z = ( Math . floor ( bestIdx / friendlyTiles . width ) + 0.5 ) * gameState . cellSize ;
2013-12-30 11:04:59 +01:00
m . debug ( "Best for value " + best [ 1 ] + " at " + uneval ( [ x , z ] ) ) ;
2013-12-08 17:24:09 +01:00
2013-09-29 15:32:52 +02:00
return [ x , z ] ;
} ;
2013-12-30 11:04:59 +01:00
m . HQ . prototype . buildTemple = function ( gameState , queues ) {
2013-09-29 15:32:52 +02:00
if ( gameState . currentPhase ( ) >= 2 ) {
if ( queues . economicBuilding . countQueuedUnits ( ) === 0 &&
2014-01-12 03:40:42 +01:00
gameState . countEntitiesAndQueuedByType ( gameState . applyCiv ( "structures/{civ}_temple" ) , true ) === 0 ) {
2013-12-30 11:04:59 +01:00
queues . economicBuilding . addItem ( new m . ConstructionPlan ( gameState , "structures/{civ}_temple" , { "base" : 1 } ) ) ;
2013-09-29 15:32:52 +02:00
}
}
} ;
2013-12-30 11:04:59 +01:00
m . HQ . prototype . buildMarket = function ( gameState , queues ) {
if ( gameState . getPopulation ( ) > this . Config . Economy . popForMarket && gameState . currentPhase ( ) >= 2 ) {
2013-09-29 15:32:52 +02:00
if ( queues . economicBuilding . countQueuedUnitsWithClass ( "BarterMarket" ) === 0 &&
2014-01-12 03:40:42 +01:00
gameState . countEntitiesAndQueuedByType ( gameState . applyCiv ( "structures/{civ}_market" ) , true ) === 0 ) {
2013-09-29 15:32:52 +02:00
//only ever build one storehouse/CC/market at a time
2013-12-30 11:04:59 +01:00
queues . economicBuilding . addItem ( new m . ConstructionPlan ( gameState , "structures/{civ}_market" , { "base" : 1 } ) ) ;
2013-09-29 15:32:52 +02:00
}
}
} ;
// Build a farmstead to go to town phase faster and prepare for research. Only really active on higher diff mode.
2013-12-30 11:04:59 +01:00
m . HQ . prototype . buildFarmstead = function ( gameState , queues ) {
2014-01-14 20:54:31 +01:00
if ( gameState . getPopulation ( ) > this . Config . Economy . popForFarmstead
&& ( gameState . currentPhase ( ) > 1 || gameState . isResearching ( gameState . townPhase ( ) ) ) ) {
2013-12-09 15:20:11 +01:00
// achtung: "DropsiteFood" does not refer to CCs.
2013-09-29 15:32:52 +02:00
if ( queues . economicBuilding . countQueuedUnitsWithClass ( "DropsiteFood" ) === 0 &&
2014-01-12 03:40:42 +01:00
gameState . countEntitiesAndQueuedByType ( gameState . applyCiv ( "structures/{civ}_farmstead" ) , true ) === 0 ) {
2013-09-29 15:32:52 +02:00
//only ever build one storehouse/CC/market at a time
2013-12-30 11:04:59 +01:00
queues . economicBuilding . addItem ( new m . ConstructionPlan ( gameState , "structures/{civ}_farmstead" , { "base" : 1 } ) ) ;
2014-01-14 20:54:31 +01:00
// add the farming plough to the research we want.
2014-02-01 01:44:12 +01:00
queues . minorTech . addItem ( new m . ResearchPlan ( gameState , "gather_farming_plows" ) ) ;
2013-09-29 15:32:52 +02:00
}
}
} ;
// TODO: generic this, probably per-base
2013-12-30 11:04:59 +01:00
m . HQ . prototype . buildDock = function ( gameState , queues ) {
2013-09-29 15:32:52 +02:00
if ( ! this . waterMap || this . dockFailed )
return ;
if ( gameState . getTimeElapsed ( ) > this . dockStartTime ) {
if ( queues . economicBuilding . countQueuedUnitsWithClass ( "NavalMarket" ) === 0 &&
2014-01-12 03:40:42 +01:00
gameState . countEntitiesAndQueuedByType ( gameState . applyCiv ( "structures/{civ}_dock" ) , true ) === 0 ) {
2013-09-29 15:32:52 +02:00
var tp = ""
if ( gameState . civ ( ) == "cart" && gameState . currentPhase ( ) > 1 )
tp = "structures/{civ}_super_dock" ;
else if ( gameState . civ ( ) !== "cart" )
tp = "structures/{civ}_dock" ;
if ( tp !== "" )
{
var remaining = this . navalManager . getUnconnectedSeas ( gameState , this . baseManagers [ 1 ] . accessIndex ) ;
2013-12-30 11:04:59 +01:00
queues . economicBuilding . addItem ( new m . ConstructionPlan ( gameState , tp , { "base" : 1 , "sea" : remaining [ 0 ] } ) ) ;
2013-09-29 15:32:52 +02:00
}
}
}
} ;
2014-01-14 20:54:31 +01:00
// Try to barter unneeded resources for needed resources.
// once per turn because the info doesn't update between a turn and fixing isn't worth it.
m . HQ . prototype . tryBartering = function ( gameState ) {
var markets = gameState . getOwnEntitiesByType ( gameState . applyCiv ( "structures/{civ}_market" ) , true ) . toEntityArray ( ) ;
if ( markets . length === 0 )
return false ;
// Available resources after account substraction
var available = gameState . ai . queueManager . getAvailableResources ( gameState ) ;
var rates = this . 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 finish a queue quickly.
for ( var j in gameState . ai . queues )
{
var queue = gameState . ai . queues [ j ] ;
if ( queue . paused || queue . length ( ) === 0 )
continue ;
var account = gameState . ai . queueManager . accounts [ j ] ;
var elem = queue . queue [ 0 ] ;
var elemCost = elem . getCost ( ) ;
for each ( var ress in elemCost . types )
{
if ( available [ ress ] >= 0 )
continue ; // don't care if we still have available resources or our rate is good enough
var need = elemCost [ ress ] - account [ ress ] ;
if ( need <= 0 || rates [ ress ] >= need / 50 ) // don't care if we don't need resources for our first item
continue ;
if ( ress == "food" && need < 400 )
continue ;
// pick the best resource to barter.
var bestToBarter = "" ;
var bestRate = 0 ;
for each ( var otherRess in elemCost . types )
{
if ( ress === otherRess )
continue ;
// I wanna keep some
if ( available [ otherRess ] < 130 + need )
return false ;
var barterRate = getBarterRate ( prices , ress , otherRess ) ;
if ( barterRate > bestRate )
{
bestRate = barterRate ;
bestToBarter = otherRess ;
}
}
if ( bestToBarter !== "" )
{
markets [ 0 ] . barter ( buy , sell , 100 ) ;
m . debug ( "Snipe bartered " + sell + " for " + buy + ", value 100" ) ;
return true ;
}
}
}
// now barter for big needs.
var needs = gameState . ai . queueManager . currentNeeds ( gameState ) ;
for each ( var sell in needs . types ) {
for each ( var buy in needs . types ) {
if ( buy != sell && needs [ sell ] <= 0 && available [ sell ] > 500 ) { // if we don't need it and have a buffer
if ( needs [ buy ] > rates [ buy ] * 80 ) { // if we need that other resource terribly.
markets [ 0 ] . barter ( buy , sell , 100 ) ;
m . debug ( "Gross bartered " + sell + " for " + buy + ", value 100" ) ;
return true ;
2013-09-29 15:32:52 +02:00
}
}
}
}
2014-01-14 20:54:31 +01:00
return false ;
2013-09-29 15:32:52 +02:00
} ;
// build more houses if needed.
// kinda ugly, lots of special cases to both build enough houses but not tooo many…
2013-12-30 11:04:59 +01:00
m . HQ . prototype . buildMoreHouses = function ( gameState , queues ) {
2013-09-29 15:32:52 +02:00
if ( gameState . getPopulationLimit ( ) < gameState . getPopulationMax ( ) ) {
var numPlanned = queues . house . length ( ) ;
if ( numPlanned < 3 || ( numPlanned < 5 && gameState . getPopulation ( ) > 80 ) )
{
2013-12-30 11:04:59 +01:00
var plan = new m . ConstructionPlan ( gameState , "structures/{civ}_house" , { "base" : 1 } ) ;
// make the difficulty available to the isGo function without having to pass it as argument
var difficulty = this . Config . difficulty ;
2013-09-29 15:32:52 +02:00
// change the starting condition to "less than 15 slots left".
plan . isGo = function ( gameState ) {
var HouseNb = gameState . countEntitiesByType ( gameState . applyCiv ( "foundation|structures/{civ}_house" ) , true ) ;
var freeSlots = 0 ;
if ( gameState . civ ( ) == "gaul" || gameState . civ ( ) == "brit" || gameState . civ ( ) == "iber" )
freeSlots = gameState . getPopulationLimit ( ) + HouseNb * 5 - gameState . getPopulation ( ) ;
else
freeSlots = gameState . getPopulationLimit ( ) + HouseNb * 10 - gameState . getPopulation ( ) ;
2013-12-30 11:04:59 +01:00
if ( gameState . getPopulation ( ) > 55 && difficulty > 1 )
2013-09-29 15:32:52 +02:00
return ( freeSlots <= 21 ) ;
2014-01-14 20:54:31 +01:00
else if ( gameState . getPopulation ( ) >= 30 && difficulty !== 0 )
return ( freeSlots <= 15 ) ;
2013-09-29 15:32:52 +02:00
else
return ( freeSlots <= 10 ) ;
}
queues . house . addItem ( plan ) ;
}
2014-01-14 20:54:31 +01:00
if ( numPlanned > 0 && this . econState == "townPhasing" )
{
var houseQueue = queues . house . queue ;
var count = gameState . getOwnStructures ( ) . filter ( API3 . Filters . byClass ( "Village" ) ) . length ;
count += queues . militaryBuilding . length ( ) ; // barracks
for ( var i = 0 ; i < numPlanned ; ++ i )
{
if ( houseQueue [ i ] . isGo ( gameState ) )
++ count ;
else if ( count < 5 )
{
houseQueue [ i ] . isGo = function ( ) { return true ; }
++ count ;
}
}
}
2013-09-29 15:32:52 +02:00
}
} ;
// checks if we have bases for all resource types (bar food for now) or if we need to expand.
2013-12-30 11:04:59 +01:00
m . HQ . prototype . checkBasesRessLevel = function ( gameState , queues ) {
2013-09-29 15:32:52 +02:00
if ( gameState . currentPhase ( ) === 1 && ! gameState . isResearching ( gameState . townPhase ( ) ) )
return ;
var count = { "wood" : 0 , "stone" : 0 , "metal" : 0 }
var capacity = { "wood" : 0 , "stone" : 0 , "metal" : 0 }
var need = { "wood" : true , "stone" : true , "metal" : true } ;
var posss = [ ] ;
2013-12-30 11:04:59 +01:00
2014-01-06 21:55:22 +01:00
for ( var i in this . baseManagers )
2013-09-29 15:32:52 +02:00
{
var base = this . baseManagers [ i ] ;
2014-01-06 21:55:22 +01:00
for ( var type in count )
2013-09-29 15:32:52 +02:00
{
2014-01-22 21:26:45 +01:00
if ( base . getResourceLevel ( gameState , type , "all" ) > 2200 * Math . max ( this . Config . difficulty , 2 ) )
2013-09-29 15:32:52 +02:00
count [ type ] ++ ;
2014-01-22 21:26:45 +01:00
capacity [ type ] += base . getWorkerCapacity ( gameState , type , true ) ;
if ( base . willGather [ type ] === 1 )
2013-09-29 15:32:52 +02:00
need [ type ] = false ;
}
}
2014-01-06 21:55:22 +01:00
for ( var type in count )
2013-09-29 15:32:52 +02:00
{
if ( count [ type ] === 0 || need [ type ]
2014-01-12 02:07:07 +01:00
|| capacity [ type ] < gameState . getOwnUnits ( ) . filter ( API3 . Filters . and ( API3 . Filters . byMetadata ( PlayerID , "subrole" , "gatherer" ) , API3 . Filters . byMetadata ( PlayerID , "gather-type" , type ) ) ) . length * 1.05 )
2013-09-29 15:32:52 +02:00
{
// plan a new base.
2014-01-12 03:40:42 +01:00
if ( gameState . countFoundationsByType ( gameState . applyCiv ( "structures/{civ}_civil_centre" ) , true ) === 0 && queues . civilCentre . length ( ) === 0 ) {
2013-09-29 15:32:52 +02:00
if ( this . outOf [ type ] && gameState . ai . playedTurn % 10 !== 0 )
continue ;
var pos = this . findBestEcoCCLocation ( gameState , type ) ;
if ( ! pos )
{
// Okay so we'll set us as out of this.
this . outOf [ type ] = true ;
} else {
2014-01-22 21:26:45 +01:00
warn ( "planning new base " ) ;
2013-09-29 15:32:52 +02:00
// base "-1" means new base.
2014-01-14 20:54:31 +01:00
queues . civilCentre . addItem ( new m . ConstructionPlan ( gameState , "structures/{civ}_civil_centre" , { "base" : - 1 } , pos ) ) ;
2013-09-29 15:32:52 +02:00
}
}
}
}
} ;
// Deals with building fortresses and towers.
// Currently build towers next to every useful dropsites.
// TODO: Fortresses are placed randomly atm.
2013-12-30 11:04:59 +01:00
m . HQ . prototype . buildDefences = function ( gameState , queues ) {
2013-09-29 15:32:52 +02:00
2014-01-12 02:07:07 +01:00
var workersNumber = gameState . getOwnEntitiesByRole ( "worker" , true ) . filter ( API3 . Filters . not ( API3 . Filters . byHasMetadata ( PlayerID , "plan" ) ) ) . length ;
2013-09-29 15:32:52 +02:00
2014-01-12 03:40:42 +01:00
if ( gameState . countEntitiesAndQueuedByType ( gameState . applyCiv ( 'structures/{civ}_defense_tower' ) , true )
2014-01-14 20:54:31 +01:00
+ queues . defenceBuilding . length ( ) < gameState . getEntityLimits ( ) [ "DefenseTower" ] && queues . defenceBuilding . length ( ) === 0 && gameState . currentPhase ( ) > 1 ) {
2014-01-06 21:55:22 +01:00
for ( var i in this . baseManagers )
2013-09-29 15:32:52 +02:00
{
2014-01-06 21:55:22 +01:00
for ( var j in this . baseManagers [ i ] . dropsites )
2013-09-29 15:32:52 +02:00
{
var amnts = this . baseManagers [ i ] . dropsites [ j ] ;
var dpEnt = gameState . getEntityById ( j ) ;
if ( dpEnt !== undefined && dpEnt . getMetadata ( PlayerID , "defenseTower" ) !== true )
if ( amnts [ "wood" ] || amnts [ "metal" ] || amnts [ "stone" ] )
{
var position = dpEnt . position ( ) ;
if ( position ) {
2014-01-14 20:54:31 +01:00
queues . defenceBuilding . addItem ( new m . ConstructionPlan ( gameState , 'structures/{civ}_defense_tower' , { "base" : i } , position ) ) ;
2013-09-29 15:32:52 +02:00
}
dpEnt . setMetadata ( PlayerID , "defenseTower" , true ) ;
}
}
}
}
var numFortresses = 0 ;
for ( var i in this . bFort ) {
2014-01-12 03:40:42 +01:00
numFortresses += gameState . countEntitiesAndQueuedByType ( gameState . applyCiv ( this . bFort [ i ] ) , true ) ;
2013-09-29 15:32:52 +02:00
}
if ( queues . defenceBuilding . length ( ) < 1 && ( gameState . currentPhase ( ) > 2 || gameState . isResearching ( "phase_city_generic" ) ) )
{
if ( workersNumber >= 80 && gameState . getTimeElapsed ( ) > numFortresses * this . fortressLapseTime + this . fortressStartTime )
{
if ( ! this . fortressStartTime )
this . fortressStartTime = gameState . getTimeElapsed ( ) ;
2013-12-30 11:04:59 +01:00
queues . defenceBuilding . addItem ( new m . ConstructionPlan ( gameState , this . bFort [ 0 ] , { "base" : 1 } ) ) ;
m . debug ( "Building a fortress" ) ;
2013-09-29 15:32:52 +02:00
}
}
if ( gameState . countEntitiesByType ( gameState . applyCiv ( this . bFort [ i ] ) , true ) >= 1 ) {
// let's add a siege building plan to the current attack plan if there is none currently.
if ( this . upcomingAttacks [ "CityAttack" ] . length !== 0 )
{
var attack = this . upcomingAttacks [ "CityAttack" ] [ 0 ] ;
if ( ! attack . unitStat [ "Siege" ] )
{
// no minsize as we don't want the plan to fail at the last minute though.
var stat = { "priority" : 1.1 , "minSize" : 0 , "targetSize" : 4 , "batchSize" : 2 , "classes" : [ "Siege" ] ,
"interests" : [ [ "siegeStrength" , 3 ] , [ "cost" , 1 ] ] , "templates" : [ ] } ;
if ( gameState . civ ( ) == "cart" || gameState . civ ( ) == "maur" )
stat [ "classes" ] = [ "Elephant" ] ;
attack . addBuildOrder ( gameState , "Siege" , stat , true ) ;
}
}
}
} ;
2013-12-30 11:04:59 +01:00
m . HQ . prototype . buildBlacksmith = function ( gameState , queues ) {
if ( gameState . getTimeElapsed ( ) > this . Config . Military . timeForBlacksmith * 1000 ) {
2013-09-29 15:32:52 +02:00
if ( queues . militaryBuilding . length ( ) === 0 &&
2014-01-12 03:40:42 +01:00
gameState . countEntitiesAndQueuedByType ( gameState . applyCiv ( "structures/{civ}_blacksmith" ) , true ) === 0 ) {
2013-09-29 15:32:52 +02:00
var tp = gameState . getTemplate ( gameState . applyCiv ( "structures/{civ}_blacksmith" ) ) ;
if ( tp . available ( gameState ) )
2013-12-30 11:04:59 +01:00
queues . militaryBuilding . addItem ( new m . ConstructionPlan ( gameState , "structures/{civ}_blacksmith" , { "base" : 1 } ) ) ;
2013-09-29 15:32:52 +02:00
}
}
} ;
// Deals with constructing military buildings (barracks, stables…)
// They are mostly defined by Config.js. This is unreliable since changes could be done easily.
// TODO: We need to determine these dynamically. Also doesn't build fortresses since the above function does that.
// TODO: building placement is bad. Choice of buildings is also fairly dumb.
2013-12-30 11:04:59 +01:00
m . HQ . prototype . constructTrainingBuildings = function ( gameState , queues ) {
2013-09-29 15:32:52 +02:00
Engine . ProfileStart ( "Build buildings" ) ;
2014-01-12 02:07:07 +01:00
var workersNumber = gameState . getOwnEntitiesByRole ( "worker" , true ) . filter ( API3 . Filters . not ( API3 . Filters . byHasMetadata ( PlayerID , "plan" ) ) ) . length ;
2013-09-29 15:32:52 +02:00
2014-01-14 20:54:31 +01:00
var barrackNb = gameState . countEntitiesAndQueuedByType ( gameState . applyCiv ( this . bModerate [ 0 ] ) , true ) ;
// first barracks.
if ( workersNumber > this . Config . Military . popForBarracks1 || ( this . econState == "townPhasing" && gameState . getOwnStructures ( ) . filter ( API3 . Filters . byClass ( "Village" ) ) . length < 5 ) ) {
if ( barrackNb + queues . militaryBuilding . length ( ) < 1 ) {
2013-12-30 11:04:59 +01:00
m . debug ( "Trying to build barracks" ) ;
2014-01-14 20:54:31 +01:00
var plan = new m . ConstructionPlan ( gameState , this . bModerate [ 0 ] , { "base" : 1 } ) ;
plan . onStart = function ( gameState ) { gameState . ai . queueManager . changePriority ( "militaryBuilding" , 130 ) ; } ;
queues . militaryBuilding . addItem ( plan ) ;
2013-09-29 15:32:52 +02:00
}
}
2014-01-14 20:54:31 +01:00
// second barracks.
if ( barrackNb < 2 && workersNumber > this . Config . Military . popForBarracks2 )
2013-09-29 15:32:52 +02:00
if ( queues . militaryBuilding . length ( ) < 1 )
2013-12-30 11:04:59 +01:00
queues . militaryBuilding . addItem ( new m . ConstructionPlan ( gameState , this . bModerate [ 0 ] , { "base" : 1 } ) ) ;
2013-09-29 15:32:52 +02:00
2014-01-14 20:54:31 +01:00
// third barracks (optional 4th/5th for some civs as they rely on barracks more.)
if ( barrackNb === 2 && barrackNb + queues . militaryBuilding . length ( ) < 3 && workersNumber > 125 )
if ( queues . militaryBuilding . length ( ) === 0 )
2013-09-29 15:32:52 +02:00
{
2013-12-30 11:04:59 +01:00
queues . militaryBuilding . addItem ( new m . ConstructionPlan ( gameState , this . bModerate [ 0 ] , { "base" : 1 } ) ) ;
2013-09-29 15:32:52 +02:00
if ( gameState . civ ( ) == "gaul" || gameState . civ ( ) == "brit" || gameState . civ ( ) == "iber" ) {
2013-12-30 11:04:59 +01:00
queues . militaryBuilding . addItem ( new m . ConstructionPlan ( gameState , this . bModerate [ 0 ] , { "base" : 1 } ) ) ;
queues . militaryBuilding . addItem ( new m . ConstructionPlan ( gameState , this . bModerate [ 0 ] , { "base" : 1 } ) ) ;
2013-09-29 15:32:52 +02:00
}
}
2014-01-14 20:54:31 +01:00
2013-09-29 15:32:52 +02:00
//build advanced military buildings
2013-12-30 11:04:59 +01:00
if ( workersNumber >= this . Config . Military . popForBarracks2 - 15 && gameState . currentPhase ( ) > 2 ) {
2013-09-29 15:32:52 +02:00
if ( queues . militaryBuilding . length ( ) === 0 ) {
var inConst = 0 ;
for ( var i in this . bAdvanced )
2014-01-12 02:07:07 +01:00
inConst += gameState . countFoundationsByType ( gameState . applyCiv ( this . bAdvanced [ i ] ) ) ;
2013-09-29 15:32:52 +02:00
if ( inConst == 0 && this . bAdvanced && this . bAdvanced . length !== 0 ) {
var i = Math . floor ( Math . random ( ) * this . bAdvanced . length ) ;
2014-01-12 03:40:42 +01:00
if ( gameState . countEntitiesAndQueuedByType ( gameState . applyCiv ( this . bAdvanced [ i ] ) , true ) < 1 ) {
2013-12-30 11:04:59 +01:00
queues . militaryBuilding . addItem ( new m . ConstructionPlan ( gameState , this . bAdvanced [ i ] , { "base" : 1 } ) ) ;
2013-09-29 15:32:52 +02:00
}
}
}
}
2014-01-14 20:54:31 +01:00
// build second advanced building except for some civs.
2013-09-29 15:32:52 +02:00
if ( gameState . civ ( ) !== "gaul" && gameState . civ ( ) !== "brit" && gameState . civ ( ) !== "iber" &&
workersNumber > 130 && gameState . currentPhase ( ) > 2 )
{
var Const = 0 ;
for ( var i in this . bAdvanced )
Const += gameState . countEntitiesByType ( gameState . applyCiv ( this . bAdvanced [ i ] ) , true ) ;
if ( inConst == 1 ) {
var i = Math . floor ( Math . random ( ) * this . bAdvanced . length ) ;
2014-01-12 03:40:42 +01:00
if ( gameState . countEntitiesAndQueuedByType ( gameState . applyCiv ( this . bAdvanced [ i ] ) , true ) < 1 ) {
2013-12-30 11:04:59 +01:00
queues . militaryBuilding . addItem ( new m . ConstructionPlan ( gameState , this . bAdvanced [ i ] , { "base" : 1 } ) ) ;
queues . militaryBuilding . addItem ( new m . ConstructionPlan ( gameState , this . bAdvanced [ i ] , { "base" : 1 } ) ) ;
2013-09-29 15:32:52 +02:00
}
}
}
Engine . ProfileStop ( ) ;
} ;
// TODO: use pop(). Currently unused as this is too gameable.
2013-12-30 11:04:59 +01:00
m . HQ . prototype . garrisonAllFemales = function ( gameState ) {
2014-01-12 02:07:07 +01:00
var buildings = gameState . getOwnStructures ( ) . filter ( API3 . Filters . byCanGarrison ( ) ) . toEntityArray ( ) ;
var females = gameState . getOwnUnits ( ) . filter ( API3 . Filters . byClass ( "Support" ) ) ;
2013-09-29 15:32:52 +02:00
var cache = { } ;
females . forEach ( function ( ent ) {
for ( var i in buildings )
{
if ( ent . position ( ) )
{
var struct = buildings [ i ] ;
if ( ! cache [ struct . id ( ) ] )
cache [ struct . id ( ) ] = 0 ;
if ( struct . garrisoned ( ) && struct . garrisonMax ( ) - struct . garrisoned ( ) . length - cache [ struct . id ( ) ] > 0 )
{
ent . garrison ( struct ) ;
cache [ struct . id ( ) ] ++ ;
break ;
}
}
}
} ) ;
this . hasGarrisonedFemales = true ;
} ;
2013-12-30 11:04:59 +01:00
m . HQ . prototype . ungarrisonAll = function ( gameState ) {
2013-09-29 15:32:52 +02:00
this . hasGarrisonedFemales = false ;
2014-01-12 02:07:07 +01:00
var buildings = gameState . getOwnStructures ( ) . filter ( API3 . Filters . and ( API3 . Filters . byClass ( "Structure" ) , API3 . Filters . byCanGarrison ( ) ) ) . toEntityArray ( ) ;
2013-09-29 15:32:52 +02:00
buildings . forEach ( function ( struct ) {
if ( struct . garrisoned ( ) && struct . garrisoned ( ) . length )
struct . unloadAll ( ) ;
} ) ;
} ;
2013-12-30 11:04:59 +01:00
m . HQ . prototype . pausePlan = function ( gameState , planName ) {
2013-09-29 15:32:52 +02:00
for ( var attackType in this . upcomingAttacks ) {
for ( var i in this . upcomingAttacks [ attackType ] ) {
var attack = this . upcomingAttacks [ attackType ] [ i ] ;
if ( attack . getName ( ) == planName )
attack . setPaused ( gameState , true ) ;
}
}
for ( var attackType in this . startedAttacks ) {
for ( var i in this . startedAttacks [ attackType ] ) {
var attack = this . startedAttacks [ attackType ] [ i ] ;
if ( attack . getName ( ) == planName )
attack . setPaused ( gameState , true ) ;
}
}
}
2013-12-30 11:04:59 +01:00
m . HQ . prototype . unpausePlan = function ( gameState , planName ) {
2013-09-29 15:32:52 +02:00
for ( var attackType in this . upcomingAttacks ) {
for ( var i in this . upcomingAttacks [ attackType ] ) {
var attack = this . upcomingAttacks [ attackType ] [ i ] ;
if ( attack . getName ( ) == planName )
attack . setPaused ( gameState , false ) ;
}
}
for ( var attackType in this . startedAttacks ) {
for ( var i in this . startedAttacks [ attackType ] ) {
var attack = this . startedAttacks [ attackType ] [ i ] ;
if ( attack . getName ( ) == planName )
attack . setPaused ( gameState , false ) ;
}
}
}
2013-12-30 11:04:59 +01:00
m . HQ . prototype . pauseAllPlans = function ( gameState ) {
2013-09-29 15:32:52 +02:00
for ( var attackType in this . upcomingAttacks ) {
for ( var i in this . upcomingAttacks [ attackType ] ) {
var attack = this . upcomingAttacks [ attackType ] [ i ] ;
attack . setPaused ( gameState , true ) ;
}
}
for ( var attackType in this . startedAttacks ) {
for ( var i in this . startedAttacks [ attackType ] ) {
var attack = this . startedAttacks [ attackType ] [ i ] ;
attack . setPaused ( gameState , true ) ;
}
}
}
2013-12-30 11:04:59 +01:00
m . HQ . prototype . unpauseAllPlans = function ( gameState ) {
2013-09-29 15:32:52 +02:00
for ( var attackType in this . upcomingAttacks ) {
for ( var i in this . upcomingAttacks [ attackType ] ) {
var attack = this . upcomingAttacks [ attackType ] [ i ] ;
attack . setPaused ( gameState , false ) ;
}
}
for ( var attackType in this . startedAttacks ) {
for ( var i in this . startedAttacks [ attackType ] ) {
var attack = this . startedAttacks [ attackType ] [ i ] ;
attack . setPaused ( gameState , false ) ;
}
}
}
// Some functions are run every turn
// Others once in a while
2013-12-30 11:04:59 +01:00
m . HQ . prototype . update = function ( gameState , queues , events ) {
2013-09-29 15:32:52 +02:00
Engine . ProfileStart ( "Headquarters update" ) ;
this . checkEvents ( gameState , events , queues ) ;
//this.buildMoreHouses(gameState);
this . trainMoreWorkers ( gameState , queues ) ;
// sandbox doesn't expand.
2013-12-30 11:04:59 +01:00
if ( this . Config . difficulty !== 0 )
2013-09-29 15:32:52 +02:00
this . checkBasesRessLevel ( gameState , queues ) ;
this . buildMoreHouses ( gameState , queues ) ;
2014-01-12 20:12:55 +01:00
if ( gameState . getTimeElapsed ( ) > this . techStartTime && gameState . currentPhase ( ) > 2 )
2013-09-29 15:32:52 +02:00
this . tryResearchTechs ( gameState , queues ) ;
2013-12-30 11:04:59 +01:00
if ( this . Config . difficulty > 1 )
2013-09-29 15:32:52 +02:00
this . tryBartering ( gameState ) ;
this . buildFarmstead ( gameState , queues ) ;
this . buildMarket ( gameState , queues ) ;
// Deactivated: the temple had no useful purpose for the AI now.
2014-01-12 03:40:42 +01:00
//if (gameState.countEntitiesAndQueuedByType(gameState.applyCiv("structures/{civ}_market"), true) === 1)
2013-09-29 15:32:52 +02:00
// this.buildTemple(gameState, queues);
this . buildDock ( gameState , queues ) ; // not if not a water map.
Engine . ProfileStart ( "Constructing military buildings and building defences" ) ;
this . constructTrainingBuildings ( gameState , queues ) ;
this . buildBlacksmith ( gameState , queues ) ;
if ( gameState . getTimeElapsed ( ) > this . defenceBuildingTime )
this . buildDefences ( gameState , queues ) ;
Engine . ProfileStop ( ) ;
2014-01-06 21:55:22 +01:00
for ( var i in this . baseManagers )
2013-09-29 15:32:52 +02:00
{
this . baseManagers [ i ] . checkEvents ( gameState , events , queues )
2013-12-30 11:04:59 +01:00
if ( ( ( + i + gameState . ai . playedTurn ) % ( m . playerGlobals [ PlayerID ] . uniqueIDBases - 1 ) ) === 0 )
2013-09-29 15:32:52 +02:00
this . baseManagers [ i ] . update ( gameState , queues , events ) ;
}
this . navalManager . update ( gameState , queues , events ) ;
this . defenceManager . update ( gameState , events , this ) ;
Engine . ProfileStart ( "Looping through attack plans" ) ;
// TODO: bump this into a function.
// TODO: implement some form of check before starting a new attack plans. Sometimes it is not the priority.
if ( 1 ) {
for ( var attackType in this . upcomingAttacks ) {
for ( var i = 0 ; i < this . upcomingAttacks [ attackType ] . length ; ++ i ) {
var attack = this . upcomingAttacks [ attackType ] [ i ] ;
// okay so we'll get the support plan
if ( ! attack . isStarted ( ) ) {
var updateStep = attack . updatePreparation ( gameState , this , events ) ;
// now we're gonna check if the preparation time is over
if ( updateStep === 1 || attack . isPaused ( ) ) {
// just chillin'
} else if ( updateStep === 0 || updateStep === 3 ) {
2013-12-30 11:04:59 +01:00
m . debug ( "Military Manager: " + attack . getType ( ) + " plan " + attack . getName ( ) + " aborted." ) ;
2013-09-29 15:32:52 +02:00
if ( updateStep === 3 ) {
this . attackPlansEncounteredWater = true ;
2013-12-30 11:04:59 +01:00
m . debug ( "No attack path found. Aborting." ) ;
2013-09-29 15:32:52 +02:00
}
attack . Abort ( gameState , this ) ;
this . upcomingAttacks [ attackType ] . splice ( i -- , 1 ) ;
} else if ( updateStep === 2 ) {
var chatText = "I am launching an attack against " + gameState . sharedScript . playersData [ attack . targetPlayer ] . name + "." ;
if ( Math . random ( ) < 0.2 )
chatText = "Attacking " + gameState . sharedScript . playersData [ attack . targetPlayer ] . name + "." ;
else if ( Math . random ( ) < 0.3 )
chatText = "I have sent an army against " + gameState . sharedScript . playersData [ attack . targetPlayer ] . name + "." ;
else if ( Math . random ( ) < 0.3 )
chatText = "I'm starting an attack against " + gameState . sharedScript . playersData [ attack . targetPlayer ] . name + "." ;
gameState . ai . chatTeam ( chatText ) ;
2013-12-30 11:04:59 +01:00
m . debug ( "Military Manager: Starting " + attack . getType ( ) + " plan " + attack . getName ( ) ) ;
2013-09-29 15:32:52 +02:00
attack . StartAttack ( gameState , this ) ;
this . startedAttacks [ attackType ] . push ( attack ) ;
this . upcomingAttacks [ attackType ] . splice ( i -- , 1 ) ;
}
} else {
var chatText = "I am launching an attack against " + gameState . sharedScript . playersData [ attack . targetPlayer ] . name + "." ;
if ( Math . random ( ) < 0.2 )
chatText = "Attacking " + gameState . sharedScript . playersData [ attack . targetPlayer ] . name + "." ;
else if ( Math . random ( ) < 0.3 )
chatText = "I have sent an army against " + gameState . sharedScript . playersData [ attack . targetPlayer ] . name + "." ;
else if ( Math . random ( ) < 0.3 )
chatText = "I'm starting an attack against " + gameState . sharedScript . playersData [ attack . targetPlayer ] . name + "." ;
gameState . ai . chatTeam ( chatText ) ;
2013-12-30 11:04:59 +01:00
m . debug ( "Military Manager: Starting " + attack . getType ( ) + " plan " + attack . getName ( ) ) ;
2013-09-29 15:32:52 +02:00
this . startedAttacks [ attackType ] . push ( attack ) ;
this . upcomingAttacks [ attackType ] . splice ( i -- , 1 ) ;
}
}
}
}
for ( var attackType in this . startedAttacks ) {
for ( var i = 0 ; i < this . startedAttacks [ attackType ] . length ; ++ i ) {
var attack = this . startedAttacks [ attackType ] [ i ] ;
// okay so then we'll update the attack.
if ( ! attack . isPaused ( ) )
{
var remaining = attack . update ( gameState , this , events ) ;
if ( remaining == 0 || remaining == undefined ) {
2013-12-30 11:04:59 +01:00
m . debug ( "Military Manager: " + attack . getType ( ) + " plan " + attack . getName ( ) + " is now finished." ) ;
2013-09-29 15:32:52 +02:00
attack . Abort ( gameState ) ;
this . startedAttacks [ attackType ] . splice ( i -- , 1 ) ;
}
}
}
}
2014-01-14 20:54:31 +01:00
// creating plans after updating because an aborted plan might be reused in that case.
2013-09-29 15:32:52 +02:00
// TODO: remove the limitation to attacks when on water maps.
2014-01-14 20:54:31 +01:00
if ( ! this . waterMap && ! this . attackPlansEncounteredWater )
2013-09-29 15:32:52 +02:00
{
2014-01-14 20:54:31 +01:00
if ( gameState . ai . aggressiveness > 0.75 && gameState . countEntitiesByType ( gameState . applyCiv ( this . bModerate [ 0 ] ) , true ) >= 1
&& gameState . getTimeElapsed ( ) > this . attackPlansStartTime && gameState . getTimeElapsed ( ) < 360000 )
{
if ( this . upcomingAttacks [ "Rush" ] . length === 0 )
{
// we have a barracks and we want to rush, rush.
var AttackPlan = new m . CityAttack ( gameState , this , this . Config , this . TotalAttackNumber , - 1 , "Rush" ) ;
m . debug ( "Headquarters: Rushing plan " + this . TotalAttackNumber ) ;
this . TotalAttackNumber ++ ;
this . upcomingAttacks [ "Rush" ] . push ( AttackPlan ) ;
}
}
// if we have a barracks, there's no water, we're at age >= 1 and we've decided to attack.
else if ( gameState . countEntitiesByType ( gameState . applyCiv ( this . bModerate [ 0 ] ) , true ) >= 1 && ! this . attackPlansEncounteredWater
&& gameState . getTimeElapsed ( ) > this . attackPlansStartTime && ( gameState . currentPhase ( ) > 1 || gameState . isResearching ( gameState . townPhase ( ) ) ) ) {
2013-09-29 15:32:52 +02:00
if ( gameState . countEntitiesByType ( gameState . applyCiv ( "structures/{civ}_dock" ) , true ) === 0 && this . waterMap )
{
// wait till we get a dock.
2014-01-14 20:54:31 +01:00
} else if ( this . upcomingAttacks [ "CityAttack" ] . length === 0 ) {
2013-09-29 15:32:52 +02:00
// basically only the first plan, really.
2014-01-14 20:54:31 +01:00
var Lalala = undefined ;
if ( gameState . getTimeElapsed ( ) < 12 * 60000 )
Lalala = new m . CityAttack ( gameState , this , this . Config , this . TotalAttackNumber , - 1 ) ;
else if ( this . Config . difficulty !== 0 )
Lalala = new m . CityAttack ( gameState , this , this . Config , this . TotalAttackNumber , - 1 , "superSized" ) ;
if ( Lalala . failed )
this . attackPlansEncounteredWater = true ; // hack
else {
m . debug ( "Military Manager: Creating the plan " + this . TotalAttackNumber ) ;
this . TotalAttackNumber ++ ;
this . upcomingAttacks [ "CityAttack" ] . push ( Lalala ) ;
2013-09-29 15:32:52 +02:00
}
}
}
}
/ *
// very old relic. This should be reimplemented someday so the code stays here.
if ( this . HarassRaiding && this . preparingRaidNumber + this . startedRaidNumber < 1 && gameState . getTimeElapsed ( ) < 780000 ) {
2013-12-30 11:04:59 +01:00
var Lalala = new m . CityAttack ( gameState , this , this . totalStartedAttackNumber , - 1 , "harass_raid" ) ;
2013-09-29 15:32:52 +02:00
if ( ! Lalala . createSupportPlans ( gameState , this , ) ) {
2013-12-30 11:04:59 +01:00
m . debug ( "Military Manager: harrassing plan not a valid option" ) ;
2013-09-29 15:32:52 +02:00
this . HarassRaiding = false ;
} else {
2013-12-30 11:04:59 +01:00
m . debug ( "Military Manager: Creating the harass raid plan " + this . totalStartedAttackNumber ) ;
2013-09-29 15:32:52 +02:00
this . totalStartedAttackNumber ++ ;
this . preparingRaidNumber ++ ;
this . currentAttacks . push ( Lalala ) ;
}
}
* /
Engine . ProfileStop ( ) ;
/ *
Engine . ProfileStop ( ) ;
Engine . ProfileStart ( "Build new Dropsites" ) ;
this . buildDropsites ( gameState , queues ) ;
Engine . ProfileStop ( ) ;
2013-12-30 11:04:59 +01:00
if ( this . Config . difficulty !== 0 )
2013-09-29 15:32:52 +02:00
this . tryBartering ( gameState ) ;
this . buildFarmstead ( gameState , queues ) ;
this . buildMarket ( gameState , queues ) ;
// Deactivated: the temple had no useful purpose for the AI now.
2014-01-12 03:40:42 +01:00
//if (gameState.countEntitiesAndQueuedByType(gameState.applyCiv("structures/{civ}_market"), true === 1)
2013-09-29 15:32:52 +02:00
// this.buildTemple(gameState, queues);
this . buildDock ( gameState , queues ) ; // not if not a water map.
* /
Engine . ProfileStop ( ) ; // Heaquarters update
} ;
2013-12-30 11:04:59 +01:00
return m ;
} ( AEGIS ) ;