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