Changeset View
Standalone View
binaries/data/mods/public/simulation/components/Attack.js
Show First 20 Lines • Show All 99 Lines • ▼ Show 20 Lines | "<Ranged>" + | ||||
"</Bonus1>" + | "</Bonus1>" + | ||||
"</Bonuses>" + | "</Bonuses>" + | ||||
"<Projectile>" + | "<Projectile>" + | ||||
"<Speed>50.0</Speed>" + | "<Speed>50.0</Speed>" + | ||||
"<Spread>2.5</Spread>" + | "<Spread>2.5</Spread>" + | ||||
"<ActorName>props/units/weapons/rock_flaming.xml</ActorName>" + | "<ActorName>props/units/weapons/rock_flaming.xml</ActorName>" + | ||||
"<ImpactActorName>props/units/weapons/rock_explosion.xml</ImpactActorName>" + | "<ImpactActorName>props/units/weapons/rock_explosion.xml</ImpactActorName>" + | ||||
"<ImpactAnimationLifetime>0.1</ImpactAnimationLifetime>" + | "<ImpactAnimationLifetime>0.1</ImpactAnimationLifetime>" + | ||||
"<FriendlyFire>false</FriendlyFire>" + | |||||
"</Projectile>" + | "</Projectile>" + | ||||
"<RestrictedClasses datatype=\"tokens\">Champion</RestrictedClasses>" + | "<RestrictedClasses datatype=\"tokens\">Champion</RestrictedClasses>" + | ||||
"<Splash>" + | "<Splash>" + | ||||
"<Shape>Circular</Shape>" + | "<Shape>Circular</Shape>" + | ||||
"<Range>20</Range>" + | "<Range>20</Range>" + | ||||
"<FriendlyFire>false</FriendlyFire>" + | "<FriendlyFire>false</FriendlyFire>" + | ||||
"<Damage>" + | "<Damage>" + | ||||
"<Hack>0.0</Hack>" + | "<Hack>0.0</Hack>" + | ||||
▲ Show 20 Lines • Show All 53 Lines • ▼ Show 20 Lines | "<element name='Ranged'>" + | ||||
"<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'>" + | "<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'>" + | ||||
"<data type='nonNegativeInteger'/>" + | "<data type='nonNegativeInteger'/>" + | ||||
"</element>" + | "</element>" + | ||||
"<element name='RepeatTime' a:help='Time between attacks (in milliseconds). The attack animation will be stretched to match this time'>" + | "<element name='RepeatTime' a:help='Time between attacks (in milliseconds). The attack animation will be stretched to match this time'>" + | ||||
"<data type='positiveInteger'/>" + | "<data type='positiveInteger'/>" + | ||||
"</element>" + | "</element>" + | ||||
"<element name='Delay' a:help='Delay of the damage in milliseconds'><ref name='nonNegativeDecimal'/></element>" + | "<element name='Delay' a:help='Delay of the damage in milliseconds'><ref name='nonNegativeDecimal'/></element>" + | ||||
"<optional>" + | "<optional>" + | ||||
"<element name='Splash'>" + | "<element name='Splash'>" + | ||||
Freagarach: When I remove this optional element entirely, the error does not appear when loading. So it… | |||||
Done Inline Actionsyou should use "e; instead of "'" in the help sentence :) Stan: you should use "e; instead of "'" in the help sentence :) | |||||
"<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>" + | ||||
"<element name='Damage'>" + | "<element name='Damage'>" + | ||||
DamageTypes.BuildSchema("damage strength") + | DamageTypes.BuildSchema("damage strength") + | ||||
"</element>" + | "</element>" + | ||||
Attack.prototype.bonusesSchema + | Attack.prototype.bonusesSchema + | ||||
"</interleave>" + | "</interleave>" + | ||||
"</element>" + | "</element>" + | ||||
"</optional>" + | "</optional>" + | ||||
"<element name='Projectile'>" + | "<element name='Projectile'>" + | ||||
"<interleave>" + | "<interleave>" + | ||||
"<element name='Speed' a:help='Speed of projectiles (in meters per second).'>" + | "<element name='Speed' a:help='Speed of projectiles (in meters per second).'>" + | ||||
"<ref name='positiveDecimal'/>" + | "<ref name='positiveDecimal'/>" + | ||||
"</element>" + | "</element>" + | ||||
"<element name='Spread' a:help='Standard deviation of the bivariate normal distribution of hits at 100 meters. A disk at 100 meters from the attacker with this radius (2x this radius, 3x this radius) is expected to include the landing points of 39.3% (86.5%, 98.9%) of the rounds.'><ref name='nonNegativeDecimal'/></element>" + | "<element name='Spread' a:help='Standard deviation of the bivariate normal distribution of hits at 100 meters. A disk at 100 meters from the attacker with this radius (2x this radius, 3x this radius) is expected to include the landing points of 39.3% (86.5%, 98.9%) of the rounds.'><ref name='nonNegativeDecimal'/></element>" + | ||||
"<element name='Gravity' a:help='The gravity affecting the projectile. This affects the shape of the flight curve.'>" + | "<element name='Gravity' a:help='The gravity affecting the projectile. This affects the shape of the flight curve.'>" + | ||||
"<ref name='nonNegativeDecimal'/>" + | "<ref name='nonNegativeDecimal'/>" + | ||||
"</element>" + | "</element>" + | ||||
"<element name='FriendlyFire' a:help='Whether the attack can hurt non enemy units'><data type='boolean'/></element>" + | |||||
Done Inline ActionsMaybe it could be optionnal ? Stan: Maybe it could be optionnal ? | |||||
Done Inline ActionsNone of the other items are optional, so in terms of coherency it's probably better if it's not, but I agree that repeating these everywhere is kind of annoying... wraitii: None of the other items are optional, so in terms of coherency it's probably better if it's not… | |||||
Done Inline ActionsOne could say the same of e.g. Gravity ;) Freagarach: One could say the same of e.g. `Gravity` ;) | |||||
Done Inline ActionsOkay, a thought here. The argument to have it non-optional is coherency. I like things being optional, to keep templates as clean as possible. Would it be an idea to make more things optional? E.g.:
So just make everything that *can* be optional optional. Freagarach: Okay, a thought here. The argument to have it non-optional is coherency. I like things being… | |||||
Done Inline ActionsI would say that gravity should be always stated and delay can be optional. Or friendlyfire is not optional or make it false by default so if not in template it is false. It goes against common sence. Element is called FriendlyFire so it should be false by default. It is not called DisableFriendylFire. Personally I think if there is good template inheritance for units, a lot of things does not have to be repeated. Problem can be with structures. Silier: I would say that gravity should be always stated and delay can be optional.
Or friendlyfire… | |||||
Done Inline ActionsCould be, but:
(See above in "Templates.js".) Freagarach: Could be, but:
> If you make it a non-optional element, then you can do template.Attack[type]. | |||||
"<optional>" + | "<optional>" + | ||||
"<element name='LaunchPoint' a:help='Delta from the unit position where to launch the projectile.'>" + | "<element name='LaunchPoint' a:help='Delta from the unit position where to launch the projectile.'>" + | ||||
"<attribute name='y'>" + | "<attribute name='y'>" + | ||||
"<data type='decimal'/>" + | "<data type='decimal'/>" + | ||||
"</attribute>" + | "</attribute>" + | ||||
"</element>" + | "</element>" + | ||||
"</optional>" + | "</optional>" + | ||||
"<optional>" + | "<optional>" + | ||||
▲ Show 20 Lines • Show All 270 Lines • ▼ Show 20 Lines | Attack.prototype.GetAttackStrengths = function(type) | ||||
return ret; | return ret; | ||||
}; | }; | ||||
Attack.prototype.GetSplashDamage = function(type) | Attack.prototype.GetSplashDamage = function(type) | ||||
{ | { | ||||
if (!this.template[type].Splash) | if (!this.template[type].Splash) | ||||
return false; | return false; | ||||
let splash = {}; | let splash = { | ||||
splash.damage = this.GetAttackStrengths(type + ".Splash"); | "damage": this.GetAttackStrengths(type + ".Splash"), | ||||
splash.friendlyFire = this.template[type].Splash.FriendlyFire != "false"; | "friendlyFire": this.template[type].Splash.FriendlyFire != "false", | ||||
splash.shape = this.template[type].Splash.Shape; | "shape": this.template[type].Splash.Shape | ||||
}; | |||||
return splash; | return splash; | ||||
}; | }; | ||||
Attack.prototype.GetRange = function(type) | Attack.prototype.GetRange = function(type) | ||||
{ | { | ||||
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); | ||||
▲ Show 20 Lines • Show All 78 Lines • ▼ Show 20 Lines | if (type == "Ranged") | ||||
actorName = this.template[type].Projectile.ActorName || ""; | actorName = this.template[type].Projectile.ActorName || ""; | ||||
impactActorName = this.template[type].Projectile.ImpactActorName || ""; | impactActorName = this.template[type].Projectile.ImpactActorName || ""; | ||||
impactAnimationLifetime = this.template[type].Projectile.ImpactAnimationLifetime || 0; | impactAnimationLifetime = this.template[type].Projectile.ImpactAnimationLifetime || 0; | ||||
// TODO: Use unit rotation to implement x/z offsets. | // TODO: Use unit rotation to implement x/z offsets. | ||||
let deltaLaunchPoint = new Vector3D(0, this.template[type].Projectile.LaunchPoint["@y"], 0.0); | let deltaLaunchPoint = new Vector3D(0, this.template[type].Projectile.LaunchPoint["@y"], 0.0); | ||||
let launchPoint = Vector3D.add(selfPosition, deltaLaunchPoint); | let launchPoint = Vector3D.add(selfPosition, deltaLaunchPoint); | ||||
let cmpVisual = Engine.QueryInterface(this.entity, IID_Visual); | let cmpVisual = Engine.QueryInterface(this.entity, IID_Visual); | ||||
if (cmpVisual) | if (cmpVisual) | ||||
{ | { | ||||
// if the projectile definition is missing from the template | // if the projectile definition is missing from the template | ||||
// then fallback to the projectile name and launchpoint in the visual actor | // then fallback to the projectile name and launchpoint in the visual actor | ||||
if (!actorName) | if (!actorName) | ||||
actorName = cmpVisual.GetProjectileActor(); | actorName = cmpVisual.GetProjectileActor(); | ||||
Show All 15 Lines | let data = { | ||||
"target": target, | "target": target, | ||||
"strengths": this.GetAttackStrengths(type), | "strengths": this.GetAttackStrengths(type), | ||||
"position": realTargetPosition, | "position": realTargetPosition, | ||||
"direction": missileDirection, | "direction": missileDirection, | ||||
"projectileId": id, | "projectileId": id, | ||||
"bonus": this.GetBonusTemplate(type), | "bonus": this.GetBonusTemplate(type), | ||||
"isSplash": false, | "isSplash": false, | ||||
"attackerOwner": attackerOwner, | "attackerOwner": attackerOwner, | ||||
"friendlyFire": this.template[type].Projectile.FriendlyFire != "false", | |||||
Done Inline Actionsthis will return true, and "false", I guess it should return boolean always ;) Stan: this will return true, and "false", I guess it should return boolean always ;) | |||||
"attackImpactSound": attackImpactSound, | "attackImpactSound": attackImpactSound, | ||||
"statusEffects": this.template[type].StatusEffects | "statusEffects": this.template[type].StatusEffects | ||||
}; | }; | ||||
if (this.template[type].Splash) | if (this.template[type].Splash && +this.template[type].Splash.Range > 0) | ||||
Done Inline Actionscould change that one as well. Stan: could change that one as well. | |||||
{ | data.splash = { | ||||
data.friendlyFire = this.template[type].Splash.FriendlyFire != "false"; | "friendlyFire": this.template[type].Splash.FriendlyFire != "false", | ||||
data.radius = +this.template[type].Splash.Range; | "radius": +this.template[type].Splash.Range, | ||||
data.shape = this.template[type].Splash.Shape; | "shape": this.template[type].Splash.Shape, | ||||
data.isSplash = true; | "strengths": this.GetAttackStrengths(type + ".Splash"), | ||||
data.splashStrengths = this.GetAttackStrengths(type + ".Splash"); | "bonus": this.GetBonusTemplate(type + ".Splash") | ||||
data.splashBonus = this.GetBonusTemplate(type + ".Splash"); | }; | ||||
} | |||||
cmpTimer.SetTimeout(SYSTEM_ENTITY, IID_Damage, "MissileHit", timeToTarget * 1000 + +this.template[type].Delay, data); | cmpTimer.SetTimeout(SYSTEM_ENTITY, IID_Damage, "MissileHit", timeToTarget * 1000 + +this.template[type].Delay, data); | ||||
} | } | ||||
else if (type == "Capture") | else if (type == "Capture") | ||||
{ | { | ||||
if (attackerOwner == INVALID_PLAYER) | if (attackerOwner == INVALID_PLAYER) | ||||
return; | return; | ||||
let multiplier = GetDamageBonus(this.entity, target, type, this.GetBonusTemplate(type)); | let multiplier = GetDamageBonus(this.entity, target, type, this.GetBonusTemplate(type)); | ||||
▲ Show 20 Lines • Show All 96 Lines • Show Last 20 Lines |
When I remove this optional element entirely, the error does not appear when loading. So it seems that the error lies here or somewhere where this is parsed, but I cannot find it ;)