]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/common/weapons/w_electro.qc
Merge branch 'Mario/qc_updates' into TimePath/csqc_prediction
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / weapons / w_electro.qc
1 #ifdef REGISTER_WEAPON
2 REGISTER_WEAPON(
3 /* WEP_##id  */ ELECTRO,
4 /* function  */ W_Electro,
5 /* ammotype  */ ammo_cells,
6 /* impulse   */ 5,
7 /* flags     */ WEP_FLAG_NORMAL | WEP_FLAG_RELOADABLE | WEP_FLAG_CANCLIMB | WEP_TYPE_SPLASH,
8 /* rating    */ BOT_PICKUP_RATING_MID,
9 /* color     */ '0 0.5 1',
10 /* modelname */ "electro",
11 /* simplemdl */ "foobar",
12 /* crosshair */ "gfx/crosshairelectro 0.5",
13 /* wepimg    */ "weaponelectro",
14 /* refname   */ "electro",
15 /* wepname   */ _("Electro")
16 );
17
18 #define ELECTRO_SETTINGS(w_cvar,w_prop) ELECTRO_SETTINGS_LIST(w_cvar, w_prop, ELECTRO, electro)
19 #define ELECTRO_SETTINGS_LIST(w_cvar,w_prop,id,sn) \
20         w_cvar(id, sn, BOTH, ammo) \
21         w_cvar(id, sn, BOTH, animtime) \
22         w_cvar(id, sn, BOTH, damage) \
23         w_cvar(id, sn, BOTH, edgedamage) \
24         w_cvar(id, sn, BOTH, force) \
25         w_cvar(id, sn, BOTH, radius) \
26         w_cvar(id, sn, BOTH, refire) \
27         w_cvar(id, sn, BOTH, speed) \
28         w_cvar(id, sn, BOTH, spread) \
29         w_cvar(id, sn, BOTH, lifetime) \
30         w_cvar(id, sn, PRI,  comboradius) \
31         w_cvar(id, sn, PRI,  midaircombo_explode) \
32         w_cvar(id, sn, PRI,  midaircombo_interval) \
33         w_cvar(id, sn, PRI,  midaircombo_radius) \
34         w_cvar(id, sn, SEC,  bouncefactor) \
35         w_cvar(id, sn, SEC,  bouncestop) \
36         w_cvar(id, sn, SEC,  count) \
37         w_cvar(id, sn, SEC,  damageforcescale) \
38         w_cvar(id, sn, SEC,  damagedbycontents) \
39         w_cvar(id, sn, SEC,  health) \
40         w_cvar(id, sn, SEC,  refire2) \
41         w_cvar(id, sn, SEC,  speed_up) \
42         w_cvar(id, sn, SEC,  speed_z) \
43         w_cvar(id, sn, SEC,  touchexplode) \
44         w_cvar(id, sn, NONE, combo_comboradius) \
45         w_cvar(id, sn, NONE, combo_comboradius_thruwall) \
46         w_cvar(id, sn, NONE, combo_damage) \
47         w_cvar(id, sn, NONE, combo_edgedamage) \
48         w_cvar(id, sn, NONE, combo_force) \
49         w_cvar(id, sn, NONE, combo_radius) \
50         w_cvar(id, sn, NONE, combo_speed) \
51         w_cvar(id, sn, NONE, combo_safeammocheck) \
52         w_prop(id, sn, float,  reloading_ammo, reload_ammo) \
53         w_prop(id, sn, float,  reloading_time, reload_time) \
54         w_prop(id, sn, float,  switchdelay_raise, switchdelay_raise) \
55         w_prop(id, sn, float,  switchdelay_drop, switchdelay_drop) \
56         w_prop(id, sn, string, weaponreplace, weaponreplace) \
57         w_prop(id, sn, float,  weaponstart, weaponstart) \
58         w_prop(id, sn, float,  weaponstartoverride, weaponstartoverride) \
59         w_prop(id, sn, float,  weaponthrowable, weaponthrowable)
60
61 #ifdef SVQC
62 ELECTRO_SETTINGS(WEP_ADD_CVAR, WEP_ADD_PROP)
63 .float electro_count;
64 .float electro_secondarytime;
65 void W_Electro_ExplodeCombo(void);
66 #endif
67 #else
68 #ifdef SVQC
69 void spawnfunc_weapon_electro(void) { weapon_defaultspawnfunc(WEP_ELECTRO); }
70
71 void W_Electro_TriggerCombo(vector org, float rad, entity own)
72 {
73         entity e = WarpZone_FindRadius(org, rad, !WEP_CVAR(electro, combo_comboradius_thruwall));
74         while(e)
75         {
76                 if(e.classname == "electro_orb")
77                 {
78                         // do we allow thruwall triggering?
79                         if(WEP_CVAR(electro, combo_comboradius_thruwall))
80                         {
81                                 // if distance is greater than thruwall distance, check to make sure it's not through a wall
82                                 if(vlen(e.WarpZone_findradius_dist) > WEP_CVAR(electro, combo_comboradius_thruwall))
83                                 {
84                                         WarpZone_TraceLine(org, e.origin, MOVE_NOMONSTERS, e);
85                                         if(trace_fraction != 1)
86                                         {
87                                                 // trigger is through a wall and outside of thruwall range, abort
88                                                 e = e.chain;
89                                                 continue;
90                                         }
91                                 }
92                         }
93
94                         // change owner to whoever caused the combo explosion
95                         e.realowner = own;
96                         e.takedamage = DAMAGE_NO;
97                         e.classname = "electro_orb_chain";
98
99                         // now set the next one to trigger as well
100                         e.think = W_Electro_ExplodeCombo;
101
102                         // delay combo chains, looks cooler
103                         e.nextthink =
104                                 (
105                                         time
106                                         +
107                                         (WEP_CVAR(electro, combo_speed) ?
108                                                 (vlen(e.WarpZone_findradius_dist) / WEP_CVAR(electro, combo_speed))
109                                                 :
110                                                 0
111                                         )
112                                 );
113                 }
114                 e = e.chain;
115         }
116 }
117
118 void W_Electro_ExplodeCombo(void)
119 {
120         W_Electro_TriggerCombo(self.origin, WEP_CVAR(electro, combo_comboradius), self.realowner);
121
122         self.event_damage = func_null;
123
124         RadiusDamage(
125                 self,
126                 self.realowner,
127                 WEP_CVAR(electro, combo_damage),
128                 WEP_CVAR(electro, combo_edgedamage),
129                 WEP_CVAR(electro, combo_radius),
130                 world,
131                 world,
132                 WEP_CVAR(electro, combo_force),
133                 WEP_ELECTRO | HITTYPE_BOUNCE, // use THIS type for a combo because primary can't bounce
134                 world
135         );
136
137         remove(self);
138 }
139
140 void W_Electro_Explode(void)
141 {
142         if(other.takedamage == DAMAGE_AIM)
143                 if(IS_PLAYER(other))
144                         if(DIFF_TEAM(self.realowner, other))
145                                 if(other.deadflag == DEAD_NO)
146                                         if(IsFlying(other))
147                                                 Send_Notification(NOTIF_ONE, self.realowner, MSG_ANNCE, ANNCE_ACHIEVEMENT_ELECTROBITCH);
148
149         self.event_damage = func_null;
150         self.takedamage = DAMAGE_NO;
151
152         if(self.movetype == MOVETYPE_BOUNCE)
153         {
154                 RadiusDamage(
155                         self,
156                         self.realowner,
157                         WEP_CVAR_SEC(electro, damage),
158                         WEP_CVAR_SEC(electro, edgedamage),
159                         WEP_CVAR_SEC(electro, radius),
160                         world,
161                         world,
162                         WEP_CVAR_SEC(electro, force),
163                         self.projectiledeathtype,
164                         other
165                 );
166         }
167         else
168         {
169                 W_Electro_TriggerCombo(self.origin, WEP_CVAR_PRI(electro, comboradius), self.realowner);
170                 RadiusDamage(
171                         self,
172                         self.realowner,
173                         WEP_CVAR_PRI(electro, damage),
174                         WEP_CVAR_PRI(electro, edgedamage),
175                         WEP_CVAR_PRI(electro, radius),
176                         world,
177                         world,
178                         WEP_CVAR_PRI(electro, force),
179                         self.projectiledeathtype,
180                         other
181                 );
182         }
183
184         remove(self);
185 }
186
187 void W_Electro_TouchExplode(void)
188 {
189         PROJECTILE_TOUCH;
190         W_Electro_Explode();
191 }
192
193 void W_Electro_Bolt_Think(void)
194 {
195         if(time >= self.ltime)
196         {
197                 self.use();
198                 return;
199         }
200
201         if(WEP_CVAR_PRI(electro, midaircombo_radius))
202         {
203                 float found = 0;
204                 entity e = WarpZone_FindRadius(self.origin, WEP_CVAR_PRI(electro, midaircombo_radius), true);
205
206                 // loop through nearby orbs and trigger them
207                 while(e)
208                 {
209                         if(e.classname == "electro_orb")
210                         {
211                                 // change owner to whoever caused the combo explosion
212                                 e.realowner = self.realowner;
213                                 e.takedamage = DAMAGE_NO;
214                                 e.classname = "electro_orb_chain";
215
216                                 // now set the next one to trigger as well
217                                 e.think = W_Electro_ExplodeCombo;
218
219                                 // delay combo chains, looks cooler
220                                 e.nextthink =
221                                         (
222                                                 time
223                                                 +
224                                                 (WEP_CVAR(electro, combo_speed) ?
225                                                         (vlen(e.WarpZone_findradius_dist) / WEP_CVAR(electro, combo_speed))
226                                                         :
227                                                         0
228                                                 )
229                                         );
230
231                                 ++found;
232                         }
233                         e = e.chain;
234                 }
235
236                 // if we triggered an orb, should we explode? if not, lets try again next time
237                 if(found && WEP_CVAR_PRI(electro, midaircombo_explode))
238                         { self.use(); }
239                 else
240                         { self.nextthink = min(time + WEP_CVAR_PRI(electro, midaircombo_interval), self.ltime); }
241         }
242         else { self.nextthink = self.ltime; }
243 }
244
245 void W_Electro_Attack_Bolt(void)
246 {
247         entity proj;
248
249         W_DecreaseAmmo(WEP_CVAR_PRI(electro, ammo));
250
251         W_SetupShot_ProjectileSize(
252                 self,
253                 '0 0 -3',
254                 '0 0 -3',
255                 false,
256                 2,
257                 "weapons/electro_fire.wav",
258                 CH_WEAPON_A,
259                 WEP_CVAR_PRI(electro, damage)
260         );
261
262         pointparticles(particleeffectnum("electro_muzzleflash"), w_shotorg, w_shotdir * 1000, 1);
263
264         proj = spawn();
265         proj.classname = "electro_bolt";
266         proj.owner = proj.realowner = self;
267         proj.bot_dodge = true;
268         proj.bot_dodgerating = WEP_CVAR_PRI(electro, damage);
269         proj.use = W_Electro_Explode;
270         proj.think = W_Electro_Bolt_Think;
271         proj.nextthink = time;
272         proj.ltime = time + WEP_CVAR_PRI(electro, lifetime);
273         PROJECTILE_MAKETRIGGER(proj);
274         proj.projectiledeathtype = WEP_ELECTRO;
275         setorigin(proj, w_shotorg);
276
277         proj.movetype = MOVETYPE_FLY;
278         W_SetupProjVelocity_PRI(proj, electro);
279         proj.angles = vectoangles(proj.velocity);
280         proj.touch = W_Electro_TouchExplode;
281         setsize(proj, '0 0 -3', '0 0 -3');
282         proj.flags = FL_PROJECTILE;
283         proj.missile_flags = MIF_SPLASH;
284
285         CSQCProjectile(proj, true, PROJECTILE_ELECTRO_BEAM, true);
286
287         other = proj; MUTATOR_CALLHOOK(EditProjectile);
288 }
289
290 void W_Electro_Orb_Touch(void)
291 {
292         PROJECTILE_TOUCH;
293         if(other.takedamage == DAMAGE_AIM)
294                 { if(WEP_CVAR_SEC(electro, touchexplode)) { W_Electro_Explode(); } }
295         else
296         {
297                 //UpdateCSQCProjectile(self);
298                 spamsound(self, CH_SHOTS, "weapons/electro_bounce.wav", VOL_BASE, ATTEN_NORM);
299                 self.projectiledeathtype |= HITTYPE_BOUNCE;
300         }
301 }
302
303 void W_Electro_Orb_Damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
304 {
305         if(self.health <= 0)
306                 return;
307
308         // note: combos are usually triggered by W_Electro_TriggerCombo, not damage
309         float is_combo = (inflictor.classname == "electro_orb_chain" || inflictor.classname == "electro_bolt");
310
311         if(!W_CheckProjectileDamage(inflictor.realowner, self.realowner, deathtype, (is_combo ? 1 : -1)))
312                 return; // g_projectiles_damage says to halt
313
314         self.health = self.health - damage;
315         if(self.health <= 0)
316         {
317                 self.takedamage = DAMAGE_NO;
318                 self.nextthink = time;
319                 if(is_combo)
320                 {
321                         // change owner to whoever caused the combo explosion
322                         self.realowner = inflictor.realowner;
323                         self.classname = "electro_orb_chain";
324                         self.think = W_Electro_ExplodeCombo;
325                         self.nextthink = time +
326                                 (
327                                         // bound the length, inflictor may be in a galaxy far far away (warpzones)
328                                         min(
329                                                 WEP_CVAR(electro, combo_radius),
330                                                 vlen(self.origin - inflictor.origin)
331                                         )
332                                         /
333                                         // delay combo chains, looks cooler
334                                         WEP_CVAR(electro, combo_speed)
335                                 );
336                 }
337                 else
338                 {
339                         self.use = W_Electro_Explode;
340                         self.think = adaptor_think2use; // not _hittype_splash, as this runs "immediately"
341                 }
342         }
343 }
344
345 void W_Electro_Attack_Orb(void)
346 {
347         W_DecreaseAmmo(WEP_CVAR_SEC(electro, ammo));
348
349         W_SetupShot_ProjectileSize(
350                 self,
351                 '0 0 -4',
352                 '0 0 -4',
353                 false,
354                 2,
355                 "weapons/electro_fire2.wav",
356                 CH_WEAPON_A,
357                 WEP_CVAR_SEC(electro, damage)
358         );
359
360         w_shotdir = v_forward; // no TrueAim for grenades please
361
362         pointparticles(particleeffectnum("electro_muzzleflash"), w_shotorg, w_shotdir * 1000, 1);
363
364         entity proj = spawn();
365         proj.classname = "electro_orb";
366         proj.owner = proj.realowner = self;
367         proj.use = W_Electro_Explode;
368         proj.think = adaptor_think2use_hittype_splash;
369         proj.bot_dodge = true;
370         proj.bot_dodgerating = WEP_CVAR_SEC(electro, damage);
371         proj.nextthink = time + WEP_CVAR_SEC(electro, lifetime);
372         PROJECTILE_MAKETRIGGER(proj);
373         proj.projectiledeathtype = WEP_ELECTRO | HITTYPE_SECONDARY;
374         setorigin(proj, w_shotorg);
375
376         //proj.glow_size = 50;
377         //proj.glow_color = 45;
378         proj.movetype = MOVETYPE_BOUNCE;
379         W_SetupProjVelocity_UP_SEC(proj, electro);
380         proj.touch = W_Electro_Orb_Touch;
381         setsize(proj, '0 0 -4', '0 0 -4');
382         proj.takedamage = DAMAGE_YES;
383         proj.damageforcescale = WEP_CVAR_SEC(electro, damageforcescale);
384         proj.health = WEP_CVAR_SEC(electro, health);
385         proj.event_damage = W_Electro_Orb_Damage;
386         proj.flags = FL_PROJECTILE;
387         proj.damagedbycontents = (WEP_CVAR_SEC(electro, damagedbycontents));
388
389         proj.bouncefactor = WEP_CVAR_SEC(electro, bouncefactor);
390         proj.bouncestop = WEP_CVAR_SEC(electro, bouncestop);
391         proj.missile_flags = MIF_SPLASH | MIF_ARC;
392
393 #if 0
394         entity p2;
395         p2 = spawn();
396         copyentity(proj, p2);
397         setmodel(p2, "models/ebomb.mdl");
398         setsize(p2, proj.mins, proj.maxs);
399 #endif
400
401         CSQCProjectile(proj, true, PROJECTILE_ELECTRO, false); // no culling, it has sound
402
403         other = proj; MUTATOR_CALLHOOK(EditProjectile);
404 }
405
406 void W_Electro_CheckAttack(void)
407 {
408         if(self.electro_count > 1)
409         if(self.BUTTON_ATCK2)
410         if(weapon_prepareattack(1, -1))
411         {
412                 W_Electro_Attack_Orb();
413                 self.electro_count -= 1;
414                 weapon_thinkf(WFRAME_FIRE2, WEP_CVAR_SEC(electro, animtime), W_Electro_CheckAttack);
415                 return;
416         }
417         // WEAPONTODO: when the player releases the button, cut down the length of refire2?
418         w_ready();
419 }
420
421 .float bot_secondary_electromooth;
422 float W_Electro(float req)
423 {
424         float ammo_amount;
425         switch(req)
426         {
427                 case WR_AIM:
428                 {
429                         self.BUTTON_ATCK = self.BUTTON_ATCK2 = false;
430                         if(vlen(self.origin-self.enemy.origin) > 1000) { self.bot_secondary_electromooth = 0; }
431                         if(self.bot_secondary_electromooth == 0)
432                         {
433                                 float shoot;
434
435                                 if(WEP_CVAR_PRI(electro, speed))
436                                         shoot = bot_aim(WEP_CVAR_PRI(electro, speed), 0, WEP_CVAR_PRI(electro, lifetime), false);
437                                 else
438                                         shoot = bot_aim(1000000, 0, 0.001, false);
439
440                                 if(shoot)
441                                 {
442                                         self.BUTTON_ATCK = true;
443                                         if(random() < 0.01) self.bot_secondary_electromooth = 1;
444                                 }
445                         }
446                         else
447                         {
448                                 if(bot_aim(WEP_CVAR_SEC(electro, speed), WEP_CVAR_SEC(electro, speed_up), WEP_CVAR_SEC(electro, lifetime), true))
449                                 {
450                                         self.BUTTON_ATCK2 = true;
451                                         if(random() < 0.03) self.bot_secondary_electromooth = 0;
452                                 }
453                         }
454
455                         return true;
456                 }
457                 case WR_THINK:
458                 {
459                         if(autocvar_g_balance_electro_reload_ammo) // forced reload // WEAPONTODO
460                         {
461                                 ammo_amount = 0;
462                                 if(self.clip_load >= WEP_CVAR_PRI(electro, ammo))
463                                         ammo_amount = 1;
464                                 if(self.clip_load >= WEP_CVAR_SEC(electro, ammo))
465                                         ammo_amount += 1;
466
467                                 if(!ammo_amount)
468                                 {
469                                         WEP_ACTION(self.weapon, WR_RELOAD);
470                                         return false;
471                                 }
472
473                                 return true;
474                         }
475
476                         if(self.BUTTON_ATCK)
477                         {
478                                 if(weapon_prepareattack(0, WEP_CVAR_PRI(electro, refire)))
479                                 {
480                                                 W_Electro_Attack_Bolt();
481                                                 weapon_thinkf(WFRAME_FIRE1, WEP_CVAR_PRI(electro, animtime), w_ready);
482                                 }
483                         }
484                         else if(self.BUTTON_ATCK2)
485                         {
486                                 if(time >= self.electro_secondarytime)
487                                 if(weapon_prepareattack(1, WEP_CVAR_SEC(electro, refire)))
488                                 {
489                                         W_Electro_Attack_Orb();
490                                         self.electro_count = WEP_CVAR_SEC(electro, count);
491                                         weapon_thinkf(WFRAME_FIRE2, WEP_CVAR_SEC(electro, animtime), W_Electro_CheckAttack);
492                                         self.electro_secondarytime = time + WEP_CVAR_SEC(electro, refire2) * W_WeaponRateFactor();
493                                 }
494                         }
495
496                         return true;
497                 }
498                 case WR_INIT:
499                 {
500                         precache_model("models/weapons/g_electro.md3");
501                         precache_model("models/weapons/v_electro.md3");
502                         precache_model("models/weapons/h_electro.iqm");
503                         precache_sound("weapons/electro_bounce.wav");
504                         precache_sound("weapons/electro_fire.wav");
505                         precache_sound("weapons/electro_fire2.wav");
506                         precache_sound("weapons/electro_impact.wav");
507                         precache_sound("weapons/electro_impact_combo.wav");
508                         ELECTRO_SETTINGS(WEP_SKIP_CVAR, WEP_SET_PROP);
509                         return true;
510                 }
511                 case WR_CHECKAMMO1:
512                 {
513                         ammo_amount = self.WEP_AMMO(ELECTRO) >= WEP_CVAR_PRI(electro, ammo);
514                         ammo_amount += self.(weapon_load[WEP_ELECTRO]) >= WEP_CVAR_PRI(electro, ammo);
515                         return ammo_amount;
516                 }
517                 case WR_CHECKAMMO2:
518                 {
519                         if(WEP_CVAR(electro, combo_safeammocheck)) // true if you can fire at least one secondary blob AND one primary shot after it, otherwise false.
520                         {
521                                 ammo_amount = self.WEP_AMMO(ELECTRO) >= WEP_CVAR_SEC(electro, ammo) + WEP_CVAR_PRI(electro, ammo);
522                                 ammo_amount += self.(weapon_load[WEP_ELECTRO]) >= WEP_CVAR_SEC(electro, ammo) + WEP_CVAR_PRI(electro, ammo);
523                         }
524                         else
525                         {
526                                 ammo_amount = self.WEP_AMMO(ELECTRO) >= WEP_CVAR_SEC(electro, ammo);
527                                 ammo_amount += self.(weapon_load[WEP_ELECTRO]) >= WEP_CVAR_SEC(electro, ammo);
528                         }
529                         return ammo_amount;
530                 }
531                 case WR_CONFIG:
532                 {
533                         ELECTRO_SETTINGS(WEP_CONFIG_WRITE_CVARS, WEP_CONFIG_WRITE_PROPS);
534                         return true;
535                 }
536                 case WR_RESETPLAYER:
537                 {
538                         self.electro_secondarytime = time;
539                         return true;
540                 }
541                 case WR_RELOAD:
542                 {
543                         W_Reload(min(WEP_CVAR_PRI(electro, ammo), WEP_CVAR_SEC(electro, ammo)), "weapons/reload.wav");
544                         return true;
545                 }
546                 case WR_SUICIDEMESSAGE:
547                 {
548                         if(w_deathtype & HITTYPE_SECONDARY)
549                                 return WEAPON_ELECTRO_SUICIDE_ORBS;
550                         else
551                                 return WEAPON_ELECTRO_SUICIDE_BOLT;
552                 }
553                 case WR_KILLMESSAGE:
554                 {
555                         if(w_deathtype & HITTYPE_SECONDARY)
556                         {
557                                 return WEAPON_ELECTRO_MURDER_ORBS;
558                         }
559                         else
560                         {
561                                 if(w_deathtype & HITTYPE_BOUNCE)
562                                         return WEAPON_ELECTRO_MURDER_COMBO;
563                                 else
564                                         return WEAPON_ELECTRO_MURDER_BOLT;
565                         }
566                 }
567         }
568         return false;
569 }
570 #endif
571 #ifdef CSQC
572 float W_Electro(float req)
573 {
574         switch(req)
575         {
576                 case WR_IMPACTEFFECT:
577                 {
578                         vector org2;
579                         org2 = w_org + w_backoff * 6;
580                         if(w_deathtype & HITTYPE_SECONDARY)
581                         {
582                                 pointparticles(particleeffectnum("electro_ballexplode"), org2, '0 0 0', 1);
583                                 if(!w_issilent)
584                                         sound(self, CH_SHOTS, "weapons/electro_impact.wav", VOL_BASE, ATTEN_NORM);
585                         }
586                         else
587                         {
588                                 if(w_deathtype & HITTYPE_BOUNCE)
589                                 {
590                                         // this is sent as "primary (w_deathtype & HITTYPE_BOUNCE)" to distinguish it from (w_deathtype & HITTYPE_SECONDARY) bounced balls
591                                         pointparticles(particleeffectnum("electro_combo"), org2, '0 0 0', 1);
592                                         if(!w_issilent)
593                                                 sound(self, CH_SHOTS, "weapons/electro_impact_combo.wav", VOL_BASE, ATTEN_NORM);
594                                 }
595                                 else
596                                 {
597                                         pointparticles(particleeffectnum("electro_impact"), org2, '0 0 0', 1);
598                                         if(!w_issilent)
599                                                 sound(self, CH_SHOTS, "weapons/electro_impact.wav", VOL_BASE, ATTEN_NORM);
600                                 }
601                         }
602
603                         return true;
604                 }
605                 case WR_INIT:
606                 {
607                         precache_sound("weapons/electro_impact.wav");
608                         precache_sound("weapons/electro_impact_combo.wav");
609                         return true;
610                 }
611                 case WR_ZOOMRETICLE:
612                 {
613                         // no weapon specific image for this weapon
614                         return false;
615                 }
616         }
617         return false;
618 }
619 #endif
620 #endif