]> icculus.org git repositories - divverent/nexuiz.git/blob - data/qcsrc/gamec/g_damage.c
no damage when gameover (thanks KadaverJack)
[divverent/nexuiz.git] / data / qcsrc / gamec / g_damage.c
1
2 float checkrules_firstblood;
3
4 void GiveFrags (entity attacker, entity targ, float f)
5 {
6         if(f > 0 && cvar("g_domination") && cvar("g_domination_disable_frags"))
7                 return;
8         else if(f > 0 && cvar("g_runematch"))
9                 f = RunematchHandleFrags(attacker, targ, f);
10
11         if(f)
12                 attacker.frags = attacker.frags + f;
13 }
14
15 void Obituary (entity attacker, entity targ, float deathtype)
16 {
17         string  s;
18
19         if (targ.classname == "player" || targ.classname == "corpse")
20         {
21                 if (targ.classname == "corpse")
22                         s = "A corpse";
23                 else
24                         s = targ.netname;
25
26                 if (targ == attacker)
27                 {
28                         if (deathtype == IT_GRENADE_LAUNCHER)
29                                 bprint ("^1",s, " detonated\n");
30                         else if (deathtype == IT_ELECTRO)
31                                 bprint ("^1",s, " played with plasma\n");
32                         else if (deathtype == IT_ROCKET_LAUNCHER)
33                                 bprint ("^1",s, " exploded\n");
34                         else if (deathtype == DEATH_KILL)
35                                 bprint ("^1",s, " couldn't take it anymore\n");
36                         else
37                                 bprint ("^1",s, " couldn't resist the urge to self-destruct\n");
38                         GiveFrags(attacker, targ, -1);
39                         //targ.frags = targ.frags - 1;
40                         if (targ.killcount > 2)
41                                 bprint ("^1",s," ended it all with a ",ftos(targ.killcount)," kill spree\n");
42                 }
43                 else if (teamplay && attacker.team == targ.team)
44                 {
45                         bprint ("^1", attacker.netname, " mows down a teammate\n");
46                         GiveFrags(attacker, targ, -1);
47                         //attacker.frags = attacker.frags - 1;
48                         if (targ.killcount > 2)
49                                 bprint ("^1",s,"'s ",ftos(targ.killcount)," kill spree was endeded by a teammate!\n");
50                         if (attacker.killcount > 2)
51                                 bprint ("^1",attacker.netname," ended a ",ftos(attacker.killcount)," kill spree by killing a teammate\n");
52                         attacker.killcount = 0;
53                 }
54                 else if (attacker.classname == "player" || attacker.classname == "gib")
55                 {
56                         if (!checkrules_firstblood)
57                         {
58                                 checkrules_firstblood = TRUE;
59                                 //sound(world, CHAN_AUTO, "announcer/firstblood.wav", 1, ATTN_NONE);
60                                 bprint("^1",attacker.netname, " drew first blood", "\n");
61                         }
62
63                         if (deathtype == IT_LASER)
64                                 bprint ("^1",s, " was blasted by ", attacker.netname, "\n");
65                         else if (deathtype == IT_UZI)
66                                 bprint ("^1",s, " was riddled full of holes by ", attacker.netname, "\n");
67                         else if (deathtype == IT_SHOTGUN)
68                                 bprint ("^1",s, " was gunned by ", attacker.netname, "\n");
69                         else if (deathtype == IT_GRENADE_LAUNCHER)
70                                 bprint ("^1", s, " was blasted by ", attacker.netname, "\n");
71                         else if (deathtype == IT_ELECTRO)
72                                 bprint ("^1",s, " was blasted by ", attacker.netname, "\n");
73                         else if (deathtype == IT_CRYLINK)
74                                 bprint ("^1",s, " was blasted by ", attacker.netname, "\n");
75                         else if (deathtype == IT_NEX)
76                                 bprint ("^1",s, " has been vaporized by ", attacker.netname, "\n");
77                         else if (deathtype == IT_HAGAR)
78                                 bprint ("^1",s, " was pummeled by ", attacker.netname, "\n");
79                         else if (deathtype == IT_ROCKET_LAUNCHER)
80                                 bprint ("^1",s, " was blasted by ", attacker.netname, "\n");
81                         else if (deathtype == DEATH_TELEFRAG)
82                                 bprint ("^1",s, " was telefragged by ", attacker.netname, "\n");
83                         else if (deathtype == DEATH_DROWN)
84                                 bprint ("^1",s, " was drowned by ", attacker.netname, "\n");
85                         else if (deathtype == DEATH_SLIME)
86                                 bprint ("^1",s, " was slimed by ", attacker.netname, "\n");
87                         else if (deathtype == DEATH_LAVA)
88                                 bprint ("^1",s, " was cooked by ", attacker.netname, "\n");
89                         else if (deathtype == DEATH_FALL)
90                                 bprint ("^1",s, " was grounded by ", attacker.netname, "\n");
91                         else if (deathtype == DEATH_HURTTRIGGER)
92                                 bprint ("^1",s, " was thrown into a world of hurt by ", attacker.netname, "\n");
93                         else
94                                 bprint ("^1",s, " was killed by ", attacker.netname, "\n");
95
96                         GiveFrags(attacker, targ, 1);
97                         //attacker.frags = attacker.frags + 1;
98                         if (targ.killcount > 2)
99                                 bprint ("^1",s,"'s ", ftos(targ.killcount), " kill spree was ended by ", attacker.netname, "\n");
100                         attacker.killcount = attacker.killcount + 1;
101                         if (attacker.killcount > 2)
102                                 bprint ("^1",attacker.netname," has ",ftos(attacker.killcount)," kills in a row\n");
103                 }
104                 else
105                 {
106                         if (deathtype == DEATH_HURTTRIGGER && attacker.message != "")
107                                 bprint ("^1",s, " ", attacker.message, "\n");
108                         else if (deathtype == DEATH_DROWN)
109                                 bprint ("^1",s, " drowned\n");
110                         else if (deathtype == DEATH_SLIME)
111                                 bprint ("^1",s, " was slimed\n");
112                         else if (deathtype == DEATH_LAVA)
113                                 bprint ("^1",s, " turned into hot slag\n");
114                         else if (deathtype == DEATH_FALL)
115                                 bprint ("^1",s, " hit the ground with a crunch\n");
116                         else
117                                 bprint ("^1",s, " died\n");
118                         GiveFrags(targ, targ, -1);
119                         //targ.frags = targ.frags - 1;
120                         if (targ.killcount > 2)
121                                 bprint ("^1",s," died with a ",ftos(targ.killcount)," kill spree\n");
122                 }
123                 // FIXME: this should go in PutClientInServer
124                 if (targ.killcount)
125                         targ.killcount = 0;
126         }
127 }
128
129 // these are updated by each Damage call for use in button triggering and such
130 entity damage_targ;
131 entity damage_inflictor;
132 entity damage_attacker;
133
134 void Damage (entity targ, entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
135 {
136         if (gameover)
137                 return;
138
139         local entity oldself;
140         oldself = self;
141         self = targ;
142         damage_targ = targ;
143         damage_inflictor = inflictor;
144         damage_attacker = attacker;     
145         // nullify damage if teamplay is on
146         if (teamplay)
147         if (attacker.team)
148         if (attacker.team == targ.team)
149         if (teamplay == 1 || (teamplay == 3 && attacker != targ))
150                 damage = 0;
151
152         // midair gamemode: damage only while in the air
153         if (cvar("g_midair")
154             && self.classname == "player" // e.g. grenades take damage
155             && self.flags & FL_ONGROUND) {
156                 damage = 0;
157         }
158
159         // apply strength multiplier
160         if (attacker.items & IT_STRENGTH)
161         {
162                 damage = damage * cvar("g_balance_powerup_strength_damage");
163                 force = force * cvar("g_balance_powerup_strength_force");
164         }
165         // apply invincibility multiplier
166         if (targ.items & IT_INVINCIBLE)
167                 damage = damage * cvar("g_balance_powerup_invincible_takedamage");
168
169
170         if(cvar("g_runematch"))
171         {
172                 // apply strength rune
173                 if (attacker.runes & RUNE_STRENGTH)
174                 {
175                         if(attacker.runes & CURSE_WEAK) // have both curse & rune
176                         {
177                                 damage = damage * cvar("g_balance_rune_strength_combo_damage");
178                                 force = force * cvar("g_balance_rune_strength_combo_force");
179                         }
180                         else
181                         {
182                                 damage = damage * cvar("g_balance_rune_strength_damage");
183                                 force = force * cvar("g_balance_rune_strength_force");
184                         }
185                 }
186                 else if (attacker.runes & CURSE_WEAK)
187                 {
188                         damage = damage * cvar("g_balance_curse_weak_damage");
189                         force = force * cvar("g_balance_curse_weak_force");
190                 }
191
192                 // apply defense rune
193                 if (targ.runes & RUNE_DEFENSE)
194                 {
195                         if (targ.runes & CURSE_VULNER) // have both curse & rune
196                                 damage = damage * cvar("g_balance_rune_defense_combo_takedamage");
197                         else
198                                 damage = damage * cvar("g_balance_rune_defense_takedamage");
199                 }
200                 else if (targ.runes & CURSE_VULNER)
201                         damage = damage * cvar("g_balance_curse_vulner_takedamage");
202         }
203
204         // apply push
205         if (self.damageforcescale)
206         {
207                 self.velocity = self.velocity + self.damageforcescale * force;
208                 self.flags = self.flags - (self.flags & FL_ONGROUND);
209         }
210         // apply damage
211         if (self.event_damage)
212                 self.event_damage (inflictor, attacker, damage, deathtype, hitloc, force);
213         self = oldself;
214
215         if(targ.classname == "player" && attacker.classname == "player" && attacker != targ && attacker.health > 2)
216         {
217                 // Savage: vampire mode
218                 if(cvar("g_vampire"))
219                 {
220                         attacker.health += damage;
221                 }
222                 if(cvar("g_runematch"))
223                 {
224                         if (attacker.runes & RUNE_VAMPIRE)
225                         {
226                         // apply vampire rune
227                                 if (attacker.runes & CURSE_EMPATHY) // have the curse too
228                                 {
229                                         //attacker.health = attacker.health + damage * cvar("g_balance_rune_vampire_combo_absorb");
230                                         attacker.health = bound(
231                                                 3, 
232                                                 attacker.health + damage * cvar("g_balance_rune_vampire_combo_absorb"), 
233                                                 1000);
234                                 }
235                                 else
236                                 {
237                                         //attacker.health = attacker.health + damage * cvar("g_balance_rune_vampire_absorb");
238                                         attacker.health = bound(
239                                                 3, 
240                                                 attacker.health + damage * cvar("g_balance_rune_vampire_absorb"), 
241                                                 1000);
242                                 }
243                         }
244                         // apply empathy curse
245                         else if (attacker.runes & CURSE_EMPATHY)
246                         {
247                                 attacker.health = bound(
248                                         3, 
249                                         attacker.health + damage * cvar("g_balance_curse_empathy_takedamage"), 
250                                         attacker.health);
251                         }
252                 }
253         }
254 }
255
256 void RadiusDamage (entity inflictor, entity attacker, float coredamage, float edgedamage, float rad, entity ignore, float forceintensity, float deathtype)
257 {
258         entity  targ;
259         float   finaldmg;
260         float   power;
261         vector  blastorigin;
262         vector  force;
263         vector  m1;
264         vector  m2;
265         vector  nearest;
266         vector  diff;
267
268         blastorigin = (inflictor.origin + (inflictor.mins + inflictor.maxs) * 0.5);
269
270         targ = findradius (blastorigin, rad);
271         while (targ)
272         {
273                 if (targ != inflictor)
274                         if (ignore != targ)
275                         {
276                                 // LordHavoc: measure distance to nearest point on target (not origin)
277                                 // (this guarentees 100% damage on a touch impact)
278                                 nearest = blastorigin;
279                                 m1 = targ.origin + targ.mins;
280                                 m2 = targ.origin + targ.maxs;
281                                 if (nearest_x < m1_x) nearest_x = m1_x;
282                                 if (nearest_y < m1_y) nearest_y = m1_y;
283                                 if (nearest_z < m1_z) nearest_z = m1_z;
284                                 if (nearest_x > m2_x) nearest_x = m2_x;
285                                 if (nearest_y > m2_y) nearest_y = m2_y;
286                                 if (nearest_z > m2_z) nearest_z = m2_z;
287                                 diff = nearest - blastorigin;
288                                 // round up a little on the damage to ensure full damage on impacts
289                                 // and turn the distance into a fraction of the radius
290                                 power = 1 - ((vlen (diff) - 2) / rad);
291                                 //bprint(" ");
292                                 //bprint(ftos(power));
293                                 if (power > 0)
294                                 {
295                                         if (power > 1)
296                                                 power = 1;
297                                         finaldmg = coredamage * power + edgedamage * (1 - power);
298                                         if (finaldmg > 0)
299                                         {
300                                                 force = normalize((m1 + m2) * 0.5 - blastorigin) * (finaldmg / coredamage) * forceintensity;
301                                                 if (targ == attacker)
302                                                         finaldmg = finaldmg * cvar("g_balance_selfdamagepercent");      // Partial damage if the attacker hits himself
303                                                 Damage (targ, inflictor, attacker, finaldmg, deathtype, inflictor.origin, force);
304                                         }
305                                 }
306                         }
307                 targ = targ.chain;
308         }
309 }
310
311 /*
312 entity  multi_ent;
313 float   multi_damage;
314 vector  multi_force;
315
316 void ClearMultiDamage (void)
317 {
318         multi_ent = world;
319         multi_damage = 0;
320         multi_force = '0 0 0';
321 }
322
323 void ApplyMultiDamage (void)
324 {
325         if (!multi_ent)
326                 return;
327
328         Damage (self, multi_ent.origin, multi_ent, 0, multi_damage, multi_force);
329 }
330
331 void AddMultiDamage (entity hit, float damage, vector force)
332 {
333         if (!hit)
334                 return;
335
336         if (hit != multi_ent)
337         {
338                 ApplyMultiDamage ();
339                 ClearMultiDamage ();
340                 multi_ent = hit;
341         }
342         multi_damage = multi_damage + damage;
343         multi_force = multi_force + force;
344 }
345
346 void FireBullets (float shotcount, vector dir, vector spread, float deathtype)
347 {
348         vector  direction;
349         vector  source;
350         vector  vel;
351         vector  org;
352
353         makevectors (self.v_angle);
354
355         source = self.origin + v_forward * 10;  // FIXME
356         source_x = self.absmin_z + self.size_z * 0.7;   // ??? whaddabout view_ofs
357
358         // LordHavoc: better to use normal damage
359         //ClearMultiDamage ();
360         while (shotcount > 0)
361         {
362                 direction = dir + crandom () * spread_x * v_right + crandom () * spread_y * v_up;
363
364                 traceline (source, source + direction * 2048, FALSE, self);
365                 if (trace_fraction != 1.0)
366                 {
367                         vel = normalize (direction + v_up * crandom () + v_right * crandom ());
368                         vel = vel + 2 * trace_plane_normal;
369                         vel = vel * 200;
370
371                         org = trace_endpos - direction * 4;
372
373                         if (!trace_ent.takedamage)
374                                 te_gunshot (org);
375                         // LordHavoc: better to use normal damage
376                         //AddMultiDamage (trace_ent, 4, direction * 4);
377                         Damage (trace_ent, self, self, 4, deathtype, trace_endpos, direction * 4);
378                 }
379
380                 shotcount = shotcount + 1;
381         }
382
383         // LordHavoc: better to use normal damage
384         //ApplyMultiDamage ();
385 }
386 */