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 @@
+