Index: binaries/data/mods/public/simulation/components/Buildable.js =================================================================== --- /dev/null +++ binaries/data/mods/public/simulation/components/Buildable.js @@ -0,0 +1,45 @@ +class Buildable +{ + constructor() { } + Init() + { + } + + get Schema() + { + return "Defines whether the entity can be built." + + "" + + "" + + "1.0" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + ""; + } + + /** + * @return {boolean} - Whether the building builds itself + */ + IsAutoBuildable() + { + return this.template && this.template.AutoBuild && +this.template.AutoBuild.Rate != 0; + } + + /** + * @return {number} - The rate with technologies and aura modification applied. + */ + GetAutoBuildRate() + { + return ApplyValueModificationsToEntity("Foundation/AutoBuild/Rate", this.template.AutoBuild ? +this.template.AutoBuild.Rate : 0, this.entity); + } +} + +// We have no dynamic state to save +Buildable.prototype.Serialize = null; + +Engine.RegisterComponentType(IID_Buildable, "Buildable", Buildable); Index: binaries/data/mods/public/simulation/components/Foundation.js =================================================================== --- binaries/data/mods/public/simulation/components/Foundation.js +++ binaries/data/mods/public/simulation/components/Foundation.js @@ -1,7 +1,6 @@ function Foundation() {} -Foundation.prototype.Schema = - ""; +Foundation.prototype.Schema = ""; Foundation.prototype.Init = function() { @@ -16,8 +15,15 @@ this.totalBuilderRate = 0; // Total amount of work the builders do each second this.buildMultiplier = 1; // Multiplier for the amount of work builders do this.buildTimePenalty = 0.7; // Penalty for having multiple builders - + this.isAutoBuildable = false; this.previewEntity = INVALID_ENTITY; + + let cmpBuildable = Engine.QueryInterface(this.entity, IID_Buildable); + if (cmpBuildable && cmpBuildable.IsAutoBuildable()) + { + this.isAutoBuildable = true; + this.StartTimer(); + } }; Foundation.prototype.InitialiseConstruction = function(owner, template) @@ -124,7 +130,20 @@ if (this.builders.has(builderEnt)) return; - this.builders.set(builderEnt, Engine.QueryInterface(builderEnt, IID_Builder).GetRate()); + let rate = 0; + let cmpBuilder = Engine.QueryInterface(builderEnt, IID_Builder); + if (cmpBuilder) + rate = cmpBuilder.GetRate(); + else if(this.isAutoBuildable) + { + let cmpBuildable = Engine.QueryInterface(this.entity, IID_Buildable); + if (cmpBuildable) + rate = cmpBuildable.GetAutoBuildRate(); + } + else + return; + + this.builders.set(builderEnt, rate); this.totalBuilderRate += this.builders.get(builderEnt); this.SetBuildMultiplier(); @@ -261,8 +280,8 @@ } var cmpFoundationPosition = Engine.QueryInterface(this.entity, IID_Position); - var pos = cmpFoundationPosition.GetPosition2D(); - var rot = cmpFoundationPosition.GetRotation(); + let pos = cmpFoundationPosition.GetPosition2D(); + let rot = cmpFoundationPosition.GetRotation(); cmpPreviewPosition.SetYRotation(rot.y); cmpPreviewPosition.SetXZRotation(rot.x, rot.z); cmpPreviewPosition.JumpTo(pos.x, pos.y); @@ -319,9 +338,9 @@ Engine.DestroyEntity(building); return; } - var pos = cmpPosition.GetPosition2D(); + let pos = cmpPosition.GetPosition2D(); cmpBuildingPosition.JumpTo(pos.x, pos.y); - var rot = cmpPosition.GetRotation(); + let rot = cmpPosition.GetRotation(); cmpBuildingPosition.SetYRotation(rot.y); cmpBuildingPosition.SetXZRotation(rot.x, rot.z); // TODO: should add a ICmpPosition::CopyFrom() instead of all this @@ -421,5 +440,33 @@ return cmpHealth.GetMaxHitpoints() / cmpCost.GetBuildTime(); }; +Foundation.prototype.StartTimer = function() +{ + if (this.timer) + return; + + this.AddBuilder(this.entity); + let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); + this.timer = cmpTimer.SetInterval(this.entity, IID_Foundation, "AutoBuild", 0, 1000, undefined); +}; + +Foundation.prototype.CancelTimer = function() +{ + if (!this.timer) + return; + + this.RemoveBuilder(this.entity); + let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); + cmpTimer.CancelTimer(this.timer); + delete this.timer; +}; + + +Foundation.prototype.AutoBuild = function() +{ + let cmpBuildable = Engine.QueryInterface(this.entity, IID_Buildable); + this.Build(this.entity, cmpBuildable.GetAutoBuildRate()); +}; + Engine.RegisterComponentType(IID_Foundation, "Foundation", Foundation); Index: binaries/data/mods/public/simulation/components/interfaces/Buildable.js =================================================================== --- /dev/null +++ binaries/data/mods/public/simulation/components/interfaces/Buildable.js @@ -0,0 +1 @@ +Engine.RegisterInterface("Buildable"); Index: binaries/data/mods/public/simulation/components/tests/test_Foundation.js =================================================================== --- binaries/data/mods/public/simulation/components/tests/test_Foundation.js +++ binaries/data/mods/public/simulation/components/tests/test_Foundation.js @@ -1,24 +1,27 @@ Engine.LoadHelperScript("Player.js"); +Engine.LoadHelperScript("ValueModification.js"); Engine.LoadComponentScript("interfaces/Builder.js"); Engine.LoadComponentScript("interfaces/Cost.js"); Engine.LoadComponentScript("interfaces/Foundation.js"); Engine.LoadComponentScript("interfaces/Health.js"); +Engine.LoadComponentScript("interfaces/ModifiersManager.js"); Engine.LoadComponentScript("interfaces/StatisticsTracker.js"); Engine.LoadComponentScript("interfaces/TerritoryDecay.js"); Engine.LoadComponentScript("interfaces/Trigger.js"); +Engine.LoadComponentScript("interfaces/Timer.js"); Engine.LoadComponentScript("Foundation.js"); - +Engine.LoadComponentScript("Timer.js"); let player = 1; let playerEnt = 3; let foundationEnt = 20; let previewEnt = 21; let newEnt = 22; +let finalTemplate = "structures/athen_civil_centre.xml"; function testFoundation(...mocks) { ResetState(); - let finalTemplate = "structures/athen_civil_centre.xml"; let foundationHP = 1; let maxHP = 100; let rot = new Vector3D(1, 2, 3); @@ -209,3 +212,44 @@ }, }]); +// Test autobuild feature. +const foundationEnt2 = 42; +let turnLength = 0.2; +let currentFoundationHP = 1; +let cmpTimer = ConstructComponent(SYSTEM_ENTITY, "Timer"); +const cmpAutoBuildingFoundation = ConstructComponent(foundationEnt2, "Foundation", { "AutoBuild": { "Rate": "1.0" } }); +AddMock(foundationEnt2, IID_Cost, { + "GetBuildTime": () => 50, + "GetResourceCosts": () => ({ "wood": 100 }), +}); +AddMock(foundationEnt2, IID_Health, { + "GetHitpoints": () => currentFoundationHP, + "GetMaxHitpoints": () => 100, + "Increase": hp => { + currentFoundationHP = Math.min(currentFoundationHP + hp, 100); + cmpAutoBuildingFoundation.OnHealthChanged(); + }, +}); +cmpAutoBuildingFoundation.InitialiseConstruction(player, finalTemplate); + +// We start at 3 cause there is no delay on the first run. +cmpTimer.OnUpdate({ "turnLength": turnLength }); + +for (let i = 0; i < 10; ++i) +{ + if (i == 8) + { + cmpAutoBuildingFoundation.CancelTimer(); + TS_ASSERT_EQUALS(cmpAutoBuildingFoundation.GetNumBuilders(), 0); + } + + let currentPercentage = cmpAutoBuildingFoundation.GetBuildPercentage(); + cmpTimer.OnUpdate({ "turnLength": turnLength * 5 }); + let newPercentage = cmpAutoBuildingFoundation.GetBuildPercentage(); + + if (i >= 8) + TS_ASSERT_EQUALS(currentPercentage, newPercentage); + else + // Rate * Max Health / Cost. + TS_ASSERT_EQUALS(currentPercentage + 2, newPercentage); +} Index: binaries/data/mods/public/simulation/templates/special/filter/foundation.xml =================================================================== --- binaries/data/mods/public/simulation/templates/special/filter/foundation.xml +++ binaries/data/mods/public/simulation/templates/special/filter/foundation.xml @@ -2,6 +2,7 @@ + Index: binaries/data/mods/public/simulation/templates/structures/athen_house.xml =================================================================== --- binaries/data/mods/public/simulation/templates/structures/athen_house.xml +++ binaries/data/mods/public/simulation/templates/structures/athen_house.xml @@ -4,6 +4,11 @@ athen Oikos + + + 1 + + structures/hellenes/house.xml Index: binaries/data/mods/public/simulation/templates/template_structure.xml =================================================================== --- binaries/data/mods/public/simulation/templates/template_structure.xml +++ binaries/data/mods/public/simulation/templates/template_structure.xml @@ -44,6 +44,7 @@ 9.8 +