]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/server/w_electro.qc
Port new code to all weapons, part 1
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / w_electro.qc
1 #ifdef REGISTER_WEAPON
2 REGISTER_WEAPON(ELECTRO, w_electro, IT_CELLS, 5, WEP_FLAG_NORMAL | WEP_TYPE_SPLASH, BOT_PICKUP_RATING_MID, "electro", "electro", _("Electro"));
3 #else
4 #ifdef SVQC
5 .float electro_count;
6 .float electro_secondarytime;
7
8 // weapon load persistence, for weapons that support reloading
9 .float electro_load;
10
11 void W_Electro_SetAmmoCounter()
12 {
13         // set clip_load to the weapon we have switched to, if the gun uses reloading
14         if(!autocvar_g_balance_electro_reload_ammo)
15                 self.clip_load = 0; // also keeps crosshair ammo from displaying
16         else
17         {
18                 self.clip_load = self.electro_load;
19                 self.clip_size = autocvar_g_balance_electro_reload_ammo; // for the crosshair ammo display
20         }
21 }
22
23 void W_Electro_Reload()
24 {
25         self.reload_ammo_player = ammo_cells;
26         self.reload_ammo_min = min(autocvar_g_balance_electro_primary_ammo, autocvar_g_balance_electro_secondary_ammo);
27         self.reload_ammo_amount = autocvar_g_balance_electro_reload_ammo;
28         self.reload_time = autocvar_g_balance_electro_reload_time;
29         self.reload_sound = "weapons/reload.wav";
30
31         W_Reload();
32 }
33
34 void W_Plasma_Explode_Combo (void);
35
36 void W_Plasma_TriggerCombo(vector org, float rad, entity own)
37 {
38         local entity e;
39         e = WarpZone_FindRadius(org, rad, TRUE);
40         while (e)
41         {
42                 if (e.classname == "plasma")
43                 {
44                         // change owner to whoever caused the combo explosion
45                         e.owner = own;
46                         e.takedamage = DAMAGE_NO;
47                         e.classname = "plasma_chain";
48                         e.think = W_Plasma_Explode_Combo;
49                         e.nextthink = time + vlen(e.WarpZone_findradius_dist) / autocvar_g_balance_electro_combo_speed; // delay combo chains, looks cooler
50                 }
51                 e = e.chain;
52         }
53 }
54
55 void W_Plasma_Explode (void)
56 {
57         if(other.takedamage == DAMAGE_AIM)
58                 if(other.classname == "player")
59                         if(IsDifferentTeam(self.owner, other))
60                                 if(other.deadflag == DEAD_NO)
61                                         if(IsFlying(other))
62                                                 AnnounceTo(self.owner, "electrobitch");
63
64         self.event_damage = SUB_Null;
65         self.takedamage = DAMAGE_NO;
66         if (self.movetype == MOVETYPE_BOUNCE)
67         {
68                 RadiusDamage (self, self.owner, autocvar_g_balance_electro_secondary_damage, autocvar_g_balance_electro_secondary_edgedamage, autocvar_g_balance_electro_secondary_radius, world, autocvar_g_balance_electro_secondary_force, self.projectiledeathtype, other);
69         }
70         else
71         {
72                 W_Plasma_TriggerCombo(self.origin, autocvar_g_balance_electro_primary_comboradius, self.owner);
73                 RadiusDamage (self, self.owner, autocvar_g_balance_electro_primary_damage, autocvar_g_balance_electro_primary_edgedamage, autocvar_g_balance_electro_primary_radius, world, autocvar_g_balance_electro_primary_force, self.projectiledeathtype, other);
74         }
75
76         remove (self);
77 }
78
79 void W_Plasma_Explode_Combo (void)
80 {
81         W_Plasma_TriggerCombo(self.origin, autocvar_g_balance_electro_combo_comboradius, self.owner);
82
83         self.event_damage = SUB_Null;
84         RadiusDamage (self, self.owner, autocvar_g_balance_electro_combo_damage, autocvar_g_balance_electro_combo_edgedamage, autocvar_g_balance_electro_combo_radius, world, autocvar_g_balance_electro_combo_force, WEP_ELECTRO | HITTYPE_BOUNCE, world); // use THIS type for a combo because primary can't bounce
85         remove (self);
86 }
87
88 void W_Plasma_Touch (void)
89 {
90         //self.velocity = self.velocity  * 0.1;
91
92         PROJECTILE_TOUCH;
93         if (other.takedamage == DAMAGE_AIM) {
94                 W_Plasma_Explode ();
95         } else {
96                 //UpdateCSQCProjectile(self);
97                 spamsound (self, CHAN_PROJECTILE, "weapons/electro_bounce.wav", VOL_BASE, ATTN_NORM);
98                 self.projectiledeathtype |= HITTYPE_BOUNCE;
99         }
100 }
101
102 void W_Plasma_TouchExplode (void)
103 {
104         PROJECTILE_TOUCH;
105         W_Plasma_Explode ();
106 }
107
108 void W_Plasma_Damage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
109 {
110         if(self.health <= 0)
111                 return;
112         // note: combos are usually triggered by W_Plasma_TriggerCombo, not damage
113         self.health = self.health - damage;
114         if (self.health <= 0)
115         {
116                 self.takedamage = DAMAGE_NO;
117                 self.nextthink = time;
118                 if (inflictor.classname == "plasma_chain" || inflictor.classname == "plasma_prim")
119                 {
120                         // change owner to whoever caused the combo explosion
121                         self.owner = inflictor.owner;
122                         self.classname = "plasma_chain";
123                         self.think = W_Plasma_Explode_Combo;
124                         self.nextthink = time + min(autocvar_g_balance_electro_combo_radius, vlen(self.origin - inflictor.origin)) / autocvar_g_balance_electro_combo_speed; // delay combo chains, looks cooler
125                                 //                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bounding the length, because inflictor may be in a galaxy far far away (warpzones)
126                 }
127                 else
128                 {
129                         self.use = W_Plasma_Explode;
130                         self.think = adaptor_think2use; // not _hittype_splash, as this runs "immediately"
131                 }
132         }
133 }
134
135 void W_Electro_Attack()
136 {
137         local entity proj;
138
139         // if this weapon is reloadable, decrease its load. Else decrease the player's ammo
140         if not(self.items & IT_UNLIMITED_WEAPON_AMMO)
141         {
142                 if(autocvar_g_balance_electro_reload_ammo)
143                 {
144                         self.clip_load -= autocvar_g_balance_electro_primary_ammo;
145                         self.electro_load = self.clip_load;
146                 }
147                 else
148                         self.ammo_cells -= autocvar_g_balance_electro_primary_ammo;
149         }
150
151         W_SetupShot_ProjectileSize (self, '0 0 -3', '0 0 -3', FALSE, 2, "weapons/electro_fire.wav", CHAN_WEAPON, autocvar_g_balance_electro_primary_damage);
152
153         pointparticles(particleeffectnum("electro_muzzleflash"), w_shotorg, w_shotdir * 1000, 1);
154
155         proj = spawn ();
156         proj.classname = "plasma_prim";
157         proj.owner = self;
158         proj.bot_dodge = TRUE;
159         proj.bot_dodgerating = autocvar_g_balance_electro_primary_damage;
160         proj.use = W_Plasma_Explode;
161         proj.think = adaptor_think2use_hittype_splash;
162         proj.nextthink = time + autocvar_g_balance_electro_primary_lifetime;
163         PROJECTILE_MAKETRIGGER(proj);
164         proj.projectiledeathtype = WEP_ELECTRO;
165         setorigin(proj, w_shotorg);
166
167         proj.movetype = MOVETYPE_FLY;
168         W_SETUPPROJECTILEVELOCITY(proj, g_balance_electro_primary);
169         proj.angles = vectoangles(proj.velocity);
170         proj.touch = W_Plasma_TouchExplode;
171         setsize(proj, '0 0 -3', '0 0 -3');
172         proj.flags = FL_PROJECTILE;
173
174         //sound (proj, CHAN_PAIN, "weapons/electro_fly.wav", VOL_BASE, ATTN_NORM);
175         //sounds bad
176
177         CSQCProjectile(proj, TRUE, PROJECTILE_ELECTRO_BEAM, TRUE);
178
179         other = proj; MUTATOR_CALLHOOK(EditProjectile);
180 }
181
182 void W_Electro_Attack2()
183 {
184         local entity proj;
185
186         // if this weapon is reloadable, decrease its load. Else decrease the player's ammo
187         if not(self.items & IT_UNLIMITED_WEAPON_AMMO)
188         {
189                 if(autocvar_g_balance_electro_reload_ammo)
190                 {
191                         self.clip_load -= autocvar_g_balance_electro_secondary_ammo;
192                         self.electro_load = self.clip_load;
193                 }
194                 else
195                         self.ammo_cells -= autocvar_g_balance_electro_secondary_ammo;
196         }
197
198         W_SetupShot_ProjectileSize (self, '0 0 -4', '0 0 -4', FALSE, 2, "weapons/electro_fire2.wav", CHAN_WEAPON, autocvar_g_balance_electro_secondary_damage);
199
200         w_shotdir = v_forward; // no TrueAim for grenades please
201
202         pointparticles(particleeffectnum("electro_muzzleflash"), w_shotorg, w_shotdir * 1000, 1);
203
204         proj = spawn ();
205         proj.classname = "plasma";
206         proj.owner = self;
207         proj.use = W_Plasma_Explode;
208         proj.think = adaptor_think2use_hittype_splash;
209         proj.bot_dodge = TRUE;
210         proj.bot_dodgerating = autocvar_g_balance_electro_secondary_damage;
211         proj.nextthink = time + autocvar_g_balance_electro_secondary_lifetime;
212         PROJECTILE_MAKETRIGGER(proj);
213         proj.projectiledeathtype = WEP_ELECTRO | HITTYPE_SECONDARY;
214         setorigin(proj, w_shotorg);
215
216         //proj.glow_size = 50;
217         //proj.glow_color = 45;
218         proj.movetype = MOVETYPE_BOUNCE;
219         W_SETUPPROJECTILEVELOCITY_UP(proj, g_balance_electro_secondary);
220         proj.touch = W_Plasma_Touch;
221         setsize(proj, '0 0 -4', '0 0 -4');
222         proj.takedamage = DAMAGE_YES;
223         proj.damageforcescale = autocvar_g_balance_electro_secondary_damageforcescale;
224         proj.health = autocvar_g_balance_electro_secondary_health;
225         proj.event_damage = W_Plasma_Damage;
226         proj.flags = FL_PROJECTILE;
227
228         proj.bouncefactor = autocvar_g_balance_electro_secondary_bouncefactor;
229         proj.bouncestop = autocvar_g_balance_electro_secondary_bouncestop;
230
231 #if 0
232         entity p2;
233         p2 = spawn();
234         copyentity(proj, p2);
235         setmodel(p2, "models/ebomb.mdl");
236         setsize(p2, proj.mins, proj.maxs);
237 #endif
238
239         CSQCProjectile(proj, TRUE, PROJECTILE_ELECTRO, FALSE); // no culling, it has sound
240
241         other = proj; MUTATOR_CALLHOOK(EditProjectile);
242 }
243
244 .vector hook_start, hook_end;
245 float lgbeam_send(entity to, float sf)
246 {
247         WriteByte(MSG_ENTITY, ENT_CLIENT_LGBEAM);
248         sf = sf & 0x7F;
249         if(sound_allowed(MSG_BROADCAST, self.owner))
250                 sf |= 0x80;
251         WriteByte(MSG_ENTITY, sf);
252         if(sf & 1)
253         {
254                 WriteByte(MSG_ENTITY, num_for_edict(self.owner));
255                 WriteCoord(MSG_ENTITY, autocvar_g_balance_electro_primary_range);
256         }
257         if(sf & 2)
258         {
259                 WriteCoord(MSG_ENTITY, self.hook_start_x);
260                 WriteCoord(MSG_ENTITY, self.hook_start_y);
261                 WriteCoord(MSG_ENTITY, self.hook_start_z);
262         }
263         if(sf & 4)
264         {
265                 WriteCoord(MSG_ENTITY, self.hook_end_x);
266                 WriteCoord(MSG_ENTITY, self.hook_end_y);
267                 WriteCoord(MSG_ENTITY, self.hook_end_z);
268         }
269         return TRUE;
270 }
271 .entity lgbeam;
272 .float prevlgfire;
273 float lgbeam_checkammo()
274 {
275         if(self.owner.items & IT_UNLIMITED_WEAPON_AMMO)
276                 return TRUE;
277         else if(autocvar_g_balance_electro_reload_ammo)
278                 return self.owner.clip_load > 0;
279         else
280                 return self.owner.ammo_cells > 0;
281 }
282
283 void lgbeam_think()
284 {
285         self.owner.prevlgfire = time;
286         if (self != self.owner.lgbeam)
287         {
288                 remove(self);
289                 return;
290         }
291
292         if (self.owner.weaponentity.state != WS_INUSE || !lgbeam_checkammo() || self.owner.deadflag != DEAD_NO || !self.owner.BUTTON_ATCK || self.owner.freezetag_frozen)
293         {
294                 if(self == self.owner.lgbeam)
295                         self.owner.lgbeam = world;
296                 remove(self);
297                 return;
298         }
299
300         self.nextthink = time;
301
302         makevectors(self.owner.v_angle);
303
304         float dt, f;
305         dt = frametime;
306         // if this weapon is reloadable, decrease its load. Else decrease the player's ammo
307         if not(self.owner.items & IT_UNLIMITED_WEAPON_AMMO)
308         {
309                 if(autocvar_g_balance_electro_primary_ammo)
310                 {
311                         if(autocvar_g_balance_electro_reload_ammo)
312                         {
313                                 dt = min(dt, self.owner.clip_load / autocvar_g_balance_electro_primary_ammo);
314                                 self.owner.clip_load = max(0, self.owner.clip_load - autocvar_g_balance_electro_primary_ammo * frametime);
315                                 self.owner.electro_load = self.owner.clip_load;
316                         }
317                         else
318                         {
319                                 dt = min(dt, self.owner.ammo_cells / autocvar_g_balance_electro_primary_ammo);
320                                 self.owner.ammo_cells = max(0, self.owner.ammo_cells - autocvar_g_balance_electro_primary_ammo * frametime);
321                         }
322                 }
323         }
324
325         W_SetupShot_Range(self.owner, TRUE, 0, "", 0, autocvar_g_balance_electro_primary_damage * dt, autocvar_g_balance_electro_primary_range);
326         WarpZone_traceline_antilag(self.owner, w_shotorg, w_shotend, MOVE_NORMAL, self.owner, ANTILAG_LATENCY(self.owner));
327
328         // apply the damage
329         if(trace_ent)
330         {
331                 vector force;
332                 force = w_shotdir * autocvar_g_balance_electro_primary_force + '0 0 1' * autocvar_g_balance_electro_primary_force_up;
333
334                 f = ExponentialFalloff(autocvar_g_balance_electro_primary_falloff_mindist, autocvar_g_balance_electro_primary_falloff_maxdist, autocvar_g_balance_electro_primary_falloff_halflifedist, vlen(WarpZone_UnTransformOrigin(WarpZone_trace_transform, trace_endpos) - w_shotorg));
335
336                 if(accuracy_isgooddamage(self.owner, trace_ent))
337                         accuracy_add(self.owner, WEP_ELECTRO, 0, autocvar_g_balance_electro_primary_damage * dt * f);
338                 Damage (trace_ent, self.owner, self.owner, autocvar_g_balance_electro_primary_damage * dt * f, WEP_ELECTRO, trace_endpos, force * dt);
339         }
340         W_Plasma_TriggerCombo(trace_endpos, autocvar_g_balance_electro_primary_comboradius, self.owner);
341
342         // draw effect
343         if(w_shotorg != self.hook_start)
344         {
345                 self.SendFlags |= 2;
346                 self.hook_start = w_shotorg;
347         }
348         if(w_shotend != self.hook_end)
349         {
350                 self.SendFlags |= 4;
351                 self.hook_end = w_shotend;
352         }
353 }
354
355 // experimental lightning gun
356 void W_Electro_Attack3 (void)
357 {
358         // only play fire sound if 0.5 sec has passed since player let go the fire button
359         if(time - self.prevlgfire > 0.5)
360                 sound (self, CHAN_WEAPON, "weapons/lgbeam_fire.wav", VOL_BASE, ATTN_NORM);
361
362         entity beam, oldself;
363
364         self.lgbeam = beam = spawn();
365         beam.classname = "lgbeam";
366         beam.solid = SOLID_NOT;
367         beam.think = lgbeam_think;
368         beam.owner = self;
369         beam.movetype = MOVETYPE_NONE;
370         beam.shot_spread = 0;
371         beam.bot_dodge = TRUE;
372         beam.bot_dodgerating = autocvar_g_balance_electro_primary_damage;
373         Net_LinkEntity(beam, FALSE, 0, lgbeam_send);
374
375         oldself = self;
376         self = beam;
377         self.think();
378         self = oldself;
379 }
380
381 void ElectroInit()
382 {
383         weapon_action(WEP_ELECTRO, WR_PRECACHE);
384         electro_shotorigin[0] = shotorg_adjust_values(CL_Weapon_GetShotOrg(WEP_ELECTRO), FALSE, FALSE, 1);
385         electro_shotorigin[1] = shotorg_adjust_values(CL_Weapon_GetShotOrg(WEP_ELECTRO), FALSE, FALSE, 2);
386         electro_shotorigin[2] = shotorg_adjust_values(CL_Weapon_GetShotOrg(WEP_ELECTRO), FALSE, FALSE, 3);
387         electro_shotorigin[3] = shotorg_adjust_values(CL_Weapon_GetShotOrg(WEP_ELECTRO), FALSE, FALSE, 4);
388 }
389
390 void spawnfunc_weapon_electro (void)
391 {
392         weapon_defaultspawnfunc(WEP_ELECTRO);
393 }
394
395 void w_electro_checkattack()
396 {
397         if(self.electro_count > 1)
398         if(self.BUTTON_ATCK2)
399         if(weapon_prepareattack(1, -1))
400         {
401                 W_Electro_Attack2();
402                 self.electro_count -= 1;
403                 weapon_thinkf(WFRAME_FIRE2, autocvar_g_balance_electro_secondary_animtime, w_electro_checkattack);
404                 return;
405         }
406
407         w_ready();
408 }
409
410 .float bot_secondary_electromooth;
411 .float BUTTON_ATCK_prev;
412 float w_electro(float req)
413 {
414         float ammo_amount;
415         if (req == WR_AIM)
416         {
417                 self.BUTTON_ATCK=FALSE;
418                 self.BUTTON_ATCK2=FALSE;
419                 if(vlen(self.origin-self.enemy.origin) > 1000)
420                         self.bot_secondary_electromooth = 0;
421                 if(self.bot_secondary_electromooth == 0)
422                 {
423                         float shoot;
424
425                         if(autocvar_g_balance_electro_primary_speed)
426                                 shoot = bot_aim(autocvar_g_balance_electro_primary_speed, 0, autocvar_g_balance_electro_primary_lifetime, FALSE);
427                         else
428                                 shoot = bot_aim(1000000, 0, 0.001, FALSE);
429
430                         if(shoot)
431                         {
432                                 self.BUTTON_ATCK = TRUE;
433                                 if(random() < 0.01) self.bot_secondary_electromooth = 1;
434                         }
435                 }
436                 else
437                 {
438                         if(bot_aim(autocvar_g_balance_electro_secondary_speed, autocvar_g_balance_grenadelauncher_secondary_speed_up, autocvar_g_balance_electro_secondary_lifetime, TRUE))
439                         {
440                                 self.BUTTON_ATCK2 = TRUE;
441                                 if(random() < 0.03) self.bot_secondary_electromooth = 0;
442                         }
443                 }
444         }
445         else if (req == WR_THINK)
446         {
447                 if(autocvar_g_balance_electro_reload_ammo) // forced reload
448                 {
449                         if(autocvar_g_balance_electro_lightning)
450                         {
451                                 if(self.clip_load > 0)
452                                         ammo_amount = 1;
453                         }
454                         else if(self.clip_load >= autocvar_g_balance_electro_primary_ammo)
455                                 ammo_amount = 1;
456                         if(self.clip_load >= autocvar_g_balance_electro_secondary_ammo)
457                                 ammo_amount += 1;
458
459                         if(!ammo_amount)
460                         {
461                                 W_Electro_Reload();
462                                 return FALSE;
463                         }
464                 }
465                 if (self.BUTTON_ATCK)
466                 {
467                         if(autocvar_g_balance_electro_lightning)
468                                 if(self.BUTTON_ATCK_prev)
469                                 {
470                                         // prolong the animtime while the gun is being fired
471                                         if(self.animstate_startframe == self.anim_shoot_x && self.animstate_numframes == self.anim_shoot_y)
472                                                 weapon_thinkf(WFRAME_DONTCHANGE, autocvar_g_balance_electro_primary_animtime, w_ready);
473                                         else
474                                                 weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_electro_primary_animtime, w_ready);
475                                 }
476                         if (weapon_prepareattack(0, (autocvar_g_balance_electro_lightning ? 0 : autocvar_g_balance_electro_primary_refire)))
477                         {
478                                 if(autocvar_g_balance_electro_lightning)
479                                 {
480                                         if ((!self.lgbeam) || wasfreed(self.lgbeam))
481                                         {
482                                                 W_Electro_Attack3();
483                                         }
484                                         if(!self.BUTTON_ATCK_prev)
485                                         {
486                                                 weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_electro_primary_animtime, w_ready);
487                                                 self.BUTTON_ATCK_prev = 1;
488                                         }
489                                 }
490                                 else
491                                 {
492                                         W_Electro_Attack();
493                                         weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_electro_primary_animtime, w_ready);
494                                 }
495                         }
496                 } else {
497                         if(autocvar_g_balance_electro_lightning)
498                         {
499                                 if (self.BUTTON_ATCK_prev != 0)
500                                 {
501                                         weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_electro_primary_animtime, w_ready);
502                                         ATTACK_FINISHED(self) = time + autocvar_g_balance_electro_primary_refire * W_WeaponRateFactor();
503                                 }
504                                 self.BUTTON_ATCK_prev = 0;
505                         }
506
507                         if (self.BUTTON_ATCK2)
508                         {
509                                 if (time >= self.electro_secondarytime)
510                                 if (weapon_prepareattack(1, autocvar_g_balance_electro_secondary_refire))
511                                 {
512                                         W_Electro_Attack2();
513                                         self.electro_count = autocvar_g_balance_electro_secondary_count;
514                                         weapon_thinkf(WFRAME_FIRE2, autocvar_g_balance_electro_secondary_animtime, w_electro_checkattack);
515                                         self.electro_secondarytime = time + autocvar_g_balance_electro_secondary_refire2 * W_WeaponRateFactor();
516                                 }
517                         }
518                 }
519         }
520         else if (req == WR_PRECACHE)
521         {
522                 precache_model ("models/weapons/g_electro.md3");
523                 precache_model ("models/weapons/v_electro.md3");
524                 precache_model ("models/weapons/h_electro.iqm");
525                 precache_sound ("weapons/electro_bounce.wav");
526                 precache_sound ("weapons/electro_fire.wav");
527                 precache_sound ("weapons/electro_fire2.wav");
528                 precache_sound ("weapons/electro_impact.wav");
529                 precache_sound ("weapons/electro_impact_combo.wav");
530                 precache_sound ("weapons/reload.wav");
531                 if(autocvar_g_balance_electro_lightning)
532                 {
533                         precache_sound ("weapons/lgbeam_fire.wav");
534                 }
535         }
536         else if (req == WR_SETUP)
537         {
538                 weapon_setup(WEP_ELECTRO);
539                 W_Electro_SetAmmoCounter();
540         }
541         else if (req == WR_CHECKAMMO1)
542         {
543                 if(autocvar_g_balance_electro_lightning)
544                 {
545                         ammo_amount = !autocvar_g_balance_electro_primary_ammo || (self.ammo_cells > 0);
546                         if(autocvar_g_balance_electro_lightning)
547                                 ammo_amount += self.electro_load > 0;
548                 }
549                 else
550                 {
551                         ammo_amount = self.ammo_cells >= autocvar_g_balance_electro_primary_ammo;
552                         if(autocvar_g_balance_electro_lightning)
553                                 ammo_amount += self.electro_load >= autocvar_g_balance_electro_primary_ammo;
554                 }
555                 return ammo_amount;
556         }
557         else if (req == WR_CHECKAMMO2)
558         {
559                 ammo_amount = self.ammo_cells >= autocvar_g_balance_electro_secondary_ammo;
560                 ammo_amount += self.electro_load >= autocvar_g_balance_electro_secondary_ammo;
561                 return ammo_amount;
562         }
563         else if (req == WR_RESETPLAYER)
564         {
565                 self.electro_secondarytime = time;
566
567                 // all weapons must be fully loaded when we spawn
568                 self.electro_load = autocvar_g_balance_electro_reload_ammo;
569         }
570         else if (req == WR_RELOAD)
571         {
572                 W_Electro_Reload();
573         }
574         return TRUE;
575 };
576 #endif
577 #ifdef CSQC
578 float w_electro(float req)
579 {
580         if(req == WR_IMPACTEFFECT)
581         {
582                 vector org2;
583                 org2 = w_org + w_backoff * 6;
584                 if(w_deathtype & HITTYPE_SECONDARY)
585                 {
586                         pointparticles(particleeffectnum("electro_ballexplode"), org2, '0 0 0', 1);
587                         if(!w_issilent)
588                                 sound(self, CHAN_PROJECTILE, "weapons/electro_impact.wav", VOL_BASE, ATTN_NORM);
589                 }
590                 else
591                 {
592                         if(w_deathtype & HITTYPE_BOUNCE)
593                         {
594                                 // this is sent as "primary (w_deathtype & HITTYPE_BOUNCE)" to distinguish it from (w_deathtype & HITTYPE_SECONDARY) bounced balls
595                                 pointparticles(particleeffectnum("electro_combo"), org2, '0 0 0', 1);
596                                 if(!w_issilent)
597                                         sound(self, CHAN_PROJECTILE, "weapons/electro_impact_combo.wav", VOL_BASE, ATTN_NORM);
598                         }
599                         else
600                         {
601                                 pointparticles(particleeffectnum("electro_impact"), org2, '0 0 0', 1);
602                                 if(!w_issilent)
603                                         sound(self, CHAN_PROJECTILE, "weapons/electro_impact.wav", VOL_BASE, ATTN_NORM);
604                         }
605                 }
606         }
607         else if(req == WR_PRECACHE)
608         {
609                 precache_sound("weapons/electro_impact.wav");
610                 precache_sound("weapons/electro_impact_combo.wav");
611         }
612         else if (req == WR_SUICIDEMESSAGE)
613         {
614                 if(w_deathtype & HITTYPE_SECONDARY)
615                         w_deathtypestring = _("%s could not remember where they put plasma");
616                 else
617                         w_deathtypestring = _("%s played with plasma");
618         }
619         else if (req == WR_KILLMESSAGE)
620         {
621                 if(w_deathtype & HITTYPE_SECONDARY)
622                 {
623                         if(w_deathtype & HITTYPE_SPLASH) // unchecked: BOUNCE
624                                 w_deathtypestring = _("%s just noticed %s's blue ball");
625                         else // unchecked: BOUNCE
626                                 w_deathtypestring = _("%s got in touch with %s's blue ball");
627                 }
628                 else
629                 {
630                         if(w_deathtype & HITTYPE_BOUNCE) // combo
631                                 w_deathtypestring = _("%s felt the electrifying air of %s's combo");
632                         else if(w_deathtype & HITTYPE_SPLASH)
633                                 w_deathtypestring = _("%s got too close to %s's blue beam");
634                         else
635                                 w_deathtypestring = _("%s was blasted by %s's blue beam");
636                 }
637         }
638         return TRUE;
639 }
640 #endif
641 #endif