Index: ps/trunk/binaries/data/mods/public/simulation/components/AutoBuildable.js =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/components/AutoBuildable.js +++ ps/trunk/binaries/data/mods/public/simulation/components/AutoBuildable.js @@ -0,0 +1,99 @@ +class AutoBuildable +{ + Init() + { + this.rate = ApplyValueModificationsToEntity("AutoBuildable/Rate", +this.template.Rate , this.entity); + if (this.rate) + this.StartTimer(); + } + + get Schema() + { + return "Defines whether the entity can be built by itself." + + "" + + "1.0" + + "" + + "" + + "" + + ""; + } + + /** + * @return {number} - The rate with technologies and aura modification applied. + */ + GetRate() + { + return this.rate; + } + + UpdateRate() + { + this.rate = ApplyValueModificationsToEntity("AutoBuildable/Rate", +this.template.Rate , this.entity); + + if (this.rate) + this.StartTimer(); + } + + StartTimer() + { + if (this.timer || !this.rate) + return; + + let cmpFoundation = Engine.QueryInterface(this.entity, IID_Foundation); + if (!cmpFoundation) + return; + + cmpFoundation.AddBuilder(this.entity); + let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); + this.timer = cmpTimer.SetInterval(this.entity, IID_AutoBuildable, "AutoBuild", 0, 1000, undefined); + } + + CancelTimer() + { + if (!this.timer) + return; + + let cmpFoundation = Engine.QueryInterface(this.entity, IID_Foundation); + if (cmpFoundation) + cmpFoundation.RemoveBuilder(this.entity); + + let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); + cmpTimer.CancelTimer(this.timer); + delete this.timer; + } + + AutoBuild() + { + if (!this.rate) + { + this.CancelTimer(); + return; + } + let cmpFoundation = Engine.QueryInterface(this.entity, IID_Foundation); + if (!cmpFoundation) + { + this.CancelTimer(); + return; + } + + cmpFoundation.Build(this.entity, this.rate); + } +} + +AutoBuildable.prototype.OnValueModification = function(msg) +{ + if (msg.component != "AutoBuildable") + return; + + this.UpdateRate(); +}; + +AutoBuildable.prototype.OnOwnershipChanged = function(msg) +{ + if (msg.to == INVALID_PLAYER) + return; + + this.UpdateRate(); +} + +Engine.RegisterComponentType(IID_AutoBuildable, "AutoBuildable", AutoBuildable); Index: ps/trunk/binaries/data/mods/public/simulation/components/Foundation.js =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/components/Foundation.js +++ ps/trunk/binaries/data/mods/public/simulation/components/Foundation.js @@ -152,7 +152,12 @@ if (this.builders.has(builderEnt)) return false; - let buildRate = Engine.QueryInterface(builderEnt, IID_Builder).GetRate(); + let cmpBuilder = Engine.QueryInterface(builderEnt, IID_Builder) || + Engine.QueryInterface(this.entity, IID_AutoBuildable); + if (!cmpBuilder) + return false; + + let buildRate = cmpBuilder.GetRate(); this.builders.set(builderEnt, buildRate); this.totalBuilderRate += buildRate; Index: ps/trunk/binaries/data/mods/public/simulation/components/interfaces/AutoBuildable.js =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/components/interfaces/AutoBuildable.js +++ ps/trunk/binaries/data/mods/public/simulation/components/interfaces/AutoBuildable.js @@ -0,0 +1 @@ +Engine.RegisterInterface("AutoBuildable"); Index: ps/trunk/binaries/data/mods/public/simulation/components/tests/test_AutoBuildable.js =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/components/tests/test_AutoBuildable.js +++ ps/trunk/binaries/data/mods/public/simulation/components/tests/test_AutoBuildable.js @@ -0,0 +1,16 @@ +Engine.LoadHelperScript("ValueModification.js"); +Engine.LoadComponentScript("interfaces/AutoBuildable.js"); +Engine.LoadComponentScript("interfaces/Foundation.js"); +Engine.LoadComponentScript("interfaces/ModifiersManager.js"); +Engine.LoadComponentScript("AutoBuildable.js"); + +const cmpBuildableAuto = ConstructComponent(10, "AutoBuildable", { + "Rate": "1.0" +}); + +TS_ASSERT_EQUALS(cmpBuildableAuto.GetRate(), 1); + +const cmpBuildableNoRate = ConstructComponent(12, "AutoBuildable", { + "Rate": "0" +}); +TS_ASSERT_EQUALS(cmpBuildableNoRate.GetRate(), 0); Index: ps/trunk/binaries/data/mods/public/simulation/components/tests/test_Foundation.js =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/components/tests/test_Foundation.js +++ ps/trunk/binaries/data/mods/public/simulation/components/tests/test_Foundation.js @@ -1,24 +1,29 @@ Engine.LoadHelperScript("Player.js"); +Engine.LoadHelperScript("ValueModification.js"); +Engine.LoadComponentScript("interfaces/AutoBuildable.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("AutoBuildable.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 +214,53 @@ }, }]); +// Test autobuild feature. +const foundationEnt2 = 42; +let turnLength = 0.2; +let currentFoundationHP = 1; +let cmpTimer = ConstructComponent(SYSTEM_ENTITY, "Timer"); + +AddMock(foundationEnt2, IID_Cost, { + "GetBuildTime": () => 50, + "GetResourceCosts": () => ({ "wood": 100 }), +}); + + + +const cmpAutoBuildingFoundation = ConstructComponent(foundationEnt2, "Foundation", {}); +AddMock(foundationEnt2, IID_Health, { + "GetHitpoints": () => currentFoundationHP, + "GetMaxHitpoints": () => 100, + "Increase": hp => { + currentFoundationHP = Math.min(currentFoundationHP + hp, 100); + cmpAutoBuildingFoundation.OnHealthChanged(); + }, +}); + +const cmpBuildableAuto = ConstructComponent(foundationEnt2, "AutoBuildable", { + "Rate": "1.0" +}); + +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) + { + cmpBuildableAuto.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: ps/trunk/binaries/data/mods/public/simulation/templates/special/filter/foundation.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/special/filter/foundation.xml +++ ps/trunk/binaries/data/mods/public/simulation/templates/special/filter/foundation.xml @@ -2,6 +2,7 @@ +