Changeset View
Changeset View
Standalone View
Standalone View
binaries/data/mods/public/simulation/components/Attack.js
Show First 20 Lines • Show All 432 Lines • ▼ Show 20 Lines | Attack.prototype.GetRange = function(type) | ||||||||||||||
min = ApplyValueModificationsToEntity("Attack/" + type + "/MinRange", min, this.entity); | min = ApplyValueModificationsToEntity("Attack/" + type + "/MinRange", min, this.entity); | ||||||||||||||
let elevationBonus = +(this.template[type].ElevationBonus || 0); | let elevationBonus = +(this.template[type].ElevationBonus || 0); | ||||||||||||||
elevationBonus = ApplyValueModificationsToEntity("Attack/" + type + "/ElevationBonus", elevationBonus, this.entity); | elevationBonus = ApplyValueModificationsToEntity("Attack/" + type + "/ElevationBonus", elevationBonus, this.entity); | ||||||||||||||
return { "max": max, "min": min, "elevationBonus": elevationBonus }; | return { "max": max, "min": min, "elevationBonus": elevationBonus }; | ||||||||||||||
}; | }; | ||||||||||||||
/** | /** | ||||||||||||||
Stan: You should use doxygen style comments. I'm not sure this function even needs a comment as it's… | |||||||||||||||
Done Inline Actionsdoxygen = C++, JSdoc = JS. GetElevationDamageBonus would indeed remove the last bit of ambiguity making the comment unneeded. elexis: doxygen = C++, JSdoc = JS.
GetElevationDamageBonus would indeed remove the last bit of… | |||||||||||||||
* Attack the target entity. This should only be called after a successful range check, | * Attack the target entity. This should only be called after a successful range check, | ||||||||||||||
* and should only be called after GetTimers().repeat msec has passed since the last | * and should only be called after GetTimers().repeat msec has passed since the last | ||||||||||||||
* call to PerformAttack. | * call to PerformAttack. | ||||||||||||||
*/ | */ | ||||||||||||||
Done Inline Actions-> Damage component I guess elexis: -> Damage component I guess | |||||||||||||||
Attack.prototype.PerformAttack = function(type, target) | Attack.prototype.PerformAttack = function(type, target) | ||||||||||||||
{ | { | ||||||||||||||
let attackerOwner = Engine.QueryInterface(this.entity, IID_Ownership).GetOwner(); | let cmpPosition = Engine.QueryInterface(this.entity, IID_Position); | ||||||||||||||
if (!cmpPosition || !cmpPosition.IsInWorld()) | |||||||||||||||
return; | |||||||||||||||
let selfPosition = cmpPosition.GetPosition(); | |||||||||||||||
StanUnsubmitted Done Inline ActionsNot sure we need that temp. variable. Stan: Not sure we need that temp. variable. | |||||||||||||||
FreagarachAuthorUnsubmitted Done Inline ActionsIt is needed further up in the code as well :) For the TTT calculation. Freagarach: It is needed further up in the code as well :) For the TTT calculation. | |||||||||||||||
let attackerData = { | |||||||||||||||
"owner": Engine.QueryInterface(this.entity, IID_Ownership).GetOwner(), | |||||||||||||||
"entity": this.entity, | |||||||||||||||
"position": selfPosition, | |||||||||||||||
"elevationBonus": this.GetRange(type).elevationBonus | |||||||||||||||
}; | |||||||||||||||
// If this is a ranged attack, then launch a projectile | // If this is a ranged attack, then launch a projectile | ||||||||||||||
if (type == "Ranged") | if (type == "Ranged") | ||||||||||||||
{ | { | ||||||||||||||
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 | ||||||||||||||
let horizSpeed = +this.template[type].Projectile.Speed; | let horizSpeed = +this.template[type].Projectile.Speed; | ||||||||||||||
let gravity = +this.template[type].Projectile.Gravity; | let gravity = +this.template[type].Projectile.Gravity; | ||||||||||||||
// horizSpeed /= 2; gravity /= 2; // slow it down for testing | // horizSpeed /= 2; gravity /= 2; // slow it down for testing | ||||||||||||||
let cmpPosition = Engine.QueryInterface(this.entity, IID_Position); | |||||||||||||||
if (!cmpPosition || !cmpPosition.IsInWorld()) | |||||||||||||||
return; | |||||||||||||||
let selfPosition = cmpPosition.GetPosition(); | |||||||||||||||
let cmpTargetPosition = Engine.QueryInterface(target, IID_Position); | let cmpTargetPosition = Engine.QueryInterface(target, IID_Position); | ||||||||||||||
if (!cmpTargetPosition || !cmpTargetPosition.IsInWorld()) | if (!cmpTargetPosition || !cmpTargetPosition.IsInWorld()) | ||||||||||||||
return; | return; | ||||||||||||||
let targetPosition = cmpTargetPosition.GetPosition(); | let targetPosition = cmpTargetPosition.GetPosition(); | ||||||||||||||
let previousTargetPosition = Engine.QueryInterface(target, IID_Position).GetPreviousPosition(); | let previousTargetPosition = Engine.QueryInterface(target, IID_Position).GetPreviousPosition(); | ||||||||||||||
let targetVelocity = Vector3D.sub(targetPosition, previousTargetPosition).div(turnLength); | let targetVelocity = Vector3D.sub(targetPosition, previousTargetPosition).div(turnLength); | ||||||||||||||
▲ Show 20 Lines • Show All 50 Lines • ▼ Show 20 Lines | if (type == "Ranged") | ||||||||||||||
let cmpSound = Engine.QueryInterface(this.entity, IID_Sound); | let cmpSound = Engine.QueryInterface(this.entity, IID_Sound); | ||||||||||||||
if (cmpSound) | if (cmpSound) | ||||||||||||||
attackImpactSound = cmpSound.GetSoundGroup("attack_impact_" + type.toLowerCase()); | attackImpactSound = cmpSound.GetSoundGroup("attack_impact_" + type.toLowerCase()); | ||||||||||||||
let data = { | let data = { | ||||||||||||||
"type": type, | "type": type, | ||||||||||||||
"attackData": this.GetAttackEffectsData(type), | "attackData": this.GetAttackEffectsData(type), | ||||||||||||||
"target": target, | "target": target, | ||||||||||||||
"attacker": this.entity, | "attackerData": attackerData, | ||||||||||||||
"attackerOwner": attackerOwner, | |||||||||||||||
"position": realTargetPosition, | "position": realTargetPosition, | ||||||||||||||
"direction": missileDirection, | "direction": missileDirection, | ||||||||||||||
"projectileId": id, | "projectileId": id, | ||||||||||||||
"attackImpactSound": attackImpactSound | "attackImpactSound": attackImpactSound | ||||||||||||||
Done Inline Actionswold be better to only pass atomic values rather than doing any kind of computation (logic) here elexis: wold be better to only pass atomic values rather than doing any kind of computation (logic) here | |||||||||||||||
}; | }; | ||||||||||||||
if (this.template[type].Splash) | if (this.template[type].Splash) | ||||||||||||||
data.splash = { | data.splash = { | ||||||||||||||
"friendlyFire": this.template[type].Splash.FriendlyFire != "false", | "friendlyFire": this.template[type].Splash.FriendlyFire != "false", | ||||||||||||||
"radius": +this.template[type].Splash.Range, | "radius": +this.template[type].Splash.Range, | ||||||||||||||
"shape": this.template[type].Splash.Shape, | "shape": this.template[type].Splash.Shape, | ||||||||||||||
"attackData": this.GetAttackEffectsData(type, true), | "attackData": this.GetAttackEffectsData(type, true), | ||||||||||||||
}; | }; | ||||||||||||||
cmpTimer.SetTimeout(SYSTEM_ENTITY, IID_DelayedDamage, "MissileHit", +this.template[type].Delay + timeToTarget * 1000, data); | cmpTimer.SetTimeout(SYSTEM_ENTITY, IID_DelayedDamage, "MissileHit", +this.template[type].Delay + timeToTarget * 1000, data); | ||||||||||||||
} | } | ||||||||||||||
else | else | ||||||||||||||
Attacking.HandleAttackEffects(type, this.GetAttackEffectsData(type), target, this.entity, attackerOwner); | Attacking.HandleAttackEffects(type, this.GetAttackEffectsData(type), target, attackerData); | ||||||||||||||
}; | }; | ||||||||||||||
/** | /** | ||||||||||||||
* Get the predicted time of collision between a projectile (or a chaser) | * Get the predicted time of collision between a projectile (or a chaser) | ||||||||||||||
* and its target, assuming they both move in straight line at a constant speed. | * and its target, assuming they both move in straight line at a constant speed. | ||||||||||||||
* Vertical component of movement is ignored. | * Vertical component of movement is ignored. | ||||||||||||||
* @param {Vector3D} selfPosition - the 3D position of the projectile (or chaser). | * @param {Vector3D} selfPosition - the 3D position of the projectile (or chaser). | ||||||||||||||
* @param {number} horizSpeed - the horizontal speed of the projectile (or chaser). | * @param {number} horizSpeed - the horizontal speed of the projectile (or chaser). | ||||||||||||||
* @param {Vector3D} targetPosition - the 3D position of the target. | * @param {Vector3D} targetPosition - the 3D position of the target. | ||||||||||||||
* @param {Vector3D} targetVelocity - the 3D velocity vector of the target. | * @param {Vector3D} targetVelocity - the 3D velocity vector of the target. | ||||||||||||||
* @return {Vector3D|boolean} - the 3D predicted position or false if the collision will not happen. | * @return {Vector3D|boolean} - the 3D predicted position or false if the collision will not happen. | ||||||||||||||
*/ | */ | ||||||||||||||
Attack.prototype.PredictTimeToTarget = function(selfPosition, horizSpeed, targetPosition, targetVelocity) | Attack.prototype.PredictTimeToTarget = function(selfPosition, horizSpeed, targetPosition, targetVelocity) | ||||||||||||||
{ | { | ||||||||||||||
let relativePosition = new Vector3D.sub(targetPosition, selfPosition); | let relativePosition = new Vector3D.sub(targetPosition, selfPosition); | ||||||||||||||
let a = targetVelocity.x * targetVelocity.x + targetVelocity.z * targetVelocity.z - horizSpeed * horizSpeed; | let a = targetVelocity.x * targetVelocity.x + targetVelocity.z * targetVelocity.z - horizSpeed * horizSpeed; | ||||||||||||||
let b = relativePosition.x * targetVelocity.x + relativePosition.z * targetVelocity.z; | let b = relativePosition.x * targetVelocity.x + relativePosition.z * targetVelocity.z; | ||||||||||||||
let c = relativePosition.x * relativePosition.x + relativePosition.z * relativePosition.z; | let c = relativePosition.x * relativePosition.x + relativePosition.z * relativePosition.z; | ||||||||||||||
// The predicted time to reach the target is the smallest non negative solution | // The predicted time to reach the target is the smallest non negative solution | ||||||||||||||
// (when it exists) of the equation a t^2 + 2 b t + c = 0. | // (when it exists) of the equation a t^2 + 2 b t + c = 0. | ||||||||||||||
// Using c>=0, we can straightly compute the right solution. | // Using c>=0, we can straightly compute the right solution. | ||||||||||||||
if (c == 0) | if (c == 0) | ||||||||||||||
return 0; | return 0; | ||||||||||||||
let disc = b * b - a * c; | let disc = b * b - a * c; | ||||||||||||||
if (a < 0 || b < 0 && disc >= 0) | if (a < 0 || b < 0 && disc >= 0) | ||||||||||||||
return c / (Math.sqrt(disc) - b); | return c / (Math.sqrt(disc) - b); | ||||||||||||||
return false; | return false; | ||||||||||||||
Done Inline Actions
(or even go the whole way, and: Attacking.HandleAttackEffects(target, { "type": type, "attackData": this.GetAttackEffectsData(type), "attacker": this.entity, "attackerOwner": attackerOwner, "attackerPosition": selfPosition, "attackHeightOffset": this.GetRange(type).elevationBonus }); ) wraitii: (or even go the whole way, and:
```
Attacking.HandleAttackEffects(target, {
"type": type… | |||||||||||||||
}; | }; | ||||||||||||||
Attack.prototype.OnValueModification = function(msg) | Attack.prototype.OnValueModification = function(msg) | ||||||||||||||
{ | { | ||||||||||||||
if (msg.component != "Attack") | if (msg.component != "Attack") | ||||||||||||||
return; | return; | ||||||||||||||
let cmpUnitAI = Engine.QueryInterface(this.entity, IID_UnitAI); | let cmpUnitAI = Engine.QueryInterface(this.entity, IID_UnitAI); | ||||||||||||||
Show All 27 Lines |
Wildfire Games · Phabricator
You should use doxygen style comments. I'm not sure this function even needs a comment as it's self explicit but maybe for parameters.