function BattleDetection() {} BattleDetection.prototype.Schema = "Detects the occurence of battles." + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + ""; BattleDetection.prototype.Init = function() { // Load values from template. this.interval = +this.template.TimerInterval; this.recordLength = +this.template.RecordLength; this.damageRateThreshold = +this.template.DamageRateThreshold; this.alertnessBattleThreshold = +this.template.AlertnessBattleThreshold; this.alertnessPeaceThreshold = +this.template.AlertnessPeaceThreshold; this.alertnessMax = +this.template.AlertnessMax; // Initialize variables. this.damage = 0; // Damage counter. Accumulative damage done over the current timer period. this.damageRecord = []; // Damage record. Array of elements representing total damage done in a given timer cycle. this.alertness = 0; // Alertness level. Incremented if damage rate exceeds 'damageRateThreshold' over a given timer period and decremented if it does not. }; BattleDetection.prototype.setState = function(state) { if (state != this.state) { var cmpPlayer = Engine.QueryInterface(this.entity, IID_Player); this.state = state; Engine.PostMessage(this.entity, MT_BattleStateChanged, { "player": cmpPlayer.GetPlayerID(), "to": this.state }); } }; BattleDetection.prototype.GetState = function() { return this.state; } BattleDetection.prototype.TimerHandler = function(data, lateness) { // Reset the timer if (data.timerRepeat === undefined) { this.timer = undefined; } this.damageRecord.unshift(this.damage); if (this.damageRecord.length > this.recordLength) this.damageRecord.splice(this.recordLength, this.damageRecord.length-1); // Discard any elements beyond 'recordLength'. this.damage = 0; // Reset damage counter for the next timer period. // Always update alertness if not already alert, or once per 'recordLength' otherwise. if (!this.alertness || this.recordControl++ == this.recordLength-1) { var recordDamage = this.damageRecord.reduce(function(a, b) {return a + b;}, 0); // Sum up all values in the damage record. var damageRate = recordDamage / (this.recordLength * this.interval); if (damageRate > this.damageRateThreshold) this.alertness = Math.min(this.alertnessMax, this.alertness+1); // Increment alertness up to 'alertnessMax'. else this.alertness = Math.max(0, this.alertness-1); // Decrement alertness down to zero. // Stop the damage rate timer if we're no longer alert. if (!this.alertness) this.stopTimer(); if (this.alertness >= this.alertnessBattleThreshold) this.setState("BATTLE"); else if (this.alertness <= this.alertnessPeaceThreshold) this.setState("PEACE"); } if (this.recordControl > this.recordLength-1) this.recordControl = 0; }; /** * Set up the damage rate timer to run after 'offset' msecs, and then optionally * every 'repeat' msecs until stopTimer is called, if 'repeat' is set. A "Timer" message * will be sent each time the timer runs. Must not be called if a timer is already active. */ BattleDetection.prototype.startTimer = function(offset, repeat) { if (this.timer) { this.stopTimer(); error("Called startTimer when there's already an active timer."); } this.recordControl = 0; this.damage = 0; // Reset damage counter for the first timer period. var data = { "timerRepeat": repeat }; var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); if (repeat === undefined) this.timer = cmpTimer.SetTimeout(this.entity, IID_BattleDetection, "TimerHandler", offset, data); else this.timer = cmpTimer.SetInterval(this.entity, IID_BattleDetection, "TimerHandler", offset, repeat, data); }; /** * Stop the current damage rate timer. */ BattleDetection.prototype.stopTimer = function() { if (!this.timer) return; var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); cmpTimer.CancelTimer(this.timer); this.timer = undefined; }; BattleDetection.prototype.OnGlobalAttacked = function(msg) { var cmpPlayer = Engine.QueryInterface(this.entity, IID_Player); // Only register attacks dealt by myself. var cmpAttackerOwnership = Engine.QueryInterface(msg.attacker, IID_Ownership); if (!cmpAttackerOwnership || cmpAttackerOwnership.GetOwner() != cmpPlayer.GetPlayerID()) return; // Don't register attacks dealt against Gaia or invalid player or myself. var cmpTargetOwnership = Engine.QueryInterface(msg.target, IID_Ownership); if (!cmpTargetOwnership || cmpTargetOwnership.GetOwner() <= 0 || cmpTargetOwnership.GetOwner() == cmpPlayer.GetPlayerID()) return; // If the damage rate timer isn't already started, start it now. if (!this.timer) this.startTimer(0, this.interval); // Add damage of this attack to the damage counter. if (msg.damage) this.damage += msg.damage; }; Engine.RegisterComponentType(IID_BattleDetection, "BattleDetection", BattleDetection);