Changeset View
Changeset View
Standalone View
Standalone View
binaries/data/mods/public/simulation/helpers/Attacking.js
Show First 20 Lines • Show All 150 Lines • ▼ Show 20 Lines | |||||
}; | }; | ||||
/** | /** | ||||
* Calculate the total effect taking bonus and resistance into account. | * Calculate the total effect taking bonus and resistance into account. | ||||
* | * | ||||
* @param {number} target - The target of the attack. | * @param {number} target - The target of the attack. | ||||
* @param {Object} effectData - The effects calculate the effect for. | * @param {Object} effectData - The effects calculate the effect for. | ||||
* @param {string} effectType - The type of effect to apply (e.g. Damage, Capture or ApplyStatus). | * @param {string} effectType - The type of effect to apply (e.g. Damage, Capture or ApplyStatus). | ||||
* @param {Vector3D} attackerPosition - The position of the attacker when performing the attack. | |||||
* @param {number} attackHeightOffset - The offset of the origin of the attack, | |||||
* relative to the ground. | |||||
* @param {number} bonusMultiplier - The factor to multiply the total effect with. | * @param {number} bonusMultiplier - The factor to multiply the total effect with. | ||||
* @param {Object} cmpResistance - Optionally the resistance component of the target. | * @param {Object} cmpResistance - Optionally the resistance component of the target. | ||||
* | * | ||||
* @return {number} - The total value of the effect. | * @return {number} - The total value of the effect. | ||||
*/ | */ | ||||
Attacking.prototype.GetTotalAttackEffects = function(target, effectData, effectType, bonusMultiplier, cmpResistance) | Attacking.prototype.GetTotalAttackEffects = function(target, effectData, effectType, attackerPosition, attackHeightOffset, bonusMultiplier, cmpResistance) | ||||
{ | { | ||||
let total = 0; | let total = 0; | ||||
if (!cmpResistance) | if (!cmpResistance) | ||||
cmpResistance = Engine.QueryInterface(target, IID_Resistance); | cmpResistance = Engine.QueryInterface(target, IID_Resistance); | ||||
let resistanceStrengths = cmpResistance ? cmpResistance.GetEffectiveResistanceAgainst(effectType) : {}; | let resistanceStrengths = cmpResistance ? cmpResistance.GetEffectiveResistanceAgainst(effectType) : {}; | ||||
if (effectType == "Damage") | if (effectType == "Damage") | ||||
{ | |||||
bonusMultiplier *= this.GetElevationDamageMultiplier(target, attackerPosition, attackHeightOffset); | |||||
for (let type in effectData.Damage) | for (let type in effectData.Damage) | ||||
total += effectData.Damage[type] * Math.pow(0.9, resistanceStrengths.Damage ? resistanceStrengths.Damage[type] || 0 : 0); | total += effectData.Damage[type] * Math.pow(0.9, resistanceStrengths.Damage ? resistanceStrengths.Damage[type] || 0 : 0); | ||||
} | |||||
else if (effectType == "Capture") | else if (effectType == "Capture") | ||||
{ | { | ||||
total = effectData.Capture * Math.pow(0.9, resistanceStrengths.Capture || 0); | total = effectData.Capture * Math.pow(0.9, resistanceStrengths.Capture || 0); | ||||
// If Health is lower we are more susceptible to capture attacks. | // If Health is lower we are more susceptible to capture attacks. | ||||
let cmpHealth = Engine.QueryInterface(target, IID_Health); | let cmpHealth = Engine.QueryInterface(target, IID_Health); | ||||
if (cmpHealth) | if (cmpHealth) | ||||
total /= 0.1 + 0.9 * cmpHealth.GetHitpoints() / cmpHealth.GetMaxHitpoints(); | total /= 0.1 + 0.9 * cmpHealth.GetHitpoints() / cmpHealth.GetMaxHitpoints(); | ||||
▲ Show 20 Lines • Show All 42 Lines • ▼ Show 20 Lines | |||||
/** | /** | ||||
* Damages units around a given origin. | * Damages units around a given origin. | ||||
* @param {Object} data - The data sent by the caller. | * @param {Object} data - The data sent by the caller. | ||||
* @param {string} data.type - The type of damage. | * @param {string} data.type - The type of damage. | ||||
* @param {Object} data.attackData - The attack data. | * @param {Object} data.attackData - The attack data. | ||||
* @param {number} data.attacker - The entity id of the attacker. | * @param {number} data.attacker - The entity id of the attacker. | ||||
* @param {number} data.attackerOwner - The player id of the attacker. | * @param {number} data.attackerOwner - The player id of the attacker. | ||||
* @param {Vector3D} data.attackerPosition - The position of the attacker when the attack was initiated. | |||||
* @param {number} data.attackHeightOffset - The offset of the origin of the attack, | |||||
* relative to the ground. | |||||
* @param {Vector2D} data.origin - The origin of the projectile hit. | * @param {Vector2D} data.origin - The origin of the projectile hit. | ||||
* @param {number} data.radius - The radius of the splash damage. | * @param {number} data.radius - The radius of the splash damage. | ||||
* @param {string} data.shape - The shape of the radius. | * @param {string} data.shape - The shape of the radius. | ||||
* @param {Vector3D} [data.direction] - The unit vector defining the direction. Needed for linear splash damage. | * @param {Vector3D} [data.direction] - The unit vector defining the direction. Needed for linear splash damage. | ||||
* @param {boolean} data.friendlyFire - A flag indicating if allied entities also ought to be damaged. | * @param {boolean} data.friendlyFire - A flag indicating if allied entities also ought to be damaged. | ||||
*/ | */ | ||||
Attacking.prototype.CauseDamageOverArea = function(data) | Attacking.prototype.CauseDamageOverArea = function(data) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 50 Lines • ▼ Show 20 Lines | |||||
* Handle an attack peformed on an entity. | * Handle an attack peformed on an entity. | ||||
* | * | ||||
* @param {number} target - The targetted entityID. | * @param {number} target - The targetted entityID. | ||||
* @param {Object} data - The data of the attack. | * @param {Object} data - The data of the attack. | ||||
* @param {string} data.type - The type of attack that was performed (e.g. "Melee" or "Capture"). | * @param {string} data.type - The type of attack that was performed (e.g. "Melee" or "Capture"). | ||||
* @param {Object} data.effectData - The effects use. | * @param {Object} data.effectData - The effects use. | ||||
* @param {number} data.attacker - The entityID that attacked us. | * @param {number} data.attacker - The entityID that attacked us. | ||||
* @param {number} data.attackerOwner - The playerID that owned the attacker when the attack was performed. | * @param {number} data.attackerOwner - The playerID that owned the attacker when the attack was performed. | ||||
* @param {Vector3D} data.attackerPosition - The position of the attacker when the attack was initiated. | |||||
* @param {number} data.attackHeightOffset - The offset of the origin of the attack, | |||||
* relative to the ground. | |||||
* @param {number} bonusMultiplier - The factor to multiply the total effect with, defaults to 1. | * @param {number} bonusMultiplier - The factor to multiply the total effect with, defaults to 1. | ||||
* | * | ||||
* @return {boolean} - Whether we handled the attack. | * @return {boolean} - Whether we handled the attack. | ||||
*/ | */ | ||||
Attacking.prototype.HandleAttackEffects = function(target, data, bonusMultiplier = 1) | Attacking.prototype.HandleAttackEffects = function(target, data, bonusMultiplier = 1) | ||||
{ | { | ||||
let cmpResistance = Engine.QueryInterface(target, IID_Resistance); | let cmpResistance = Engine.QueryInterface(target, IID_Resistance); | ||||
if (cmpResistance && cmpResistance.IsInvulnerable()) | if (cmpResistance && cmpResistance.IsInvulnerable()) | ||||
return false; | return false; | ||||
bonusMultiplier *= !data.attackData.Bonuses ? 1 : this.GetAttackBonus(data.attacker, target, data.type, data.attackData.Bonuses); | bonusMultiplier *= !data.attackData.Bonuses ? 1 : this.GetAttackBonus(data.attacker, target, data.type, data.attackData.Bonuses); | ||||
let targetState = {}; | let targetState = {}; | ||||
for (let receiver of g_AttackEffects.Receivers()) | for (let receiver of g_AttackEffects.Receivers()) | ||||
{ | { | ||||
if (!data.attackData[receiver.type]) | if (!data.attackData[receiver.type]) | ||||
continue; | continue; | ||||
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](this.GetTotalAttackEffects(target, data.attackData, receiver.type, bonusMultiplier, cmpResistance), data.attacker, data.attackerOwner)); | Object.assign(targetState, | ||||
cmpReceiver[receiver.method]( | |||||
this.GetTotalAttackEffects(target, | |||||
data.attackData, | |||||
receiver.type, | |||||
data.attackerPosition, | |||||
data.attackHeightOffset, | |||||
bonusMultiplier, | |||||
cmpResistance | |||||
), | |||||
data.attacker, | |||||
data.attackerOwner | |||||
)); | |||||
} | } | ||||
if (!Object.keys(targetState).length) | if (!Object.keys(targetState).length) | ||||
return false; | return false; | ||||
Engine.PostMessage(target, MT_Attacked, { | Engine.PostMessage(target, MT_Attacked, { | ||||
"type": data.type, | "type": data.type, | ||||
"target": target, | "target": target, | ||||
Show All 18 Lines | |||||
/** | /** | ||||
* Calculates the attack damage multiplier against a target. | * Calculates the attack damage multiplier against a target. | ||||
* @param {number} source - The source entity's id. | * @param {number} source - The source entity's id. | ||||
* @param {number} target - The target entity's id. | * @param {number} target - The target entity's id. | ||||
* @param {string} type - The type of attack. | * @param {string} type - The type of attack. | ||||
* @param {Object} template - The bonus' template. | * @param {Object} template - The bonus' template. | ||||
* @return {number} - The source entity's attack bonus against the specified target. | * @return {number} - The source entity's attack bonus against the specified target. | ||||
*/ | */ | ||||
Stan: Multiplier instead of Bonus ?No strong feeling. | |||||
Attacking.prototype.GetAttackBonus = function(source, target, type, template) | Attacking.prototype.GetAttackBonus = function(source, target, type, template) | ||||
{ | { | ||||
let cmpIdentity = Engine.QueryInterface(target, IID_Identity); | let cmpIdentity = Engine.QueryInterface(target, IID_Identity); | ||||
if (!cmpIdentity) | if (!cmpIdentity) | ||||
return 1; | return 1; | ||||
let attackBonus = 1; | let attackBonus = 1; | ||||
let targetClasses = cmpIdentity.GetClassesList(); | let targetClasses = cmpIdentity.GetClassesList(); | ||||
let targetCiv = cmpIdentity.GetCiv(); | let targetCiv = cmpIdentity.GetCiv(); | ||||
// Multiply the bonuses for all matching classes. | // Multiply the bonuses for all matching classes. | ||||
for (let key in template) | for (let key in template) | ||||
{ | { | ||||
let bonus = template[key]; | let bonus = template[key]; | ||||
if (bonus.Civ && bonus.Civ !== targetCiv) | if (bonus.Civ && bonus.Civ !== targetCiv) | ||||
continue; | continue; | ||||
if (!bonus.Classes || MatchesClassList(targetClasses, bonus.Classes)) | if (!bonus.Classes || MatchesClassList(targetClasses, bonus.Classes)) | ||||
attackBonus *= ApplyValueModificationsToEntity("Attack/" + type + "/Bonuses/" + key + "/Multiplier", +bonus.Multiplier, source); | attackBonus *= ApplyValueModificationsToEntity("Attack/" + type + "/Bonuses/" + key + "/Multiplier", +bonus.Multiplier, source); | ||||
} | } | ||||
return attackBonus; | return attackBonus; | ||||
}; | }; | ||||
/** | |||||
* Calculate the damage bonus for entities with a height difference. | |||||
* For an explanation of the numbers, see Phab:D781. | |||||
* | |||||
* @param {number} target - The entity ID of the target. | |||||
* @param {Vector3D} attackerPosition - The original position of the attacker. | |||||
* @param {number} attackHeightOffset - The attack height offset of the attack, | |||||
* relative to the ground. | |||||
* | |||||
* @return {number} - The factor that the damage will be multiplied with. | |||||
*/ | |||||
Attacking.prototype.GetElevationDamageMultiplier = function(target, attackerPosition, attackHeightOffset) | |||||
{ | |||||
let cmpTargetPosition = Engine.QueryInterface(target, IID_Position); | |||||
if (!cmpTargetPosition || !cmpTargetPosition.IsInWorld()) | |||||
return 1; | |||||
let targetPosition = cmpTargetPosition.GetPosition(); | |||||
let elevationDifference = attackerPosition.y + attackHeightOffset - targetPosition.y; | |||||
return Math.max(0.1, 1 + 0.01 * elevationDifference); | |||||
}; | |||||
var AttackingInstance = new Attacking(); | var AttackingInstance = new Attacking(); | ||||
Engine.RegisterGlobal("Attacking", AttackingInstance); | Engine.RegisterGlobal("Attacking", AttackingInstance); | ||||
Engine.RegisterGlobal("g_AttackEffects", new AttackEffects()); | Engine.RegisterGlobal("g_AttackEffects", new AttackEffects()); |
Wildfire Games · Phabricator
Multiplier instead of Bonus ?No strong feeling.