Changeset View
Changeset View
Standalone View
Standalone View
ps/trunk/binaries/data/mods/public/simulation/ai/petra/navalManager.js
Show All 32 Lines | m.NavalManager = function(Config) | ||||
// shore-line regions where we can load and unload units | // shore-line regions where we can load and unload units | ||||
this.landingZones = {}; | this.landingZones = {}; | ||||
}; | }; | ||||
/** More initialisation for stuff that needs the gameState */ | /** More initialisation for stuff that needs the gameState */ | ||||
m.NavalManager.prototype.init = function(gameState, deserializing) | m.NavalManager.prototype.init = function(gameState, deserializing) | ||||
{ | { | ||||
// finished docks | // docks | ||||
this.docks = gameState.getOwnStructures().filter(API3.Filters.and(API3.Filters.byClassesOr(["Dock", "Shipyard"]), | this.docks = gameState.getOwnStructures().filter(API3.Filters.byClassesOr(["Dock", "Shipyard"])); | ||||
API3.Filters.not(API3.Filters.isFoundation()))); | |||||
this.docks.registerUpdates(); | this.docks.registerUpdates(); | ||||
this.ships = gameState.getOwnUnits().filter(API3.Filters.and(API3.Filters.byClass("Ship"), API3.Filters.not(API3.Filters.byMetadata(PlayerID, "role", "trader")))); | this.ships = gameState.getOwnUnits().filter(API3.Filters.and(API3.Filters.byClass("Ship"), API3.Filters.not(API3.Filters.byMetadata(PlayerID, "role", "trader")))); | ||||
// note: those two can overlap (some transport ships are warships too and vice-versa). | // note: those two can overlap (some transport ships are warships too and vice-versa). | ||||
this.transportShips = this.ships.filter(API3.Filters.and(API3.Filters.byCanGarrison(), API3.Filters.not(API3.Filters.byClass("FishingBoat")))); | this.transportShips = this.ships.filter(API3.Filters.and(API3.Filters.byCanGarrison(), API3.Filters.not(API3.Filters.byClass("FishingBoat")))); | ||||
this.warShips = this.ships.filter(API3.Filters.byClass("Warship")); | this.warShips = this.ships.filter(API3.Filters.byClass("Warship")); | ||||
this.fishShips = this.ships.filter(API3.Filters.byClass("FishingBoat")); | this.fishShips = this.ships.filter(API3.Filters.byClass("FishingBoat")); | ||||
▲ Show 20 Lines • Show All 47 Lines • ▼ Show 20 Lines | else | ||||
this.wantedFishShips.push(this.Config.Economy.targetNumFishers); | this.wantedFishShips.push(this.Config.Economy.targetNumFishers); | ||||
else | else | ||||
this.wantedFishShips.push(0); | this.wantedFishShips.push(0); | ||||
this.neededTransportShips.push(0); | this.neededTransportShips.push(0); | ||||
this.neededWarShips.push(0); | this.neededWarShips.push(0); | ||||
} | } | ||||
} | } | ||||
// load units and buildings from the config files | |||||
let civ = gameState.getPlayerCiv(); | |||||
if (civ in this.Config.buildings.naval) | |||||
this.bNaval = this.Config.buildings.naval[civ]; | |||||
else | |||||
this.bNaval = this.Config.buildings.naval['default']; | |||||
for (let i in this.bNaval) | |||||
this.bNaval[i] = gameState.applyCiv(this.bNaval[i]); | |||||
if (deserializing) | if (deserializing) | ||||
return; | return; | ||||
// determination of the possible landing zones | // determination of the possible landing zones | ||||
let width = gameState.getPassabilityMap().width; | let width = gameState.getPassabilityMap().width; | ||||
let length = width * gameState.getPassabilityMap().height; | let length = width * gameState.getPassabilityMap().height; | ||||
for (let i = 0; i < length; ++i) | for (let i = 0; i < length; ++i) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 137 Lines • ▼ Show 20 Lines | return around.every(a => | ||||
return true; | return true; | ||||
}); | }); | ||||
}; | }; | ||||
/** get the list of seas (or lands) around this region not connected by a dock */ | /** get the list of seas (or lands) around this region not connected by a dock */ | ||||
m.NavalManager.prototype.getUnconnectedSeas = function(gameState, region) | m.NavalManager.prototype.getUnconnectedSeas = function(gameState, region) | ||||
{ | { | ||||
let seas = gameState.ai.accessibility.regionLinks[region].slice(); | let seas = gameState.ai.accessibility.regionLinks[region].slice(); | ||||
let docks = gameState.getOwnStructures().filter(API3.Filters.byClass("Dock")); | this.docks.forEach(function (dock) { | ||||
docks.forEach(function (dock) { | if (!dock.hasClass("Dock") || dock.getMetadata(PlayerID, "access") !== region) | ||||
if (dock.getMetadata(PlayerID, "access") !== region) | |||||
return; | return; | ||||
let i = seas.indexOf(dock.getMetadata(PlayerID, "sea")); | let i = seas.indexOf(dock.getMetadata(PlayerID, "sea")); | ||||
if (i !== -1) | if (i !== -1) | ||||
seas.splice(i--,1); | seas.splice(i--,1); | ||||
}); | }); | ||||
return seas; | return seas; | ||||
}; | }; | ||||
m.NavalManager.prototype.checkEvents = function(gameState, queues, events) | m.NavalManager.prototype.checkEvents = function(gameState, queues, events) | ||||
{ | { | ||||
for (let evt of events.ConstructionFinished) | for (let evt of events.Create) | ||||
{ | { | ||||
if (!evt || !evt.newentity) | if (!evt.entity) | ||||
continue; | continue; | ||||
let entity = gameState.getEntityById(evt.newentity); | let ent = gameState.getEntityById(evt.entity); | ||||
if (entity && entity.hasClass("Dock") && entity.isOwn(PlayerID)) | if (ent && ent.isOwn(PlayerID) && ent.foundationProgress() !== undefined && (ent.hasClass("Dock") || ent.hasClass("Shipyard"))) | ||||
this.setAccessIndices(gameState, entity); | this.setAccessIndices(gameState, ent); | ||||
} | } | ||||
for (let evt of events.TrainingFinished) | for (let evt of events.TrainingFinished) | ||||
{ | { | ||||
if (!evt || !evt.entities) | if (!evt.entities) | ||||
continue; | continue; | ||||
for (let entId of evt.entities) | for (let entId of evt.entities) | ||||
{ | { | ||||
let entity = gameState.getEntityById(entId); | let ent = gameState.getEntityById(entId); | ||||
if (!entity || !entity.hasClass("Ship") || !entity.isOwn(PlayerID)) | if (!ent || !ent.hasClass("Ship") || !ent.isOwn(PlayerID)) | ||||
continue; | continue; | ||||
this.setShipIndex(gameState, entity); | this.setShipIndex(gameState, ent); | ||||
} | } | ||||
} | } | ||||
for (let evt of events.Destroy) | for (let evt of events.Destroy) | ||||
{ | { | ||||
if (!evt.entityObj || evt.entityObj.owner() !== PlayerID || !evt.metadata || !evt.metadata[PlayerID]) | if (!evt.entityObj || evt.entityObj.owner() !== PlayerID || !evt.metadata || !evt.metadata[PlayerID]) | ||||
continue; | continue; | ||||
if (!evt.entityObj.hasClass("Ship") || !evt.metadata[PlayerID].transporter) | if (!evt.entityObj.hasClass("Ship") || !evt.metadata[PlayerID].transporter) | ||||
continue; | continue; | ||||
let plan = this.getPlan(evt.metadata[PlayerID].transporter); | let plan = this.getPlan(evt.metadata[PlayerID].transporter); | ||||
if (!plan) | if (!plan) | ||||
continue; | continue; | ||||
let shipId = evt.entityObj.id(); | let shipId = evt.entityObj.id(); | ||||
if (this.Config.debug > 1) | if (this.Config.debug > 1) | ||||
API3.warn("one ship " + shipId + " from plan " + plan.ID + " destroyed during " + plan.state); | API3.warn("one ship " + shipId + " from plan " + plan.ID + " destroyed during " + plan.state); | ||||
if (plan.state === "boarding") | if (plan.state === "boarding") | ||||
{ | { | ||||
// just reset the units onBoard metadata and wait for a new ship to be assigned to this plan | // just reset the units onBoard metadata and wait for a new ship to be assigned to this plan | ||||
plan.units.forEach(function (ent) { | plan.units.forEach(function (ent) { | ||||
if ((ent.getMetadata(PlayerID, "onBoard") === "onBoard" && ent.position()) || | if (ent.getMetadata(PlayerID, "onBoard") === "onBoard" && ent.position() || | ||||
ent.getMetadata(PlayerID, "onBoard") === shipId) | ent.getMetadata(PlayerID, "onBoard") === shipId) | ||||
ent.setMetadata(PlayerID, "onBoard", undefined); | ent.setMetadata(PlayerID, "onBoard", undefined); | ||||
}); | }); | ||||
plan.needTransportShips = !plan.transportShips.hasEntities(); | plan.needTransportShips = !plan.transportShips.hasEntities(); | ||||
} | } | ||||
else if (plan.state === "sailing") | else if (plan.state === "sailing") | ||||
{ | { | ||||
let endIndex = plan.endIndex; | let endIndex = plan.endIndex; | ||||
let self = this; | let self = this; | ||||
Show All 12 Lines | else if (plan.state === "sailing") | ||||
if (access !== endIndex) | if (access !== endIndex) | ||||
self.requireTransport(gameState, ent, access, endIndex, endPos); | self.requireTransport(gameState, ent, access, endIndex, endPos); | ||||
}); | }); | ||||
} | } | ||||
} | } | ||||
for (let evt of events.OwnershipChanged) // capture events | for (let evt of events.OwnershipChanged) // capture events | ||||
{ | { | ||||
if (evt.to === PlayerID) | if (evt.to !== PlayerID) | ||||
{ | continue; | ||||
let ent = gameState.getEntityById(evt.entity); | let ent = gameState.getEntityById(evt.entity); | ||||
if (ent && ent.hasClass("Dock")) | if (ent && (ent.hasClass("Dock") || ent.hasClass("Shipyard"))) | ||||
this.setAccessIndices(gameState, ent); | this.setAccessIndices(gameState, ent); | ||||
} | } | ||||
} | |||||
}; | }; | ||||
m.NavalManager.prototype.getPlan = function(ID) | m.NavalManager.prototype.getPlan = function(ID) | ||||
{ | { | ||||
for (let plan of this.transportPlans) | for (let plan of this.transportPlans) | ||||
if (plan.ID === ID) | if (plan.ID === ID) | ||||
return plan; | return plan; | ||||
▲ Show 20 Lines • Show All 139 Lines • ▼ Show 20 Lines | for (let sea = 0; sea < this.neededTransportShips.length; sea++) | ||||
if (this.neededTransportShips[sea] > 2) | if (this.neededTransportShips[sea] > 2) | ||||
++this.wantedTransportShips[sea]; | ++this.wantedTransportShips[sea]; | ||||
}; | }; | ||||
m.NavalManager.prototype.maintainFleet = function(gameState, queues) | m.NavalManager.prototype.maintainFleet = function(gameState, queues) | ||||
{ | { | ||||
if (queues.ships.hasQueuedUnits()) | if (queues.ships.hasQueuedUnits()) | ||||
return; | return; | ||||
if (!gameState.getOwnEntitiesByClass("Dock", true).filter(API3.Filters.isBuilt()).hasEntities() && | if (!this.docks.filter(API3.Filters.isBuilt()).hasEntities()) | ||||
!gameState.getOwnEntitiesByClass("Shipyard", true).filter(API3.Filters.isBuilt()).hasEntities()) | |||||
return; | return; | ||||
// check if we have enough transport ships per region. | // check if we have enough transport ships per region. | ||||
for (let sea = 0; sea < this.seaShips.length; ++sea) | for (let sea = 0; sea < this.seaShips.length; ++sea) | ||||
{ | { | ||||
if (this.seaShips[sea] === undefined) | if (this.seaShips[sea] === undefined) | ||||
continue; | continue; | ||||
if (gameState.countOwnQueuedEntitiesWithMetadata("sea", sea) > 0) | if (gameState.countOwnQueuedEntitiesWithMetadata("sea", sea) > 0) | ||||
continue; | continue; | ||||
▲ Show 20 Lines • Show All 111 Lines • ▼ Show 20 Lines | if (queues.dock.countQueuedUnitsWithClass("NavalMarket") === 0 && | ||||
dockStarted = true; | dockStarted = true; | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
} | } | ||||
if (gameState.currentPhase() < 2 || gameState.getPopulation() < this.Config.Economy.popForTown + 15 || | if (gameState.currentPhase() < 2 || gameState.getPopulation() < this.Config.Economy.popForTown + 15 || | ||||
queues.militaryBuilding.hasQueuedUnits() || this.bNaval.length === 0) | queues.militaryBuilding.hasQueuedUnits()) | ||||
return; | return; | ||||
let docks = gameState.getOwnStructures().filter(API3.Filters.byClass("Dock")); | if (!this.docks.filter(API3.Filters.byClass("Dock")).hasEntities() || | ||||
if (!docks.hasEntities()) | this.docks.filter(API3.Filters.byClass("Shipyard")).hasEntities()) | ||||
return; | |||||
let template; | |||||
if (gameState.ai.HQ.canBuild(gameState, "structures/{civ}_super_dock")) | |||||
template = "structures/{civ}_super_dock"; | |||||
else if (gameState.ai.HQ.canBuild(gameState, "structures/{civ}_shipyard")) | |||||
template = "structures/{civ}_shipyard"; | |||||
else | |||||
return; | return; | ||||
let nNaval = 0; | |||||
for (let naval of this.bNaval) | |||||
nNaval += gameState.countEntitiesAndQueuedByType(naval, true); | |||||
if (nNaval === 0 || (nNaval < this.bNaval.length && gameState.getPopulation() > 120)) | |||||
{ | |||||
for (let naval of this.bNaval) | |||||
{ | |||||
if (gameState.countEntitiesAndQueuedByType(naval, true) < 1 && gameState.ai.HQ.canBuild(gameState, naval)) | |||||
{ | |||||
let wantedLand = {}; | let wantedLand = {}; | ||||
for (let base of gameState.ai.HQ.baseManagers) | for (let base of gameState.ai.HQ.baseManagers) | ||||
if (base.anchor) | if (base.anchor) | ||||
wantedLand[base.accessIndex] = true; | wantedLand[base.accessIndex] = true; | ||||
let sea = docks.toEntityArray()[0].getMetadata(PlayerID, "sea"); | let sea = this.docks.toEntityArray()[0].getMetadata(PlayerID, "sea"); | ||||
queues.militaryBuilding.addPlan(new m.ConstructionPlan(gameState, naval, { "land": wantedLand, "sea": sea })); | queues.militaryBuilding.addPlan(new m.ConstructionPlan(gameState, template, { "land": wantedLand, "sea": sea })); | ||||
break; | |||||
} | |||||
} | |||||
} | |||||
}; | }; | ||||
/** goal can be either attack (choose ship with best arrowCount) or transport (choose ship with best capacity) */ | /** goal can be either attack (choose ship with best arrowCount) or transport (choose ship with best capacity) */ | ||||
m.NavalManager.prototype.getBestShip = function(gameState, sea, goal) | m.NavalManager.prototype.getBestShip = function(gameState, sea, goal) | ||||
{ | { | ||||
let civ = gameState.getPlayerCiv(); | let civ = gameState.getPlayerCiv(); | ||||
let trainableShips = []; | let trainableShips = []; | ||||
gameState.getOwnTrainingFacilities().filter(API3.Filters.byMetadata(PlayerID, "sea", sea)).forEach(function(ent) { | gameState.getOwnTrainingFacilities().filter(API3.Filters.byMetadata(PlayerID, "sea", sea)).forEach(function(ent) { | ||||
▲ Show 20 Lines • Show All 122 Lines • Show Last 20 Lines |
Wildfire Games · Phabricator