Changeset View
Changeset View
Standalone View
Standalone View
ps/trunk/binaries/data/mods/public/simulation/components/Attack.js
Show First 20 Lines • Show All 51 Lines • ▼ Show 20 Lines | "<Ranged>" + | ||||
"<AttackName>Bow</AttackName>" + | "<AttackName>Bow</AttackName>" + | ||||
"<Damage>" + | "<Damage>" + | ||||
"<Hack>0.0</Hack>" + | "<Hack>0.0</Hack>" + | ||||
"<Pierce>10.0</Pierce>" + | "<Pierce>10.0</Pierce>" + | ||||
"<Crush>0.0</Crush>" + | "<Crush>0.0</Crush>" + | ||||
"</Damage>" + | "</Damage>" + | ||||
"<MaxRange>44.0</MaxRange>" + | "<MaxRange>44.0</MaxRange>" + | ||||
"<MinRange>20.0</MinRange>" + | "<MinRange>20.0</MinRange>" + | ||||
"<ElevationBonus>15.0</ElevationBonus>" + | "<Origin>" + | ||||
"<X>0</X>" + | |||||
"<Y>10.0</Y>" + | |||||
"<Z>0</Z>" + | |||||
"</Origin>" + | |||||
"<PrepareTime>800</PrepareTime>" + | "<PrepareTime>800</PrepareTime>" + | ||||
"<RepeatTime>1600</RepeatTime>" + | "<RepeatTime>1600</RepeatTime>" + | ||||
"<Delay>1000</Delay>" + | "<EffectDelay>1000</EffectDelay>" + | ||||
"<Bonuses>" + | "<Bonuses>" + | ||||
"<Bonus1>" + | "<Bonus1>" + | ||||
"<Classes>Cavalry</Classes>" + | "<Classes>Cavalry</Classes>" + | ||||
"<Multiplier>2</Multiplier>" + | "<Multiplier>2</Multiplier>" + | ||||
"</Bonus1>" + | "</Bonus1>" + | ||||
"</Bonuses>" + | "</Bonuses>" + | ||||
"<Projectile>" + | "<Projectile>" + | ||||
"<Speed>50.0</Speed>" + | "<Speed>50.0</Speed>" + | ||||
Show All 38 Lines | "<element>" + | ||||
"<text/>" + | "<text/>" + | ||||
"</element>" + | "</element>" + | ||||
AttackHelper.BuildAttackEffectsSchema() + | AttackHelper.BuildAttackEffectsSchema() + | ||||
"<element name='MaxRange' a:help='Maximum attack range (in metres)'><ref name='nonNegativeDecimal'/></element>" + | "<element name='MaxRange' a:help='Maximum attack range (in metres)'><ref name='nonNegativeDecimal'/></element>" + | ||||
"<optional>" + | "<optional>" + | ||||
"<element name='MinRange' a:help='Minimum attack range (in metres). Defaults to 0.'><ref name='nonNegativeDecimal'/></element>" + | "<element name='MinRange' a:help='Minimum attack range (in metres). Defaults to 0.'><ref name='nonNegativeDecimal'/></element>" + | ||||
"</optional>" + | "</optional>" + | ||||
"<optional>"+ | "<optional>"+ | ||||
"<element name='ElevationBonus' a:help='The offset height from which the attack occurs, relative to the entity position. Defaults to 0.'><ref name='nonNegativeDecimal'/></element>" + | "<element name='Origin' a:help='The offset from which the attack occurs, relative to the entity position. Defaults to {0,0,0}.'>" + | ||||
"<interleave>" + | |||||
"<element name='X'>" + | |||||
"<ref name='nonNegativeDecimal'/>" + | |||||
"</element>" + | |||||
"<element name='Y'>" + | |||||
"<ref name='nonNegativeDecimal'/>" + | |||||
"</element>" + | |||||
"<element name='Z'>" + | |||||
"<ref name='nonNegativeDecimal'/>" + | |||||
"</element>" + | |||||
"</interleave>" + | |||||
"</element>" + | |||||
"</optional>" + | "</optional>" + | ||||
"<optional>" + | "<optional>" + | ||||
"<element name='RangeOverlay'>" + | "<element name='RangeOverlay'>" + | ||||
"<interleave>" + | "<interleave>" + | ||||
"<element name='LineTexture'><text/></element>" + | "<element name='LineTexture'><text/></element>" + | ||||
"<element name='LineTextureMask'><text/></element>" + | "<element name='LineTextureMask'><text/></element>" + | ||||
"<element name='LineThickness'><ref name='nonNegativeDecimal'/></element>" + | "<element name='LineThickness'><ref name='nonNegativeDecimal'/></element>" + | ||||
"</interleave>" + | "</interleave>" + | ||||
"</element>" + | "</element>" + | ||||
"</optional>" + | "</optional>" + | ||||
"<optional>" + | "<optional>" + | ||||
"<element name='PrepareTime' a:help='Time from the start of the attack command until the attack actually occurs (in milliseconds). This value relative to RepeatTime should closely match the \"event\" point in the actor's attack animation. Defaults to 0.'>" + | "<element name='PrepareTime' a:help='Time from the start of the attack command until the attack actually occurs (in milliseconds). This value relative to RepeatTime should closely match the \"event\" point in the actor's attack animation. Defaults to 0.'>" + | ||||
"<data type='nonNegativeInteger'/>" + | "<data type='nonNegativeInteger'/>" + | ||||
"</element>" + | "</element>" + | ||||
"</optional>" + | "</optional>" + | ||||
"<element name='RepeatTime' a:help='Time between attacks (in milliseconds). The attack animation will be stretched to match this time'>" + // TODO: it shouldn't be stretched | "<element name='RepeatTime' a:help='Time between attacks (in milliseconds). The attack animation will be stretched to match this time'>" + // TODO: it shouldn't be stretched | ||||
"<data type='positiveInteger'/>" + | "<data type='positiveInteger'/>" + | ||||
"</element>" + | "</element>" + | ||||
"<optional>" + | "<optional>" + | ||||
"<element name='Delay' a:help='Delay of applying the effects in milliseconds after the attack has landed. Defaults to 0.'><ref name='nonNegativeDecimal'/></element>" + | "<element name='EffectDelay' a:help='Delay of applying the effects, in milliseconds after the attack has landed. Defaults to 0.'><ref name='nonNegativeDecimal'/></element>" + | ||||
"</optional>" + | "</optional>" + | ||||
"<optional>" + | "<optional>" + | ||||
"<element name='Splash'>" + | "<element name='Splash'>" + | ||||
"<interleave>" + | "<interleave>" + | ||||
"<element name='Shape' a:help='Shape of the splash damage, can be circular or linear'><text/></element>" + | "<element name='Shape' a:help='Shape of the splash damage, can be circular or linear'><text/></element>" + | ||||
"<element name='Range' a:help='Size of the area affected by the splash'><ref name='nonNegativeDecimal'/></element>" + | "<element name='Range' a:help='Size of the area affected by the splash'><ref name='nonNegativeDecimal'/></element>" + | ||||
"<element name='FriendlyFire' a:help='Whether the splash damage can hurt non enemy units'><data type='boolean'/></element>" + | "<element name='FriendlyFire' a:help='Whether the splash damage can hurt non enemy units'><data type='boolean'/></element>" + | ||||
AttackHelper.BuildAttackEffectsSchema() + | AttackHelper.BuildAttackEffectsSchema() + | ||||
▲ Show 20 Lines • Show All 286 Lines • ▼ Show 20 Lines | if (!type) | ||||
return this.GetFullAttackRange(); | return this.GetFullAttackRange(); | ||||
let max = +this.template[type].MaxRange; | let max = +this.template[type].MaxRange; | ||||
max = ApplyValueModificationsToEntity("Attack/" + type + "/MaxRange", max, this.entity); | max = ApplyValueModificationsToEntity("Attack/" + type + "/MaxRange", max, this.entity); | ||||
let min = +(this.template[type].MinRange || 0); | let min = +(this.template[type].MinRange || 0); | ||||
min = ApplyValueModificationsToEntity("Attack/" + type + "/MinRange", min, this.entity); | min = ApplyValueModificationsToEntity("Attack/" + type + "/MinRange", min, this.entity); | ||||
let elevationBonus = +(this.template[type].ElevationBonus || 0); | return { "max": max, "min": min }; | ||||
elevationBonus = ApplyValueModificationsToEntity("Attack/" + type + "/ElevationBonus", elevationBonus, this.entity); | }; | ||||
return { "max": max, "min": min, "elevationBonus": elevationBonus }; | Attack.prototype.GetAttackYOrigin = function(type) | ||||
{ | |||||
if (!this.template[type].Origin) | |||||
return 0; | |||||
return ApplyValueModificationsToEntity("Attack/" + type + "/Origin/Y", +this.template[type].Origin.Y, this.entity); | |||||
}; | }; | ||||
/** | /** | ||||
* @param {number} target - The target to attack. | * @param {number} target - The target to attack. | ||||
* @param {string} type - The type of attack to use. | * @param {string} type - The type of attack to use. | ||||
* @param {number} callerIID - The IID to notify on specific events. | * @param {number} callerIID - The IID to notify on specific events. | ||||
* | * | ||||
* @return {boolean} - Whether we started attacking. | * @return {boolean} - Whether we started attacking. | ||||
▲ Show 20 Lines • Show All 146 Lines • ▼ Show 20 Lines | let data = { | ||||
"type": type, | "type": type, | ||||
"attackData": this.GetAttackEffectsData(type), | "attackData": this.GetAttackEffectsData(type), | ||||
"splash": this.GetSplashData(type), | "splash": this.GetSplashData(type), | ||||
"attacker": this.entity, | "attacker": this.entity, | ||||
"attackerOwner": attackerOwner, | "attackerOwner": attackerOwner, | ||||
"target": target, | "target": target, | ||||
}; | }; | ||||
let delay = +(this.template[type].Delay || 0); | let delay = +(this.template[type].EffectDelay || 0); | ||||
if (this.template[type].Projectile) | if (this.template[type].Projectile) | ||||
{ | { | ||||
let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); | let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); | ||||
let turnLength = cmpTimer.GetLatestTurnLength()/1000; | let turnLength = cmpTimer.GetLatestTurnLength()/1000; | ||||
// In the future this could be extended: | // In the future this could be extended: | ||||
// * Obstacles like trees could reduce the probability of the target being hit | // * Obstacles like trees could reduce the probability of the target being hit | ||||
// * Obstacles like walls should block projectiles entirely | // * Obstacles like walls should block projectiles entirely | ||||
▲ Show 20 Lines • Show All 112 Lines • ▼ Show 20 Lines | if (type == "Ranged") | ||||
let cmpPositionSelf = Engine.QueryInterface(this.entity, IID_Position); | let cmpPositionSelf = Engine.QueryInterface(this.entity, IID_Position); | ||||
if (!cmpPositionSelf || !cmpPositionSelf.IsInWorld()) | if (!cmpPositionSelf || !cmpPositionSelf.IsInWorld()) | ||||
return false; | return false; | ||||
let positionSelf = cmpPositionSelf.GetPosition(); | let positionSelf = cmpPositionSelf.GetPosition(); | ||||
let positionTarget = cmpPositionTarget.GetPosition(); | let positionTarget = cmpPositionTarget.GetPosition(); | ||||
let heightDifference = positionSelf.y + range.elevationBonus - positionTarget.y; | const heightDifference = positionSelf.y + this.GetAttackYOrigin(type) - positionTarget.y; | ||||
range.max = Math.sqrt(Math.square(range.max) + 2 * range.max * heightDifference); | range.max = Math.sqrt(Math.square(range.max) + 2 * range.max * heightDifference); | ||||
if (range.max < 0) | if (range.max < 0) | ||||
return false; | return false; | ||||
} | } | ||||
let cmpObstructionManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_ObstructionManager); | let cmpObstructionManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_ObstructionManager); | ||||
return cmpObstructionManager.IsInTargetRange(this.entity, target, range.min, range.max, false); | return cmpObstructionManager.IsInTargetRange(this.entity, target, range.min, range.max, false); | ||||
}; | }; | ||||
Show All 34 Lines |
Wildfire Games · Phabricator