Xonotic
electro.qc
Go to the documentation of this file.
1 #include "electro.qh"
2 
3 #ifdef SVQC
5 
6 void W_Electro_TriggerCombo(vector org, float rad, entity own)
7 {
8  entity e = WarpZone_FindRadius(org, rad, !WEP_CVAR(electro, combo_comboradius_thruwall));
9  while(e)
10  {
11  if(e.classname == "electro_orb")
12  {
13  // do we allow thruwall triggering?
14  if(WEP_CVAR(electro, combo_comboradius_thruwall))
15  {
16  // if distance is greater than thruwall distance, check to make sure it's not through a wall
17  if(vdist(e.WarpZone_findradius_dist, >, WEP_CVAR(electro, combo_comboradius_thruwall)))
18  {
19  WarpZone_TraceLine(org, e.origin, MOVE_NOMONSTERS, e);
20  if(trace_fraction != 1)
21  {
22  // trigger is through a wall and outside of thruwall range, abort
23  e = e.chain;
24  continue;
25  }
26  }
27  }
28 
29  // change owner to whoever caused the combo explosion
30  e.realowner = own;
31  e.takedamage = DAMAGE_NO;
32  e.classname = "electro_orb_chain";
33 
34  // now set the next one to trigger as well
35  setthink(e, W_Electro_ExplodeCombo);
36 
37  // delay combo chains, looks cooler
38  float delay = 0;
39  if (WEP_CVAR(electro, combo_speed))
40  delay = vlen(e.WarpZone_findradius_dist) / WEP_CVAR(electro, combo_speed);
41  e.nextthink = time + delay;
42  }
43  e = e.chain;
44  }
45 }
46 
47 void W_Electro_ExplodeCombo(entity this)
48 {
49  W_Electro_TriggerCombo(this.origin, WEP_CVAR(electro, combo_comboradius), this.realowner);
50 
51  this.event_damage = func_null;
52  this.velocity = this.movedir; // particle fx and decals need .velocity
53 
55  this,
56  this.realowner,
57  WEP_CVAR(electro, combo_damage),
58  WEP_CVAR(electro, combo_edgedamage),
59  WEP_CVAR(electro, combo_radius),
60  NULL,
61  NULL,
62  WEP_CVAR(electro, combo_force),
63  WEP_ELECTRO.m_id | HITTYPE_BOUNCE, // use THIS type for a combo because primary can't bounce
64  this.weaponentity_fld,
65  NULL
66  );
67 
68  delete(this);
69 }
70 
71 void W_Electro_Explode(entity this, entity directhitentity)
72 {
73  if(directhitentity.takedamage == DAMAGE_AIM)
74  if(IS_PLAYER(directhitentity))
75  if(DIFF_TEAM(this.realowner, directhitentity))
76  if(!IS_DEAD(directhitentity))
77  if(IsFlying(directhitentity))
78  Send_Notification(NOTIF_ONE, this.realowner, MSG_ANNCE, ANNCE_ACHIEVEMENT_ELECTROBITCH);
79 
80  this.event_damage = func_null;
81  this.takedamage = DAMAGE_NO;
82  this.velocity = this.movedir; // particle fx and decals need .velocity
83 
84  if(this.move_movetype == MOVETYPE_BOUNCE || this.classname == "electro_orb") // TODO: classname is more reliable anyway?
85  {
87  this,
88  this.realowner,
89  WEP_CVAR_SEC(electro, damage),
90  WEP_CVAR_SEC(electro, edgedamage),
91  WEP_CVAR_SEC(electro, radius),
92  NULL,
93  NULL,
94  WEP_CVAR_SEC(electro, force),
96  this.weaponentity_fld,
97  directhitentity
98  );
99  }
100  else
101  {
102  W_Electro_TriggerCombo(this.origin, WEP_CVAR_PRI(electro, comboradius), this.realowner);
103  RadiusDamage(
104  this,
105  this.realowner,
106  WEP_CVAR_PRI(electro, damage),
107  WEP_CVAR_PRI(electro, edgedamage),
108  WEP_CVAR_PRI(electro, radius),
109  NULL,
110  NULL,
111  WEP_CVAR_PRI(electro, force),
112  this.projectiledeathtype,
113  this.weaponentity_fld,
114  directhitentity
115  );
116  }
117 
118  delete(this);
119 }
120 
121 void W_Electro_Explode_use(entity this, entity actor, entity trigger)
122 {
123  W_Electro_Explode(this, trigger);
124 }
125 
126 void W_Electro_TouchExplode(entity this, entity toucher)
127 {
128  PROJECTILE_TOUCH(this, toucher);
129  W_Electro_Explode(this, toucher);
130 }
131 
132 
133 //void sys_phys_update_single(entity this);
134 
135 void W_Electro_Bolt_Think(entity this)
136 {
137  // sys_phys_update_single(this);
138  if(time >= this.ltime)
139  {
140  this.use(this, NULL, NULL);
141  return;
142  }
143 
144  if(WEP_CVAR_PRI(electro, midaircombo_radius))
145  {
146  float found = 0;
147  entity e = WarpZone_FindRadius(this.origin, WEP_CVAR_PRI(electro, midaircombo_radius), true);
148 
149  // loop through nearby orbs and trigger them
150  while(e)
151  {
152  if(e.classname == "electro_orb")
153  {
154  bool explode;
155  if (this.owner == e.owner)
156  {
157  explode = WEP_CVAR_PRI(electro, midaircombo_own);
158  }
159  else if (SAME_TEAM(this.owner, e.owner))
160  {
161  explode = WEP_CVAR_PRI(electro, midaircombo_teammate);
162  }
163  else
164  {
165  explode = WEP_CVAR_PRI(electro, midaircombo_enemy);
166  }
167 
168  if (explode)
169  {
170  // change owner to whoever caused the combo explosion
171  e.realowner = this.realowner;
172  e.takedamage = DAMAGE_NO;
173  e.classname = "electro_orb_chain";
174 
175  // Only first orb explosion uses midaircombo_speed, others use the normal combo_speed.
176  // This allows to avoid the delay on the first explosion which looks better
177  // (the bolt and orb should explode together because they interacted together)
178  // while keeping the chaining delay.
179  setthink(e, W_Electro_ExplodeCombo);
180  float delay = 0;
181  if (WEP_CVAR_PRI(electro, midaircombo_speed))
182  delay = vlen(e.WarpZone_findradius_dist) / WEP_CVAR_PRI(electro, midaircombo_speed);
183  e.nextthink = time + delay;
184 
185  ++found;
186  }
187  }
188  e = e.chain;
189  }
190 
191  // if we triggered an orb, should we explode? if not, lets try again next time
192  if(found && WEP_CVAR_PRI(electro, midaircombo_explode))
193  { this.use(this, NULL, NULL); }
194  else
195  { this.nextthink = min(time + WEP_CVAR_PRI(electro, midaircombo_interval), this.ltime); }
196  }
197  else { this.nextthink = this.ltime; }
198  // this.nextthink = time;
199 }
200 
201 void W_Electro_Attack_Bolt(Weapon thiswep, entity actor, .entity weaponentity)
202 {
203  entity proj;
204 
205  W_DecreaseAmmo(thiswep, actor, WEP_CVAR_PRI(electro, ammo), weaponentity);
206 
208  actor,
209  weaponentity,
210  '0 0 -3',
211  '0 0 -3',
212  false,
213  2,
214  SND_ELECTRO_FIRE,
215  CH_WEAPON_A,
216  WEP_CVAR_PRI(electro, damage),
217  thiswep.m_id
218  );
219 
220  W_MuzzleFlash(thiswep, actor, weaponentity, w_shotorg, w_shotdir);
221 
222  proj = new(electro_bolt);
223  proj.owner = proj.realowner = actor;
224  proj.bot_dodge = true;
225  proj.bot_dodgerating = WEP_CVAR_PRI(electro, damage);
226  proj.use = W_Electro_Explode_use;
227  setthink(proj, W_Electro_Bolt_Think);
228  proj.nextthink = time;
229  proj.ltime = time + WEP_CVAR_PRI(electro, lifetime);
231  proj.projectiledeathtype = thiswep.m_id;
232  proj.weaponentity_fld = weaponentity;
233  setorigin(proj, w_shotorg);
234 
235  // if (IS_CSQC)
236  set_movetype(proj, MOVETYPE_FLY);
237  W_SetupProjVelocity_PRI(proj, electro);
238  proj.angles = vectoangles(proj.velocity);
239  settouch(proj, W_Electro_TouchExplode);
240  setsize(proj, '0 0 -3', '0 0 -3');
241  proj.flags = FL_PROJECTILE;
242  IL_PUSH(g_projectiles, proj);
243  IL_PUSH(g_bot_dodge, proj);
244  proj.missile_flags = MIF_SPLASH;
245 
246  CSQCProjectile(proj, true, PROJECTILE_ELECTRO_BEAM, true);
247 
248  MUTATOR_CALLHOOK(EditProjectile, actor, proj);
249  // proj.com_phys_pos = proj.origin;
250  // proj.com_phys_vel = proj.velocity;
251 }
252 
253 void W_Electro_Orb_Follow_Think(entity this)
254 {
255  if (time > this.death_time)
256  {
258  return;
259  }
260  if (this.move_movetype == MOVETYPE_FOLLOW)
261  {
262  int lost = LostMovetypeFollow(this);
263  if (lost == 2)
264  {
265  // FIXME if player disconnected, it isn't possible to drop the orb at player's origin
266  // see comment in LostMovetypeFollow implementation
267  delete(this);
268  return;
269  }
270  if (lost)
271  {
272  // drop the orb at the corpse's location
275 
277  this.nextthink = this.death_time;
278  return;
279  }
280  }
281  this.nextthink = time;
282 }
283 
284 void W_Electro_Orb_Stick(entity this, entity to)
285 {
286  entity newproj = spawn();
287  newproj.classname = this.classname;
288 
289  newproj.bot_dodge = this.bot_dodge;
290  newproj.bot_dodgerating = this.bot_dodgerating;
291 
292  newproj.owner = this.owner;
293  newproj.realowner = this.realowner;
294  setorigin(newproj, this.origin);
295  setmodel(newproj, MDL_PROJECTILE_ELECTRO);
296  setsize(newproj, this.mins, this.maxs);
297  newproj.angles = vectoangles(-trace_plane_normal); // face against the surface
298  newproj.traileffectnum = _particleeffectnum(EFFECT_TR_NEXUIZPLASMA.eent_eff_name);
299 
300  newproj.movedir = -trace_plane_normal;
301 
302  newproj.takedamage = this.takedamage;
303  newproj.damageforcescale = this.damageforcescale;
305  newproj.event_damage = this.event_damage;
306  newproj.spawnshieldtime = this.spawnshieldtime;
307  newproj.damagedbycontents = true;
308  IL_PUSH(g_damagedbycontents, newproj);
309 
310  set_movetype(newproj, MOVETYPE_NONE); // lock the orb in place
311  newproj.projectiledeathtype = this.projectiledeathtype;
312  newproj.weaponentity_fld = this.weaponentity_fld;
313 
314  settouch(newproj, func_null);
315  if(WEP_CVAR_SEC(electro, stick_lifetime) > 0){
316  newproj.death_time = time + WEP_CVAR_SEC(electro, stick_lifetime);
317  }else{
318  newproj.death_time = this.death_time;
319  }
320  newproj.use = this.use;
321  newproj.flags = this.flags;
322  IL_PUSH(g_projectiles, newproj);
323  IL_PUSH(g_bot_dodge, newproj);
324 
325  // check if limits are enabled (we can tell by checking if the original orb is listed) and push it to the list if so
326  if(LimitedElectroBallRubbleList && IL_CONTAINS(LimitedElectroBallRubbleList, this))
327  {
328  ReplaceOldListedChildRubble(LimitedElectroBallRubbleList, newproj, this);
329  }
330 
331  delete(this);
332 
333  if(to)
334  {
335  SetMovetypeFollow(newproj, to);
336 
337  setthink(newproj, W_Electro_Orb_Follow_Think);
338  newproj.nextthink = time;
339  }
340  else
341  {
343  newproj.nextthink = newproj.death_time;
344  }
345 }
346 
347 void W_Electro_Orb_Touch(entity this, entity toucher)
348 {
349  PROJECTILE_TOUCH(this, toucher);
350  if(toucher.takedamage == DAMAGE_AIM && WEP_CVAR_SEC(electro, touchexplode))
351  { W_Electro_Explode(this, toucher); }
352  else if(toucher.owner != this.owner && toucher.classname != this.classname) // don't stick to player's other projectiles!
353  {
354  //UpdateCSQCProjectile(this);
355  spamsound(this, CH_SHOTS, SND_ELECTRO_BOUNCE, VOL_BASE, ATTEN_NORM);
357 
358  if(WEP_CVAR_SEC(electro, stick)){
359  if(WEP_CVAR_SEC(electro, stick_lifetime) == 0){
360  W_Electro_Explode(this, toucher);
361  } else {
362  W_Electro_Orb_Stick(this, toucher);
363  }
364  }
365  }
366 }
367 
368 void W_Electro_Orb_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
369 {
370  if(GetResource(this, RES_HEALTH) <= 0)
371  return;
372 
373  // note: combos are usually triggered by W_Electro_TriggerCombo, not damage
374  float is_combo = (inflictor.classname == "electro_orb_chain" || inflictor.classname == "electro_bolt");
375 
376  if(!W_CheckProjectileDamage(inflictor.realowner, this.realowner, deathtype, (is_combo ? 1 : -1)))
377  return; // g_projectiles_damage says to halt
378 
379  TakeResource(this, RES_HEALTH, damage);
380  if(GetResource(this, RES_HEALTH) <= 0)
381  {
382  this.takedamage = DAMAGE_NO;
383  this.nextthink = time;
384  if(is_combo)
385  {
386  // change owner to whoever caused the combo explosion
387  this.realowner = inflictor.realowner;
388  this.classname = "electro_orb_chain";
389  setthink(this, W_Electro_ExplodeCombo);
390  // delay combo chains, looks cooler
391  // bound the length, inflictor may be in a galaxy far far away (warpzones)
392  float len = min(WEP_CVAR(electro, combo_radius), vlen(this.origin - inflictor.origin));
393  float delay = len / WEP_CVAR(electro, combo_speed);
394  this.nextthink = time + delay;
395  }
396  else
397  {
398  this.use = W_Electro_Explode_use;
399  setthink(this, adaptor_think2use); // not _hittype_splash, as this runs "immediately"
400  }
401  }
402 }
403 
404 void W_Electro_Attack_Orb(Weapon thiswep, entity actor, .entity weaponentity)
405 {
406  W_DecreaseAmmo(thiswep, actor, WEP_CVAR_SEC(electro, ammo), weaponentity);
407 
409  actor,
410  weaponentity,
411  '-4 -4 -4',
412  '4 4 4',
413  false,
414  2,
415  SND_ELECTRO_FIRE2,
416  CH_WEAPON_A,
417  WEP_CVAR_SEC(electro, damage),
418  thiswep.m_id | HITTYPE_SECONDARY
419  );
420 
421  w_shotdir = v_forward; // no TrueAim for grenades please
422 
423  W_MuzzleFlash(thiswep, actor, weaponentity, w_shotorg, w_shotdir);
424 
425  entity proj = new(electro_orb);
426  proj.owner = proj.realowner = actor;
427  proj.use = W_Electro_Explode_use;
429  proj.bot_dodge = true;
430  proj.bot_dodgerating = WEP_CVAR_SEC(electro, damage);
431  proj.nextthink = time + WEP_CVAR_SEC(electro, lifetime);
432  proj.death_time = time + WEP_CVAR_SEC(electro, lifetime);
434  proj.projectiledeathtype = thiswep.m_id | HITTYPE_SECONDARY;
435  proj.weaponentity_fld = weaponentity;
436  setorigin(proj, w_shotorg);
437 
438  //proj.glow_size = 50;
439  //proj.glow_color = 45;
441  W_SetupProjVelocity_UP_SEC(proj, electro);
442  settouch(proj, W_Electro_Orb_Touch);
443  setsize(proj, '-4 -4 -4', '4 4 4');
444  proj.takedamage = DAMAGE_YES;
445  proj.damageforcescale = WEP_CVAR_SEC(electro, damageforcescale);
447  proj.event_damage = W_Electro_Orb_Damage;
448  proj.flags = FL_PROJECTILE;
449  IL_PUSH(g_projectiles, proj);
450  IL_PUSH(g_bot_dodge, proj);
451  proj.damagedbycontents = (WEP_CVAR_SEC(electro, damagedbycontents));
452  if(proj.damagedbycontents)
454 
455  proj.bouncefactor = WEP_CVAR_SEC(electro, bouncefactor);
456  proj.bouncestop = WEP_CVAR_SEC(electro, bouncestop);
457  proj.missile_flags = MIF_SPLASH | MIF_ARC;
458 
459  if(WEP_CVAR_SEC(electro, limit) > 0)
460  {
461  if (!LimitedElectroBallRubbleList)
462  LimitedElectroBallRubbleList = IL_NEW();
463  ListNewChildRubble(LimitedElectroBallRubbleList, proj);
464  LimitedChildrenRubble(LimitedElectroBallRubbleList, "electro_orb", WEP_CVAR_SEC(electro, limit), adaptor_think2use_hittype_splash, actor);
465  }
466 
467  CSQCProjectile(proj, true, PROJECTILE_ELECTRO, false); // no culling, it has sound
468 
469  MUTATOR_CALLHOOK(EditProjectile, actor, proj);
470 }
471 
472 void W_Electro_CheckAttack(Weapon thiswep, entity actor, .entity weaponentity, int fire)
473 {
474  if(actor.(weaponentity).electro_count > 1)
475  if(PHYS_INPUT_BUTTON_ATCK2(actor))
476  if(weapon_prepareattack(thiswep, actor, weaponentity, true, -1))
477  {
478  W_Electro_Attack_Orb(thiswep, actor, weaponentity);
479  actor.(weaponentity).electro_count -= 1;
480  actor.(weaponentity).electro_secondarytime = time;
481  weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR_SEC(electro, animtime), W_Electro_CheckAttack);
482  return;
483  }
484  w_ready(thiswep, actor, weaponentity, fire);
485 }
486 
487 .float bot_secondary_electromooth;
488 
489 METHOD(Electro, wr_aim, void(entity thiswep, entity actor, .entity weaponentity))
490 {
491  PHYS_INPUT_BUTTON_ATCK(actor) = PHYS_INPUT_BUTTON_ATCK2(actor) = false;
492  if(vdist(actor.origin - actor.enemy.origin, >, 1000)) { actor.bot_secondary_electromooth = 0; }
493  if(actor.bot_secondary_electromooth == 0)
494  {
495  float shoot;
496 
497  if(WEP_CVAR_PRI(electro, speed))
498  shoot = bot_aim(actor, weaponentity, WEP_CVAR_PRI(electro, speed), 0, WEP_CVAR_PRI(electro, lifetime), false);
499  else
500  shoot = bot_aim(actor, weaponentity, 1000000, 0, 0.001, false);
501 
502  if(shoot)
503  {
504  PHYS_INPUT_BUTTON_ATCK(actor) = true;
505  if(random() < 0.01) actor.bot_secondary_electromooth = 1;
506  }
507  }
508  else
509  {
510  if(bot_aim(actor, weaponentity, WEP_CVAR_SEC(electro, speed), WEP_CVAR_SEC(electro, speed_up), WEP_CVAR_SEC(electro, lifetime), true))
511  {
512  PHYS_INPUT_BUTTON_ATCK2(actor) = true;
513  if(random() < 0.03) actor.bot_secondary_electromooth = 0;
514  }
515  }
516 }
517 METHOD(Electro, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
518 {
519  if(autocvar_g_balance_electro_reload_ammo) // forced reload // WEAPONTODO
520  {
521  float ammo_amount = 0;
522  if(actor.(weaponentity).clip_load >= WEP_CVAR_PRI(electro, ammo))
523  ammo_amount = 1;
524  if(actor.(weaponentity).clip_load >= WEP_CVAR_SEC(electro, ammo))
525  ammo_amount += 1;
526 
527  if(!ammo_amount)
528  {
529  thiswep.wr_reload(thiswep, actor, weaponentity);
530  return;
531  }
532  }
533 
534  if(fire & 1)
535  {
536  if(time >= actor.(weaponentity).electro_secondarytime + WEP_CVAR_SEC(electro, refire2) * W_WeaponRateFactor(actor))
537  if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(electro, refire)))
538  {
539  W_Electro_Attack_Bolt(thiswep, actor, weaponentity);
540  weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(electro, animtime), w_ready);
541  }
542  }
543  else if(fire & 2)
544  {
545  if(time >= actor.(weaponentity).electro_secondarytime + WEP_CVAR_SEC(electro, refire) * W_WeaponRateFactor(actor))
546  if(weapon_prepareattack(thiswep, actor, weaponentity, true, -1))
547  {
548  W_Electro_Attack_Orb(thiswep, actor, weaponentity);
549  actor.(weaponentity).electro_count = WEP_CVAR_SEC(electro, count);
550  actor.(weaponentity).electro_secondarytime = time;
551  weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR_SEC(electro, animtime), W_Electro_CheckAttack);
552  }
553  }
554 }
555 METHOD(Electro, wr_checkammo1, bool(entity thiswep, entity actor, .entity weaponentity))
556 {
557  float ammo_amount = GetResource(actor, thiswep.ammo_type) >= WEP_CVAR_PRI(electro, ammo);
558  ammo_amount += actor.(weaponentity).(weapon_load[thiswep.m_id]) >= WEP_CVAR_PRI(electro, ammo);
559  return ammo_amount;
560 }
561 METHOD(Electro, wr_checkammo2, bool(entity thiswep, entity actor, .entity weaponentity))
562 {
563  float ammo_amount;
564  if(WEP_CVAR(electro, combo_safeammocheck)) // true if you can fire at least one secondary blob AND one primary shot after it, otherwise false.
565  {
566  ammo_amount = GetResource(actor, thiswep.ammo_type) >= WEP_CVAR_SEC(electro, ammo) + WEP_CVAR_PRI(electro, ammo);
567  ammo_amount += actor.(weaponentity).(weapon_load[thiswep.m_id]) >= WEP_CVAR_SEC(electro, ammo) + WEP_CVAR_PRI(electro, ammo);
568  }
569  else
570  {
571  ammo_amount = GetResource(actor, thiswep.ammo_type) >= WEP_CVAR_SEC(electro, ammo);
572  ammo_amount += actor.(weaponentity).(weapon_load[thiswep.m_id]) >= WEP_CVAR_SEC(electro, ammo);
573  }
574  return ammo_amount;
575 }
576 METHOD(Electro, wr_reload, void(entity thiswep, entity actor, .entity weaponentity))
577 {
578  W_Reload(actor, weaponentity, min(WEP_CVAR_PRI(electro, ammo), WEP_CVAR_SEC(electro, ammo)), SND_RELOAD);
579 }
580 METHOD(Electro, wr_suicidemessage, Notification(entity thiswep))
581 {
583  return WEAPON_ELECTRO_SUICIDE_ORBS;
584  else
585  return WEAPON_ELECTRO_SUICIDE_BOLT;
586 }
587 METHOD(Electro, wr_killmessage, Notification(entity thiswep))
588 {
590  {
591  return WEAPON_ELECTRO_MURDER_ORBS;
592  }
593  else
594  {
596  return WEAPON_ELECTRO_MURDER_COMBO;
597  else
598  return WEAPON_ELECTRO_MURDER_BOLT;
599  }
600 }
601 
602 #endif
603 #ifdef CSQC
604 
605 METHOD(Electro, wr_impacteffect, void(entity thiswep, entity actor))
606 {
607  vector org2;
608  org2 = w_org + w_backoff * 6;
609  if(w_deathtype & HITTYPE_SECONDARY)
610  {
611  pointparticles(EFFECT_ELECTRO_BALLEXPLODE, org2, '0 0 0', 1);
612  if(!w_issilent)
613  sound(actor, CH_SHOTS, SND_ELECTRO_IMPACT, VOL_BASE, ATTEN_NORM);
614  }
615  else
616  {
618  {
619  // this is sent as "primary (w_deathtype & HITTYPE_BOUNCE)" to distinguish it from (w_deathtype & HITTYPE_SECONDARY) bounced balls
620  pointparticles(EFFECT_ELECTRO_COMBO, org2, '0 0 0', 1);
621  if(!w_issilent)
622  sound(actor, CH_SHOTS, SND_ELECTRO_IMPACT_COMBO, VOL_BASE, ATTEN_NORM);
623  }
624  else
625  {
626  pointparticles(EFFECT_ELECTRO_IMPACT, org2, '0 0 0', 1);
627  if(!w_issilent)
628  sound(actor, CH_SHOTS, SND_ELECTRO_IMPACT, VOL_BASE, ATTEN_NORM);
629  }
630  }
631 }
632 
633 #endif
#define WEP_CVAR_PRI(wepname, name)
Definition: all.qh:300
#define PHYS_INPUT_BUTTON_ATCK2(s)
Definition: player.qh:148
bool bot_aim(entity this,.entity weaponentity, float shotspeed, float shotspeedupward, float maxshottime, float applygravity)
float MOVETYPE_NONE
Definition: progsdefs.qc:246
#define WEP_CVAR_SEC(wepname, name)
Definition: all.qh:301
float weapon_load[REGISTRY_MAX(Weapons)]
Definition: weaponsystem.qh:29
const int HITTYPE_BOUNCE
Definition: all.qh:28
float speed
Definition: subs.qh:41
vector w_shotorg
Definition: tracing.qh:18
float spawnshieldtime
Definition: damage.qh:64
#define PROJECTILE_MAKETRIGGER(e)
Definition: common.qh:29
bool SetResourceExplicit(entity e, Resource res_type, float amount)
Sets the resource amount of an entity without calling any hooks.
Definition: cl_resources.qc:15
const int MIF_ARC
Definition: common.qh:35
#define W_SetupProjVelocity_UP_SEC(ent, wepname)
Definition: tracing.qh:55
const int MIF_SPLASH
Definition: common.qh:34
float MOVETYPE_TOSS
Definition: progsdefs.qc:252
#define IL_NEW()
#define W_SetupShot_ProjectileSize(ent, wepent, mi, ma, antilag, recoil, snd, chan, maxdamage, deathtype)
Definition: tracing.qh:29
float W_CheckProjectileDamage(entity inflictor, entity projowner, int deathtype, float exception)
Definition: common.qc:49
float damageforcescale
Definition: damage.qh:137
IntrusiveList g_damagedbycontents
Definition: damage.qh:155
entity() spawn
float DAMAGE_AIM
Definition: progsdefs.qc:284
void w_ready(Weapon thiswep, entity actor,.entity weaponentity, int fire)
float radius
Definition: impulse.qh:11
vector maxs
Definition: csprogsdefs.qc:113
#define WEP_CVAR(wepname, name)
Definition: all.qh:299
vector w_shotdir
Definition: tracing.qh:19
entity weaponentity_fld
Definition: weaponsystem.qh:27
entity to
Definition: self.qh:96
float bouncestop
origin
Definition: ent_cs.qc:114
string classname
Definition: csprogsdefs.qc:107
float MOVETYPE_BOUNCE
Definition: progsdefs.qc:256
#define METHOD(cname, name, prototype)
Definition: oo.qh:257
void CSQCProjectile(entity e, float clientanimate, int type, float docull)
#define DIFF_TEAM(a, b)
Definition: teams.qh:240
ERASEABLE bool IL_CONTAINS(IntrusiveList this, entity it)
float ltime
Definition: progsdefs.qc:107
entity owner
Definition: main.qh:73
float move_movetype
Definition: movetypes.qh:76
IntrusiveList g_bot_dodge
Definition: api.qh:150
void TakeResource(entity receiver, Resource res_type, float amount)
Takes an entity some resource.
Definition: cl_resources.qc:31
#define PROJECTILE_TOUCH(e, t)
Definition: common.qh:27
#define setmodel(this, m)
Definition: model.qh:26
RES_HEALTH
Definition: ent_cs.qc:126
float ammo
Definition: sv_turrets.qh:44
#define W_SetupProjVelocity_PRI(ent, wepname)
Definition: tracing.qh:64
float bouncefactor
vector movedir
Definition: progsdefs.qc:203
float lifetime
Definition: powerups.qc:23
const float MOVE_NOMONSTERS
Definition: csprogsdefs.qc:253
vector mins
Definition: csprogsdefs.qc:113
ERASEABLE entity IL_PUSH(IntrusiveList this, entity it)
Push to tail.
float damagedbycontents
Definition: damage.qh:48
const int CH_WEAPON_A
Definition: sound.qh:7
bool weapon_prepareattack(Weapon thiswep, entity actor,.entity weaponentity, bool secondary, float attacktime)
#define pointparticles
Definition: csprogsdefs.qh:13
float delay
Definition: subs.qh:38
#define NULL
Definition: post.qh:17
float bot_dodgerating
Definition: api.qh:39
const float VOL_BASE
Definition: sound.qh:36
#define PHYS_INPUT_BUTTON_ATCK(s)
Definition: player.qh:146
float takedamage
Definition: progsdefs.qc:147
#define SAME_TEAM(a, b)
Definition: teams.qh:239
const int HITTYPE_SECONDARY
Definition: all.qh:25
#define IS_DEAD(s)
Definition: utils.qh:26
entity WarpZone_FindRadius(vector org, float rad, bool needlineofsight)
Definition: common.qc:669
const float ATTEN_NORM
Definition: sound.qh:30
float nextthink
Definition: csprogsdefs.qc:121
const int CH_SHOTS
Definition: sound.qh:14
bool IsFlying(entity this)
Definition: player.qc:804
float w_deathtype
Definition: damage.qh:97
vector(float skel, float bonenum) _skel_get_boneabs_hidden
IntrusiveList g_projectiles
Definition: common.qh:46
float GetResource(entity e, Resource res_type)
Returns the current amount of resource the given entity has.
Definition: cl_resources.qc:10
const int PROJECTILE_ELECTRO
Definition: projectiles.qh:3
float flags
Definition: csprogsdefs.qc:129
#define vdist(v, cmp, f)
Vector distance comparison, avoids sqrt()
Definition: vector.qh:8
float count
Definition: powerups.qc:22
float MOVETYPE_FOLLOW
void WarpZone_TraceLine(vector org, vector end, float nomonsters, entity forent)
Definition: common.qc:338
entity Notification
always last
Definition: all.qh:82
float health
Definition: progsdefs.qc:137
void weapon_thinkf(entity actor,.entity weaponentity, WFRAME fr, float t, void(Weapon thiswep, entity actor,.entity weaponentity, int fire) func)
float RadiusDamage(entity inflictor, entity attacker, float coredamage, float edgedamage, float rad, entity cantbe, entity mustbe, float forceintensity, int deathtype,.entity weaponentity, entity directhitentity)
Definition: damage.qc:1057
const int PROJECTILE_ELECTRO_BEAM
Definition: projectiles.qh:7
entity realowner
Definition: common.qh:25
#define MUTATOR_CALLHOOK(id,...)
Definition: base.qh:140
float bot_dodge
Definition: api.qh:40
setorigin(ent, v)
#define setthink(e, f)
vector trace_plane_normal
Definition: csprogsdefs.qc:38
void adaptor_think2use_hittype_splash(entity this)
Definition: common.qc:110
#define use
Definition: csprogsdefs.qh:50
void W_DecreaseAmmo(Weapon wep, entity actor, float ammo_use,.entity weaponentity)
#define sound(e, c, s, v, a)
Definition: sound.qh:52
fields which are explicitly/manually set are marked with "M", fields set automatically are marked wit...
Definition: weapon.qh:41
float time
Definition: csprogsdefs.qc:16
vector velocity
Definition: csprogsdefs.qc:103
int m_id
Definition: weapon.qh:42
float death_time
float trace_fraction
Definition: csprogsdefs.qc:36
float W_WeaponRateFactor(entity this)
Definition: weaponsystem.qc:33
float DAMAGE_NO
Definition: progsdefs.qc:282
void set_movetype(entity this, int mt)
float MOVETYPE_FLY
Definition: progsdefs.qc:251
#define IS_PLAYER(v)
Definition: utils.qh:9
var void func_null()
vector v_forward
Definition: csprogsdefs.qc:31
float DAMAGE_YES
Definition: progsdefs.qc:283
void W_Reload(entity actor,.entity weaponentity, float sent_ammo_min, Sound sent_sound)
int projectiledeathtype
Definition: common.qh:20