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