Index: binaries/data/mods/public/simulation/components/BuildingAI.js =================================================================== --- binaries/data/mods/public/simulation/components/BuildingAI.js +++ binaries/data/mods/public/simulation/components/BuildingAI.js @@ -73,12 +73,7 @@ BuildingAI.prototype.OnDestroy = function() { - if (this.timer) - { - let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); - cmpTimer.CancelTimer(this.timer); - this.timer = undefined; - } + this.StopTimer(); // Clean up range queries let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager); @@ -96,6 +91,13 @@ if (msg.component != "Attack") return; + // Restart the timer if the attack repeat time has changed + if (this.timer && msg.valueNames.indexOf("Attack/" + attackType + "/RepeatTime") != -1) + { + this.StopTimer(); + this.StartTimer(0); + } + this.targetUnits = []; this.SetupRangeQuery(); this.SetupGaiaRangeQuery(); @@ -203,7 +205,7 @@ this.StartTimer(); }; -BuildingAI.prototype.StartTimer = function() +BuildingAI.prototype.StartTimer = function(offset) { if (this.timer) return; @@ -215,8 +217,20 @@ var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); var attackTimers = cmpAttack.GetTimers(attackType); + // Rather than figure out the correct offset when resetting the timer, use an estimate of half of the repeat time this.timer = cmpTimer.SetInterval(this.entity, IID_BuildingAI, "FireArrows", - attackTimers.prepare, attackTimers.repeat / roundCount, null); + offset === undefined ? attackTimers.prepare : attackTimers.repeat / roundCount / 2, + attackTimers.repeat / roundCount, null); +}; + +BuildingAI.prototype.StopTimer = function() +{ + if (!this.timer) + return; + + let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); + cmpTimer.CancelTimer(this.timer); + this.timer = undefined; }; BuildingAI.prototype.GetDefaultArrowCount = function() @@ -276,12 +290,7 @@ { if (!this.targetUnits.length && !this.unitAITarget) { - if (!this.timer) - return; - - let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); - cmpTimer.CancelTimer(this.timer); - this.timer = undefined; + this.StopTimer(); return; } Index: binaries/data/mods/public/simulation/components/UnitAI.js =================================================================== --- binaries/data/mods/public/simulation/components/UnitAI.js +++ binaries/data/mods/public/simulation/components/UnitAI.js @@ -177,6 +177,10 @@ // ignore }, + "ValueModification": function(msg) { + // ignore + }, + // Formation handlers: "FormationLeave": function(msg) { @@ -1935,13 +1939,14 @@ // If the repeat time since the last attack hasn't elapsed, // delay this attack to avoid attacking too fast. - var prepare = this.attackTimers.prepare; + let prepare = this.attackTimers.prepare; + let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); if (this.lastAttacked) { - var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); - var repeatLeft = this.lastAttacked + this.attackTimers.repeat - cmpTimer.GetTime(); + let repeatLeft = this.lastAttacked + this.attackTimers.repeat - cmpTimer.GetTime(); prepare = Math.max(prepare, repeatLeft); } + this.lastAttacked = cmpTimer.GetTime() + prepare - this.attackTimers.repeat; this.oldAttackType = this.order.data.attackType; // add prefix + no capital first letter for attackType @@ -2074,6 +2079,27 @@ this.WalkToHeldPosition(); }, + "ValueModification": function(msg) { + // Restart the timer if the attack repeat time has changed + if (msg.data.valueNames.indexOf("Attack/" + this.oldAttackType + "/RepeatTime") != -1) + { + let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); + let cmpAttack = Engine.QueryInterface(this.entity, IID_Attack); + let attackTimers = cmpAttack.GetTimers(this.order.data.attackType); + + let oldRepeatLeft = this.lastAttacked + this.attackTimers.repeat - cmpTimer.GetTime(); + let scale = attackTimers.repeat / this.attackTimers.repeat; + let repeatLeft = Math.round(scale * oldRepeatLeft); + + this.attackTimers = attackTimers; + this.lastAttacked = cmpTimer.GetTime() + repeatLeft - this.attackTimers.repeat; + + this.StopTimer(); + this.StartTimer(repeatLeft, this.attackTimers.repeat); + this.SetAnimationSync(repeatLeft, this.attackTimers.repeat); + } + }, + // TODO: respond to target deaths immediately, rather than waiting // until the next Timer event @@ -2567,13 +2593,14 @@ // If the repeat time since the last heal hasn't elapsed, // delay the action to avoid healing too fast. - var prepare = this.healTimers.prepare; + let prepare = this.healTimers.prepare; + let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); if (this.lastHealed) { - var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); - var repeatLeft = this.lastHealed + this.healTimers.repeat - cmpTimer.GetTime(); + let repeatLeft = this.lastHealed + this.healTimers.repeat - cmpTimer.GetTime(); prepare = Math.max(prepare, repeatLeft); } + this.lastHealed = cmpTimer.GetTime() + prepare - this.healTimers.repeat; this.SelectAnimation("heal", false, 1.0, "heal"); this.SetAnimationSync(prepare, this.healTimers.repeat); @@ -2633,7 +2660,29 @@ if (this.GetStance().respondHoldGround) this.WalkToHeldPosition(); }, + + "ValueModification": function(msg) { + // Restart the timer if the attack repeat time has changed + if (msg.data.valueNames.indexOf("Heal/Rate") != -1) + { + let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); + let cmpHeal = Engine.QueryInterface(this.entity, IID_Heal); + let healTimers = cmpHeal.GetTimers(); + + let oldRepeatLeft = this.lastHealed + this.healTimers.repeat - cmpTimer.GetTime(); + let scale = healTimers.repeat / this.healTimers.repeat; + let repeatLeft = Math.round(scale * oldRepeatLeft); + + this.healTimers = healTimers; + this.lastHealed = cmpTimer.GetTime() + repeatLeft - this.healTimers.repeat; + + this.StopTimer(); + this.StartTimer(repeatLeft, this.healTimers.repeat); + this.SetAnimationSync(repeatLeft, this.healTimers.repeat); + } + }, }, + "CHASING": { "enter": function () { this.SelectAnimation("move"); @@ -4100,6 +4149,11 @@ this.UnitFsm.ProcessMessage(this, {"type": "PackFinished", "packed": msg.packed}); }; +UnitAI.prototype.OnValueModification = function(msg) +{ + this.UnitFsm.ProcessMessage(this, {"type": "ValueModification", "data": msg}); +}; + //// Helper functions to be called by the FSM //// UnitAI.prototype.GetWalkSpeed = function()