Xonotic
devastator.qc
Go to the documentation of this file.
1 #include "devastator.qh"
2 
3 #ifdef SVQC
4 
5 .entity lastrocket;
6 
7 void W_Devastator_Unregister(entity this)
8 {
9  for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
10  {
11  .entity weaponentity = weaponentities[slot];
12  if(this.realowner.(weaponentity).lastrocket == this)
13  this.realowner.(weaponentity).lastrocket = NULL;
14  }
15 }
16 
17 void W_Devastator_Explode(entity this, entity directhitentity)
18 {
19  W_Devastator_Unregister(this);
20 
21  if(directhitentity.takedamage == DAMAGE_AIM)
22  if(IS_PLAYER(directhitentity))
23  if(DIFF_TEAM(this.realowner, directhitentity))
24  if(!IS_DEAD(directhitentity))
25  if(IsFlying(directhitentity))
26  Send_Notification(NOTIF_ONE, this.realowner, MSG_ANNCE, ANNCE_ACHIEVEMENT_AIRSHOT);
27 
28  this.event_damage = func_null;
29  this.takedamage = DAMAGE_NO;
30 
32  this,
33  this.realowner,
34  WEP_CVAR(devastator, damage),
35  WEP_CVAR(devastator, edgedamage),
36  WEP_CVAR(devastator, radius),
37  NULL,
38  NULL,
39  WEP_CVAR(devastator, force),
41  this.weaponentity_fld,
42  directhitentity
43  );
44 
45  Weapon thiswep = WEP_DEVASTATOR;
46  .entity weaponentity = this.weaponentity_fld;
47  if(this.realowner.(weaponentity).m_weapon == thiswep)
48  {
49  if(GetResource(this.realowner, thiswep.ammo_type) < WEP_CVAR(devastator, ammo))
50  if(!(this.realowner.items & IT_UNLIMITED_AMMO))
51  {
52  this.realowner.cnt = thiswep.m_id;
53  ATTACK_FINISHED(this.realowner, weaponentity) = time;
54  this.realowner.(weaponentity).m_switchweapon = w_getbestweapon(this.realowner, weaponentity);
55  }
56  }
57  delete(this);
58 }
59 
60 void W_Devastator_Explode_think(entity this)
61 {
62  W_Devastator_Explode(this, NULL);
63 }
64 
65 void W_Devastator_DoRemoteExplode(entity this, .entity weaponentity)
66 {
67  W_Devastator_Unregister(this);
68 
69  this.event_damage = func_null;
70  this.takedamage = DAMAGE_NO;
71 
72  bool handled_as_rocketjump = false;
73  entity head = NULL;
74  bool allow_rocketjump = WEP_CVAR(devastator, remote_jump);
75  MUTATOR_CALLHOOK(AllowRocketJumping, allow_rocketjump);
76  allow_rocketjump = M_ARGV(0, bool);
77 
78  if(allow_rocketjump && WEP_CVAR(devastator, remote_jump_radius))
79  {
80  head = WarpZone_FindRadius(
81  this.origin,
82  WEP_CVAR(devastator, remote_jump_radius),
83  false
84  );
85 
86  while(head)
87  {
88  if(head.takedamage && (head == this.realowner))
89  {
90  if(vdist(this.origin - head.WarpZone_findradius_nearest, <=, WEP_CVAR(devastator, remote_jump_radius)))
91  {
92  // we handled this as a rocketjump :)
93  handled_as_rocketjump = true;
94 
95  // modify velocity
96  if(WEP_CVAR(devastator, remote_jump_velocity_z_add))
97  {
98  head.velocity_x *= 0.9;
99  head.velocity_y *= 0.9;
100  head.velocity_z = bound(
101  WEP_CVAR(devastator, remote_jump_velocity_z_min),
102  head.velocity.z + WEP_CVAR(devastator, remote_jump_velocity_z_add),
103  WEP_CVAR(devastator, remote_jump_velocity_z_max)
104  );
105  }
106 
107  // now do the damage
108  RadiusDamage(
109  this,
110  head,
111  WEP_CVAR(devastator, remote_jump_damage),
112  WEP_CVAR(devastator, remote_jump_damage),
113  WEP_CVAR(devastator, remote_jump_radius),
114  NULL,
115  head,
116  (WEP_CVAR(devastator, remote_jump_force) ? WEP_CVAR(devastator, remote_jump_force) : 0),
118  this.weaponentity_fld,
119  NULL
120  );
121  break;
122  }
123  }
124  head = head.chain;
125  }
126  }
127 
128  RadiusDamage(
129  this,
130  this.realowner,
131  WEP_CVAR(devastator, remote_damage),
132  WEP_CVAR(devastator, remote_edgedamage),
133  WEP_CVAR(devastator, remote_radius),
134  (handled_as_rocketjump ? head : NULL),
135  NULL,
136  WEP_CVAR(devastator, remote_force),
138  this.weaponentity_fld,
139  NULL
140  );
141 
142  Weapon thiswep = WEP_DEVASTATOR;
143  if(this.realowner.(weaponentity).m_weapon == thiswep)
144  {
145  if(GetResource(this.realowner, thiswep.ammo_type) < WEP_CVAR(devastator, ammo))
146  if(!(this.realowner.items & IT_UNLIMITED_AMMO))
147  {
148  this.realowner.cnt = thiswep.m_id;
149  ATTACK_FINISHED(this.realowner, weaponentity) = time;
150  this.realowner.(weaponentity).m_switchweapon = w_getbestweapon(this.realowner, weaponentity);
151  }
152  }
153  delete(this);
154 }
155 
156 void W_Devastator_RemoteExplode(entity this, .entity weaponentity)
157 {
158  if(!IS_DEAD(this.realowner))
159  if(this.realowner.(weaponentity).lastrocket)
160  {
161  if((this.spawnshieldtime >= 0)
162  ? (time >= this.spawnshieldtime) // timer
163  : (vdist(NearestPointOnBox(this.realowner, this.origin) - this.origin, >, WEP_CVAR(devastator, remote_radius))) // safety device
164  )
165  {
166  W_Devastator_DoRemoteExplode(this, weaponentity);
167  }
168  }
169 }
170 
171 vector W_Devastator_SteerTo(vector thisdir, vector goaldir, float maxturn_cos)
172 {
173  if(thisdir * goaldir > maxturn_cos)
174  return goaldir;
175  if(thisdir * goaldir < -0.9998) // less than 1 degree and opposite
176  return thisdir; // refuse to guide (better than letting a numerical error happen)
177  float f, m2;
178  vector v;
179  // solve:
180  // g = normalize(thisdir + goaldir * X)
181  // thisdir * g = maxturn
182  //
183  // gg = thisdir + goaldir * X
184  // (thisdir * gg)^2 = maxturn^2 * (gg * gg)
185  //
186  // (1 + (thisdir * goaldir) * X)^2 = maxturn^2 * (1 + X*X + 2 * X * thisdir * goaldir)
187  f = thisdir * goaldir;
188  // (1 + f * X)^2 = maxturn^2 * (1 + X*X + 2 * X * f)
189  // 0 = (m^2 - f^2) * x^2 + (2 * f * (m^2 - 1)) * x + (m^2 - 1)
190  m2 = maxturn_cos * maxturn_cos;
191  v = solve_quadratic(m2 - f * f, 2 * f * (m2 - 1), m2 - 1);
192  return normalize(thisdir + goaldir * v.y); // the larger solution!
193 }
194 // assume thisdir == -goaldir:
195 // f == -1
196 // v = solve_qadratic(m2 - 1, -2 * (m2 - 1), m2 - 1)
197 // (m2 - 1) x^2 - 2 * (m2 - 1) * x + (m2 - 1) = 0
198 // x^2 - 2 * x + 1 = 0
199 // (x - 1)^2 = 0
200 // x = 1
201 // normalize(thisdir + goaldir)
202 // normalize(0)
203 
204 void W_Devastator_Think(entity this)
205 {
206  vector desireddir, olddir, newdir, desiredorigin, goal;
207  float velspeed, f;
208  this.nextthink = time;
209  if(time > this.cnt)
210  {
212  W_Devastator_Explode(this, NULL);
213  return;
214  }
215 
216  // accelerate
217  makevectors(this.angles.x * '-1 0 0' + this.angles.y * '0 1 0');
218  velspeed = WEP_CVAR(devastator, speed) * W_WeaponSpeedFactor(this.realowner) - (this.velocity * v_forward);
219  if(velspeed > 0)
220  this.velocity = this.velocity + v_forward * min(WEP_CVAR(devastator, speedaccel) * W_WeaponSpeedFactor(this.realowner) * frametime, velspeed);
221 
222  // laser guided, or remote detonation
223  .entity weaponentity = this.weaponentity_fld;
224  if(this.realowner.(weaponentity).m_weapon == WEP_DEVASTATOR)
225  {
226  if(this == this.realowner.(weaponentity).lastrocket)
227  if(!this.realowner.(weaponentity).rl_release)
228  if(!PHYS_INPUT_BUTTON_ATCK2(this))
229  if(WEP_CVAR(devastator, guiderate))
230  if(time > this.pushltime)
231  if(!IS_DEAD(this.realowner))
232  {
233  f = WEP_CVAR(devastator, guideratedelay);
234  if(f)
235  f = bound(0, (time - this.pushltime) / f, 1);
236  else
237  f = 1;
238 
239  vector md = this.realowner.(weaponentity).movedir;
240  vector vecs = ((md.x > 0) ? md : '0 0 0');
241 
242  vector dv = v_right * -vecs.y + v_up * vecs.z;
243 
244  if(!W_DualWielding(this.realowner))
245  dv = '0 0 0'; // don't override!
246 
247  velspeed = vlen(this.velocity);
248 
249  makevectors(this.realowner.v_angle);
250  desireddir = WarpZone_RefSys_TransformVelocity(this.realowner, this, v_forward);
251  desiredorigin = WarpZone_RefSys_TransformOrigin(this.realowner, this, this.realowner.origin + this.realowner.view_ofs + dv);
252  olddir = normalize(this.velocity);
253 
254  // now it gets tricky... we want to move like some curve to approximate the target direction
255  // but we are limiting the rate at which we can turn!
256  goal = desiredorigin + ((this.origin - desiredorigin) * desireddir + WEP_CVAR(devastator, guidegoal)) * desireddir;
257  newdir = W_Devastator_SteerTo(olddir, normalize(goal - this.origin), cos(WEP_CVAR(devastator, guiderate) * f * frametime * DEG2RAD));
258 
259  this.velocity = newdir * velspeed;
260  this.angles = vectoangles(this.velocity);
261 
262  if(!this.count)
263  {
264  Send_Effect(EFFECT_ROCKET_GUIDE, this.origin, this.velocity, 1);
265  // TODO add a better sound here
266  sound(this.realowner, CH_WEAPON_B, SND_ROCKET_MODE, VOL_BASE, ATTN_NORM);
267  this.count = 1;
268  }
269  }
270 
271  if(this.rl_detonate_later)
272  W_Devastator_RemoteExplode(this, weaponentity);
273  }
274 
275  if(this.csqcprojectile_clientanimate == 0)
276  UpdateCSQCProjectile(this);
277 }
278 
279 void W_Devastator_Touch(entity this, entity toucher)
280 {
281  if(WarpZone_Projectile_Touch(this, toucher))
282  {
283  if(wasfreed(this))
284  W_Devastator_Unregister(this);
285  return;
286  }
287  W_Devastator_Unregister(this);
288  W_Devastator_Explode(this, toucher);
289 }
290 
291 void W_Devastator_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
292 {
293  if(GetResource(this, RES_HEALTH) <= 0)
294  return;
295 
296  if(!W_CheckProjectileDamage(inflictor.realowner, this.realowner, deathtype, -1)) // no exceptions
297  return; // g_projectiles_damage says to halt
298 
299  TakeResource(this, RES_HEALTH, damage);
300  this.angles = vectoangles(this.velocity);
301 
302  if(GetResource(this, RES_HEALTH) <= 0)
303  W_PrepareExplosionByDamage(this, attacker, W_Devastator_Explode_think);
304 }
305 
306 void W_Devastator_Attack(Weapon thiswep, entity actor, .entity weaponentity, int fire)
307 {
308  W_DecreaseAmmo(thiswep, actor, WEP_CVAR(devastator, ammo), weaponentity);
309 
310  W_SetupShot_ProjectileSize(actor, weaponentity, '-3 -3 -3', '3 3 3', false, 5, SND_ROCKET_FIRE, CH_WEAPON_A, WEP_CVAR(devastator, damage), thiswep.m_id);
311  W_MuzzleFlash(thiswep, actor, weaponentity, w_shotorg, w_shotdir);
312 
313  entity missile = WarpZone_RefSys_SpawnSameRefSys(actor);
314  missile.weaponentity_fld = weaponentity;
315  missile.owner = missile.realowner = actor;
316  actor.(weaponentity).lastrocket = missile;
317  if(WEP_CVAR(devastator, detonatedelay) >= 0)
318  missile.spawnshieldtime = time + WEP_CVAR(devastator, detonatedelay);
319  else
320  missile.spawnshieldtime = -1; // NOTE: proximity based when rocket jumping
321  missile.pushltime = time + WEP_CVAR(devastator, guidedelay);
322  missile.classname = "rocket";
323  missile.bot_dodge = true;
324  missile.bot_dodgerating = WEP_CVAR(devastator, damage) * 2; // * 2 because it can be detonated inflight which makes it even more dangerous
325 
326  missile.takedamage = DAMAGE_YES;
327  missile.damageforcescale = WEP_CVAR(devastator, damageforcescale);
328  SetResourceExplicit(missile, RES_HEALTH, WEP_CVAR(devastator, health));
329  missile.event_damage = W_Devastator_Damage;
330  missile.damagedbycontents = true;
331  IL_PUSH(g_damagedbycontents, missile);
332 
333  set_movetype(missile, MOVETYPE_FLY);
334  PROJECTILE_MAKETRIGGER(missile);
335  missile.projectiledeathtype = thiswep.m_id;
336  setsize(missile, '-3 -3 -3', '3 3 3'); // give it some size so it can be shot
337 
338  setorigin(missile, w_shotorg - v_forward * 3); // move it back so it hits the wall at the right point
339  W_SetupProjVelocity_Basic(missile, WEP_CVAR(devastator, speedstart), 0);
340  missile.angles = vectoangles(missile.velocity);
341 
342  settouch(missile, W_Devastator_Touch);
343  setthink(missile, W_Devastator_Think);
344  missile.nextthink = time;
345  missile.cnt = time + WEP_CVAR(devastator, lifetime);
346  missile.rl_detonate_later = (fire & 2); // allow instant detonation
347  missile.flags = FL_PROJECTILE;
348  IL_PUSH(g_projectiles, missile);
349  IL_PUSH(g_bot_dodge, missile);
350  missile.missile_flags = MIF_SPLASH;
351 
352  CSQCProjectile(missile, WEP_CVAR(devastator, guiderate) == 0 && WEP_CVAR(devastator, speedaccel) == 0, PROJECTILE_ROCKET, false); // because of fly sound
353 
354  // common properties
355  MUTATOR_CALLHOOK(EditProjectile, actor, missile);
356 
357  if (time >= missile.nextthink)
358  {
359  getthink(missile)(missile);
360  }
361 }
362 
363 METHOD(Devastator, wr_aim, void(entity thiswep, entity actor, .entity weaponentity))
364 {
365  // aim and decide to fire if appropriate
366  PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, WEP_CVAR(devastator, speed), 0, WEP_CVAR(devastator, lifetime), false);
367  if(skill >= 2) // skill 0 and 1 bots won't detonate rockets!
368  {
369  // decide whether to detonate rockets
370  float edgedamage, coredamage, edgeradius, recipricoledgeradius;
371  float selfdamage, teamdamage, enemydamage;
372  edgedamage = WEP_CVAR(devastator, edgedamage);
373  coredamage = WEP_CVAR(devastator, damage);
374  edgeradius = WEP_CVAR(devastator, radius);
375  recipricoledgeradius = 1 / edgeradius;
376  selfdamage = 0;
377  teamdamage = 0;
378  enemydamage = 0;
379  IL_EACH(g_projectiles, it.realowner == actor && it.classname == "rocket",
380  {
381  entity rocket = it;
382  IL_EACH(g_bot_targets, it.bot_attack,
383  {
384  float d = vlen(it.origin + (it.mins + it.maxs) * 0.5 - rocket.origin);
385  d = bound(0, edgedamage + (coredamage - edgedamage) * sqrt(1 - d * recipricoledgeradius), 10000);
386  // count potential damage according to type of target
387  if(it == actor)
388  selfdamage = selfdamage + d;
389  else if(SAME_TEAM(it, actor))
390  teamdamage = teamdamage + d;
391  else if(bot_shouldattack(actor, it))
392  enemydamage = enemydamage + d;
393  });
394  });
395  float desirabledamage;
396  desirabledamage = enemydamage;
397  if(StatusEffects_active(STATUSEFFECT_Shield, actor) && !StatusEffects_active(STATUSEFFECT_SpawnShield, actor))
398  desirabledamage = desirabledamage - selfdamage * autocvar_g_balance_selfdamagepercent;
399  if(teamplay && actor.team)
400  desirabledamage = desirabledamage - teamdamage;
401 
402  makevectors(actor.v_angle);
403  IL_EACH(g_projectiles, it.realowner == actor && it.classname == "rocket",
404  {
405  if(skill > 9) // normal players only do this for the target they are tracking
406  {
407  entity rocket = it;
408  IL_EACH(g_bot_targets, it.bot_attack,
409  {
410  if((v_forward * normalize(rocket.origin - it.origin) < 0.1)
411  && desirabledamage > 0.1 * coredamage
412  ) PHYS_INPUT_BUTTON_ATCK2(actor) = true;
413  });
414  }
415  else
416  {
417  //As the distance gets larger, a correct detonation gets near imposible
418  //Bots are assumed to use the rocket spawnfunc_light to see if the rocket gets near a player
419  if((v_forward * normalize(it.origin - actor.enemy.origin) < 0.1)
420  && IS_PLAYER(actor.enemy)
421  && (desirabledamage >= 0.1 * coredamage)
422  )
423  {
424  float distance = bound(300, vlen(actor.origin - actor.enemy.origin), 30000);
425  if(random() / distance * 300 > frametime * bound(0, (10 - skill) * 0.2, 1))
426  PHYS_INPUT_BUTTON_ATCK2(actor) = true;
427  }
428  }
429  });
430  // if we would be doing at X percent of the core damage, detonate it
431  // but don't fire a new shot at the same time!
432  if(desirabledamage >= 0.75 * coredamage) //this should do group damage in rare fortunate events
433  PHYS_INPUT_BUTTON_ATCK2(actor) = true;
434  if((skill > 6.5) && (selfdamage > GetResource(actor, RES_HEALTH)))
435  PHYS_INPUT_BUTTON_ATCK2(actor) = false;
436  //if(PHYS_INPUT_BUTTON_ATCK2(actor) == true)
437  // dprint(ftos(desirabledamage),"\n");
438  if(PHYS_INPUT_BUTTON_ATCK2(actor)) PHYS_INPUT_BUTTON_ATCK(actor) = false;
439  }
440 }
441 
442 METHOD(Devastator, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
443 {
444  if(WEP_CVAR(devastator, reload_ammo) && actor.(weaponentity).clip_load < WEP_CVAR(devastator, ammo)) { // forced reload
445  thiswep.wr_reload(thiswep, actor, weaponentity);
446  } else {
447  if(fire & 1)
448  {
449  if(actor.(weaponentity).rl_release || WEP_CVAR(devastator, guidestop))
450  if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR(devastator, refire)))
451  {
452  W_Devastator_Attack(thiswep, actor, weaponentity, fire);
453  weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR(devastator, animtime), w_ready);
454  actor.(weaponentity).rl_release = 0;
455  }
456  }
457  else
458  actor.(weaponentity).rl_release = 1;
459 
460  if(fire & 2)
461  if(actor.(weaponentity).m_switchweapon == thiswep)
462  {
463  bool rockfound = false;
464  IL_EACH(g_projectiles, it.realowner == actor && it.classname == "rocket",
465  {
466  if(!it.rl_detonate_later)
467  {
468  it.rl_detonate_later = true;
469  rockfound = true;
470  }
471  });
472  if(rockfound)
473  sound(actor, CH_WEAPON_B, SND_ROCKET_DET, VOL_BASE, ATTN_NORM);
474  }
475  }
476 }
477 METHOD(Devastator, wr_setup, void(entity thiswep, entity actor, .entity weaponentity))
478 {
479  actor.(weaponentity).rl_release = 1;
480 }
481 METHOD(Devastator, wr_checkammo1, bool(entity thiswep, entity actor, .entity weaponentity))
482 {
483  #if 0
484  // don't switch while guiding a missile
485  if(ATTACK_FINISHED(actor, weaponentity) <= time || PS(actor).m_weapon != WEP_DEVASTATOR)
486  {
487  ammo_amount = false;
488  if(WEP_CVAR(devastator, reload_ammo))
489  {
490  if(GetResource(actor, thiswep.ammo_type) < WEP_CVAR(devastator, ammo) && actor.(weaponentity).(weapon_load[WEP_DEVASTATOR.m_id]) < WEP_CVAR(devastator, ammo))
491  ammo_amount = true;
492  }
493  else if(GetResource(actor, thiswep.ammo_type) < WEP_CVAR(devastator, ammo))
494  ammo_amount = true;
495  return !ammo_amount;
496  }
497  #endif
498  #if 0
499  if(actor.rl_release == 0)
500  {
501  LOG_INFOF("W_Devastator(WR_CHECKAMMO1): %d, %.2f, %d: TRUE", actor.rl_release, GetResource(actor, thiswep.ammo_type), WEP_CVAR(devastator, ammo));
502  return true;
503  }
504  else
505  {
506  ammo_amount = GetResource(actor, thiswep.ammo_type) >= WEP_CVAR(devastator, ammo);
507  ammo_amount += actor.(weaponentity).(weapon_load[WEP_DEVASTATOR.m_id]) >= WEP_CVAR(devastator, ammo);
508  LOG_INFOF("W_Devastator(WR_CHECKAMMO1): %d, %.2f, %d: %s", actor.rl_release, GetResource(actor, thiswep.ammo_type), WEP_CVAR(devastator, ammo), (ammo_amount ? "TRUE" : "FALSE"));
509  return ammo_amount;
510  }
511  #else
512  float ammo_amount = GetResource(actor, thiswep.ammo_type) >= WEP_CVAR(devastator, ammo);
513  ammo_amount += actor.(weaponentity).(weapon_load[thiswep.m_id]) >= WEP_CVAR(devastator, ammo);
514  return ammo_amount;
515  #endif
516 }
517 METHOD(Devastator, wr_checkammo2, bool(entity thiswep, entity actor, .entity weaponentity))
518 {
519  return false;
520 }
521 METHOD(Devastator, wr_resetplayer, void(entity thiswep, entity actor))
522 {
523  for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
524  {
525  .entity weaponentity = weaponentities[slot];
526  actor.(weaponentity).lastrocket = NULL; // stop rocket guiding, no revenge from the grave!
527  actor.(weaponentity).rl_release = 0;
528  }
529 }
530 METHOD(Devastator, wr_reload, void(entity thiswep, entity actor, .entity weaponentity))
531 {
532  W_Reload(actor, weaponentity, WEP_CVAR(devastator, ammo), SND_RELOAD);
533 }
534 METHOD(Devastator, wr_suicidemessage, Notification(entity thiswep))
535 {
536  return WEAPON_DEVASTATOR_SUICIDE;
537 }
538 METHOD(Devastator, wr_killmessage, Notification(entity thiswep))
539 {
541  return WEAPON_DEVASTATOR_MURDER_SPLASH;
542  else
543  return WEAPON_DEVASTATOR_MURDER_DIRECT;
544 }
545 
546 #endif
547 #ifdef CSQC
548 
549 METHOD(Devastator, wr_impacteffect, void(entity thiswep, entity actor))
550 {
551  vector org2;
552  org2 = w_org + w_backoff * 12;
553  pointparticles(EFFECT_ROCKET_EXPLODE, org2, '0 0 0', 1);
554  if(!w_issilent)
555  sound(actor, CH_SHOTS, SND_ROCKET_IMPACT, VOL_BASE, ATTN_NORM);
556 }
557 
558 #endif
const int HITTYPE_SPLASH
automatically set by RadiusDamage
Definition: all.qh:27
#define PHYS_INPUT_BUTTON_ATCK2(s)
Definition: player.qh:148
#define W_SetupProjVelocity_Basic(ent, pspeed, pspread)
Definition: tracing.qh:48
#define IL_EACH(this, cond, body)
bool bot_aim(entity this,.entity weaponentity, float shotspeed, float shotspeedupward, float maxshottime, float applygravity)
float weapon_load[REGISTRY_MAX(Weapons)]
Definition: weaponsystem.qh:29
float DEG2RAD
Definition: csprogsdefs.qc:961
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
ERASEABLE vector solve_quadratic(float a, float b, float c)
ax^2 + bx + c = 0
Definition: math.qh:307
#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
#define getthink(e)
const int MIF_SPLASH
Definition: common.qh:34
#define w_getbestweapon(ent, wepent)
Definition: selection.qh:23
#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
float skill
Definition: api.qh:35
#define PS(this)
Definition: state.qh:18
#define WEP_CVAR(wepname, name)
Definition: all.qh:299
float pushltime
Definition: jumppads.qh:10
vector w_shotdir
Definition: tracing.qh:19
entity weaponentity_fld
Definition: weaponsystem.qh:27
origin
Definition: ent_cs.qc:114
#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
vector WarpZone_RefSys_TransformVelocity(entity from, entity to, vector vel)
Definition: common.qc:756
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
const float ATTN_NORM
Definition: csprogsdefs.qc:226
RES_HEALTH
Definition: ent_cs.qc:126
float ammo
Definition: sv_turrets.qh:44
vector WarpZone_RefSys_TransformOrigin(entity from, entity to, vector org)
Definition: common.qc:748
vector movedir
Definition: progsdefs.qc:203
float lifetime
Definition: powerups.qc:23
float autocvar_g_balance_selfdamagepercent
Definition: damage.qh:24
float cnt
Definition: powerups.qc:24
ERASEABLE entity IL_PUSH(IntrusiveList this, entity it)
Push to tail.
void UpdateCSQCProjectile(entity e)
const int CH_WEAPON_A
Definition: sound.qh:7
#define LOG_INFOF(...)
Definition: log.qh:71
bool W_DualWielding(entity player)
Definition: common.qc:20
vector v_up
Definition: csprogsdefs.qc:31
const int MAX_WEAPONSLOTS
Definition: weapon.qh:13
Resource ammo_type
M: ammotype : main ammo type.
Definition: weapon.qh:48
const int PROJECTILE_ROCKET
Definition: projectiles.qh:4
bool weapon_prepareattack(Weapon thiswep, entity actor,.entity weaponentity, bool secondary, float attacktime)
void W_PrepareExplosionByDamage(entity this, entity attacker, void(entity this) explode)
Definition: common.qc:91
entity WarpZone_RefSys_SpawnSameRefSys(entity me)
Definition: common.qc:791
#define pointparticles
Definition: csprogsdefs.qh:13
#define NULL
Definition: post.qh:17
float frametime
Definition: csprogsdefs.qc:17
const float VOL_BASE
Definition: sound.qh:36
#define PHYS_INPUT_BUTTON_ATCK(s)
Definition: player.qh:146
float takedamage
Definition: progsdefs.qc:147
float teamplay
Definition: progsdefs.qc:31
#define M_ARGV(x, type)
Definition: events.qh:17
#define IS_DEAD(s)
Definition: utils.qh:26
entity WarpZone_FindRadius(vector org, float rad, bool needlineofsight)
Definition: common.qc:669
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
vector v
Definition: ent_cs.qc:116
float GetResource(entity e, Resource res_type)
Returns the current amount of resource the given entity has.
Definition: cl_resources.qc:10
#define vdist(v, cmp, f)
Vector distance comparison, avoids sqrt()
Definition: vector.qh:8
float count
Definition: powerups.qc:22
float W_WeaponSpeedFactor(entity this)
Definition: weaponsystem.qc:45
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
vector v_right
Definition: csprogsdefs.qc:31
entity realowner
Definition: common.qh:25
#define MUTATOR_CALLHOOK(id,...)
Definition: base.qh:140
entity weaponentities[MAX_WEAPONSLOTS]
Definition: weapon.qh:14
setorigin(ent, v)
#define setthink(e, f)
float WarpZone_Projectile_Touch(entity this, entity toucher)
Definition: server.qc:382
#define ATTACK_FINISHED(ent, w)
Definition: weaponsystem.qh:42
vector angles
Definition: csprogsdefs.qc:104
void W_DecreaseAmmo(Weapon wep, entity actor, float ammo_use,.entity weaponentity)
#define sound(e, c, s, v, a)
Definition: sound.qh:52
float csqcprojectile_clientanimate
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
const int CH_WEAPON_B
Definition: sound.qh:8
int m_id
Definition: weapon.qh:42
#define makevectors
Definition: post.qh:21
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