diff --git a/binaries/data/mods/public/simulation/ai/aegis/base-manager.js b/binaries/data/mods/public/simulation/ai/aegis/base-manager.js index 0a814ba874..4cc3e7f34c 100644 --- a/binaries/data/mods/public/simulation/ai/aegis/base-manager.js +++ b/binaries/data/mods/public/simulation/ai/aegis/base-manager.js @@ -622,8 +622,9 @@ m.BaseManager.prototype.checkResourceLevels = function (gameState,queues) { numFarms += queues.field.countQueuedUnits(); // let's see if we need to push new farms. + var maxGatherers = gameState.getTemplate(gameState.applyCiv("structures/{civ}_field")).maxGatherers(); if (numFd < 2) - if (numFarms < Math.round(this.gatherersByType(gameState, "food").length / 4.6) || numFarms < Math.round(this.workers.length / 15.0)) + if (numFarms < Math.round(this.gatherersByType(gameState, "food").length / (maxGatherers*0.9)) || numFarms < Math.round(this.workers.length / (maxGatherers*3)) queues.field.addItem(new m.ConstructionPlan(gameState, "structures/{civ}_field", { "base" : this.ID })); // TODO: refine count to only count my base. } diff --git a/binaries/data/mods/public/simulation/ai/aegis/defence-helper.js b/binaries/data/mods/public/simulation/ai/aegis/defence-helper.js index bbb7f8b970..043c5c43a6 100755 --- a/binaries/data/mods/public/simulation/ai/aegis/defence-helper.js +++ b/binaries/data/mods/public/simulation/ai/aegis/defence-helper.js @@ -505,7 +505,7 @@ m.Army.prototype.update = function (gameState) { var id = this.entities[i]; var ent = gameState.getEntityById(id); - if (!ent.position) // shouldn't be able to happen but apparently does. + if (!ent || !ent.position()) // shouldn't be able to happen but apparently does. continue; if (API3.SquareVectorDistance(ent.position(), this.position) > this.breakawaySize) { diff --git a/binaries/data/mods/public/simulation/ai/common-api/gamestate.js b/binaries/data/mods/public/simulation/ai/common-api/gamestate.js index 9cbacacf0e..3db569cb32 100644 --- a/binaries/data/mods/public/simulation/ai/common-api/gamestate.js +++ b/binaries/data/mods/public/simulation/ai/common-api/gamestate.js @@ -157,6 +157,8 @@ m.GameState.prototype.townPhase = function() m.GameState.prototype.cityPhase = function() { + if (this.playerData.civ == "athen") + return "phase_city_athen"; return "phase_city_generic"; }; diff --git a/binaries/data/mods/public/simulation/ai/common-api/shared.js b/binaries/data/mods/public/simulation/ai/common-api/shared.js index b4dc583de5..a01afef289 100644 --- a/binaries/data/mods/public/simulation/ai/common-api/shared.js +++ b/binaries/data/mods/public/simulation/ai/common-api/shared.js @@ -131,8 +131,12 @@ m.SharedScript.prototype.init = function(state) { this._entities = {}; for (var id in state.entities) + { + // entropy generator + for (var p = 0; p < id; ++p) + Math.random(); this._entities[id] = new m.Entity(this, state.entities[id]); - + } // entity collection updated on create/destroy event. this.entities = new m.EntityCollection(this, this._entities); diff --git a/binaries/data/mods/public/simulation/components/AIInterface.js b/binaries/data/mods/public/simulation/components/AIInterface.js index f7ba2f1a61..a6d9fb0775 100644 --- a/binaries/data/mods/public/simulation/components/AIInterface.js +++ b/binaries/data/mods/public/simulation/components/AIInterface.js @@ -3,19 +3,26 @@ function AIInterface() {} AIInterface.prototype.Schema = ""; +AIInterface.prototype.EventNames = [ + "Create", + "Destroy", + "Attacked", + "RangeUpdate", + "ConstructionFinished", + "TrainingFinished", + "AIMetadata", + "PlayerDefeated", + "EntityRenamed", + "OwnershipChanged", + "Garrison", + "UnGarrison" +]; + AIInterface.prototype.Init = function() { this.events = {}; - this.events["Create"] = []; - this.events["Destroy"] = []; - this.events["Attacked"] = []; - this.events["RangeUpdate"] = []; - this.events["ConstructionFinished"] = []; - this.events["TrainingFinished"] = []; - this.events["AIMetadata"] = []; - this.events["PlayerDefeated"] = []; - this.events["EntityRenamed"] = []; - this.events["OwnershipChanged"] = []; + for each (var i in this.EventNames) + this.events[i] = []; this.changedEntities = {}; @@ -34,28 +41,13 @@ AIInterface.prototype.GetNonEntityRepresentation = function() var state = cmpGuiInterface.GetExtendedSimulationState(-1); // Add some extra AI-specific data + // add custom events and reset them for the next turn state.events = {}; - state.events["Create"] = this.events["Create"]; - state.events["Destroy"] = this.events["Destroy"]; - state.events["Attacked"] = this.events["Attacked"]; - state.events["RangeUpdate"] = this.events["RangeUpdate"]; - state.events["ConstructionFinished"] = this.events["ConstructionFinished"]; - state.events["TrainingFinished"] = this.events["TrainingFinished"]; - state.events["AIMetadata"] = this.events["AIMetadata"]; - state.events["PlayerDefeated"] = this.events["PlayerDefeated"]; - state.events["EntityRenamed"] = this.events["EntityRenamed"]; - state.events["OwnershipChanged"] = this.events["OwnershipChanged"]; - // Reset the event list for the next turn - this.events["Create"] = []; - this.events["Destroy"] = []; - this.events["Attacked"] = []; - this.events["RangeUpdate"] = []; - this.events["ConstructionFinished"] = []; - this.events["TrainingFinished"] = []; - this.events["AIMetadata"] = []; - this.events["PlayerDefeated"] = []; - this.events["EntityRenamed"] = []; - this.events["OwnershipChanged"] = []; + for each (var i in this.EventNames) + { + state.events[i] = this.events[i]; + this.events[i] = []; + } return state; }; @@ -90,18 +82,8 @@ AIInterface.prototype.GetFullRepresentation = function(flushEvents) var state = this.GetNonEntityRepresentation(); if (flushEvents) - { - state.events["Create"] = []; - state.events["Destroy"] = []; - state.events["Attacked"] = []; - state.events["RangeUpdate"] = []; - state.events["ConstructionFinished"] = []; - state.events["TrainingFinished"] = []; - state.events["AIMetadata"] = []; - state.events["PlayerDefeated"] = []; - state.events["EntityRenamed"] = []; - state.events["OwnershipChanged"] = []; - } + for each (var i in this.EventNames) + state.events[i] = []; // Add entity representations Engine.ProfileStart("proxy representations"); diff --git a/binaries/data/mods/public/simulation/components/AIProxy.js b/binaries/data/mods/public/simulation/components/AIProxy.js index a00f7b9fac..aca09bc928 100644 --- a/binaries/data/mods/public/simulation/components/AIProxy.js +++ b/binaries/data/mods/public/simulation/components/AIProxy.js @@ -34,7 +34,8 @@ AIProxy.prototype.Init = function() { this.changes = null; this.needsFullGet = true; - this.owner = -1; // for convenience now and then. + // cache some data across turns + this.owner = -1; this.cmpAIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_AIInterface); @@ -76,7 +77,7 @@ AIProxy.prototype.NotifyChange = function() if (!this.changes) { this.changes = {}; - this.cmpAIInterface.ChangedEntity(this.entity); + this.cmpAIInterface.ChangedEntity(this.entity); } }; @@ -134,6 +135,15 @@ AIProxy.prototype.OnGarrisonedUnitsChanged = function(msg) var cmpGarrisonHolder = Engine.QueryInterface(this.entity, IID_GarrisonHolder); this.changes.garrisoned = cmpGarrisonHolder.GetEntities(); + + // Send a message telling a unit garrisoned or ungarrisoned. + // I won't check if the unit is still alive so it'll be up to the AI. + var added = msg.added; + var removed = msg.removed; + for each (var ent in added) + this.cmpAIInterface.PushEvent("Garrison", {"entity" : ent, "holder": this.entity}); + for each (var ent in removed) + this.cmpAIInterface.PushEvent("UnGarrison", {"entity" : ent, "holder": this.entity}); }; AIProxy.prototype.OnResourceSupplyChanged = function(msg) diff --git a/binaries/data/mods/public/simulation/components/GarrisonHolder.js b/binaries/data/mods/public/simulation/components/GarrisonHolder.js index a30c76545c..5dfd56dce9 100644 --- a/binaries/data/mods/public/simulation/components/GarrisonHolder.js +++ b/binaries/data/mods/public/simulation/components/GarrisonHolder.js @@ -244,7 +244,7 @@ GarrisonHolder.prototype.PerformGarrison = function(entity) if (cmpAura && cmpAura.HasGarrisonAura()) cmpAura.ApplyGarrisonBonus(this.entity); - Engine.PostMessage(this.entity, MT_GarrisonedUnitsChanged, {}); + Engine.PostMessage(this.entity, MT_GarrisonedUnitsChanged, { "added" : [entity], "removed": [] }); var cmpUnitAI = Engine.QueryInterface(entity, IID_UnitAI); if (cmpUnitAI && cmpUnitAI.GetAlertRaiser()) @@ -310,7 +310,7 @@ GarrisonHolder.prototype.Eject = function(entity, forced) cmpNewPosition.JumpTo(pos.x, pos.z); // TODO: what direction should they face in? - Engine.PostMessage(this.entity, MT_GarrisonedUnitsChanged, {}); + Engine.PostMessage(this.entity, MT_GarrisonedUnitsChanged, { "added" : [], "removed": [entity] }); return true; }; @@ -563,7 +563,7 @@ GarrisonHolder.prototype.OnGlobalOwnershipChanged = function(msg) if (cmpHealth && cmpHealth.GetHitpoints() == 0) { this.entities.splice(entityIndex, 1); - Engine.PostMessage(this.entity, MT_GarrisonedUnitsChanged, {}); + Engine.PostMessage(this.entity, MT_GarrisonedUnitsChanged, { "added" : [], "removed": [msg.entity] }); this.UpdateGarrisonFlag(); } else if(!IsOwnedByMutualAllyOfEntity(this.entity, this.entities[entityIndex])) @@ -580,7 +580,7 @@ GarrisonHolder.prototype.OnGlobalEntityRenamed = function(msg) if (entityIndex != -1) { this.entities[entityIndex] = msg.newentity; - Engine.PostMessage(this.entity, MT_GarrisonedUnitsChanged, {}); + Engine.PostMessage(this.entity, MT_GarrisonedUnitsChanged, { "added" : [msg.newentity], "removed": [msg.entity] }); } }; @@ -628,7 +628,7 @@ GarrisonHolder.prototype.EjectOrKill = function(entities) this.entities.splice(entityIndex, 1); } - Engine.PostMessage(this.entity, MT_GarrisonedUnitsChanged, {}); + Engine.PostMessage(this.entity, MT_GarrisonedUnitsChanged, { "added" : [], "removed" : entities }); this.UpdateGarrisonFlag(); }; diff --git a/binaries/data/mods/public/simulation/components/TechnologyManager.js b/binaries/data/mods/public/simulation/components/TechnologyManager.js index b24b816353..0cddba8e4c 100644 --- a/binaries/data/mods/public/simulation/components/TechnologyManager.js +++ b/binaries/data/mods/public/simulation/components/TechnologyManager.js @@ -49,8 +49,6 @@ TechnologyManager.prototype.Init = function () if (this.allTechs[key].autoResearch || this.allTechs[key].top) this.autoResearchTech[key] = this.allTechs[key]; } - - this.UpdateAutoResearch(); }; TechnologyManager.prototype.OnUpdate = function () @@ -337,12 +335,12 @@ TechnologyManager.prototype.ResearchTechnology = function (tech) this.UpdateAutoResearch(); var cmpPlayer = Engine.QueryInterface(this.entity, IID_Player); - if (!cmpPlayer || ! cmpPlayer.GetPlayerID()) + if (!cmpPlayer || cmpPlayer.GetPlayerID() === undefined) return; var playerID = cmpPlayer.GetPlayerID(); var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager); var ents = cmpRangeManager.GetEntitiesByPlayer(playerID); - // TODO: Handle technology broadcasting for autoresearch properly (some components might not be initialized currently) + for (var component in modifiedComponents) { Engine.PostMessage(SYSTEM_ENTITY, MT_TemplateModification, { "player": playerID, "component": component, "valueNames": modifiedComponents[component]}); diff --git a/binaries/data/mods/public/simulation/components/interfaces/GarrisonHolder.js b/binaries/data/mods/public/simulation/components/interfaces/GarrisonHolder.js index 480c88a539..c2017f8ff3 100644 --- a/binaries/data/mods/public/simulation/components/interfaces/GarrisonHolder.js +++ b/binaries/data/mods/public/simulation/components/interfaces/GarrisonHolder.js @@ -1,6 +1,6 @@ Engine.RegisterInterface("GarrisonHolder"); -// Message of the form { } (use GetEntities if you want the current details), +// Message of the form { "added":[], "removed":[] } (and use GetEntities if you want the current details), // sent to the current entity whenever the garrisoned units change. Engine.RegisterMessageType("GarrisonedUnitsChanged"); diff --git a/binaries/data/mods/public/simulation/components/tests/test_GuiInterface.js b/binaries/data/mods/public/simulation/components/tests/test_GuiInterface.js index 60ae42e0be..3fd0fc3125 100644 --- a/binaries/data/mods/public/simulation/components/tests/test_GuiInterface.js +++ b/binaries/data/mods/public/simulation/components/tests/test_GuiInterface.js @@ -206,7 +206,6 @@ TS_ASSERT_UNEVAL_EQUALS(cmp.GetSimulationState(), { entityLimits: {"Foo": 10}, entityCounts: {"Foo": 5}, entityLimitChangers: {"Foo": {}}, - techModifications: {}, researchQueued: {}, researchStarted: {}, researchedTechs: {}, @@ -235,7 +234,6 @@ TS_ASSERT_UNEVAL_EQUALS(cmp.GetSimulationState(), { entityLimits: {"Bar": 20}, entityCounts: {"Bar": 0}, entityLimitChangers: {"Bar": {}}, - techModifications: {}, researchQueued: {}, researchStarted: {}, researchedTechs: {}, @@ -271,7 +269,6 @@ TS_ASSERT_UNEVAL_EQUALS(cmp.GetExtendedSimulationState(), { entityLimits: {"Foo": 10}, entityCounts: {"Foo": 5}, entityLimitChangers: {"Foo": {}}, - techModifications: {}, researchQueued: {}, researchStarted: {}, researchedTechs: {}, @@ -316,7 +313,6 @@ TS_ASSERT_UNEVAL_EQUALS(cmp.GetExtendedSimulationState(), { entityLimits: {"Bar": 20}, entityCounts: {"Bar": 0}, entityLimitChangers: {"Bar": {}}, - techModifications: {}, researchQueued: {}, researchStarted: {}, researchedTechs: {}, diff --git a/binaries/data/mods/public/simulation/helpers/Player.js b/binaries/data/mods/public/simulation/helpers/Player.js index 6dc73b176d..b679178c76 100644 --- a/binaries/data/mods/public/simulation/helpers/Player.js +++ b/binaries/data/mods/public/simulation/helpers/Player.js @@ -54,6 +54,11 @@ function LoadPlayerSettings(settings, newPlayers) // Add player to player manager cmpPlayerManager.AddPlayer(entID); + + // Properly autoresearch techs on init. + var cmpTechManager = Engine.QueryInterface(entID, IID_TechnologyManager); + if (cmpTechManager !== undefined) + cmpTechManager.UpdateAutoResearch(); } }