Line data Source code
1 : function Resistance() {} 2 : 3 : /** 4 : * Builds a RelaxRNG schema of possible attack effects. 5 : * 6 : * @return {string} - RelaxNG schema string. 7 : */ 8 1 : Resistance.prototype.BuildResistanceSchema = function() 9 : { 10 2 : return "" + 11 : "<oneOrMore>" + 12 : "<choice>" + 13 : "<element name='Damage'>" + 14 : "<oneOrMore>" + 15 : "<element a:help='Resistance against any number of damage types affecting health.'>" + 16 : "<anyName/>" + 17 : "<ref name='nonNegativeDecimal'/>" + 18 : "</element>" + 19 : "</oneOrMore>" + 20 : "</element>" + 21 : "<element name='Capture' a:help='Resistance against Capture attacks.'>" + 22 : "<ref name='nonNegativeDecimal'/>" + 23 : "</element>" + 24 : "<element name='ApplyStatus' a:help='Resistance against StatusEffects.'>" + 25 : "<oneOrMore>" + 26 : "<element a:help='Resistance against any number of status effects.'>" + 27 : "<anyName/>" + 28 : "<interleave>" + 29 : "<optional>" + 30 : "<element name='Duration' a:help='The reduction in duration of the status. The normal duration time is multiplied by this factor.'>" + 31 : "<ref name='nonNegativeDecimal'/>" + 32 : "</element>" + 33 : "</optional>" + 34 : "<optional>" + 35 : "<element name='BlockChance' a:help='The chance of blocking the status. In the interval [0,1].'><ref name='nonNegativeDecimal'/></element>" + 36 : "</optional>" + 37 : "</interleave>" + 38 : "</element>" + 39 : "</oneOrMore>" + 40 : "</element>" + 41 : "</choice>" + 42 : "</oneOrMore>"; 43 : }; 44 : 45 1 : Resistance.prototype.Schema = 46 : "<a:help>Controls the damage resistance of the unit.</a:help>" + 47 : "<a:example>" + 48 : "<Foundation>" + 49 : "<Damage>" + 50 : "<Hack>10.0</Hack>" + 51 : "<Pierce>0.0</Pierce>" + 52 : "<Crush>5.0</Crush>" + 53 : "</Damage>" + 54 : "<Capture>10</Capture>" + 55 : "</Foundation>" + 56 : "<Entity>" + 57 : "<Damage>" + 58 : "<Poison>5</Poison>" + 59 : "</Damage>" + 60 : "</Entity>" + 61 : "</a:example>" + 62 : "<zeroOrMore>" + 63 : "<choice>" + 64 : "<element name='Foundation' a:help='Resistance of an unfinished structure (i.e. a foundation).'>" + 65 : Resistance.prototype.BuildResistanceSchema() + 66 : "</element>" + 67 : "<element name='Entity' a:help='Resistance of an entity.'>" + 68 : Resistance.prototype.BuildResistanceSchema() + 69 : "</element>" + 70 : "</choice>" + 71 : "</zeroOrMore>"; 72 : 73 1 : Resistance.prototype.Init = function() 74 : { 75 9 : this.invulnerable = false; 76 9 : this.attackers = new Set(); 77 : }; 78 : 79 1 : Resistance.prototype.IsInvulnerable = function() 80 : { 81 12 : return this.invulnerable; 82 : }; 83 : 84 : /** 85 : * @param {number} attacker - The entity ID of the attacker to add. 86 : * @return {boolean} - Whether the attacker was added sucessfully. 87 : */ 88 1 : Resistance.prototype.AddAttacker = function(attacker) 89 : { 90 0 : if (this.attackers.has(attacker)) 91 0 : return false; 92 : 93 0 : this.attackers.add(attacker); 94 0 : return true; 95 : }; 96 : 97 : /** 98 : * @param {number} attacker - The entity ID of the attacker to remove. 99 : * @return {boolean} - Whether the attacker was attacking us previously. 100 : */ 101 1 : Resistance.prototype.RemoveAttacker = function(attacker) 102 : { 103 0 : return this.attackers.delete(attacker); 104 : }; 105 : 106 1 : Resistance.prototype.SetInvulnerability = function(invulnerability) 107 : { 108 1 : this.invulnerable = invulnerability; 109 1 : Engine.PostMessage(this.entity, MT_InvulnerabilityChanged, { "entity": this.entity, "invulnerability": invulnerability }); 110 : }; 111 : 112 : /** 113 : * Calculate the effective resistance of an entity to a particular effect. 114 : * ToDo: Support resistance against status effects. 115 : * @param {string} effectType - The type of attack effect the resistance has to be calculated for (e.g. "Damage", "Capture"). 116 : * @return {Object} - An object of the type { "Damage": { "Crush": number, "Hack": number }, "Capture": number }. 117 : */ 118 1 : Resistance.prototype.GetEffectiveResistanceAgainst = function(effectType) 119 : { 120 10 : let ret = {}; 121 : 122 10 : let template = this.GetResistanceOfForm(Engine.QueryInterface(this.entity, IID_Foundation) ? "Foundation" : "Entity"); 123 10 : if (template[effectType]) 124 7 : ret[effectType] = template[effectType]; 125 : 126 10 : return ret; 127 : }; 128 : 129 : /** 130 : * Get all separate resistances for showing in the GUI. 131 : * @return {Object} - All resistances ordered by type. 132 : */ 133 1 : Resistance.prototype.GetFullResistance = function() 134 : { 135 0 : let ret = {}; 136 0 : for (let entityForm in this.template) 137 0 : ret[entityForm] = this.GetResistanceOfForm(entityForm); 138 : 139 0 : return ret; 140 : }; 141 : 142 : /** 143 : * Get the resistance of a particular type, i.e. Foundation or Entity. 144 : * @param {string} entityForm - The form of the entity to query. 145 : * @return {Object} - An object containing the resistances. 146 : */ 147 1 : Resistance.prototype.GetResistanceOfForm = function(entityForm) 148 : { 149 10 : let ret = {}; 150 10 : let template = this.template && this.template[entityForm]; 151 10 : if (!template) 152 2 : return ret; 153 : 154 8 : if (template.Damage) 155 : { 156 2 : ret.Damage = {}; 157 2 : for (let damageType in template.Damage) 158 2 : ret.Damage[damageType] = ApplyValueModificationsToEntity("Resistance/" + entityForm + "/Damage/" + damageType, +this.template[entityForm].Damage[damageType], this.entity); 159 : } 160 : 161 8 : if (template.Capture) 162 3 : ret.Capture = ApplyValueModificationsToEntity("Resistance/" + entityForm + "/Capture", +this.template[entityForm].Capture, this.entity); 163 : 164 8 : if (template.ApplyStatus) 165 : { 166 3 : ret.ApplyStatus = {}; 167 3 : for (let effect in template.ApplyStatus) 168 4 : ret.ApplyStatus[effect] = { 169 : "duration": ApplyValueModificationsToEntity("Resistance/" + entityForm + "/ApplyStatus/" + effect + "/Duration", +(template.ApplyStatus[effect].Duration || 1), this.entity), 170 : "blockChance": ApplyValueModificationsToEntity("Resistance/" + entityForm + "/ApplyStatus/" + effect + "/BlockChance", +(template.ApplyStatus[effect].BlockChance || 0), this.entity) 171 : }; 172 : } 173 : 174 8 : return ret; 175 : }; 176 : 177 1 : Resistance.prototype.OnOwnershipChanged = function(msg) 178 : { 179 0 : if (msg.to === INVALID_PLAYER) 180 0 : for (let attacker of this.attackers) 181 0 : Engine.QueryInterface(attacker, IID_Attack)?.StopAttacking("TargetInvalidated"); 182 : }; 183 : 184 : 185 : function ResistanceMirage() {} 186 1 : ResistanceMirage.prototype.Init = function(cmpResistance) 187 : { 188 0 : this.invulnerable = cmpResistance.invulnerable; 189 0 : this.isFoundation = !!Engine.QueryInterface(cmpResistance.entity, IID_Foundation); 190 0 : this.resistanceOfForm = {}; 191 0 : for (const entityForm in cmpResistance.template) 192 0 : this.resistanceOfForm[entityForm] = cmpResistance.GetResistanceOfForm(entityForm); 193 0 : this.attackers = new Set(); 194 : }; 195 : 196 1 : ResistanceMirage.prototype.IsInvulnerable = Resistance.prototype.IsInvulnerable; 197 1 : ResistanceMirage.prototype.AddAttacker = Resistance.prototype.AddAttacker; 198 1 : ResistanceMirage.prototype.RemoveAttacker = Resistance.prototype.RemoveAttacker; 199 : 200 1 : ResistanceMirage.prototype.GetEffectiveResistanceAgainst = function(entityForm) 201 : { 202 0 : return this.GetResistanceOfForm(this.isFoundation ? "Foundation" : "Entity"); 203 : }; 204 : 205 1 : ResistanceMirage.prototype.GetResistanceOfForm = function(entityForm) 206 : { 207 0 : return this.resistanceOfForm[entityForm] || {}; 208 : }; 209 : 210 1 : ResistanceMirage.prototype.GetFullResistance = function() 211 : { 212 0 : return this.resistanceOfForm; 213 : }; 214 : 215 1 : Engine.RegisterGlobal("ResistanceMirage", ResistanceMirage); 216 : 217 1 : Resistance.prototype.Mirage = function() 218 : { 219 0 : const mirage = new ResistanceMirage(); 220 0 : mirage.Init(this); 221 0 : return mirage; 222 : }; 223 : 224 1 : Engine.RegisterComponentType(IID_Resistance, "Resistance", Resistance);