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