Changeset View
Changeset View
Standalone View
Standalone View
binaries/data/mods/public/simulation/components/Armour.js
function Armour() {} | function Armour() {} | ||||
Armour.prototype.Schema = | Armour.prototype.Schema = | ||||
"<a:help>Controls the damage resistance of the unit.</a:help>" + | "<a:help>Controls the damage resistance of the unit.</a:help>" + | ||||
"<a:example>" + | "<a:example>" + | ||||
"<Hack>10.0</Hack>" + | "<Hack>10.0</Hack>" + | ||||
"<Pierce>0.0</Pierce>" + | "<Pierce>0.0</Pierce>" + | ||||
"<Crush>5.0</Crush>" + | "<Crush>5.0</Crush>" + | ||||
"<Capture>0</Capture>" + | |||||
"</a:example>" + | "</a:example>" + | ||||
DamageTypes.BuildSchema("damage protection") + | DamageTypes.BuildSchema("damage protection") + | ||||
"<optional>" + | "<optional>" + | ||||
"<element name='Foundation' a:help='Armour given to building foundations'>" + | "<element name='Foundation' a:help='Armour given to building foundations'>" + | ||||
"<interleave>" + | "<interleave>" + | ||||
DamageTypes.BuildSchema("damage protection") + | DamageTypes.BuildSchema("damage protection") + | ||||
"</interleave>" + | "</interleave>" + | ||||
"</element>" + | "</element>" + | ||||
Show All 12 Lines | |||||
Armour.prototype.SetInvulnerability = function(invulnerability) | Armour.prototype.SetInvulnerability = function(invulnerability) | ||||
{ | { | ||||
this.invulnerable = invulnerability; | this.invulnerable = invulnerability; | ||||
Engine.PostMessage(this.entity, MT_InvulnerabilityChanged, { "entity": this.entity, "invulnerability": invulnerability }); | Engine.PostMessage(this.entity, MT_InvulnerabilityChanged, { "entity": this.entity, "invulnerability": invulnerability }); | ||||
}; | }; | ||||
/** | /** | ||||
* Take damage according to the entity's armor. | * Take damage according to the entity's armor. | ||||
* @param {number} playerID - Owner of the attacking entity. | |||||
* @param {Object} strengths - { "hack": number, "pierce": number, "crush": number } or something like that. | * @param {Object} strengths - { "hack": number, "pierce": number, "crush": number } or something like that. | ||||
* @param {number} multiplier - the damage multiplier. | * @param {number} multiplier - The damage multiplier. | ||||
* Returns object of the form { "killed": false, "change": -12 }. | * Returns object of the form { "killed": false, "captured": false, "healthChange": -12, "captureChange": 0 }. | ||||
*/ | */ | ||||
Armour.prototype.TakeDamage = function(strengths, multiplier = 1) | Armour.prototype.TakeDamage = function(playerID, strengths, multiplier = 1) | ||||
{ | { | ||||
if (this.invulnerable) | let result = { "killed": false, "captured": false, "healthChange": 0, "captureChange": 0 } | ||||
return { "killed": false, "change": 0 }; | let damages = this.GetDamage(strengths, multiplier); | ||||
for (let component in damages) | |||||
// Adjust damage values based on armour; exponential armour: damage = attack * 0.9^armour | { | ||||
var armourStrengths = this.GetArmourStrengths(); | // TODO adapt invulnerability into something scalable with damageTypes/Components (ie also make an "uncapturable") | ||||
if (component == IID_Health && this.invulnerable) | |||||
// Total is sum of individual damages | continue; | ||||
// Don't bother rounding, since HP is no longer integral. | |||||
var total = 0; | let cmpRecieveComponent = Engine.QueryInterface(this.entity, +component); | ||||
for (let type in strengths) | if (cmpRecieveComponent) | ||||
total += strengths[type] * multiplier * Math.pow(0.9, armourStrengths[type] || 0); | { | ||||
let componentResult = cmpRecieveComponent.Reduce(damages[component], playerID) | |||||
// Reduce health | for (let key in componentResult) | ||||
var cmpHealth = Engine.QueryInterface(this.entity, IID_Health); | result[key] = result[key] || componentResult[key]; | ||||
return cmpHealth.Reduce(total); | } | ||||
} | |||||
return result; | |||||
}; | }; | ||||
Armour.prototype.GetArmourStrengths = function() | Armour.prototype.GetArmourStrengths = function() | ||||
{ | { | ||||
// Work out the armour values with technology effects | // Work out the armour values with technology effects | ||||
var applyMods = (type, foundation) => { | let applyMods = (type, foundation) => { | ||||
var strength; | let strength; | ||||
if (foundation) | if (foundation) | ||||
{ | { | ||||
strength = +this.template.Foundation[type]; | strength = +(this.template.Foundation[type] || 0); | ||||
type = "Foundation/" + type; | type = "Foundation/" + type; | ||||
} | } | ||||
else | else | ||||
strength = +this.template[type]; | strength = +(this.template[type] || 0); | ||||
return ApplyValueModificationsToEntity("Armour/" + type, strength, this.entity); | return ApplyValueModificationsToEntity("Armour/" + type, strength, this.entity); | ||||
}; | }; | ||||
var foundation = Engine.QueryInterface(this.entity, IID_Foundation) && this.template.Foundation; | let foundation = Engine.QueryInterface(this.entity, IID_Foundation) && this.template.Foundation; | ||||
let ret = {}; | let ret = {}; | ||||
for (let damageType of DamageTypes.GetTypes()) | for (let damageType of DamageTypes.GetTypes()) | ||||
ret[damageType] = applyMods(damageType, foundation); | ret[damageType] = applyMods(damageType, foundation); | ||||
return ret; | return ret; | ||||
}; | }; | ||||
Armour.prototype.GetArmourMultipliers = function() | |||||
{ | |||||
let armourStrength = this.GetArmourStrengths(); | |||||
let ret = {}; | |||||
for (let strength in armourStrength) | |||||
ret[strength] = Math.pow(0.9, armourStrength[strength]); | |||||
// Capture is special, let that depend on health | |||||
let cmpHealth = Engine.QueryInterface(this.entity, IID_Health); | |||||
if (cmpHealth && cmpHealth.GetHitpoints() != 0) | |||||
{ | |||||
ret.capture = ret.capture || 1; | |||||
ret.capture *= cmpHealth.GetMaxHitpoints() / (0.1 * cmpHealth.GetMaxHitpoints() + 0.9 * cmpHealth.GetHitpoints()); | |||||
} | |||||
return ret; | |||||
}; | |||||
Armour.prototype.GetDamage = function(strengths, multiplier = 1) | |||||
{ | |||||
let armourMultipliers = this.GetArmourMultipliers(); | |||||
let damageComponents = DamageTypes.GetComponents(); | |||||
// Total is sum of individual damages per component | |||||
// Don't bother rounding, since HP is no longer integral. | |||||
let total = {}; | |||||
for (let type in strengths) | |||||
{ | |||||
if (total[damageComponents[type]] === undefined) | |||||
total[damageComponents[type]] = 0; | |||||
total[damageComponents[type]] += strengths[type] * multiplier * armourMultipliers[type]; | |||||
} | |||||
return total; | |||||
}; | |||||
Engine.RegisterComponentType(IID_DamageReceiver, "Armour", Armour); | Engine.RegisterComponentType(IID_DamageReceiver, "Armour", Armour); |
Wildfire Games · Phabricator