1 | function Damage() {}
|
---|
2 |
|
---|
3 | Damage.prototype.Schema = "<a:component type='system'/><empty/>";
|
---|
4 |
|
---|
5 | Damage.prototype.Init = function()
|
---|
6 | {
|
---|
7 | // Create dummy entity for EntitiesNearPoint
|
---|
8 | this.dummyTargetEntity = Engine.AddEntity('special/dummy');
|
---|
9 | }
|
---|
10 |
|
---|
11 | /****************************************
|
---|
12 | * Damages units around a given origin.
|
---|
13 | * data.attacker = <entity id>
|
---|
14 | * data.origin = {'x':<int>, 'z':<int>}
|
---|
15 | * data.radius = <int>
|
---|
16 | * data.shape = <string>
|
---|
17 | * data.strengths = {'hack':<float>, 'pierce':<float>, 'crush':<float>}
|
---|
18 | * ***Optional Variables***
|
---|
19 | * data.direction = <unit vector>
|
---|
20 | * data.playersToDamage = <array of player ids>
|
---|
21 | */
|
---|
22 | Damage.prototype.CauseSplashDamage = function(data)
|
---|
23 | {
|
---|
24 | // Get nearby entities and define variables
|
---|
25 | var nearEnts = this.EntitiesNearPoint(data.origin, data.radius, data.playersToDamage);
|
---|
26 | var damageMultiplier = 1;
|
---|
27 | // Cycle through all the nearby entities and damage it appropriately based on its distance from the origin.
|
---|
28 | for each (var entity in nearEnts)
|
---|
29 | {
|
---|
30 | var entityPosition = Engine.QueryInterface(entity, IID_Position).GetPosition();
|
---|
31 | if(data.shape=='circular') // circular effect with quadratic falloff in every direction
|
---|
32 | {
|
---|
33 | var squaredDistanceFromOrigin = this.VectorDistanceSquared(data.origin, entityPosition);
|
---|
34 | damageMultiplier == 1 - ((squaredDistanceFromOrigin) / (data.radius * data.radius));
|
---|
35 | }
|
---|
36 | else if(data.shape=='linear') // linear effect with quadratic falloff in two directions (only used for certain missiles)
|
---|
37 | {
|
---|
38 | // Get position of entity relative to splash origin.
|
---|
39 | var relativePos = {"x": entityPosition.x - data.origin.x, "z": entityPosition.z - data.origin.z};
|
---|
40 |
|
---|
41 | // The width of linear splash is one fifth of the normal splash radius.
|
---|
42 | var width = data.radius/5;
|
---|
43 |
|
---|
44 | // Effectivly rotate the axis to align with the missile direction.
|
---|
45 | var parallelDist = this.VectorDot(relativePos, data.direction);//x axis
|
---|
46 | var perpDist = Math.abs(this.VectorCross(relativePos, data.direction));//y axis
|
---|
47 |
|
---|
48 | // Check that the unit is within the distance at which it will get damaged.
|
---|
49 | if (parallelDist > -width && perpDist < width) // If in radius, quadratic falloff in both directions
|
---|
50 | multiplier = (data.radius*data.radius - parallelDist*parallelDist) / (data.radius*data.radius)
|
---|
51 | * (width*width - perpDist*perpDist) / (width*width);
|
---|
52 | else
|
---|
53 | multiplier = 0;
|
---|
54 | }
|
---|
55 | else // In case someone calls this function with an invalid shape.
|
---|
56 | {
|
---|
57 | warn("The "+data.shape+" splash damage shape is not implemented!");
|
---|
58 | }
|
---|
59 | // Call CauseDamage which reduces the hitpoints, posts network command, plays sounds....
|
---|
60 | this.CauseDamage({"strengths":data.strengths, "target":entity, "attacker":data.attacker, "multiplier":damageMultiplier, "type":"Splash"})
|
---|
61 | }
|
---|
62 | };
|
---|
63 |
|
---|
64 | /****************************************
|
---|
65 | * Causes damage on a given unit
|
---|
66 | * data.strengths = {'hack':<float>, 'pierce':<float>, 'crush':<float>}
|
---|
67 | * data.target = <entity id>
|
---|
68 | * data.attacker = <entity id>
|
---|
69 | * data.multiplier = <float between 1 and 0>
|
---|
70 | * data.type = <string>
|
---|
71 | */
|
---|
72 | Damage.prototype.CauseDamage = function(data)
|
---|
73 | {
|
---|
74 | // Check the target can be damaged otherwise don't do anything.
|
---|
75 | var cmpDamageReceiver = Engine.QueryInterface(data.target, IID_DamageReceiver);
|
---|
76 | if (!cmpDamageReceiver)
|
---|
77 | return;
|
---|
78 |
|
---|
79 | // Damage the target
|
---|
80 | var targetState = cmpDamageReceiver.TakeDamage(data.strengths.hack * data.multiplier, data.strengths.pierce * data.multiplier, data.strengths.crush * data.multiplier);
|
---|
81 |
|
---|
82 | // If the target was killed run some cleanup
|
---|
83 | if (targetState.killed == true)
|
---|
84 | this.TargetKilled(data.attacker, data.target);
|
---|
85 |
|
---|
86 | // Post the network command (make it work in multiplayer)
|
---|
87 | Engine.PostMessage(data.target, MT_Attacked,{ "attacker": data.attacker, "target": data.target, "type": data.type, "damage": -targetState.change });
|
---|
88 |
|
---|
89 | // Play attacking sounds
|
---|
90 | PlaySound("attack_impact", data.attacker);
|
---|
91 | };
|
---|
92 |
|
---|
93 | /****************************************
|
---|
94 | * Gets entities near a give point for given players.
|
---|
95 | * origin = {'x':<int>, 'z':<int>}
|
---|
96 | * radius = <int>
|
---|
97 | * players = <array>
|
---|
98 | * If players is not included, entities from all players are used.
|
---|
99 | */
|
---|
100 | Damage.prototype.EntitiesNearPoint = function(origin, radius, players)
|
---|
101 | {
|
---|
102 | // If there is insufficient data return an empty array.
|
---|
103 | if(!origin || !radius)
|
---|
104 | return [];
|
---|
105 |
|
---|
106 | // Move the dummy entity to the origin of the query.
|
---|
107 | var cmpDummyPosition = Engine.QueryInterface(this.dummyTargetEntity, IID_Position);
|
---|
108 | cmpDummyPosition.JumpTo(origin.x, origin.z);
|
---|
109 |
|
---|
110 | // If the players parameter is not specified use all players.
|
---|
111 | if(!players)
|
---|
112 | players = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager).GetAllPlayers();
|
---|
113 |
|
---|
114 | // Call RangeManager with dummy entity and return the result.
|
---|
115 | var rangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
|
---|
116 | var rangeQuery = rangeManager.ExecuteQuery(this.dummyTargetEntity, 0, radius, players, IID_DamageReceiver);
|
---|
117 | return rangeQuery;
|
---|
118 | };
|
---|
119 |
|
---|
120 | /****************************************
|
---|
121 | * Called when some units kills something (another unit, building, animal etc)
|
---|
122 | * killerEntity = <entity id>
|
---|
123 | * targetEntity = <entity id>
|
---|
124 | */
|
---|
125 | Damage.prototype.TargetKilled = function(killerEntity, targetEntity)
|
---|
126 | {
|
---|
127 | // Add to killer statistics.
|
---|
128 | var cmpKillerPlayerStatisticsTracker = QueryOwnerInterface(killerEntity, IID_StatisticsTracker);
|
---|
129 | if (cmpKillerPlayerStatisticsTracker)
|
---|
130 | cmpKillerPlayerStatisticsTracker.KilledEntity(targetEntity);
|
---|
131 | // Add to loser statistics.
|
---|
132 | var cmpTargetPlayerStatisticsTracker = QueryOwnerInterface(targetEntity, IID_StatisticsTracker);
|
---|
133 | if (cmpTargetPlayerStatisticsTracker)
|
---|
134 | cmpTargetPlayerStatisticsTracker.LostEntity(targetEntity);
|
---|
135 |
|
---|
136 | // If killer can collect loot, lets try to collect it.
|
---|
137 | var cmpLooter = Engine.QueryInterface(killerEntity, IID_Looter);
|
---|
138 | if (cmpLooter)
|
---|
139 | cmpLooter.Collect(targetEntity);
|
---|
140 | };
|
---|
141 |
|
---|
142 | // Gets the straight line distance between p1 and p2
|
---|
143 | Damage.prototype.VectorDistanceSquared = function(p1, p2)
|
---|
144 | {
|
---|
145 | return ((p1.x - p2.x)*(p1.x - p2.x) + (p1.z - p2.z)*(p1.z - p2.z));
|
---|
146 | };
|
---|
147 |
|
---|
148 | // Gets the dot product of two vectors.
|
---|
149 | Damage.prototype.VectorDot = function(p1, p2)
|
---|
150 | {
|
---|
151 | return (p1.x * p2.x + p1.z * p2.z);
|
---|
152 | };
|
---|
153 |
|
---|
154 | // Gets the 2D interpreted version of the cross product of two vectors.
|
---|
155 | Damage.prototype.VectorCross = function(p1, p2)
|
---|
156 | {
|
---|
157 | return (p1.x * p2.z - p1.z * p2.x);
|
---|
158 | };
|
---|
159 |
|
---|
160 | Engine.RegisterComponentType(IID_Damage, "Damage", Damage);
|
---|