0ad/binaries/data/mods/public/simulation/helpers/Damage.js
JoshuaJB 10b9ace654 Add missing line.
This was SVN commit r14232.
2013-11-26 20:01:09 +00:00

165 lines
6.2 KiB
JavaScript

// Create global Damage object.
var Damage = {};
/**
* Damages units around a given origin.
* data.attacker = <entity id>
* data.origin = {'x':<int>, 'z':<int>}
* data.radius = <int>
* data.shape = <string>
* data.strengths = {'hack':<float>, 'pierce':<float>, 'crush':<float>}
* data.type = <string>
* ***Optional Variables***
* data.direction = <unit vector>
* data.playersToDamage = <array of player ids>
*/
Damage.CauseSplashDamage = function(data)
{
// Get nearby entities and define variables
var nearEnts = Damage.EntitiesNearPoint(data.origin, data.radius, data.playersToDamage);
var damageMultiplier = 1;
// Cycle through all the nearby entities and damage it appropriately based on its distance from the origin.
for each (var entity in nearEnts)
{
var entityPosition = Engine.QueryInterface(entity, IID_Position).GetPosition();
if(data.shape == 'Circular') // circular effect with quadratic falloff in every direction
{
var squaredDistanceFromOrigin = Damage.VectorDistanceSquared(data.origin, entityPosition);
damageMultiplier == 1 - squaredDistanceFromOrigin / (data.radius * data.radius);
}
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.
var relativePos = {"x":entityPosition.x - data.origin.x, "z":entityPosition.z - data.origin.z};
// The width of linear splash is one fifth of the normal splash radius.
var width = data.radius/5;
// Effectivly rotate the axis to align with the missile direction.
var parallelDist = Damage.VectorDot(relativePos, data.direction); // z axis
var perpDist = Math.abs(Damage.VectorCross(relativePos, data.direction)); // y axis
// Check that the unit is within the distance at which it will get damaged.
if (parallelDist > -width && perpDist < width) // If in radius, quadratic falloff in both directions
damageMultiplier = (data.radius * data.radius - parallelDist * parallelDist) / (data.radius * data.radius)
* (width * width - perpDist * perpDist) / (width * width);
else
damageMultiplier = 0;
}
else // In case someone calls this function with an invalid shape.
{
warn("The " + data.shape + " splash damage shape is not implemented!");
}
// Call CauseDamage which reduces the hitpoints, posts network command, plays sounds....
Damage.CauseDamage({"strengths":data.strengths, "target":entity, "attacker":data.attacker, "multiplier":damageMultiplier, "type":data.type + ".Splash"})
}
};
/**
* Causes damage on a given unit
* data.strengths = {'hack':<float>, 'pierce':<float>, 'crush':<float>}
* data.target = <entity id>
* data.attacker = <entity id>
* data.multiplier = <float between 1 and 0>
* data.type = <string>
*/
Damage.CauseDamage = function(data)
{
// Check the target can be damaged otherwise don't do anything.
var cmpDamageReceiver = Engine.QueryInterface(data.target, IID_DamageReceiver);
if (!cmpDamageReceiver)
return;
// Damage the target
var targetState = cmpDamageReceiver.TakeDamage(data.strengths.hack * data.multiplier, data.strengths.pierce * data.multiplier, data.strengths.crush * data.multiplier, data.attacker);
// If the target was killed run some cleanup
if (targetState.killed)
Damage.TargetKilled(data.attacker, data.target);
// Post the network command (make it work in multiplayer)
Engine.PostMessage(data.target, MT_Attacked, {"attacker":data.attacker, "target":data.target, "type":data.type, "damage":-targetState.change});
// Play attacking sounds
PlaySound("attack_impact", data.attacker);
};
/**
* Gets entities near a give point for given players.
* origin = {'x':<int>, 'z':<int>}
* radius = <int>
* players = <array>
* If players is not included, entities from all players are used.
*/
Damage.EntitiesNearPoint = function(origin, radius, players)
{
// If there is insufficient data return an empty array.
if (!origin || !radius)
return [];
// Create the dummy entity used for range calculations if it doesn't exist.
if (!Damage.dummyTargetEntity)
Damage.dummyTargetEntity = Engine.AddEntity('special/dummy');
// Move the dummy entity to the origin of the query.
var cmpDummyPosition = Engine.QueryInterface(Damage.dummyTargetEntity, IID_Position);
if (!cmpDummyPosition)
return [];
cmpDummyPosition.JumpTo(origin.x, origin.z);
// If the players parameter is not specified use all players.
if (!players)
{
var playerEntities = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager).GetAllPlayerEntities();
players = [];
for (var entity in playerEntities)
players.append(Engine.QueryInterface(entity, IID_Player).GetPlayerID());
}
// Call RangeManager with dummy entity and return the result.
var rangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
var rangeQuery = rangeManager.ExecuteQuery(Damage.dummyTargetEntity, 0, radius, players, IID_DamageReceiver);
return rangeQuery;
};
/**
* Called when some units kills something (another unit, building, animal etc)
* killerEntity = <entity id>
* targetEntity = <entity id>
*/
Damage.TargetKilled = function(killerEntity, targetEntity)
{
// Add to killer statistics.
var cmpKillerPlayerStatisticsTracker = QueryOwnerInterface(killerEntity, IID_StatisticsTracker);
if (cmpKillerPlayerStatisticsTracker)
cmpKillerPlayerStatisticsTracker.KilledEntity(targetEntity);
// Add to loser statistics.
var cmpTargetPlayerStatisticsTracker = QueryOwnerInterface(targetEntity, IID_StatisticsTracker);
if (cmpTargetPlayerStatisticsTracker)
cmpTargetPlayerStatisticsTracker.LostEntity(targetEntity);
// If killer can collect loot, let's try to collect it.
var cmpLooter = Engine.QueryInterface(killerEntity, IID_Looter);
if (cmpLooter)
cmpLooter.Collect(targetEntity);
};
// Gets the straight line distance between p1 and p2
Damage.VectorDistanceSquared = function(p1, p2)
{
return (p1.x - p2.x) * (p1.x - p2.x) + (p1.z - p2.z) * (p1.z - p2.z);
};
// Gets the dot product of two vectors.
Damage.VectorDot = function(p1, p2)
{
return p1.x * p2.x + p1.z * p2.z;
};
// Gets the 2D interpreted version of the cross product of two vectors.
Damage.VectorCross = function(p1, p2)
{
return p1.x * p2.z - p1.z * p2.x;
};
Engine.RegisterGlobal("Damage", Damage);