Line data Source code
1 : function BattleDetection() {} 2 : 3 0 : BattleDetection.prototype.Schema = 4 : "<a:help>Detects the occurence of battles.</a:help>" + 5 : "<a:example/>" + 6 : "<element name='TimerInterval' a:help='Duration of one timer period. Interval over which damage should be recorded in milliseconds'>" + 7 : "<data type='positiveInteger'/>" + 8 : "</element>" + 9 : "<element name='RecordLength' a:help='Record length. Number of timer cycles over which damage rate should be calculated'>" + 10 : "<data type='positiveInteger'/>" + 11 : "</element>" + 12 : "<element name='DamageRateThreshold' a:help='Damage rate at which alertness is increased'>" + 13 : "<ref name='positiveDecimal'/>" + 14 : "</element>" + 15 : "<element name='AlertnessBattleThreshold' a:help='Alertness at which the player is considered in battle'>" + 16 : "<ref name='positiveDecimal'/>" + 17 : "</element>" + 18 : "<element name='AlertnessPeaceThreshold' a:help='Alertness at which the player is considered at peace'>" + 19 : "<ref name='nonNegativeDecimal'/>" + 20 : "</element>" + 21 : "<element name='AlertnessMax' a:help='Maximum alertness level'>" + 22 : "<ref name='positiveDecimal'/>" + 23 : "</element>"; 24 : 25 0 : BattleDetection.prototype.Init = function() 26 : { 27 : // Load values from template. 28 0 : this.interval = +this.template.TimerInterval; 29 0 : this.recordLength = +this.template.RecordLength; 30 0 : this.damageRateThreshold = +this.template.DamageRateThreshold; 31 0 : this.alertnessBattleThreshold = +this.template.AlertnessBattleThreshold; 32 0 : this.alertnessPeaceThreshold = +this.template.AlertnessPeaceThreshold; 33 0 : this.alertnessMax = +this.template.AlertnessMax; 34 : 35 : // Initialize variables. 36 0 : this.damage = 0; // Damage counter. Accumulative damage done over the current timer period. 37 0 : this.damageRecord = []; // Damage record. Array of elements representing total damage done in a given timer cycle. 38 0 : this.alertness = 0; // Alertness level. Incremented if damage rate exceeds 'damageRateThreshold' over a given timer period and decremented if it does not. 39 0 : this.state = "PEACE"; 40 : }; 41 : 42 0 : BattleDetection.prototype.SetState = function(state) 43 : { 44 0 : if (state == this.state) 45 0 : return; 46 : 47 0 : this.state = state; 48 0 : var cmpPlayer = Engine.QueryInterface(this.entity, IID_Player); 49 0 : Engine.PostMessage(this.entity, MT_BattleStateChanged, { "player": cmpPlayer.GetPlayerID(), "to": this.state }); 50 : }; 51 : 52 0 : BattleDetection.prototype.GetState = function() 53 : { 54 0 : return this.state; 55 : }; 56 : 57 0 : BattleDetection.prototype.TimerHandler = function(data, lateness) 58 : { 59 : // Reset the timer 60 0 : if (data.timerRepeat === undefined) 61 : { 62 0 : this.timer = undefined; 63 : } 64 : 65 0 : this.damageRecord.unshift(this.damage); 66 0 : if (this.damageRecord.length > this.recordLength) 67 0 : this.damageRecord.splice(this.recordLength, this.damageRecord.length-1); // Discard any elements beyond 'recordLength'. 68 0 : this.damage = 0; // Reset damage counter for the next timer period. 69 : 70 : // Always update alertness if not already alert, or once per 'recordLength' otherwise. 71 0 : if (!this.alertness || this.recordControl++ == this.recordLength-1) 72 : { 73 0 : var recordDamage = this.damageRecord.reduce(function(a, b) {return a + b;}, 0); // Sum up all values in the damage record. 74 0 : var damageRate = recordDamage / (this.recordLength * this.interval); 75 : 76 0 : if (damageRate > this.damageRateThreshold) 77 0 : this.alertness = Math.min(this.alertnessMax, this.alertness+1); // Increment alertness up to 'alertnessMax'. 78 : else 79 0 : this.alertness = Math.max(0, this.alertness-1); // Decrement alertness down to zero. 80 : 81 : // Stop the damage rate timer if we're no longer alert. 82 0 : if (!this.alertness) 83 0 : this.StopTimer(); 84 : 85 0 : if (this.alertness >= this.alertnessBattleThreshold) 86 0 : this.SetState("BATTLE"); 87 0 : else if (this.alertness <= this.alertnessPeaceThreshold) 88 0 : this.SetState("PEACE"); 89 : 90 : } 91 0 : if (this.recordControl > this.recordLength-1) 92 0 : this.recordControl = 0; 93 : }; 94 : 95 : /** 96 : * Set up the damage rate timer to run after 'offset' msecs, and then optionally 97 : * every 'repeat' msecs until StopTimer is called, if 'repeat' is set. A "Timer" message 98 : * will be sent each time the timer runs. Must not be called if a timer is already active. 99 : */ 100 0 : BattleDetection.prototype.StartTimer = function(offset, repeat) 101 : { 102 0 : if (this.timer) 103 : { 104 0 : this.StopTimer(); 105 0 : error("Called StartTimer when there's already an active timer."); 106 : } 107 : 108 0 : this.recordControl = 0; 109 0 : this.damage = 0; // Reset damage counter for the first timer period. 110 : 111 0 : var data = { "timerRepeat": repeat }; 112 0 : var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); 113 0 : if (repeat === undefined) 114 0 : this.timer = cmpTimer.SetTimeout(this.entity, IID_BattleDetection, "TimerHandler", offset, data); 115 : else 116 0 : this.timer = cmpTimer.SetInterval(this.entity, IID_BattleDetection, "TimerHandler", offset, repeat, data); 117 : }; 118 : 119 : /** 120 : * Stop the current damage rate timer. 121 : */ 122 0 : BattleDetection.prototype.StopTimer = function() 123 : { 124 0 : if (!this.timer) 125 0 : return; 126 : 127 0 : var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); 128 0 : cmpTimer.CancelTimer(this.timer); 129 0 : this.timer = undefined; 130 : }; 131 : 132 0 : BattleDetection.prototype.OnGlobalAttacked = function(msg) 133 : { 134 0 : var cmpPlayer = Engine.QueryInterface(this.entity, IID_Player); 135 : // Only register attacks dealt by myself. 136 0 : var cmpAttackerOwnership = Engine.QueryInterface(msg.attacker, IID_Ownership); 137 0 : if (!cmpAttackerOwnership || cmpAttackerOwnership.GetOwner() != cmpPlayer.GetPlayerID()) 138 0 : return; 139 : // Don't register attacks dealt against Gaia or invalid player or myself. 140 0 : var cmpTargetOwnership = Engine.QueryInterface(msg.target, IID_Ownership); 141 0 : if (!cmpTargetOwnership || cmpTargetOwnership.GetOwner() <= 0 || cmpTargetOwnership.GetOwner() == cmpPlayer.GetPlayerID()) 142 0 : return; 143 : 144 : // If the damage rate timer isn't already started, start it now. 145 0 : if (!this.timer) 146 0 : this.StartTimer(0, this.interval); 147 : // Add damage of this attack to the damage counter. 148 0 : if (msg.damage) 149 0 : this.damage += msg.damage; 150 : }; 151 : 152 0 : Engine.RegisterComponentType(IID_BattleDetection, "BattleDetection", BattleDetection); 153 :