]> icculus.org git repositories - divverent/nexuiz.git/blob - qcsrc/weapons.qc
*** empty log message ***
[divverent/nexuiz.git] / qcsrc / weapons.qc
1 // increments sprite frame, loops when end is hit.. simple
2 void(float startframe, float frame_count) animate_sprite =
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         float   loops;
187
188 // AK Let it test only every possible weapon then kick it out of the loop
189         while (loops <= 9)
190         {
191                 noammo = FALSE;
192                 
193 // AK Sombody messed up the sequence (please undo if it was extra made so)
194                 if (self.weapon == IT_ROCKET_LAUNCHER)
195                         self.weapon = IT_LASER;
196                 else if (self.weapon == IT_LASER)
197                 {
198                         self.weapon = IT_UZI;
199                         if (!self.ammo_nails)
200                                 noammo = TRUE;
201                 }
202                 else if (self.weapon == IT_UZI)
203                 {
204                         self.weapon = IT_SHOTGUN;
205                         if (!self.ammo_shells)
206                                 noammo = TRUE;
207                 }
208                 else if (self.weapon == IT_SHOTGUN)
209                 {
210                         self.weapon = IT_GRENADE_LAUNCHER;
211                         if (!self.ammo_rockets)
212                                 noammo = TRUE;
213                 }
214                 else if (self.weapon == IT_GRENADE_LAUNCHER)
215                 {
216                         self.weapon = IT_ELECTRO;
217                         if (!self.ammo_cells)
218                                 noammo = TRUE;
219                 }
220                 else if (self.weapon == IT_ELECTRO)
221                 {
222                         self.weapon = IT_CRYLINK;
223                         if (!self.ammo_cells)
224                         noammo = TRUE;
225                 }
226                 else if (self.weapon == IT_CRYLINK)
227                 {
228                         self.weapon = IT_NEX;
229                         if (!self.ammo_cells)
230                         noammo = TRUE;
231                 }
232                 else if (self.weapon == IT_NEX)
233                 {
234                         self.weapon = IT_HAGAR;
235                         if (!self.ammo_rockets)
236                         noammo = TRUE;
237                 }
238                 else if (self.weapon == IT_HAGAR)
239                 {
240                         self.weapon = IT_ROCKET_LAUNCHER;
241                         if (!self.ammo_rockets)
242                                 noammo = TRUE;
243                 }
244
245                 if ((self.items & self.weapon) && !noammo)
246                 {
247                         W_UpdateWeapon ();
248                         W_UpdateAmmo ();
249                         return;
250                 }
251                 
252                 loops++;
253         }
254 }
255
256 void W_PreviousWeapon (void)
257 {
258         float   noammo;
259
260         float   loops;
261         
262 // AK the same as above
263         while (loops <= 9)
264         {
265                 noammo = FALSE;
266                 
267                 if (self.weapon == IT_UZI)
268                         self.weapon = IT_LASER;
269                 else if (self.weapon == IT_SHOTGUN)
270                 {
271                         self.weapon = IT_UZI;
272                         if (!self.ammo_nails)
273                                 noammo = TRUE;
274                 }
275                 else if (self.weapon == IT_GRENADE_LAUNCHER)
276                 {
277                         self.weapon = IT_SHOTGUN;
278                         if (!self.ammo_shells)
279                                 noammo = TRUE;
280                 }
281                 else if (self.weapon == IT_ELECTRO)
282                 {
283                         self.weapon = IT_GRENADE_LAUNCHER;
284                         if (!self.ammo_rockets)
285                                 noammo = TRUE;
286                 }
287                 else if (self.weapon == IT_CRYLINK)
288                 {
289                         self.weapon = IT_ELECTRO;
290                         if (!self.ammo_cells)
291                                 noammo = TRUE;
292                 }
293                 else if (self.weapon == IT_NEX)
294                 {
295                         self.weapon = IT_CRYLINK;
296                         if (!self.ammo_cells)
297                                 noammo = TRUE;
298                 }
299                 else if (self.weapon == IT_HAGAR)
300                 {
301                         self.weapon = IT_NEX;
302                         if (!self.ammo_cells)
303                                 noammo = TRUE;
304                 }
305                 else if (self.weapon == IT_ROCKET_LAUNCHER)
306                 {
307                         self.weapon = IT_HAGAR;
308                         if (!self.ammo_rockets)
309                                 noammo = TRUE;
310                 }
311                 else if (self.weapon == IT_LASER)
312                 {
313                         self.weapon = IT_ROCKET_LAUNCHER;
314                         if (!self.ammo_rockets)
315                                 noammo = TRUE;
316                 }
317                 
318                 if ((self.items & self.weapon) && !noammo)
319                 {
320                         W_UpdateWeapon ();
321                         W_UpdateAmmo ();
322                         return;
323                 }
324                 
325                 loops++;
326         }
327 }
328
329 float W_CheckAmmo (void)
330 {
331         W_UpdateAmmo ();
332         if (self.weapon == IT_LASER)
333                 return TRUE;
334         else if (self.currentammo)
335                 return TRUE;
336                 
337         self.weapon = W_GetBestWeapon ();
338         W_UpdateWeapon ();
339         
340         return FALSE;
341 }
342
343 void(vector src, float bdamage, vector dir) FireRailgunBullet =
344 {
345         local   vector  v, lastpos;             
346         local   entity  saveself, last;
347
348         if (bdamage < 1)
349                 return;
350
351         last = self;
352         lastpos = src;
353         
354         while (bdamage > 0)
355         {               
356                 traceline (lastpos + dir * 2, lastpos + dir*8192, FALSE, last);
357                 last = trace_ent;
358                 lastpos = trace_endpos;
359                 if (trace_fraction != 1.0)              
360                         {
361                                 if (pointcontents(trace_endpos - dir*4) == CONTENT_SKY)
362                                         return; 
363
364                                 if (trace_ent.takedamage)
365                                 {
366                                         Damage (self, trace_endpos, trace_ent, 0, bdamage);
367                                 }               
368                         }
369                 if (last.solid == SOLID_BSP)                    
370                         bdamage = 0;    
371         }
372 };
373
374 void fireBullet (vector dir, float spread, float damage, float dtype)
375 {
376         vector  org;
377         
378         makevectors (self.v_angle);
379         
380         // use traceline_hitcorpse to make sure it can hit gibs and corpses too
381         org = self.origin + self.view_ofs;
382         traceline_hitcorpse (self, org, org + v_forward * 4096 + v_right * crandom () * spread + v_up * crandom () * spread, FALSE, self);
383         
384         // FIXME - causes excessive 'tinking'. Hopefully remove "tink1.wav" from the ricochets with csqc
385         if ((trace_fraction != 1.0) && (trace_ent != self) && (pointcontents (trace_endpos) != CONTENT_SKY))
386         {
387                 if (trace_ent == world)
388                         te_spike (trace_endpos);
389                 else if (trace_ent.classname == "player" || trace_ent.classname == "corpse" || trace_ent.classname == "gib")
390                 {
391                         Damage (self, trace_endpos, trace_ent, 0, damage);
392                         if (random () < 0.5)
393                                 sound (trace_ent, CHAN_IMPACT, "misc/BodyImpact1.wav", 1, ATTN_NORM);
394                         else
395                                 sound (trace_ent, CHAN_IMPACT, "misc/BodyImpact2.wav", 1, ATTN_NORM);
396                 }
397         }
398 }
399
400 void W_Laser_Touch (void)
401 {
402         vector  dir;
403         
404         if (other == self.owner)
405                 return; 
406         else if (pointcontents (self.origin) == CONTENT_SKY)
407         {
408                 remove (self);
409                 return;
410         }
411         
412         dir = normalize (self.owner.origin - self.origin);
413         
414         sound (self, CHAN_BODY, "weapons/NexImpact.wav", 1, ATTN_NORM);
415         
416         WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
417         WriteByte (MSG_BROADCAST, 79);
418         WriteCoord (MSG_BROADCAST, self.origin_x);
419         WriteCoord (MSG_BROADCAST, self.origin_y);
420         WriteCoord (MSG_BROADCAST, self.origin_z);
421         WriteCoord (MSG_BROADCAST, dir_x);
422         WriteCoord (MSG_BROADCAST, dir_y);
423         WriteCoord (MSG_BROADCAST, dir_z);
424         WriteByte (MSG_BROADCAST, 155);
425
426         remove (self);
427 }
428
429 void W_Laser_Attack (void)
430 {
431         entity  missile;
432         
433         sound (self, CHAN_WEAPON, "weapons/Electro_fire.wav", 1, ATTN_NORM);
434         
435         missile = spawn ();
436         missile.owner = self;
437         missile.classname = "laser";
438         
439         missile.movetype = MOVETYPE_FLY;
440         missile.solid = SOLID_BBOX;
441         
442         setmodel (missile, "models/bullet.mdl");
443         setsize (missile, '-4 -4 -4', '4 4 4');
444         setorigin (missile, self.origin + self.view_ofs);
445
446         makevectors (self.v_angle);
447         missile.velocity = v_forward * 2000;
448         missile.angles = vectoangles (missile.velocity);
449         missile.glow_color = 250; // 244, 250
450         missile.glow_size = 1020;
451         missile.glow_trail = 1; // ??? 256
452         missile.touch = W_Laser_Touch;
453         missile.think = SUB_Remove;
454         missile.nextthink = time + 2;
455         
456         self.punchangle_x = random () - 0.5;
457         self.punchangle_y = random () - 0.5;
458         self.punchangle_z = random () - 0.5;
459         
460         self.attack_finished = time + 0.3;
461 }
462
463 void W_Laser_Attack2 (void)
464 {
465         
466 }
467
468 void W_Uzi_Attack (void)
469 {
470         sound (self, CHAN_WEAPON, "weapons/Uzi_Fire.wav", 1, ATTN_NORM);
471
472         fireBullet (v_forward, 300, 8, IT_SHOTGUN);     
473
474         self.punchangle_x = random () * -2;
475         self.punchangle_y = crandom () * 0.5;
476         self.punchangle_z = crandom () * 0.5;
477         
478         self.attack_finished = time + 0.075;
479         self.ammo_nails = self.ammo_nails - 1;
480
481         vector  org; // casing code
482         org = self.origin + self.view_ofs + (v_right * 6) - (v_up * 1) + (v_forward * 20);
483         SpawnCasing (org, v_forward, ((random () * 50 + 50) * v_right) - ((random () * 25 + 25) * v_forward) - ((random () * 5 + 10) * v_up), 2);
484
485         self.effects = self.effects | EF_MUZZLEFLASH;
486 }
487
488 void W_Uzi_Attack2 (void)
489 {
490         sound (self, CHAN_WEAPON, "weapons/Uzi_Fire.wav", 1, ATTN_NORM);
491         
492         fireBullet (v_forward, 3, 10, IT_SHOTGUN);
493         
494         self.punchangle = '-0.5 0 0';
495         
496         self.attack_finished = time + 0.3;
497         self.ammo_nails = self.ammo_nails - 1;
498
499         vector  org;
500         org = self.origin + self.view_ofs + (v_right * 6) - (v_up * 1) + (v_forward * 20);
501         SpawnCasing (org, v_forward, ((random () * 50 + 50) * v_right) - ((random () * 25 + 25) * v_forward) - ((random () * 5 + 10) * v_up), 2);
502 }
503
504 void W_Shotgun_Attack (void)
505 {
506         sound (self, CHAN_WEAPON, "weapons/Shotgun_fire.wav", 1, ATTN_NORM);
507
508         float   sc;
509         sc = 7;
510         while (sc > 0)
511         {
512                 fireBullet (v_forward, 300, 8, IT_SHOTGUN);
513                 sc = sc - 1;
514         }
515
516         self.punchangle_x = -2;
517
518         self.ammo_shells = self.ammo_shells - 1;
519         self.attack_finished = time + 0.8;
520
521         vector  org; // casing code
522         org = self.origin + self.view_ofs + (v_right * 6) - (v_up * 4) + (v_forward * 15);
523         SpawnCasing (org, v_forward, ((random () * 50 + 50) * v_right) - ((random () * 25 + 25) * v_forward) - ((random () * 5 + 10) * v_up), 1);
524 }
525
526 void W_Shotgun_Attack2 (void)
527 {
528
529 }
530
531 void W_Grenade_Explode (entity ignore)
532 {
533         ImpactEffect (self, IT_GRENADE_LAUNCHER);
534
535         RadiusDamage (self.owner, self, 0, 100, world);
536
537         remove (self);
538 }
539
540 void W_Grenade_FuseExplode (void)
541 {
542         W_Grenade_Explode (world);
543 }
544
545 void W_Grenade_Touch (void)
546 {
547         if (other.classname == "player" || other.classname == "corpse")
548         {
549                 Damage (self.owner, self.origin, other, 0, 100);
550                 W_Grenade_Explode (other);
551         }
552         else
553                 sound (self, CHAN_BODY, "weapons/Grenade_Bounce.wav", 1, ATTN_NORM);
554 }
555
556 void W_Grenade_Attack (void)
557 {
558         entity  gren;
559         
560         sound (self, CHAN_WEAPON, "weapons/Grenade_fire.wav", 1, ATTN_NORM);
561         
562         self.punchangle_x = -4;
563         
564         gren = spawn ();
565         gren.owner = self;
566         gren.classname = "grenade";
567         
568         gren.movetype = MOVETYPE_BOUNCE;
569         gren.solid = SOLID_BBOX;
570         
571         gren.takedamage = DAMAGE_YES;
572         gren.health = 1;
573         gren.event_hurt = W_Grenade_Explode;
574
575         setmodel (gren, "models/grenademodel.md3");
576         setsize (gren, '0 0 0', '0 0 0');
577         
578         makevectors (self.v_angle);
579         setorigin (gren, self.origin + self.view_ofs + v_forward * 18 + v_right * 5 + v_up * -12);
580
581         gren.velocity = v_forward * 900 + v_up * 200;
582         gren.angles = vectoangles (gren.velocity);
583         gren.avelocity = '150 1500 150';
584         
585         gren.touch = W_Grenade_Touch;
586         gren.think = W_Grenade_FuseExplode;
587         gren.nextthink = time + 2;
588         
589         self.attack_finished = time + 1;
590         self.ammo_rockets = self.ammo_rockets - 1;
591 }
592
593 void W_Grenade_Attack2 (void)
594 {
595         entity  gren;
596         
597         sound (self, CHAN_WEAPON, "weapons/Grenade_fire.wav", 1, ATTN_NORM);
598         
599         self.punchangle_x = -4;
600         
601         gren = spawn ();
602         gren.owner = self;
603         gren.classname = "grenade";
604         
605         gren.movetype = MOVETYPE_TOSS;
606         gren.solid = SOLID_BBOX;
607         
608         gren.takedamage = DAMAGE_YES;
609         gren.health = 1;
610         gren.event_hurt = W_Grenade_Explode;
611         
612         setmodel (gren, "models/grenademodel.md3");
613         setsize (gren, '0 0 0', '0 0 0');
614         
615         makevectors (self.v_angle);
616         setorigin (gren, self.origin + self.view_ofs + v_forward * 18 + v_right * 5 + v_up * -12);
617         
618         gren.velocity = v_forward * 1400 + v_up * 100;
619         gren.angles = vectoangles (gren.velocity);
620         gren.avelocity = '150 1500 150';
621                 
622         gren.touch = W_Grenade_Explode;
623         gren.think = W_Grenade_FuseExplode;
624         gren.nextthink = time + 5;
625         
626         self.attack_finished = time + 1;
627         self.ammo_rockets = self.ammo_rockets - 1;
628 }
629
630 void W_Electro_Touch (void)
631 {
632         WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
633         WriteByte (MSG_BROADCAST, 79);
634         WriteCoord (MSG_BROADCAST, self.origin_x);
635         WriteCoord (MSG_BROADCAST, self.origin_y);
636         WriteCoord (MSG_BROADCAST, self.origin_z);
637         WriteCoord (MSG_BROADCAST, 0);          // SeienAbunae: groan... Useless clutter
638         WriteCoord (MSG_BROADCAST, 0);
639         WriteCoord (MSG_BROADCAST, 0);
640         WriteByte (MSG_BROADCAST, 155);
641         
642         if (other.classname == "player" || other.classname == "corpse" || other.classname == "gib")
643         {
644                 Damage (self.owner, self.origin, other, 0, 40);
645                 // SeienAbunae: the impact sound doesn't seem to play when the victim dies instead of being hurt
646                 // Maybe it's not that big of a deal
647                 if (random () < 0.5)
648                         sound (other, CHAN_IMPACT, "misc/BodyImpact1.wav", 1, ATTN_NORM);
649                 else
650                         sound (other, CHAN_IMPACT, "misc/BodyImpact2.wav", 1, ATTN_NORM);
651         }
652         
653         remove (self);
654 }
655
656 void W_Electro_Attack (void)
657 {
658         entity  proj;
659         
660         sound (self, CHAN_WEAPON, "weapons/Electro_fire.wav", 1, ATTN_NORM);
661         
662         proj = spawn ();
663         proj.owner = self;
664         proj.classname = "elec";
665         
666         proj.movetype = MOVETYPE_FLY;
667         proj.solid = SOLID_BBOX;
668         proj.effects = 1;
669         
670         makevectors (self.v_angle);
671         
672         setmodel (proj, "models/bullet.mdl");
673         setsize (proj, '0 0 0', '0 0 0');
674         setorigin (proj, self.origin + self.view_ofs + v_forward * 18 + v_right * 5 + v_up * -12);
675         
676         proj.velocity = v_forward * 3000;
677         proj.touch = W_Electro_Touch;
678         proj.think = SUB_Remove;
679         proj.nextthink = time + 3;
680         
681         self.attack_finished = time + 0.6;
682         self.ammo_cells = self.ammo_cells - 1;
683 }
684
685 void W_Plasma_Touch (void)
686 {
687         if (other.classname == "player" || other.classname == "corpse" || other.classname == "gib")
688                 Damage (self.owner, self.origin, other, 0, 15);
689
690         ImpactEffect (self, IT_ELECTRO);
691
692         remove (self);
693 }
694
695 const float w_plasma_anim_interval = 0.05;
696 .float lifetime;
697 void() W_Plasma_Think =
698 {
699         animate_sprite(0, 5);
700         
701         self.nextthink = time+ w_plasma_anim_interval;
702
703         if (self.lifetime < time) // time is up
704                 SUB_Remove();
705 };
706
707 void W_Electro_Attack2 (void)
708 {
709         entity  proj;
710         
711         sound (self, CHAN_WEAPON, "weapons/LazerGun_Fire.wav", 1, ATTN_NORM);
712         
713         proj = spawn ();
714         proj.owner = self;
715         proj.classname = "plasma";
716         
717         proj.movetype = MOVETYPE_FLY;
718         proj.solid = SOLID_BBOX;
719         proj.effects = EF_DIMLIGHT;
720         
721         makevectors (self.v_angle);
722         
723         setmodel (proj, "models/sprites/plasmashot.spr32");
724         setsize (proj, '0 0 0', '0 0 0');
725         setorigin (proj, self.origin + self.view_ofs + v_forward * 5 + v_right * 5 + v_up * -12);
726         
727         proj.velocity = v_forward * 5000;
728         proj.touch = W_Plasma_Touch;
729         proj.think = W_Plasma_Think;
730         proj.nextthink = time + w_plasma_anim_interval;
731         proj.lifetime = time + 1.5;
732
733         self.attack_finished = time + 0.175;
734         self.ammo_cells = self.ammo_cells - 1;
735 }
736
737 void W_Crylink_Attack (void)
738 {
739         vector  org;
740         
741         sound (self, CHAN_WEAPON, "weapons/crylink.wav", 1, ATTN_NORM);
742         org = self.origin + self.view_ofs + v_forward * 18 + v_right * 7 + v_up * -9;
743         makevectors (self.v_angle);
744
745         // FIXME: make it accurate!
746
747         FireRailgunBullet (org, 25, v_forward); 
748
749         traceline (org, self.origin + self.view_ofs + (v_forward * 4096), FALSE, self);
750
751         WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
752         WriteByte (MSG_BROADCAST, 76);
753         WriteCoord (MSG_BROADCAST, org_x);
754         WriteCoord (MSG_BROADCAST, org_y);
755         WriteCoord (MSG_BROADCAST, org_z);
756         WriteCoord (MSG_BROADCAST, trace_endpos_x);
757         WriteCoord (MSG_BROADCAST, trace_endpos_y);
758         WriteCoord (MSG_BROADCAST, trace_endpos_z);
759         WriteCoord (MSG_BROADCAST, self.v_angle_x);
760         WriteCoord (MSG_BROADCAST, self.v_angle_y);
761         WriteCoord (MSG_BROADCAST, self.v_angle_z);
762
763         te_spike (trace_endpos);
764
765         self.ammo_cells = self.ammo_cells - 0.25;
766         self.attack_finished = time + 0.165;
767 }
768
769 void W_Crylink_Attack2 (void)
770 {
771         vector  org;
772         vector  dir;
773         
774         makevectors (self.v_angle);
775
776         org = self.origin + self.view_ofs + v_forward * 19 + v_right * 5 + v_up * -7;
777         
778         traceline (org, self.origin + self.view_ofs + v_forward * 4096 + v_right * (random () * 100 - 50) + v_up * (random () * 100 - 50), FALSE, self);
779
780         Damage (self, trace_endpos, trace_ent, 0, 20);  
781         
782         te_lightning1 (self, org, trace_endpos);
783         
784         self.ammo_cells = self.ammo_cells - 0.25;
785         self.attack_finished = time + 0.075;
786 }
787
788 void W_Nex_Attack (void)
789 {
790         vector  org;
791         vector  dir;
792         
793         sound (self, CHAN_WEAPON, "weapons/NexFire.wav", 1, ATTN_NORM);
794         //self.effects = EF_MUZZLEFLASH;
795         self.punchangle_x = -4;
796         
797         makevectors (self.v_angle);
798
799         org = self.origin + self.view_ofs + v_forward * 18 + v_right * 8 + v_up * -5;
800         
801         // FIXME: iterate to hit multiple guys
802         // FIXME: make it accurate!
803
804         traceline (org, self.origin + self.view_ofs + (v_forward * 4096), FALSE, self);
805
806         FireRailgunBullet (org, 90, v_forward); 
807
808         WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
809         WriteByte (MSG_BROADCAST, 76);
810         WriteCoord (MSG_BROADCAST, org_x);
811         WriteCoord (MSG_BROADCAST, org_y);
812         WriteCoord (MSG_BROADCAST, org_z);
813         WriteCoord (MSG_BROADCAST, trace_endpos_x);
814         WriteCoord (MSG_BROADCAST, trace_endpos_y);
815         WriteCoord (MSG_BROADCAST, trace_endpos_z);
816         WriteCoord (MSG_BROADCAST, self.v_angle_x);
817         WriteCoord (MSG_BROADCAST, self.v_angle_y);
818         WriteCoord (MSG_BROADCAST, self.v_angle_z);
819         
820         te_plasmaburn (trace_endpos);
821         
822         dir = trace_plane_normal * 100;
823         WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
824         WriteByte (MSG_BROADCAST, TE_FLAMEJET);
825         WriteCoord (MSG_BROADCAST, trace_endpos_x);
826         WriteCoord (MSG_BROADCAST, trace_endpos_y);
827         WriteCoord (MSG_BROADCAST, trace_endpos_z);
828         WriteCoord (MSG_BROADCAST, dir_x);
829         WriteCoord (MSG_BROADCAST, dir_y);
830         WriteCoord (MSG_BROADCAST, dir_z);
831         WriteByte (MSG_BROADCAST, 255);
832         
833         PointSound (trace_endpos, "weapons/NexImpact.wav", 1, ATTN_NORM);
834         
835         self.attack_finished = time + 1;
836         self.ammo_cells = self.ammo_cells - 1;
837 }
838
839 void W_Nex_Attack2 (void)
840 {
841
842 }
843
844 void W_Hagar_Explode (void)
845 {
846         ImpactEffect (self, IT_HAGAR);
847
848         RadiusDamage (self.owner, self, 0, 100, world);
849
850         remove (self);
851 }
852
853 void W_Hagar_Touch (void)
854 {
855         if (other == self.owner)
856                 return;
857         else if (pointcontents (self.origin) == CONTENT_SKY)
858         {
859                 remove (self);
860                 return;
861         }
862         
863         W_Hagar_Explode ();
864 }
865
866 void W_Hagar_Attack (void)
867 {
868         entity  missile;
869         vector  org;
870         
871         sound (self, CHAN_WEAPON, "weapons/Hagar_Fire.wav", 1, ATTN_NORM);
872         
873         missile = spawn ();
874         missile.owner = self;
875         missile.classname = "rocket";
876         
877         missile.takedamage = DAMAGE_YES;
878         missile.health = 1;
879         missile.event_hurt = W_Hagar_Explode;
880         
881         missile.movetype = MOVETYPE_FLY;
882         missile.solid = SOLID_BBOX;
883         setmodel (missile, "models/hagarmissile.mdl");
884         setsize (missile, '0 0 0', '0 0 0');
885         
886         makevectors (self.v_angle);
887         
888         org = self.origin + self.view_ofs + v_forward * 20 + v_right * 4 + v_up * -15;
889         
890         setorigin (missile, org);
891         missile.velocity = v_forward * 2000;
892         missile.angles = vectoangles (missile.velocity);
893         
894         missile.touch = W_Hagar_Touch;
895         missile.think = SUB_Remove;
896         missile.nextthink = time + 1;
897         
898         self.attack_finished = time + 0.2;
899         self.ammo_rockets = self.ammo_rockets - 0.25;
900 }
901
902 void W_Hagar_Attack2 (void)
903 {
904         entity  missile;
905         vector  org;
906         
907         sound (self, CHAN_WEAPON, "weapons/Hagar_Fire.wav", 1, ATTN_NORM);
908         
909         missile = spawn ();
910         missile.owner = self;
911         missile.classname = "rocket";
912         
913         missile.takedamage = DAMAGE_YES;
914         missile.health = 1;
915         missile.event_hurt = W_Hagar_Explode;
916         
917         missile.movetype = MOVETYPE_FLY;
918         missile.solid = SOLID_BBOX;
919         setmodel (missile, "models/hagarmissile.mdl");
920         setsize (missile, '0 0 0', '0 0 0');
921         
922         makevectors (self.v_angle);
923         
924         org = self.origin + self.view_ofs + v_forward * 20 + v_right * 4 + v_up * -15;
925         
926         setorigin (missile, org);
927         missile.velocity = v_forward * 15000;
928         missile.angles = vectoangles (missile.velocity);
929         
930         missile.touch = W_Hagar_Touch;
931         missile.think = SUB_Remove;
932         missile.nextthink = time + 1;
933         
934         self.attack_finished = time + 0.7;
935         self.ammo_rockets = self.ammo_rockets - 0.25;
936 }
937
938 void W_Rocket_Explode (entity ignore)
939 {
940         ImpactEffect (self, IT_ROCKET_LAUNCHER);
941
942         RadiusDamage (self.owner, self, 0, 100, ignore);
943
944         remove (self);
945 }
946
947 void W_Rocket_Touch (void)
948 {
949         if (other == self.owner)
950                 return;
951         else if (pointcontents (self.origin) == CONTENT_SKY)
952         {
953                 remove (self);
954                 return;
955         }
956         else if (other.classname == "player" || other.classname == "corpse")
957         {
958                 Damage (self.owner, self.origin, other, 0, 100);
959                 W_Rocket_Explode (other);
960         }
961         else
962                 W_Rocket_Explode (world);
963 }
964
965 void W_Rocket_Attack (void)
966 {
967         entity  missile;
968         vector  org;
969         
970         sound (self, CHAN_WEAPON, "weapons/Rocket_Fire.wav", 1, ATTN_NORM);
971         
972         missile = spawn ();
973         missile.owner = self;
974         missile.classname = "rocket";
975         
976         missile.takedamage = DAMAGE_YES;
977         missile.health = 1;
978         missile.event_hurt = W_Rocket_Explode;
979         
980         missile.movetype = MOVETYPE_FLY;
981         missile.solid = SOLID_BBOX;
982         setmodel (missile, "models/rocketmissile.mdl");
983         setsize (missile, '0 0 0', '0 0 0');
984         
985         makevectors (self.v_angle);
986         
987         org = self.origin + self.view_ofs + v_forward * 20 + v_right * 4 + v_up * -15;
988         
989         setorigin (missile, org);
990         missile.velocity = v_forward * 2500;
991         missile.angles = vectoangles (missile.velocity);
992         
993         missile.touch = W_Rocket_Touch;
994         missile.think = SUB_Remove;
995         missile.nextthink = time + 1;
996         
997         self.attack_finished = time + 0.5;
998         self.ammo_rockets = self.ammo_rockets - 1;
999         
1000 }
1001
1002 void W_Rocket_Attack2 (void)
1003 {
1004
1005 }
1006
1007 void W_Attack (void)
1008 {
1009         if (self.deadflag != DEAD_NO)
1010         {
1011                 if (self.death_time < time)
1012                         PutClientInServer();
1013
1014                 return;
1015         }
1016
1017         if (!W_CheckAmmo ())
1018                 return;
1019
1020         if (self.weapon == IT_LASER)
1021                 W_Laser_Attack ();
1022         else if (self.weapon == IT_UZI)
1023                 W_Uzi_Attack ();
1024         else if (self.weapon == IT_SHOTGUN)
1025                 W_Shotgun_Attack ();
1026         else if (self.weapon == IT_GRENADE_LAUNCHER)
1027                 W_Grenade_Attack ();
1028         else if (self.weapon == IT_ELECTRO)
1029                 W_Electro_Attack ();
1030         else if (self.weapon == IT_CRYLINK)
1031                 W_Crylink_Attack ();
1032         else if (self.weapon == IT_NEX)
1033                 W_Nex_Attack ();
1034         else if (self.weapon == IT_HAGAR)
1035                 W_Hagar_Attack ();
1036         else if (self.weapon == IT_ROCKET_LAUNCHER)
1037                 W_Rocket_Attack ();
1038
1039         W_UpdateAmmo ();
1040 }
1041
1042 void W_SecondaryAttack (void)
1043 {
1044         if (self.deadflag != DEAD_NO)
1045         {
1046                 if (self.death_time < time)
1047                         PutClientInServer();
1048
1049                 return;
1050         }
1051
1052         if (!W_CheckAmmo ())
1053                 return;
1054
1055         if (self.weapon == IT_LASER)
1056                 W_Laser_Attack2 ();
1057         else if (self.weapon == IT_UZI)
1058                 W_Uzi_Attack2 ();
1059         else if (self.weapon == IT_SHOTGUN)
1060                 W_Shotgun_Attack2 ();
1061         else if (self.weapon == IT_GRENADE_LAUNCHER)
1062                 W_Grenade_Attack2 ();
1063         else if (self.weapon == IT_ELECTRO)
1064                 W_Electro_Attack2 ();
1065         else if (self.weapon == IT_CRYLINK)
1066                 W_Crylink_Attack2 ();
1067         else if (self.weapon == IT_NEX)
1068                 W_Nex_Attack2 ();
1069         else if (self.weapon == IT_HAGAR)
1070                 W_Hagar_Attack2 ();
1071         else if (self.weapon == IT_ROCKET_LAUNCHER)
1072                 W_Rocket_Attack2 ();
1073
1074         W_UpdateAmmo ();
1075 }