Changeset View
Standalone View
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 = | ||||
* Builds a RelaxRNG schema of possible attack effects. | "<element name='Damage'>" + | ||||
wraitii: separated | |||||
* See globalscripts/AttackEffects.js for possible elements. | |||||
* Attacks may also have a "Bonuses" element. | |||||
* | |||||
* @return {string} - RelaxNG schema string | |||||
*/ | |||||
const DamageSchema = "" + | |||||
"<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. | // Armour requires Foundation to not be a damage type. | ||||
"<except><name>Foundation</name></except>" + | "<except><name>Foundation</name></except>" + | ||||
"</anyName>" + | "</anyName>" + | ||||
"<ref name='nonNegativeDecimal' />" + | "<ref name='nonNegativeDecimal' />" + | ||||
"</element>" + | "</element>" + | ||||
"</oneOrMore>"; | "</oneOrMore>" + | ||||
Attacking.prototype.BuildAttackEffectsSchema = function() | |||||
{ | |||||
return "" + | |||||
"<oneOrMore>" + | |||||
"<choice>" + | |||||
"<element name='Damage'>" + | |||||
DamageSchema + | |||||
"</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='GiveStatus' a:help='Effects like poisoning or burning a unit.'>" + | |||||
const StatusEffectsSchema = | |||||
"<element name='ApplyStatus' a:help='Effects like poisoning or burning a unit.'>" + | |||||
"<oneOrMore>" + | "<oneOrMore>" + | ||||
"<element>" + | "<element>" + | ||||
"<anyName/>" + | "<anyName/>" + | ||||
"<interleave>" + | "<interleave>" + | ||||
"<element name='Name'><text/></element>" + | |||||
"<optional>" + | "<optional>" + | ||||
"<element name='Icon' a:help='Icon for the status effect'><text/></element>" + | "<element name='Icon' a:help='Icon for the status effect.'><text/></element>" + | ||||
"</optional>" + | "</optional>" + | ||||
"<optional>" + | |||||
"<element name='Tooltip'><text/></element>" + | |||||
"</optional>" + | |||||
"<optional>" + | |||||
"<element name='Duration' a:help='The duration of the status while the effect occurs.'><ref name='nonNegativeDecimal'/></element>" + | "<element name='Duration' a:help='The duration of the status while the effect occurs.'><ref name='nonNegativeDecimal'/></element>" + | ||||
"</optional>" + | |||||
"<optional>" + | |||||
"<interleave>" + | |||||
"<element name='Interval' a:help='Interval between the occurances of the effect.'><ref name='nonNegativeDecimal'/></element>" + | "<element name='Interval' a:help='Interval between the occurances of the effect.'><ref name='nonNegativeDecimal'/></element>" + | ||||
"<element name='Damage' a:help='Damage caused by the effect.'>" + DamageSchema + "</element>" + | "<oneOrMore>" + | ||||
"<choice>" + | |||||
DirectEffectsSchema + | |||||
"</choice>" + | |||||
"</oneOrMore>" + | |||||
"</interleave>" + | |||||
"</optional>" + | |||||
"<optional>" + | |||||
ModificationsSchema + | |||||
"</optional>" + | |||||
"</interleave>" + | "</interleave>" + | ||||
"</element>" + | "</element>" + | ||||
"</oneOrMore>" + | "</oneOrMore>" + | ||||
"</element>" + | "</element>"; | ||||
/** | |||||
* Builds a RelaxRNG schema of possible attack effects. | |||||
* See globalscripts/AttackEffects.js for possible elements. | |||||
* Attacks may also have a "Bonuses" element. | |||||
* | |||||
* @return {string} - RelaxNG schema string. | |||||
Done Inline ActionsMissing '.' Still not sure whether it's @returns, or @return. Stan: Missing '.' Still not sure whether it's @returns, or @return. | |||||
*/ | |||||
Attacking.prototype.BuildAttackEffectsSchema = function() | |||||
{ | |||||
return "" + | |||||
"<oneOrMore>" + | |||||
"<choice>" + | |||||
DirectEffectsSchema + | |||||
Done Inline ActionsThis should be a one or more choice probably. Freagarach: This should be a one or more choice probably. | |||||
Done Inline ActionsOptional because we could have permanent status effects. Freagarach: Optional because we could have permanent status effects. | |||||
Done Inline ActionsOptional because we can have effects with only modifiers (which are applied once and removed after duration (or not)). But for Damage a lack of interval makes no sense. Freagarach: Optional because we can have effects with only modifiers (which are applied once and removed… | |||||
StatusEffectsSchema + | |||||
"</choice>" + | "</choice>" + | ||||
"</oneOrMore>" + | "</oneOrMore>" + | ||||
"<optional>" + | "<optional>" + | ||||
"<element name='Bonuses'>" + | "<element name='Bonuses'>" + | ||||
"<zeroOrMore>" + | "<zeroOrMore>" + | ||||
Done Inline ActionsThis has to be fixed. Freagarach: This has to be fixed.
If an entity has a direct effect (i.e. `Damage` or `Capture`) then, and… | |||||
Done Inline ActionsYou can do that with <interleave> I think. Alternatively just wrap every other item in a function and have a choice of 'either you have Damage/Capture, then you need interval, or you don't'. wraitii: You can do that with <interleave> I think. Alternatively just wrap every other item in a… | |||||
Done Inline Actionsinterleave does not give the desired result. I now lean strongly towards: "let the user find out". Freagarach: `interleave` does not give the desired result. I now lean strongly towards: "let the user find… | |||||
"<element>" + | "<element>" + | ||||
"<anyName/>" + | "<anyName/>" + | ||||
"<interleave>" + | "<interleave>" + | ||||
"<optional>" + | "<optional>" + | ||||
"<element name='Civ' a:help='If an entity has this civ then the bonus is applied'><text/></element>" + | "<element name='Civ' a:help='If an entity has this civ then the bonus is applied'><text/></element>" + | ||||
"</optional>" + | "</optional>" + | ||||
"<element name='Classes' a:help='If an entity has all these classes then the bonus is applied'><text/></element>" + | "<element name='Classes' a:help='If an entity has all these classes then the bonus is applied'><text/></element>" + | ||||
"<element name='Multiplier' a:help='The effect strength is multiplied by this'><ref name='nonNegativeDecimal'/></element>" + | "<element name='Multiplier' a:help='The effect strength is multiplied by this'><ref name='nonNegativeDecimal'/></element>" + | ||||
Show All 12 Lines | Attacking.prototype.GetAttackEffectsData = function(valueModifRoot, template, entity) | ||||
let ret = {}; | let ret = {}; | ||||
if (template.Damage) | if (template.Damage) | ||||
{ | { | ||||
ret.Damage = {}; | ret.Damage = {}; | ||||
let applyMods = damageType => | let applyMods = damageType => | ||||
ApplyValueModificationsToEntity(valueModifRoot + "/Damage/" + damageType, +(template.Damage[damageType] || 0), entity); | ApplyValueModificationsToEntity(valueModifRoot + "/Damage/" + damageType, +(template.Damage[damageType] || 0), entity); | ||||
for (let damageType in template.Damage) | for (let damageType in template.Damage) | ||||
ret.Damage[damageType] = applyMods(damageType); | ret.Damage[damageType] = applyMods(damageType); | ||||
Done Inline ActionsThis shouldn't go in Attacking.js but in a separate 'ModifierTemplate' helper or something, as other code could use it (see promotion diff) wraitii: This shouldn't go in Attacking.js but in a separate 'ModifierTemplate' helper or something, as… | |||||
} | } | ||||
if (template.Capture) | if (template.Capture) | ||||
ret.Capture = ApplyValueModificationsToEntity(valueModifRoot + "/Capture", +(template.Capture || 0), entity); | ret.Capture = ApplyValueModificationsToEntity(valueModifRoot + "/Capture", +(template.Capture || 0), entity); | ||||
if (template.GiveStatus) | if (template.ApplyStatus) | ||||
ret.GiveStatus = template.GiveStatus; | ret.ApplyStatus = template.ApplyStatus; | ||||
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, cmpResistance) | ||||
▲ Show 20 Lines • Show All 147 Lines • ▼ Show 20 Lines | for (let effectType of g_EffectTypes) | ||||
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](attackData[effectType], attacker, attackerOwner, bonusMultiplier)); | ||||
} | } | ||||
let cmpPromotion = Engine.QueryInterface(attacker, IID_Promotion); | |||||
if (cmpPromotion && targetState.xp) | |||||
cmpPromotion.IncreaseXp(targetState.xp); | |||||
if (targetState.killed) | if (targetState.killed) | ||||
this.TargetKilled(attacker, target, attackerOwner); | this.TargetKilled(attacker, target, attackerOwner); | ||||
Engine.PostMessage(target, MT_Attacked, { | Engine.PostMessage(target, MT_Attacked, { | ||||
Done Inline ActionsINVALID_ENTITY Silier: INVALID_ENTITY | |||||
"type": attackType, | "type": attackType, | ||||
"target": target, | "target": target, | ||||
Done Inline ActionsThis is unrelated, no? wraitii: This is unrelated, no? | |||||
Done Inline ActionsNo indeed. Freagarach: No indeed. | |||||
"attacker": attacker, | "attacker": attacker, | ||||
"attackerOwner": attackerOwner, | "attackerOwner": attackerOwner, | ||||
"damage": -(targetState.HPchange || 0), | "damage": -(targetState.HPchange || 0), | ||||
"capture": targetState.captureChange || 0, | "capture": targetState.captureChange || 0, | ||||
"statusEffects": targetState.inflictedStatuses || [], | "statusEffects": targetState.inflictedStatuses || [], | ||||
"fromStatusEffect": !!attackData.Interval, // Only Status Effects have an interval. | |||||
}); | }); | ||||
// Only Status Effects have an interval and we do not want | |||||
// an entity to get XP from active Status Effects. | |||||
if (!!attackData.Interval) | |||||
Done Inline Actions(It seems like indirection to test for a property of statuseffects (has interval or not) rather than test some isStatusEffect or type=Statuseffect, not sure what's happening with the code however, and also inserting that type information may be less performant and more memory consumptive) elexis: (It seems like indirection to test for a property of statuseffects (has interval or not) rather… | |||||
Done Inline ActionsAgreed, I was thinking about that. Indeed the only right way would be to insert a new property. Freagarach: Agreed, I was thinking about that. Indeed the only right way would be to insert a new property. | |||||
Done Inline ActionsI will add a new property for correctness. Freagarach: I will add a new property for correctness. | |||||
return; | |||||
let cmpPromotion = Engine.QueryInterface(attacker, IID_Promotion); | |||||
if (cmpPromotion && targetState.xp) | |||||
cmpPromotion.IncreaseXp(targetState.xp); | |||||
}; | }; | ||||
/** | /** | ||||
* 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. | ||||
* @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. | ||||
▲ Show 20 Lines • Show All 47 Lines • Show Last 20 Lines |
separated