Changeset View
Changeset View
Standalone View
Standalone View
ps/trunk/binaries/data/mods/public/simulation/helpers/Attacking.js
/** | /** | ||||
* Provides attack and damage-related helpers under the Attacking umbrella (to avoid name ambiguity with the component). | * Provides attack and damage-related helpers under the Attacking umbrella (to avoid name ambiguity with the component). | ||||
*/ | */ | ||||
function Attacking() {} | function Attacking() {} | ||||
const DirectEffectsSchema = | const DirectEffectsSchema = | ||||
"<element name='Damage'>" + | "<element name='Damage'>" + | ||||
"<oneOrMore>" + | "<oneOrMore>" + | ||||
"<element a:help='One or more elements describing damage types'>" + | "<element a:help='One or more elements describing damage types'>" + | ||||
"<anyName>" + | "<anyName/>" + | ||||
// Armour requires Foundation to not be a damage type. | |||||
"<except><name>Foundation</name></except>" + | |||||
"</anyName>" + | |||||
"<ref name='nonNegativeDecimal' />" + | "<ref name='nonNegativeDecimal' />" + | ||||
"</element>" + | "</element>" + | ||||
"</oneOrMore>" + | "</oneOrMore>" + | ||||
"</element>" + | "</element>" + | ||||
"<element name='Capture' a:help='Capture points value'>" + | "<element name='Capture' a:help='Capture points value'>" + | ||||
"<ref name='nonNegativeDecimal'/>" + | "<ref name='nonNegativeDecimal'/>" + | ||||
"</element>"; | "</element>"; | ||||
▲ Show 20 Lines • Show All 141 Lines • ▼ Show 20 Lines | for (let modifier in template) | ||||
if (modifierTemplate.Multiply !== undefined) | if (modifierTemplate.Multiply !== undefined) | ||||
modifiers[modifier].Multiply = ApplyValueModificationsToEntity(valueModifRoot + "/ApplyStatus/" + effect + "/Modifiers/" + modifier + "/Multiply", +modifierTemplate.Multiply, entity); | modifiers[modifier].Multiply = ApplyValueModificationsToEntity(valueModifRoot + "/ApplyStatus/" + effect + "/Modifiers/" + modifier + "/Multiply", +modifierTemplate.Multiply, entity); | ||||
if (modifierTemplate.Replace !== undefined) | if (modifierTemplate.Replace !== undefined) | ||||
modifiers[modifier].Replace = modifierTemplate.Replace; | modifiers[modifier].Replace = modifierTemplate.Replace; | ||||
} | } | ||||
return modifiers; | return modifiers; | ||||
}; | }; | ||||
Attacking.prototype.GetTotalAttackEffects = function(effectData, effectType, cmpResistance) | /** | ||||
* Calculate the total effect taking bonus and resistance into account. | |||||
* | |||||
* @param {number} target - The target of the attack. | |||||
* @param {Object} effectData - The effects calculate the effect for. | |||||
* @param {string} effectType - The type of effect to apply (e.g. Damage, Capture or StatusEffect). | |||||
* @param {number} bonusMultiplier - The factor to multiply the total effect with. | |||||
* @param {Object} cmpResistance - Optionally the resistance component of the target. | |||||
* | |||||
* @return {number} - The total value of the effect. | |||||
*/ | |||||
Attacking.prototype.GetTotalAttackEffects = function(target, effectData, effectType, bonusMultiplier, cmpResistance) | |||||
{ | { | ||||
let total = 0; | let total = 0; | ||||
let armourStrengths = cmpResistance ? cmpResistance.GetArmourStrengths(effectType) : {}; | if (!cmpResistance) | ||||
cmpResistance = Engine.QueryInterface(target, IID_Resistance); | |||||
for (let type in effectData) | let resistanceStrengths = cmpResistance ? cmpResistance.GetEffectiveResistanceAgainst(effectType) : {}; | ||||
total += effectData[type] * Math.pow(0.9, armourStrengths[type] || 0); | |||||
return total; | if (effectType == "Damage") | ||||
for (let type in effectData.Damage) | |||||
total += effectData.Damage[type] * Math.pow(0.9, resistanceStrengths.Damage ? resistanceStrengths.Damage[type] || 0 : 0); | |||||
else if (effectType == "Capture") | |||||
{ | |||||
total = effectData.Capture * Math.pow(0.9, resistanceStrengths.Capture || 0); | |||||
// If Health is lower we are more susceptible to capture attacks. | |||||
let cmpHealth = Engine.QueryInterface(target, IID_Health); | |||||
if (cmpHealth) | |||||
total /= 0.1 + 0.9 * cmpHealth.GetHitpoints() / cmpHealth.GetMaxHitpoints(); | |||||
} | |||||
else if (effectType == "StatusEffect") | |||||
return effectData[effectType]; | |||||
return total * bonusMultiplier; | |||||
}; | }; | ||||
/** | /** | ||||
* Gives the position of the given entity, taking the lateness into account. | * Gives the position of the given entity, taking the lateness into account. | ||||
* @param {number} ent - Entity id of the entity we are finding the location for. | * @param {number} ent - Entity id of the entity we are finding the location for. | ||||
* @param {number} lateness - The time passed since the expected time to fire the function. | * @param {number} lateness - The time passed since the expected time to fire the function. | ||||
* @return {Vector3D} The location of the entity. | * @return {Vector3D} The location of the entity. | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 109 Lines • ▼ Show 20 Lines | else if (data.shape == 'Linear') // linear effect with quadratic falloff in two directions (only used for certain missiles) | ||||
else | else | ||||
damageMultiplier = 0; | damageMultiplier = 0; | ||||
} | } | ||||
else // In case someone calls this function with an invalid shape. | else // In case someone calls this function with an invalid shape. | ||||
{ | { | ||||
warn("The " + data.shape + " splash damage shape is not implemented!"); | warn("The " + data.shape + " splash damage shape is not implemented!"); | ||||
} | } | ||||
this.HandleAttackEffects(data.type + ".Splash", data.attackData, ent, data.attacker, data.attackerOwner, damageMultiplier); | this.HandleAttackEffects(ent, data.type + ".Splash", data.attackData, data.attacker, data.attackerOwner, damageMultiplier); | ||||
} | } | ||||
}; | }; | ||||
/** | |||||
Attacking.prototype.HandleAttackEffects = function(attackType, attackData, target, attacker, attackerOwner, bonusMultiplier = 1) | * Handle an attack peformed on an entity. | ||||
* | |||||
* @param {number} target - The targetted entityID. | |||||
* @param {string} attackType - The type of attack that was performed (e.g. "Melee" or "Capture"). | |||||
* @param {Object} effectData - The effects use. | |||||
* @param {number} attacker - The entityID that attacked us. | |||||
* @param {number} attackerOwner - The playerID that owned the attacker when the attack was performed. | |||||
* @param {number} bonusMultiplier - The factor to multiply the total effect with, defaults to 1. | |||||
* | |||||
* @return {boolean} - Whether we handled the attack. | |||||
*/ | |||||
Attacking.prototype.HandleAttackEffects = function(target, attackType, attackData, attacker, attackerOwner, bonusMultiplier = 1) | |||||
{ | { | ||||
let cmpResistance = Engine.QueryInterface(target, IID_Resistance); | |||||
if (cmpResistance && cmpResistance.IsInvulnerable()) | |||||
return false; | |||||
bonusMultiplier *= !attackData.Bonuses ? 1 : this.GetAttackBonus(attacker, target, attackType, attackData.Bonuses); | bonusMultiplier *= !attackData.Bonuses ? 1 : this.GetAttackBonus(attacker, target, attackType, attackData.Bonuses); | ||||
let targetState = {}; | let targetState = {}; | ||||
for (let effectType of g_EffectTypes) | for (let effectType of g_EffectTypes) | ||||
{ | { | ||||
if (!attackData[effectType]) | if (!attackData[effectType]) | ||||
continue; | continue; | ||||
let receiver = g_EffectReceiver[effectType]; | let receiver = g_EffectReceiver[effectType]; | ||||
let cmpReceiver = Engine.QueryInterface(target, global[receiver.IID]); | let cmpReceiver = Engine.QueryInterface(target, global[receiver.IID]); | ||||
if (!cmpReceiver) | if (!cmpReceiver) | ||||
continue; | continue; | ||||
Object.assign(targetState, cmpReceiver[receiver.method](attackData[effectType], attacker, attackerOwner, bonusMultiplier)); | Object.assign(targetState, cmpReceiver[receiver.method](this.GetTotalAttackEffects(target, attackData, effectType, bonusMultiplier, cmpResistance), attacker, attackerOwner)); | ||||
} | } | ||||
if (!Object.keys(targetState).length) | if (!Object.keys(targetState).length) | ||||
return; | return false; | ||||
Engine.PostMessage(target, MT_Attacked, { | Engine.PostMessage(target, MT_Attacked, { | ||||
"type": attackType, | "type": attackType, | ||||
"target": target, | "target": target, | ||||
"attacker": attacker, | "attacker": attacker, | ||||
"attackerOwner": attackerOwner, | "attackerOwner": attackerOwner, | ||||
"damage": -(targetState.healthChange || 0), | "damage": -(targetState.healthChange || 0), | ||||
"capture": targetState.captureChange || 0, | "capture": targetState.captureChange || 0, | ||||
"statusEffects": targetState.inflictedStatuses || [], | "statusEffects": targetState.inflictedStatuses || [], | ||||
"fromStatusEffect": !!attackData.StatusEffect, | "fromStatusEffect": !!attackData.StatusEffect, | ||||
}); | }); | ||||
// We do not want an entity to get XP from active Status Effects. | // We do not want an entity to get XP from active Status Effects. | ||||
if (!!attackData.StatusEffect) | if (!!attackData.StatusEffect) | ||||
return; | return true; | ||||
let cmpPromotion = Engine.QueryInterface(attacker, IID_Promotion); | let cmpPromotion = Engine.QueryInterface(attacker, IID_Promotion); | ||||
if (cmpPromotion && targetState.xp) | if (cmpPromotion && targetState.xp) | ||||
cmpPromotion.IncreaseXp(targetState.xp); | cmpPromotion.IncreaseXp(targetState.xp); | ||||
return true; | |||||
}; | }; | ||||
/** | /** | ||||
* Gets entities near a give point for given players. | * Gets entities near a give point for given players. | ||||
* @param {Vector2D} origin - The point to check around. | * @param {Vector2D} origin - The point to check around. | ||||
* @param {number} radius - The radius around the point to check. | * @param {number} radius - The radius around the point to check. | ||||
* @param {number[]} players - The players of which we need to check entities. | * @param {number[]} players - The players of which we need to check entities. | ||||
* @param {number} itf - Interface IID that returned entities must implement. Defaults to none. | * @param {number} itf - Interface IID that returned entities must implement. Defaults to none. | ||||
▲ Show 20 Lines • Show All 45 Lines • Show Last 20 Lines |
Wildfire Games · Phabricator