Changeset View
Changeset View
Standalone View
Standalone View
binaries/data/mods/public/simulation/helpers/Attacking.js
Show All 12 Lines | |||||||||
Attacking.prototype.BuildAttackEffectsSchema = function() | Attacking.prototype.BuildAttackEffectsSchema = function() | ||||||||
{ | { | ||||||||
return "" + | return "" + | ||||||||
"<oneOrMore>" + | "<oneOrMore>" + | ||||||||
"<choice>" + | "<choice>" + | ||||||||
"<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>" + | ||||||||
"<element name='StatusEffects' a:help='Effects like poisoning or burning a unit.'>" + | "<element name='StatusEffects' a:help='Effects like poisoning or burning a unit.'>" + | ||||||||
▲ Show 20 Lines • Show All 50 Lines • ▼ Show 20 Lines | if (template.StatusEffects) | ||||||||
ret.StatusEffects = template.StatusEffects; | ret.StatusEffects = template.StatusEffects; | ||||||||
if (template.Bonuses) | if (template.Bonuses) | ||||||||
ret.Bonuses = template.Bonuses; | ret.Bonuses = template.Bonuses; | ||||||||
return ret; | return ret; | ||||||||
}; | }; | ||||||||
Attacking.prototype.GetTotalAttackEffects = function(effectData, effectType, cmpResistance) | Attacking.prototype.GetTotalAttackEffects = function(effectData, effectType, target) | ||||||||
{ | { | ||||||||
let cmpResistance = Engine.QueryInterface(target, IID_Resistance); | |||||||||
let total = 0; | let total = 0; | ||||||||
let armourStrengths = cmpResistance ? cmpResistance.GetArmourStrengths(effectType) : {}; | let resistanceStrengths = {}; | ||||||||
if (cmpResistance) | |||||||||
bbUnsubmitted Done Inline Actions
bb: | |||||||||
{ | |||||||||
if (effectType == "Capture") | |||||||||
resistanceStrengths = cmpResistance.GetResistanceStrengths(effectType); | |||||||||
else | |||||||||
resistanceStrengths = cmpResistance.GetResistanceStrengths(effectType)[effectType]; | |||||||||
} | |||||||||
for (let type in effectData) | for (let type in effectData) | ||||||||
total += effectData[type] * Math.pow(0.9, armourStrengths[type] || 0); | total += effectData[type] * Math.pow(0.9, resistanceStrengths[type] || 0); | ||||||||
Done Inline ActionsresistanceStrengths ? resistanceStrengths[type] || 0 : 0 Freagarach: `resistanceStrengths ? resistanceStrengths[type] || 0 : 0` | |||||||||
return total; | return total; | ||||||||
}; | }; | ||||||||
/** | /** | ||||||||
* 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. | ||||||||
▲ Show 20 Lines • Show All 68 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 {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.minRange - The minimal radius of the area damage. | ||||||||
* @param {number} data.maxRange - The maximum radius of the area 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) | ||||||||
{ | { | ||||||||
let nearEnts = this.EntitiesNearPoint(data.origin, data.radius, | let nearEnts = this.EntitiesNearPoint(data.origin, data.minRange, data.maxRange, | ||||||||
this.GetPlayersToDamage(data.attackerOwner, data.friendlyFire)); | this.GetPlayersToDamage(data.attackerOwner, data.friendlyFire)); | ||||||||
let damageMultiplier = 1; | let damageMultiplier = 1; | ||||||||
// Cycle through all the nearby entities and damage it appropriately based on its distance from the origin. | // Cycle through all the nearby entities and damage it appropriately based on its distance from the origin. | ||||||||
for (let ent of nearEnts) | for (let ent of nearEnts) | ||||||||
{ | { | ||||||||
let entityPosition = Engine.QueryInterface(ent, IID_Position).GetPosition2D(); | let entityPosition = Engine.QueryInterface(ent, IID_Position).GetPosition2D(); | ||||||||
if (data.shape == 'Circular') // circular effect with quadratic falloff in every direction | if (data.shape == 'Circular') // circular effect with quadratic falloff in every direction | ||||||||
damageMultiplier = 1 - data.origin.distanceToSquared(entityPosition) / (data.radius * data.radius); | damageMultiplier = 1 - data.origin.distanceToSquared(entityPosition) / (data.maxRange * data.maxRange); | ||||||||
else if (data.shape == 'Linear') // linear effect with quadratic falloff in two directions (only used for certain missiles) | else if (data.shape == 'Linear') // linear effect with quadratic falloff in two directions (only used for certain missiles) | ||||||||
{ | { | ||||||||
// Get position of entity relative to splash origin. | // Get position of entity relative to splash origin. | ||||||||
let relativePos = entityPosition.sub(data.origin); | let relativePos = entityPosition.sub(data.origin); | ||||||||
// Get the position relative to the missile direction. | // Get the position relative to the missile direction. | ||||||||
let direction = Vector2D.from3D(data.direction); | let direction = Vector2D.from3D(data.direction); | ||||||||
let parallelPos = relativePos.dot(direction); | let parallelPos = relativePos.dot(direction); | ||||||||
let perpPos = relativePos.cross(direction); | let perpPos = relativePos.cross(direction); | ||||||||
// The width of linear splash is one fifth of the normal splash radius. | // The width of linear splash is one fifth of the normal splash radius. | ||||||||
let width = data.radius / 5; | let width = data.maxRange / 5; | ||||||||
// Check that the unit is within the distance splash width of the line starting at the missile's | // Check that the unit is within the distance splash width of the line starting at the missile's | ||||||||
// landing point which extends in the direction of the missile for length splash radius. | // landing point which extends in the direction of the missile for length splash radius. | ||||||||
if (parallelPos >= 0 && Math.abs(perpPos) < width) // If in radius, quadratic falloff in both directions | if (parallelPos >= 0 && Math.abs(perpPos) < width) // If in radius, quadratic falloff in both directions | ||||||||
damageMultiplier = (1 - parallelPos * parallelPos / (data.radius * data.radius)) * | damageMultiplier = (1 - parallelPos * parallelPos / (data.maxRange * data.maxRange)) * | ||||||||
(1 - perpPos * perpPos / (width * width)); | (1 - perpPos * perpPos / (width * width)); | ||||||||
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(data.type + ".Splash", data.attackData, ent, data.attacker, data.attackerOwner, damageMultiplier); | ||||||||
} | } | ||||||||
}; | }; | ||||||||
Attacking.prototype.HandleAttackEffects = function(attackType, attackData, target, attacker, attackerOwner, bonusMultiplier = 1) | Attacking.prototype.HandleAttackEffects = function(attackType, attackData, target, attacker, attackerOwner, bonusMultiplier = 1) | ||||||||
{ | { | ||||||||
let targetState = {}; | let targetState = {}; | ||||||||
for (let effectType of g_EffectTypes) | for (let effectType of g_EffectTypes) | ||||||||
{ | { | ||||||||
Done Inline Actions
bb: | |||||||||
if (!attackData[effectType]) | if (!attackData[effectType]) | ||||||||
continue; | continue; | ||||||||
bonusMultiplier *= !attackData.Bonuses ? 1 : GetAttackBonus(attacker, target, attackType, attackData.Bonuses); | bonusMultiplier *= !attackData.Bonuses ? 1 : GetAttackBonus(attacker, target, attackType, attackData.Bonuses); | ||||||||
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) | ||||||||
Show All 18 Lines | Engine.PostMessage(target, MT_Attacked, { | ||||||||
"capture": targetState.captureChange || 0, | "capture": targetState.captureChange || 0, | ||||||||
"statusEffects": targetState.inflictedStatuses || [], | "statusEffects": targetState.inflictedStatuses || [], | ||||||||
}); | }); | ||||||||
}; | }; | ||||||||
/** | /** | ||||||||
* 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} minRange - The minimum distance the entities may have from the point to check. | ||||||||
* @param {number} maxRange - The maximum distance the entities may have from 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. | ||||||||
* @return {number[]} The id's of the entities in range of the given point. | * @return {number[]} The id's of the entities in range of the given point. | ||||||||
*/ | */ | ||||||||
Attacking.prototype.EntitiesNearPoint = function(origin, radius, players) | Attacking.prototype.EntitiesNearPoint = function(origin, minRange, maxRange, players) | ||||||||
{ | { | ||||||||
// If there is insufficient data return an empty array. | // If there is insufficient data return an empty array. | ||||||||
if (!origin || !radius || !players) | if (!origin || !maxRange || !players) | ||||||||
return []; | return []; | ||||||||
return Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager).ExecuteQueryAroundPos(origin, 0, radius, players, IID_Resistance); | return Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager).ExecuteQueryAroundPos(origin, minRange, maxRange, players, IID_Resistance); | ||||||||
}; | }; | ||||||||
/** | /** | ||||||||
* Called when a unit kills something (another unit, building, animal etc). | * Called when a unit kills something (another unit, building, animal etc). | ||||||||
* @param {number} attacker - The entity id of the killer. | * @param {number} attacker - The entity id of the killer. | ||||||||
* @param {number} target - The entity id of the target. | * @param {number} target - The entity id of the target. | ||||||||
* @param {number} attackerOwner - The player id of the attacker. | * @param {number} attackerOwner - The player id of the attacker. | ||||||||
*/ | */ | ||||||||
Show All 22 Lines |
Wildfire Games · Phabricator