]> icculus.org git repositories - divverent/nexuiz.git/blob - qcsrc/weapons.qc
secondary rocket fire, faster movement, higher jumping, and new animations
[divverent/nexuiz.git] / qcsrc / weapons.qc
1 // increments sprite frame, loops when end is hit.. simple
2 void animate_sprite (float startframe, float frame_count)
3 {
4         if ((self.frame - startframe) >= (frame_count - 1 ))
5                 self.frame = startframe;
6         else
7                 self.frame = self.frame + 1;
8 }
9
10 void W_UpdateAmmo (void)
11 {
12         self.items = self.items - (self.items & (IT_NAILS | IT_SHELLS | IT_ROCKETS | IT_CELLS));
13
14         if (self.weapon == IT_LASER)
15                 self.currentammo = 1;
16         else if (self.weapon == IT_UZI)
17         {
18                 self.currentammo = self.ammo_nails;
19                 self.items = self.items | IT_NAILS;
20         }
21         else if (self.weapon == IT_SHOTGUN)
22         {
23                 self.currentammo = self.ammo_shells;
24                 self.items = self.items | IT_SHELLS;
25         }
26         else if (self.weapon == IT_GRENADE_LAUNCHER || self.weapon == IT_HAGAR || self.weapon == IT_ROCKET_LAUNCHER)
27         {
28                 self.currentammo = self.ammo_rockets;
29                 self.items = self.items | IT_ROCKETS;
30         }
31         else if (self.weapon == IT_ELECTRO || self.weapon == IT_NEX || self.weapon == IT_CRYLINK)
32         {
33                 self.currentammo = self.ammo_cells;
34                 self.items = self.items | IT_CELLS;
35         }
36 }
37
38 void W_UpdateWeapon (void)
39 {
40         if (self.weapon == IT_LASER)
41                 self.weaponmodel = "models/weapons/w_laser.md3";
42         else if (self.weapon == IT_UZI)
43                 self.weaponmodel = "models/weapons/w_uzi.md3";
44         else if (self.weapon == IT_SHOTGUN)
45                 self.weaponmodel = "models/weapons/w_shotgun.md3";
46         else if (self.weapon == IT_GRENADE_LAUNCHER)
47                 self.weaponmodel = "models/weapons/w_gl.md3";
48         else if (self.weapon == IT_ELECTRO)
49                 self.weaponmodel = "models/weapons/w_electro.md3";
50         else if (self.weapon == IT_CRYLINK)
51                 self.weaponmodel = "models/weapons/w_crylink.md3";
52         else if (self.weapon == IT_NEX)
53                 self.weaponmodel = "models/weapons/w_nex.md3";
54         else if (self.weapon == IT_HAGAR)
55                 self.weaponmodel = "models/weapons/w_hagar.md3";
56         else if (self.weapon == IT_ROCKET_LAUNCHER)
57                 self.weaponmodel = "models/weapons/w_rl.md3";
58         else
59                 objerror ("Illegal weapon - please register your guns please!");
60 }
61
62 float W_GetBestWeapon (void)
63 {
64         if ((self.items & IT_ROCKET_LAUNCHER) && self.ammo_rockets)
65                 return IT_ROCKET_LAUNCHER;
66         else if ((self.items & IT_HAGAR) && self.ammo_rockets)
67                 return IT_HAGAR;
68         else if ((self.items & IT_NEX) && self.ammo_cells)
69                 return IT_NEX;
70         else if ((self.items & IT_CRYLINK) && self.ammo_cells)
71                 return IT_CRYLINK;
72         else if ((self.items & IT_ELECTRO) && self.ammo_cells)
73                 return IT_ELECTRO;
74         else if ((self.items & IT_GRENADE_LAUNCHER) && self.ammo_rockets)
75                 return IT_GRENADE_LAUNCHER;
76         else if ((self.items & IT_SHOTGUN) && self.ammo_shells)
77                 return IT_SHOTGUN;
78         else if ((self.items & IT_UZI) && self.ammo_nails)
79                 return IT_UZI;
80         else
81                 return IT_LASER;
82 }
83
84 void W_GiveWeapon (entity e, float wep) // FIXME - make it 'smarter'
85 {
86         entity oldself;
87
88         if (!wep)
89                 return;
90
91         if (!(e.items & wep))
92         {
93                 e.items = e.items | wep;
94                 e.weapon = wep;
95         }
96
97         oldself = self;
98         self = e;
99
100         W_UpdateWeapon ();
101         W_UpdateAmmo ();
102
103         self = oldself;
104 }
105
106 void W_SwitchWeapon (float wep)
107 {
108         float           nextwep;
109         var float       noammo = FALSE;
110
111         if (wep == 1)
112                 nextwep = IT_LASER;
113         else if (wep == 2)
114         {
115                 nextwep = IT_UZI;
116                 if (!self.ammo_nails)
117                         noammo = TRUE;
118         }
119         else if (wep == 3)
120         {
121                 nextwep = IT_SHOTGUN;
122                 if (!self.ammo_shells)
123                         noammo = TRUE;
124         }
125         else if (wep == 4)
126         {
127                 nextwep = IT_GRENADE_LAUNCHER;
128                 if (!self.ammo_rockets)
129                         noammo = TRUE;
130         }
131         else if (wep == 5)
132         {
133                 nextwep = IT_ELECTRO;
134                 if (!self.ammo_cells)
135                         noammo = TRUE;
136         }
137         else if (wep == 6)
138         {
139                 nextwep = IT_CRYLINK;
140                 if (!self.ammo_cells)
141                         noammo = TRUE;
142         }
143         else if (wep == 7)
144         {
145                 nextwep = IT_NEX;
146                 if (!self.ammo_cells)
147                         noammo = TRUE;
148         }
149         else if (wep == 8)
150         {
151                 nextwep = IT_HAGAR;
152                 if (!self.ammo_rockets)
153                         noammo = TRUE;
154         }
155         else if (wep == 9)
156         {
157                 nextwep = IT_ROCKET_LAUNCHER;
158                 if (!self.ammo_rockets)
159                         noammo = TRUE;
160         }
161
162
163         if (!(self.items & nextwep))
164         {
165                 sprint (self, "You don't own that weapon\n");
166                 return;
167         }
168         else if (noammo)
169         {
170                 sprint (self, "You don't have any ammo for that weapon\n");
171                 return;
172         }
173
174         self.weapon = nextwep;
175         W_UpdateWeapon ();
176         W_UpdateAmmo ();
177         self.attack_finished = time + 0.2;
178         if (self.viewzoom != 1)
179                 self.viewzoom = 1;
180 }
181
182 void W_NextWeapon (void)
183 {
184         float   noammo;
185
186         while (TRUE)
187         {
188                 noammo = FALSE;
189
190                 if (self.weapon == IT_ROCKET_LAUNCHER)
191                         self.weapon = IT_LASER;
192                 else if (self.weapon == IT_LASER)
193                 {
194                         self.weapon = IT_UZI;
195                         if (!self.ammo_nails)
196                                 noammo = TRUE;
197                 }
198                 else if (self.weapon == IT_UZI)
199                 {
200                         self.weapon = IT_SHOTGUN;
201                         if (!self.ammo_shells)
202                                 noammo = TRUE;
203                 }
204                 else if (self.weapon == IT_SHOTGUN)
205                 {
206                         self.weapon = IT_GRENADE_LAUNCHER;
207                         if (!self.ammo_rockets)
208                                 noammo = TRUE;
209                 }
210                 else if (self.weapon == IT_GRENADE_LAUNCHER)
211                 {
212                         self.weapon = IT_ELECTRO;
213                         if (!self.ammo_cells)
214                                 noammo = TRUE;
215                 }
216                 else if (self.weapon == IT_ELECTRO)
217                 {
218                         self.weapon = IT_CRYLINK;
219                         if (!self.ammo_cells)
220                         noammo = TRUE;
221                 }
222                 else if (self.weapon == IT_CRYLINK)
223                 {
224                         self.weapon = IT_NEX;
225                         if (!self.ammo_cells)
226                         noammo = TRUE;
227                 }
228                 else if (self.weapon == IT_NEX)
229                 {
230                         self.weapon = IT_HAGAR;
231                         if (!self.ammo_rockets)
232                         noammo = TRUE;
233                 }
234                 else if (self.weapon == IT_HAGAR)
235                 {
236                         self.weapon = IT_ROCKET_LAUNCHER;
237                         if (!self.ammo_rockets)
238                                 noammo = TRUE;
239                 }
240
241                 if ((self.items & self.weapon) && !noammo)
242                 {
243                         W_UpdateWeapon ();
244                         W_UpdateAmmo ();
245                         return;
246                 }
247         }
248 }
249
250 void W_PreviousWeapon (void)
251 {
252         float   noammo;
253
254         while (TRUE)
255         {
256                 noammo = FALSE;
257
258                 if (self.weapon == IT_UZI)
259                         self.weapon = IT_LASER;
260                 else if (self.weapon == IT_SHOTGUN)
261                 {
262                         self.weapon = IT_UZI;
263                         if (!self.ammo_nails)
264                                 noammo = TRUE;
265                 }
266                 else if (self.weapon == IT_GRENADE_LAUNCHER)
267                 {
268                         self.weapon = IT_SHOTGUN;
269                         if (!self.ammo_shells)
270                                 noammo = TRUE;
271                 }
272                 else if (self.weapon == IT_ELECTRO)
273                 {
274                         self.weapon = IT_GRENADE_LAUNCHER;
275                         if (!self.ammo_rockets)
276                                 noammo = TRUE;
277                 }
278                 else if (self.weapon == IT_CRYLINK)
279                 {
280                         self.weapon = IT_ELECTRO;
281                         if (!self.ammo_cells)
282                                 noammo = TRUE;
283                 }
284                 else if (self.weapon == IT_NEX)
285                 {
286                         self.weapon = IT_CRYLINK;
287                         if (!self.ammo_cells)
288                                 noammo = TRUE;
289                 }
290                 else if (self.weapon == IT_HAGAR)
291                 {
292                         self.weapon = IT_NEX;
293                         if (!self.ammo_cells)
294                                 noammo = TRUE;
295                 }
296                 else if (self.weapon == IT_ROCKET_LAUNCHER)
297                 {
298                         self.weapon = IT_HAGAR;
299                         if (!self.ammo_rockets)
300                                 noammo = TRUE;
301                 }
302                 else if (self.weapon == IT_LASER)
303                 {
304                         self.weapon = IT_ROCKET_LAUNCHER;
305                         if (!self.ammo_rockets)
306                                 noammo = TRUE;
307                 }
308
309                 if ((self.items & self.weapon) && !noammo)
310                 {
311                         W_UpdateWeapon ();
312                         W_UpdateAmmo ();
313                         return;
314                 }
315         }
316 }
317
318 float W_CheckAmmo (void)
319 {
320         W_UpdateAmmo ();
321         if (self.weapon == IT_LASER)
322                 return TRUE;
323         else if (self.currentammo)
324                 return TRUE;
325
326         self.weapon = W_GetBestWeapon ();
327         W_UpdateWeapon ();
328
329         return FALSE;
330 }
331
332 void FireRailgunBullet (vector src, float bdamage, vector dir)
333 {
334         vector  v, lastpos;
335         entity  saveself, last;
336
337         if (bdamage < 1)
338                 return;
339
340         last = self;
341         lastpos = src;
342
343         while (bdamage > 0)
344         {
345                 traceline_hitcorpse (self, lastpos + dir * 2, lastpos + dir*8192, FALSE, last);
346                 last = trace_ent;
347                 lastpos = trace_endpos;
348                 if (trace_fraction != 1.0)
349                 {
350                         if (pointcontents(trace_endpos - dir*4) == CONTENT_SKY)
351                                 return;
352
353                         if (trace_ent.takedamage || trace_ent.classname == "case")
354                         {
355                                 if (trace_ent.classname == "player" || trace_ent.classname == "corpse" || trace_ent.classname == "gib")
356                                         te_blood (trace_endpos, dir * bdamage * 16, bdamage);
357                                 Damage (self, trace_endpos, trace_ent, 0, bdamage, dir * bdamage);
358                         }
359                 }
360                 if (last.solid == SOLID_BSP)
361                         bdamage = 0;
362         }
363 }
364
365 void fireBullet (vector dir, float spread, float damage, float dtype)
366 {
367         vector  org;
368
369         makevectors (self.v_angle);
370
371         // use traceline_hitcorpse to make sure it can hit gibs and corpses too
372         org = self.origin + self.view_ofs;
373         traceline_hitcorpse (self, org, org + v_forward * 4096 + v_right * crandom () * spread + v_up * crandom () * spread, FALSE, self);
374
375         // FIXME - causes excessive 'tinking'. Hopefully remove "tink1.wav" from the ricochets with csqc
376         if ((trace_fraction != 1.0) && (trace_ent != self) && (pointcontents (trace_endpos) != CONTENT_SKY))
377         {
378                 if (trace_ent == world)
379                         te_spike (trace_endpos);
380                 else if (trace_ent.classname == "case")
381                 {
382 //                      te_spike (trace_endpos);
383                         Damage (self, trace_endpos, trace_ent, 0, damage, dir * damage);
384                 }
385                 else if (trace_ent.classname == "player" || trace_ent.classname == "corpse" || trace_ent.classname == "gib")
386                 {
387                         te_blood (trace_endpos, dir * damage * 16, damage);
388                         Damage (self, trace_endpos, trace_ent, 0, damage, dir * damage);
389                         if (random () < 0.5)
390                                 sound (trace_ent, CHAN_IMPACT, "misc/BodyImpact1.wav", 1, ATTN_NORM);
391                         else
392                                 sound (trace_ent, CHAN_IMPACT, "misc/BodyImpact2.wav", 1, ATTN_NORM);
393                 }
394         }
395 }
396
397 void W_Laser_Touch (void)
398 {
399         vector  dir;
400
401         if (other == self.owner)
402                 return;
403         else if (pointcontents (self.origin) == CONTENT_SKY)
404         {
405                 remove (self);
406                 return;
407         }
408
409         dir = normalize (self.owner.origin - self.origin);
410
411         sound (self, CHAN_BODY, "weapons/NexImpact.wav", 1, ATTN_NORM);
412
413         WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
414         WriteByte (MSG_BROADCAST, 79);
415         WriteCoord (MSG_BROADCAST, self.origin_x);
416         WriteCoord (MSG_BROADCAST, self.origin_y);
417         WriteCoord (MSG_BROADCAST, self.origin_z);
418         WriteCoord (MSG_BROADCAST, dir_x);
419         WriteCoord (MSG_BROADCAST, dir_y);
420         WriteCoord (MSG_BROADCAST, dir_z);
421         WriteByte (MSG_BROADCAST, 155);
422
423         Damage(self.owner, self.origin, other, 0, 20, dir * 40);
424
425         remove (self);
426 }
427
428 void W_Laser_Attack (void)
429 {
430         entity  missile;
431
432         sound (self, CHAN_WEAPON, "weapons/Electro_fire.wav", 1, ATTN_NORM);
433
434         missile = spawn ();
435         missile.owner = self;
436         missile.classname = "laser";
437
438         missile.movetype = MOVETYPE_FLY;
439         missile.solid = SOLID_BBOX;
440
441         setmodel (missile, "models/bullet.mdl");
442         setsize (missile, '0 0 0', '0 0 0');
443         setorigin (missile, self.origin + self.view_ofs + v_forward * 18 + v_right * 5 + v_up * -12);
444
445         makevectors (self.v_angle);
446         missile.velocity = v_forward * 2000;
447         missile.angles = vectoangles (missile.velocity);
448         missile.glow_color = 250; // 244, 250
449         missile.glow_size = 1020;
450         missile.glow_trail = 1; // ??? 256
451         missile.touch = W_Laser_Touch;
452         missile.think = SUB_Remove;
453         missile.nextthink = time + 2;
454
455         self.punchangle_x = random () - 0.5;
456         self.punchangle_y = random () - 0.5;
457         self.punchangle_z = random () - 0.5;
458
459         self.attack_finished = time + 0.3;
460 }
461
462 void W_Laser_Attack2 (void)
463 {
464
465 }
466
467 void W_Uzi_Attack (void)
468 {
469         sound (self, CHAN_WEAPON, "weapons/Uzi_Fire.wav", 1, ATTN_NORM);
470
471         fireBullet (v_forward, 300, 8, IT_SHOTGUN);
472
473         self.punchangle_x = random () * -2;
474         self.punchangle_y = crandom () * 0.5;
475         self.punchangle_z = crandom () * 0.5;
476
477         self.attack_finished = time + 0.075;
478         self.ammo_nails = self.ammo_nails - 1;
479
480         vector  org; // casing code
481         org = self.origin + self.view_ofs + (v_right * 6) - (v_up * 1) + (v_forward * 20);
482         SpawnCasing (org, v_forward, ((random () * 50 + 50) * v_right) - ((random () * 25 + 25) * v_forward) - ((random () * 5 + 10) * v_up), 1);
483
484         self.effects = self.effects | EF_MUZZLEFLASH;
485 }
486
487 void W_Uzi_Attack2 (void)
488 {
489         sound (self, CHAN_WEAPON, "weapons/Uzi_Fire.wav", 1, ATTN_NORM);
490
491         fireBullet (v_forward, 3, 10, IT_SHOTGUN);
492
493         self.punchangle = '-0.5 0 0';
494
495         self.attack_finished = time + 0.3;
496         self.ammo_nails = self.ammo_nails - 1;
497
498         vector  org;
499         org = self.origin + self.view_ofs + (v_right * 6) - (v_up * 1) + (v_forward * 20);
500         SpawnCasing (org, v_forward, ((random () * 50 + 50) * v_right) - ((random () * 25 + 25) * v_forward) - ((random () * 5 + 10) * v_up), 1);
501 }
502
503 void W_Shotgun_Attack (void)
504 {
505         float   sc;
506
507         sound (self, CHAN_WEAPON, "weapons/Shotgun_fire.wav", 1, ATTN_NORM);
508
509         for (sc = 7; sc > 0; sc = sc - 1)
510                 fireBullet (v_forward, 300, 8, IT_SHOTGUN);
511
512         self.punchangle_x = -2;
513
514         self.ammo_shells = self.ammo_shells - 1;
515         self.attack_finished = time + 0.8;
516
517         vector  org; // casing code
518         org = self.origin + self.view_ofs + (v_right * 6) - (v_up * 4) + (v_forward * 15);
519         SpawnCasing (org, v_forward, ((random () * 50 + 50) * v_right) - ((random () * 25 + 25) * v_forward) - ((random () * 5 + 10) * v_up), 2);
520 }
521
522 void W_Shotgun_Attack2 (void)
523 {
524
525 }
526
527 void W_Grenade_Explode (entity ignore)
528 {
529         ImpactEffect (self, IT_GRENADE_LAUNCHER);
530
531         RadiusDamage (self.owner, self, 0, 100, 50, 100, world, 400);
532
533         remove (self);
534 }
535
536 void W_Grenade_FuseExplode (void)
537 {
538         W_Grenade_Explode (world);
539 }
540
541 void W_Grenade_Touch (void)
542 {
543         if (other.classname == "player" || other.classname == "corpse")
544                 W_Grenade_Explode (other);
545         else
546                 sound (self, CHAN_BODY, "weapons/Grenade_Bounce.wav", 1, ATTN_NORM);
547 }
548
549 void W_Grenade_Attack (void)
550 {
551         entity  gren;
552
553         sound (self, CHAN_WEAPON, "weapons/Grenade_fire.wav", 1, ATTN_NORM);
554
555         self.punchangle_x = -4;
556
557         gren = spawn ();
558         gren.owner = self;
559         gren.classname = "grenade";
560
561         gren.movetype = MOVETYPE_BOUNCE;
562         gren.solid = SOLID_BBOX;
563
564         gren.takedamage = DAMAGE_YES;
565         gren.damageforcescale = 4;
566         gren.health = 1;
567         gren.event_hurt = W_Grenade_Explode;
568
569         setmodel (gren, "models/grenademodel.md3");
570         setsize (gren, '-6 -6 -3', '6 6 3');
571
572         makevectors (self.v_angle);
573         setorigin (gren, self.origin + self.view_ofs + v_forward * 18 + v_right * 5 + v_up * -12);
574
575         gren.velocity = v_forward * 900 + v_up * 200;
576         gren.angles = vectoangles (gren.velocity);
577         gren.avelocity = '150 1500 150';
578
579         gren.touch = W_Grenade_Touch;
580         gren.think = W_Grenade_FuseExplode;
581         gren.nextthink = time + 2;
582
583         self.attack_finished = time + 1;
584         self.ammo_rockets = self.ammo_rockets - 1;
585 }
586
587 void W_Grenade_Attack2 (void)
588 {
589         entity  gren;
590
591         sound (self, CHAN_WEAPON, "weapons/Grenade_fire.wav", 1, ATTN_NORM);
592
593         self.punchangle_x = -4;
594
595         gren = spawn ();
596         gren.owner = self;
597         gren.classname = "grenade";
598
599         gren.movetype = MOVETYPE_TOSS;
600         gren.solid = SOLID_BBOX;
601
602         gren.takedamage = DAMAGE_YES;
603         gren.damageforcescale = 4;
604         gren.health = 1;
605         gren.event_hurt = W_Grenade_Explode;
606
607         setmodel (gren, "models/grenademodel.md3");
608         setsize (gren, '-6 -6 -3', '6 6 3');
609
610         makevectors (self.v_angle);
611         setorigin (gren, self.origin + self.view_ofs + v_forward * 18 + v_right * 5 + v_up * -12);
612
613         gren.velocity = v_forward * 1400 + v_up * 100;
614         gren.angles = vectoangles (gren.velocity);
615         gren.avelocity = '150 1500 150';
616
617         gren.touch = W_Grenade_Explode;
618         gren.think = W_Grenade_FuseExplode;
619         gren.nextthink = time + 5;
620
621         self.attack_finished = time + 1;
622         self.ammo_rockets = self.ammo_rockets - 1;
623 }
624
625 void W_Electro_Touch (void)
626 {
627         vector dir;
628         WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
629         WriteByte (MSG_BROADCAST, 79);
630         WriteCoord (MSG_BROADCAST, self.origin_x);
631         WriteCoord (MSG_BROADCAST, self.origin_y);
632         WriteCoord (MSG_BROADCAST, self.origin_z);
633         WriteCoord (MSG_BROADCAST, 0);          // SeienAbunae: groan... Useless clutter
634         WriteCoord (MSG_BROADCAST, 0);
635         WriteCoord (MSG_BROADCAST, 0);
636         WriteByte (MSG_BROADCAST, 155);
637
638         // LordHavoc: why damage only flesh?
639         //if (other.classname == "player" || other.classname == "corpse" || other.classname == "gib")
640         {
641                 if (random () < 0.5)
642                         sound (other, CHAN_IMPACT, "misc/BodyImpact1.wav", 1, ATTN_NORM);
643                 else
644                         sound (other, CHAN_IMPACT, "misc/BodyImpact2.wav", 1, ATTN_NORM);
645                 dir = normalize(self.velocity);
646                 Damage (self.owner, self.origin, other, 0, 40, dir * 80);
647         }
648
649         remove (self);
650 }
651
652 void W_Electro_Attack (void)
653 {
654         entity  proj;
655
656         sound (self, CHAN_WEAPON, "weapons/Electro_fire.wav", 1, ATTN_NORM);
657
658         proj = spawn ();
659         proj.owner = self;
660         proj.classname = "elec";
661
662         proj.movetype = MOVETYPE_FLY;
663         proj.solid = SOLID_BBOX;
664         proj.effects = 1;
665
666         makevectors (self.v_angle);
667
668         setmodel (proj, "models/bullet.mdl");
669         setsize (proj, '0 0 0', '0 0 0');
670         setorigin (proj, self.origin + self.view_ofs + v_forward * 18 + v_right * 5 + v_up * -12);
671
672         proj.velocity = v_forward * 3000;
673         proj.touch = W_Electro_Touch;
674         proj.think = SUB_Remove;
675         proj.nextthink = time + 3;
676
677         self.attack_finished = time + 0.6;
678         self.ammo_cells = self.ammo_cells - 1;
679 }
680
681 void W_Plasma_Touch (void)
682 {
683         vector dir;
684         dir = normalize(self.velocity);
685         // LordHavoc: why damage only flesh?
686         //if (other.classname == "player" || other.classname == "corpse" || other.classname == "gib")
687                 Damage (self.owner, self.origin, other, 0, 15, dir * 30);
688
689         ImpactEffect (self, IT_ELECTRO);
690
691         remove (self);
692 }
693
694 const float w_plasma_anim_interval = 0.05;
695 .float lifetime;
696 void W_Plasma_Think (void)
697 {
698         float a;
699
700         a = random () * 5;
701         animate_sprite(a, 5);
702
703         self.nextthink = time + w_plasma_anim_interval;
704
705         if (self.lifetime < time) // time is up
706                 SUB_Remove();
707 }
708
709 void W_Electro_Attack2 (void)
710 {
711         entity  proj;
712
713         sound (self, CHAN_WEAPON, "weapons/LazerGun_Fire.wav", 1, ATTN_NORM);
714
715         proj = spawn ();
716         proj.owner = self;
717         proj.classname = "plasma";
718
719         proj.movetype = MOVETYPE_FLY;
720         proj.solid = SOLID_BBOX;
721         proj.effects = EF_DIMLIGHT;
722
723         makevectors (self.v_angle);
724
725         setmodel (proj, "models/sprites/plasmashot.spr32");
726         setsize (proj, '0 0 0', '0 0 0');
727         setorigin (proj, self.origin + self.view_ofs + v_forward * 5 + v_right * 5 + v_up * -12);
728
729         proj.velocity = v_forward * 5000;
730         proj.touch = W_Plasma_Touch;
731         proj.think = W_Plasma_Think;
732         proj.nextthink = time + w_plasma_anim_interval;
733         proj.lifetime = time + 1.5;
734
735         self.attack_finished = time + 0.175;
736         self.ammo_cells = self.ammo_cells - 1;
737 }
738
739 void W_Crylink_Attack (void)
740 {
741         vector  org;
742
743         sound (self, CHAN_WEAPON, "weapons/crylink.wav", 1, ATTN_NORM);
744         org = self.origin + self.view_ofs + v_forward * 18 + v_right * 7 + v_up * -9;
745         makevectors (self.v_angle);
746
747         // FIXME: make it accurate!
748
749         FireRailgunBullet (org, 25, v_forward);
750
751         traceline (org, self.origin + self.view_ofs + (v_forward * 4096), FALSE, self);
752
753         WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
754         WriteByte (MSG_BROADCAST, 76);
755         WriteCoord (MSG_BROADCAST, org_x);
756         WriteCoord (MSG_BROADCAST, org_y);
757         WriteCoord (MSG_BROADCAST, org_z);
758         WriteCoord (MSG_BROADCAST, trace_endpos_x);
759         WriteCoord (MSG_BROADCAST, trace_endpos_y);
760         WriteCoord (MSG_BROADCAST, trace_endpos_z);
761         WriteCoord (MSG_BROADCAST, self.v_angle_x);
762         WriteCoord (MSG_BROADCAST, self.v_angle_y);
763         WriteCoord (MSG_BROADCAST, self.v_angle_z);
764
765         te_spike (trace_endpos);
766
767         self.ammo_cells = self.ammo_cells - 0.25;
768         self.attack_finished = time + 0.165;
769 }
770
771 void W_Crylink_Attack2 (void)
772 {
773         vector  org;
774         vector  dir;
775
776         makevectors (self.v_angle);
777
778         org = self.origin + self.view_ofs + v_forward * 19 + v_right * 5 + v_up * -7;
779
780         traceline (org, self.origin + self.view_ofs + v_forward * 4096 + v_right * (random () * 100 - 50) + v_up * (random () * 100 - 50), FALSE, self);
781
782         Damage (self, trace_endpos, trace_ent, 0, 20, v_forward * 10);
783
784         te_lightning1 (self, org, trace_endpos);
785
786         self.ammo_cells = self.ammo_cells - 0.25;
787         self.attack_finished = time + 0.075;
788 }
789
790 void W_Nex_Attack (void)
791 {
792         vector  org;
793         vector  dir;
794
795         sound (self, CHAN_WEAPON, "weapons/NexFire.wav", 1, ATTN_NORM);
796         //self.effects = EF_MUZZLEFLASH;
797         self.punchangle_x = -4;
798
799         makevectors (self.v_angle);
800
801         org = self.origin + self.view_ofs + v_forward * 18 + v_right * 8 + v_up * -5;
802
803         // FIXME: make it accurate!
804
805         traceline (org, self.origin + self.view_ofs + (v_forward * 4096), FALSE, self);
806
807         FireRailgunBullet (org, 90, v_forward);
808
809         WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
810         WriteByte (MSG_BROADCAST, 76);
811         WriteCoord (MSG_BROADCAST, org_x);
812         WriteCoord (MSG_BROADCAST, org_y);
813         WriteCoord (MSG_BROADCAST, org_z);
814         WriteCoord (MSG_BROADCAST, trace_endpos_x);
815         WriteCoord (MSG_BROADCAST, trace_endpos_y);
816         WriteCoord (MSG_BROADCAST, trace_endpos_z);
817         WriteCoord (MSG_BROADCAST, self.v_angle_x);
818         WriteCoord (MSG_BROADCAST, self.v_angle_y);
819         WriteCoord (MSG_BROADCAST, self.v_angle_z);
820
821         te_plasmaburn (trace_endpos);
822
823         dir = trace_plane_normal * 100;
824         WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
825         WriteByte (MSG_BROADCAST, TE_FLAMEJET);
826         WriteCoord (MSG_BROADCAST, trace_endpos_x);
827         WriteCoord (MSG_BROADCAST, trace_endpos_y);
828         WriteCoord (MSG_BROADCAST, trace_endpos_z);
829         WriteCoord (MSG_BROADCAST, dir_x);
830         WriteCoord (MSG_BROADCAST, dir_y);
831         WriteCoord (MSG_BROADCAST, dir_z);
832         WriteByte (MSG_BROADCAST, 255);
833
834         PointSound (trace_endpos, "weapons/NexImpact.wav", 1, ATTN_NORM);
835
836         self.attack_finished = time + 1;
837         self.ammo_cells = self.ammo_cells - 1;
838 }
839
840 void W_Nex_Attack2 (void)
841 {
842
843 }
844
845 void W_Hagar_Explode (void)
846 {
847         ImpactEffect (self, IT_HAGAR);
848
849         RadiusDamage (self.owner, self, 0, 100, 50, 100, world, 150);
850
851         remove (self);
852 }
853
854 void W_Hagar_Touch (void)
855 {
856         if (other == self.owner)
857                 return;
858         else if (pointcontents (self.origin) == CONTENT_SKY)
859         {
860                 remove (self);
861                 return;
862         }
863
864         W_Hagar_Explode ();
865 }
866
867 void W_Hagar_Attack (void)
868 {
869         entity  missile;
870         vector  org;
871
872         sound (self, CHAN_WEAPON, "weapons/Hagar_Fire.wav", 1, ATTN_NORM);
873
874         missile = spawn ();
875         missile.owner = self;
876         missile.classname = "rocket";
877
878         missile.takedamage = DAMAGE_YES;
879         missile.damageforcescale = 4;
880         missile.health = 1;
881         missile.event_hurt = W_Hagar_Explode;
882
883         missile.movetype = MOVETYPE_FLY;
884         missile.solid = SOLID_BBOX;
885         setmodel (missile, "models/hagarmissile.mdl");
886         setsize (missile, '0 0 0', '0 0 0');
887
888         makevectors (self.v_angle);
889
890         setorigin (missile, self.origin + self.view_ofs + v_forward * 18 + v_right * 5 + v_up * -12);
891
892         missile.velocity = v_forward * 2000;
893         missile.angles = vectoangles (missile.velocity);
894         setorigin (missile, self.origin + self.view_ofs + v_forward * 18 + v_right * 5 + v_up * -12);
895
896         missile.touch = W_Hagar_Touch;
897         missile.think = SUB_Remove;
898         missile.nextthink = time + 1;
899
900         self.attack_finished = time + 0.2;
901         self.ammo_rockets = self.ammo_rockets - 0.25;
902 }
903
904 void W_Hagar_Attack2 (void)
905 {
906         entity  missile;
907         vector  org;
908
909         sound (self, CHAN_WEAPON, "weapons/Hagar_Fire.wav", 1, ATTN_NORM);
910
911         missile = spawn ();
912         missile.owner = self;
913         missile.classname = "rocket";
914
915         missile.takedamage = DAMAGE_YES;
916         missile.damageforcescale = 4;
917         missile.health = 1;
918         missile.event_hurt = W_Hagar_Explode;
919
920         missile.movetype = MOVETYPE_FLY;
921         missile.solid = SOLID_BBOX;
922         setmodel (missile, "models/hagarmissile.mdl");
923         setsize (missile, '0 0 0', '0 0 0');
924
925         makevectors (self.v_angle);
926
927         setorigin (missile, self.origin + self.view_ofs + v_forward * 18 + v_right * 5 + v_up * -12);
928
929         missile.velocity = v_forward * 15000;
930         missile.angles = vectoangles (missile.velocity);
931
932         missile.touch = W_Hagar_Touch;
933         missile.think = SUB_Remove;
934         missile.nextthink = time + 1;
935
936         self.attack_finished = time + 0.7;
937         self.ammo_rockets = self.ammo_rockets - 0.25;
938 }
939
940 void W_Rocket_Explode (entity ignore)
941 {
942         ImpactEffect (self, IT_ROCKET_LAUNCHER);
943
944         RadiusDamage (self.owner, self, 0, 100, 50, 100, ignore, 600);
945
946         remove (self);
947 }
948
949 void W_Rocket_Touch (void)
950 {
951         if (other == self.owner)
952                 return;
953         else if (pointcontents (self.origin) == CONTENT_SKY)
954         {
955                 remove (self);
956                 return;
957         }
958         else
959                 W_Rocket_Explode (world);
960 }
961
962 void W_Rocket_Attack (void)
963 {
964         entity  missile;
965         vector  org;
966
967         sound (self, CHAN_WEAPON, "weapons/Rocket_Fire.wav", 1, ATTN_NORM);
968
969         missile = spawn ();
970         missile.owner = self;
971         missile.classname = "rocket";
972
973         missile.takedamage = DAMAGE_YES;
974         missile.damageforcescale = 4;
975         missile.health = 1;
976         missile.event_hurt = W_Rocket_Explode;
977
978         missile.movetype = MOVETYPE_FLY;
979         missile.solid = SOLID_BBOX;
980         setmodel (missile, "models/rocketmissile.mdl");
981         setsize (missile, '0 0 0', '0 0 0');
982
983         makevectors (self.v_angle);
984
985         org = self.origin + self.view_ofs + v_forward * 20 + v_right * 4 + v_up * -15;
986
987         setorigin (missile, org);
988         missile.velocity = v_forward * 2500;
989         missile.angles = vectoangles (missile.velocity);
990
991         missile.touch = W_Rocket_Touch ;
992         missile.think = SUB_Remove;
993         missile.nextthink = time + 1;
994
995         self.attack_finished = time + 1.5;
996         self.ammo_rockets = self.ammo_rockets - 1;
997
998 }
999
1000 void W_Rocket2_Explode (entity ignore)
1001 {
1002         ImpactEffect (self, IT_ROCKET_LAUNCHER);
1003
1004         RadiusDamage (self.owner, self, 0, 15, 5, 200, ignore, 400);
1005
1006         remove (self);
1007 }
1008
1009 void W_Rocket2_Touch (void)
1010 {
1011         if (other == self.owner)
1012                 return;
1013         else if (pointcontents (self.origin) == CONTENT_SKY)
1014         {
1015                 remove (self);
1016                 return;
1017         }
1018         else
1019                 W_Rocket2_Explode (world);
1020 }
1021
1022 void W_Rocket_Attack2 (void)
1023 {
1024         entity  missile;
1025         vector  org;
1026
1027         //sound (self, CHAN_WEAPON, "weapons/Rocket_Fire.wav", 1, ATTN_NORM);
1028
1029         missile = spawn ();
1030         missile.owner = self;
1031         missile.classname = "rocket";
1032
1033         missile.takedamage = DAMAGE_YES;
1034         missile.damageforcescale = 4;
1035         missile.health = 1;
1036         missile.event_hurt = W_Rocket2_Explode;
1037
1038         missile.movetype = MOVETYPE_FLY;
1039         missile.solid = SOLID_BBOX;
1040         setmodel (missile, "models/rocketmissile.mdl");
1041         setsize (missile, '0 0 0', '0 0 0');
1042
1043         makevectors (self.v_angle);
1044
1045         org = self.origin + self.view_ofs + v_forward * 20 + v_right * 4 + v_up * -15;
1046
1047         setorigin (missile, org);
1048         missile.velocity = v_forward * 1500;
1049         missile.angles = vectoangles (missile.velocity);
1050
1051         missile.touch = W_Rocket2_Touch;
1052         missile.think = SUB_Remove;
1053         missile.nextthink = time + 1;
1054
1055         self.attack_finished = time + 1;
1056         self.ammo_rockets = self.ammo_rockets - 1;
1057 }
1058
1059 void W_Attack (void)
1060 {
1061         if (self.deadflag != DEAD_NO)
1062         {
1063                 if (self.death_time < time)
1064                         PutClientInServer();
1065
1066                 return;
1067         }
1068
1069         if (!W_CheckAmmo ())
1070                 return;
1071
1072         if (self.weapon == IT_LASER)
1073                 W_Laser_Attack ();
1074         else if (self.weapon == IT_UZI)
1075                 W_Uzi_Attack ();
1076         else if (self.weapon == IT_SHOTGUN)
1077                 W_Shotgun_Attack ();
1078         else if (self.weapon == IT_GRENADE_LAUNCHER)
1079                 W_Grenade_Attack ();
1080         else if (self.weapon == IT_ELECTRO)
1081                 W_Electro_Attack ();
1082         else if (self.weapon == IT_CRYLINK)
1083                 W_Crylink_Attack ();
1084         else if (self.weapon == IT_NEX)
1085                 W_Nex_Attack ();
1086         else if (self.weapon == IT_HAGAR)
1087                 W_Hagar_Attack ();
1088         else if (self.weapon == IT_ROCKET_LAUNCHER)
1089                 W_Rocket_Attack ();
1090
1091         W_UpdateAmmo ();
1092 }
1093
1094 void W_SecondaryAttack (void)
1095 {
1096         if (self.deadflag != DEAD_NO)
1097         {
1098                 if (self.death_time < time)
1099                         PutClientInServer();
1100
1101                 return;
1102         }
1103
1104         if (!W_CheckAmmo ())
1105                 return;
1106
1107         if (self.weapon == IT_LASER)
1108                 W_Laser_Attack2 ();
1109         else if (self.weapon == IT_UZI)
1110                 W_Uzi_Attack2 ();
1111         else if (self.weapon == IT_SHOTGUN)
1112                 W_Shotgun_Attack2 ();
1113         else if (self.weapon == IT_GRENADE_LAUNCHER)
1114                 W_Grenade_Attack2 ();
1115         else if (self.weapon == IT_ELECTRO)
1116                 W_Electro_Attack2 ();
1117         else if (self.weapon == IT_CRYLINK)
1118                 W_Crylink_Attack2 ();
1119         else if (self.weapon == IT_NEX)
1120                 W_Nex_Attack2 ();
1121         else if (self.weapon == IT_HAGAR)
1122                 W_Hagar_Attack2 ();
1123         else if (self.weapon == IT_ROCKET_LAUNCHER)
1124                 W_Rocket_Attack2 ();
1125
1126         W_UpdateAmmo ();
1127 }