Xonotic
arc.qc
Go to the documentation of this file.
1 #include "arc.qh"
2 
3 #ifdef SVQC
6 
7 bool W_Arc_Beam_Send(entity this, entity to, int sf)
8 {
9  WriteHeader(MSG_ENTITY, ENT_CLIENT_ARC_BEAM);
10 
11  // Truncate information when this beam is displayed to the owner client
12  // - The owner client has no use for beam start position or directions,
13  // it always figures this information out for itself with csqc code.
14  // - Spectating the owner also truncates this information.
15  float drawlocal = ((to == this.owner) || ((to.enemy == this.owner) && IS_SPEC(to)));
16  if(drawlocal) { sf &= ~ARC_SF_LOCALMASK; }
17 
18  WriteByte(MSG_ENTITY, sf);
19  WriteByte(MSG_ENTITY, weaponslot(this.weaponentity_fld));
20 
21  if(sf & ARC_SF_SETTINGS) // settings information
22  {
23  WriteShort(MSG_ENTITY, WEP_CVAR(arc, beam_degreespersegment));
24  WriteShort(MSG_ENTITY, WEP_CVAR(arc, beam_distancepersegment));
25  WriteShort(MSG_ENTITY, WEP_CVAR(arc, beam_maxangle));
26  WriteCoord(MSG_ENTITY, WEP_CVAR(arc, beam_range));
27  WriteShort(MSG_ENTITY, WEP_CVAR(arc, beam_returnspeed));
28  WriteByte(MSG_ENTITY, WEP_CVAR(arc, beam_tightness) * 10);
29 
30  WriteByte(MSG_ENTITY, drawlocal);
31  WriteByte(MSG_ENTITY, etof(this.owner));
32  }
33  if(sf & ARC_SF_START) // starting location
34  {
35  WriteVector(MSG_ENTITY, this.beam_start);
36  }
37  if(sf & ARC_SF_WANTDIR) // want/aim direction
38  {
39  WriteVector(MSG_ENTITY, this.beam_wantdir);
40  }
41  if(sf & ARC_SF_BEAMDIR) // beam direction
42  {
43  WriteAngleVector(MSG_ENTITY, this.beam_dir);
44  }
45  if(sf & ARC_SF_BEAMTYPE) // beam type
46  {
47  WriteByte(MSG_ENTITY, this.beam_type);
48  }
49 
50  return true;
51 }
52 
53 void Reset_ArcBeam(entity player, vector forward)
54 {
55  for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
56  {
57  .entity weaponentity = weaponentities[slot];
58  if(!player.(weaponentity).arc_beam)
59  continue;
60  player.(weaponentity).arc_beam.beam_dir = forward;
61  player.(weaponentity).arc_beam.beam_teleporttime = time;
62  }
63 }
64 
65 float Arc_GetHeat_Percent(entity player, .entity weaponentity)
66 {
67  if ( WEP_CVAR(arc, overheat_max) <= 0 || WEP_CVAR(arc, overheat_max) <= 0 )
68  {
69  player.arc_overheat = 0;
70  return 0;
71  }
72 
73  if ( player.(weaponentity).arc_beam )
74  return player.(weaponentity).arc_beam.beam_heat/WEP_CVAR(arc, overheat_max);
75 
76  if ( player.arc_overheat > time )
77  {
78  return (player.arc_overheat-time) / WEP_CVAR(arc, overheat_max)
79  * player.arc_cooldown;
80  }
81 
82  return 0;
83 }
84 void Arc_Player_SetHeat(entity player, .entity weaponentity)
85 {
86  player.(weaponentity).arc_heat_percent = Arc_GetHeat_Percent(player, weaponentity);
87  //dprint("Heat: ",ftos(player.arc_heat_percent*100),"%\n");
88 }
89 
90 void W_Arc_Bolt_Explode(entity this, entity directhitentity)
91 {
92  this.event_damage = func_null;
93  RadiusDamage(this, this.realowner, WEP_CVAR(arc, bolt_damage), WEP_CVAR(arc, bolt_edgedamage), WEP_CVAR(arc, bolt_radius), NULL, NULL, WEP_CVAR(arc, bolt_force), this.projectiledeathtype, this.weaponentity_fld, directhitentity);
94 
95  delete(this);
96 }
97 
98 void W_Arc_Bolt_Explode_use(entity this, entity actor, entity trigger)
99 {
100  W_Arc_Bolt_Explode(this, trigger);
101 }
102 
103 void W_Arc_Bolt_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
104 {
105  if(GetResource(this, RES_HEALTH) <= 0)
106  return;
107 
108  if(!W_CheckProjectileDamage(inflictor.realowner, this.realowner, deathtype, -1))
109  return; // g_projectiles_damage says to halt
110 
111  TakeResource(this, RES_HEALTH, damage);
112  this.angles = vectoangles(this.velocity);
113 
114  if(GetResource(this, RES_HEALTH) <= 0)
115  W_PrepareExplosionByDamage(this, attacker, getthink(this));
116 }
117 
118 void W_Arc_Bolt_Touch(entity this, entity toucher)
119 {
120  PROJECTILE_TOUCH(this, toucher);
121  if(this.cnt >= WEP_CVAR(arc, bolt_bounce_count) || !WEP_CVAR(arc, bolt_bounce_count) || toucher.takedamage == DAMAGE_AIM) {
122  this.use(this, NULL, toucher);
123  } else {
124  this.cnt++;
125  Send_Effect(EFFECT_BALL_SPARKS, this.origin, this.velocity, 1);
126  this.angles = vectoangles(this.velocity);
127  this.owner = NULL;
129  if(WEP_CVAR(arc, bolt_bounce_explode))
130  RadiusDamage(this, this.realowner, WEP_CVAR(arc, bolt_damage), WEP_CVAR(arc, bolt_edgedamage), WEP_CVAR(arc, bolt_radius), NULL, NULL, WEP_CVAR(arc, bolt_force), this.projectiledeathtype, this.weaponentity_fld, toucher);
131  if(this.cnt == 1 && WEP_CVAR(arc, bolt_bounce_lifetime))
132  this.nextthink = time + WEP_CVAR(arc, bolt_bounce_lifetime);
133  }
134 }
135 
136 void W_Arc_Attack_Bolt(Weapon thiswep, entity actor, .entity weaponentity, int fire)
137 {
138  W_SetupShot(actor, weaponentity, false, 2, SND_ELECTRO_FIRE2, CH_WEAPON_A, WEP_CVAR(arc, bolt_damage), thiswep.m_id | HITTYPE_SECONDARY);
139 
140  W_MuzzleFlash(thiswep, actor, weaponentity, w_shotorg, w_shotdir);
141 
142  entity missile = new(missile);
143  missile.owner = missile.realowner = actor;
144  missile.bot_dodge = true;
145  IL_PUSH(g_bot_dodge, missile);
146  missile.bot_dodgerating = WEP_CVAR(arc, bolt_damage);
147 
148  missile.takedamage = DAMAGE_YES;
149  SetResourceExplicit(missile, RES_HEALTH, WEP_CVAR(arc, bolt_health));
150  missile.damageforcescale = WEP_CVAR(arc, bolt_damageforcescale);
151  missile.event_damage = W_Arc_Bolt_Damage;
152  missile.damagedbycontents = true;
153  IL_PUSH(g_damagedbycontents, missile);
154 
155  settouch(missile, W_Arc_Bolt_Touch);
156  missile.cnt = 0;
157  missile.use = W_Arc_Bolt_Explode_use;
159  missile.nextthink = time + WEP_CVAR(arc, bolt_lifetime);
160  PROJECTILE_MAKETRIGGER(missile);
161  missile.projectiledeathtype = thiswep.m_id | HITTYPE_SECONDARY;
162  missile.weaponentity_fld = weaponentity;
163  setorigin(missile, w_shotorg);
164  setsize(missile, '0 0 0', '0 0 0');
165 
167  W_SetupProjVelocity_PRE(missile, arc, bolt_);
168 
169  missile.angles = vectoangles(missile.velocity);
170  missile.flags = FL_PROJECTILE;
171  IL_PUSH(g_projectiles, missile);
172  missile.missile_flags = MIF_SPLASH;
173 
174  CSQCProjectile(missile, true, PROJECTILE_ARC_BOLT, true);
175 
176  MUTATOR_CALLHOOK(EditProjectile, actor, missile);
177 
178  actor.(weaponentity).misc_bulletcounter = actor.(weaponentity).misc_bulletcounter + 1;
179  if(actor.(weaponentity).misc_bulletcounter == 0)
180  {
181  ATTACK_FINISHED(actor, weaponentity) = time + WEP_CVAR(arc, bolt_refire2) * W_WeaponRateFactor(actor);
182  weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR(arc, bolt_refire), w_ready);
183  }
184  else
185  {
186  weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR(arc, bolt_refire), W_Arc_Attack_Bolt);
187  }
188 }
189 
190 void W_Arc_Beam_Think(entity this)
191 {
192  .entity weaponentity = this.weaponentity_fld;
193  entity own = this.owner;
194  if(this != own.(weaponentity).arc_beam)
195  {
196  delete(this);
197  return;
198  }
199 
200  float burst = 0;
201  if( (PHYS_INPUT_BUTTON_ATCK2(own) && !WEP_CVAR(arc, bolt)) || this.beam_bursting)
202  {
203  if(!this.beam_bursting)
204  this.beam_bursting = true;
205  burst = ARC_BT_BURSTMASK;
206  }
207 
208  Weapon thiswep = WEP_ARC;
209 
210  // TODO: use standard weapon use checks here!
211  if(
212  !IS_PLAYER(own)
213  ||
214  IS_DEAD(own)
215  ||
216  game_stopped
217  ||
218  !weapon_prepareattack_check(thiswep, own, weaponentity, this.beam_bursting, -1)
219  ||
220  own.(weaponentity).m_switchweapon != WEP_ARC
221  ||
222  (!PHYS_INPUT_BUTTON_ATCK(own) && !burst )
223  ||
224  own.vehicle
225  ||
226  (WEP_CVAR(arc, overheat_max) > 0 && this.beam_heat >= WEP_CVAR(arc, overheat_max))
227  )
228  {
229  if ( WEP_CVAR(arc, cooldown) > 0 )
230  {
231  float cooldown_speed = 0;
232  if ( this.beam_heat > WEP_CVAR(arc, overheat_min) && WEP_CVAR(arc, cooldown) > 0 )
233  {
234  cooldown_speed = WEP_CVAR(arc, cooldown);
235  }
236  else if ( !burst )
237  {
238  cooldown_speed = this.beam_heat / WEP_CVAR(arc, beam_refire);
239  }
240 
241  if ( cooldown_speed )
242  {
243  if ( WEP_CVAR(arc, cooldown_release) || (WEP_CVAR(arc, overheat_max) > 0 && this.beam_heat >= WEP_CVAR(arc, overheat_max)) )
244  own.arc_overheat = time + this.beam_heat / cooldown_speed;
245  own.arc_cooldown = cooldown_speed;
246  }
247 
248  if ( WEP_CVAR(arc, overheat_max) > 0 && this.beam_heat >= WEP_CVAR(arc, overheat_max) )
249  {
250  Send_Effect(EFFECT_ARC_OVERHEAT,
251  this.beam_start, this.beam_wantdir, 1 );
252  sound(this, CH_WEAPON_A, SND_ARC_STOP, VOL_BASE, ATTN_NORM);
253  }
254  }
255 
256  if(this == own.(weaponentity).arc_beam) { own.(weaponentity).arc_beam = NULL; }
257  if(!thiswep.wr_checkammo1(thiswep, own, weaponentity) && !(own.items & IT_UNLIMITED_AMMO))
258  {
259  // note: this doesn't force the switch
260  W_SwitchToOtherWeapon(own, weaponentity);
261  }
262  own.(weaponentity).arc_BUTTON_ATCK_prev = false; // allow switching weapons
263  delete(this);
264  return;
265  }
266 
267  // decrease ammo
268  float coefficient = frametime;
269  if(!(own.items & IT_UNLIMITED_AMMO))
270  {
271  float rootammo;
272  if(burst)
273  { rootammo = WEP_CVAR(arc, burst_ammo); }
274  else
275  { rootammo = WEP_CVAR(arc, beam_ammo); }
276 
277  if(rootammo)
278  {
279  coefficient = min(coefficient, GetResource(own, thiswep.ammo_type) / rootammo);
280  SetResource(own, thiswep.ammo_type, max(0, GetResource(own, thiswep.ammo_type) - (rootammo * frametime)));
281  }
282  }
283  float heat_speed = burst ? WEP_CVAR(arc, burst_heat) : WEP_CVAR(arc, beam_heat);
284  this.beam_heat = min( WEP_CVAR(arc, overheat_max), this.beam_heat + heat_speed*frametime );
285 
286  makevectors(own.v_angle);
287 
289  own,
290  weaponentity,
291  true,
292  0,
293  SND_Null,
294  0,
295  WEP_CVAR(arc, beam_damage) * coefficient,
296  WEP_CVAR(arc, beam_range),
297  thiswep.m_id
298  );
299 
300  // After teleport, "lock" the beam until the teleport is confirmed.
301  if (time < this.beam_teleporttime + ANTILAG_LATENCY(own)) {
302  w_shotdir = this.beam_dir;
303  }
304 
305  // network information: shot origin and want/aim direction
306  if(this.beam_start != w_shotorg)
307  {
308  this.SendFlags |= ARC_SF_START;
309  this.beam_start = w_shotorg;
310  }
311  if(this.beam_wantdir != w_shotdir)
312  {
313  this.SendFlags |= ARC_SF_WANTDIR;
314  this.beam_wantdir = w_shotdir;
315  }
316 
317  if(!this.beam_initialized)
318  {
319  this.beam_dir = w_shotdir;
320  this.beam_initialized = true;
321  }
322 
323  // WEAPONTODO: Detect player velocity so that the beam curves when moving too
324  // idea: blend together this.beam_dir with the inverted direction the player is moving in
325  // might have to make some special accomodation so that it only uses view_right and view_up
326 
327  // note that if we do this, it'll always be corrected to a maximum angle by beam_maxangle handling
328 
329  float segments;
330  if(this.beam_dir != w_shotdir)
331  {
332  // calculate how much we're going to move the end of the beam to the want position
333  // WEAPONTODO (server and client):
334  // blendfactor never actually becomes 0 in this situation, which is a problem
335  // regarding precision... this means that this.beam_dir and w_shotdir approach
336  // eachother, however they never actually become the same value with this method.
337  // Perhaps we should do some form of rounding/snapping?
338  float angle = vlen(w_shotdir - this.beam_dir) * RAD2DEG;
339  if(angle && (angle > WEP_CVAR(arc, beam_maxangle)))
340  {
341  // if the angle is greater than maxangle, force the blendfactor to make this the maximum factor
342  float blendfactor = bound(
343  0,
344  (1 - (WEP_CVAR(arc, beam_returnspeed) * frametime)),
345  min(WEP_CVAR(arc, beam_maxangle) / angle, 1)
346  );
347  if(vdist(this.beam_dir - w_shotdir, <, 0.01))
348  this.beam_dir = w_shotdir;
349  else
350  this.beam_dir = normalize((w_shotdir * (1 - blendfactor)) + (this.beam_dir * blendfactor));
351  }
352  else
353  {
354  // the radius is not too far yet, no worries :D
355  float blendfactor = bound(
356  0,
357  (1 - (WEP_CVAR(arc, beam_returnspeed) * frametime)),
358  1
359  );
360  if(vdist(this.beam_dir - w_shotdir, <, 0.01))
361  this.beam_dir = w_shotdir;
362  else
363  this.beam_dir = normalize((w_shotdir * (1 - blendfactor)) + (this.beam_dir * blendfactor));
364  }
365 
366  // network information: beam direction
367  this.SendFlags |= ARC_SF_BEAMDIR;
368 
369  // calculate how many segments are needed
370  float max_allowed_segments;
371 
372  if(WEP_CVAR(arc, beam_distancepersegment))
373  {
374  max_allowed_segments = min(
375  ARC_MAX_SEGMENTS,
376  1 + (vlen(w_shotdir / WEP_CVAR(arc, beam_distancepersegment)))
377  );
378  }
379  else { max_allowed_segments = ARC_MAX_SEGMENTS; }
380 
381  if(WEP_CVAR(arc, beam_degreespersegment))
382  {
383  segments = bound(
384  1,
385  (
386  min(
387  angle,
388  WEP_CVAR(arc, beam_maxangle)
389  )
390  /
391  WEP_CVAR(arc, beam_degreespersegment)
392  ),
393  max_allowed_segments
394  );
395  }
396  else { segments = 1; }
397  }
398  else { segments = 1; }
399 
400  vector beam_endpos = (w_shotorg + (this.beam_dir * WEP_CVAR(arc, beam_range)));
401  vector beam_controlpoint = w_shotorg + w_shotdir * (WEP_CVAR(arc, beam_range) * (1 - WEP_CVAR(arc, beam_tightness)));
402 
403  float i;
404  float new_beam_type = 0;
405  vector last_origin = w_shotorg;
406  for(i = 1; i <= segments; ++i)
407  {
408  // WEAPONTODO (client):
409  // In order to do nice fading and pointing on the starting segment, we must always
410  // have that drawn as a separate triangle... However, that is difficult to do when
411  // keeping in mind the above problems and also optimizing the amount of segments
412  // drawn on screen at any given time. (Automatic beam quality scaling, essentially)
413 
414  vector new_origin = bezier_quadratic_getpoint(
415  w_shotorg,
416  beam_controlpoint,
417  beam_endpos,
418  i / segments);
419  vector new_dir = normalize(new_origin - last_origin);
420 
422  own,
423  last_origin,
424  new_origin,
425  MOVE_NORMAL,
426  own,
427  ANTILAG_LATENCY(own)
428  );
429 
430  // Do all the transforms for warpzones right now, as we already
431  // "are" in the post-trace system (if we hit a player, that's
432  // always BEHIND the last passed wz).
433  last_origin = trace_endpos;
435  beam_controlpoint = WarpZone_TransformOrigin(WarpZone_trace_transform, beam_controlpoint);
436  beam_endpos = WarpZone_TransformOrigin(WarpZone_trace_transform, beam_endpos);
438 
439  bool is_player = (
441  ||
442  trace_ent.classname == "body"
443  ||
445  );
446 
447  if(trace_ent)
448  {
449  if(SAME_TEAM(own, trace_ent))
450  {
451  float roothealth = ((burst) ? WEP_CVAR(arc, burst_healing_hps) : WEP_CVAR(arc, beam_healing_hps));
452  float rootarmor = ((burst) ? WEP_CVAR(arc, burst_healing_aps) : WEP_CVAR(arc, beam_healing_aps));
453  float hplimit = ((IS_PLAYER(trace_ent)) ? WEP_CVAR(arc, beam_healing_hmax) : RES_LIMIT_NONE);
454  Heal(trace_ent, own, (roothealth * coefficient), hplimit);
455  if(IS_PLAYER(trace_ent) && rootarmor)
456  {
457  if(GetResource(trace_ent, RES_ARMOR) <= WEP_CVAR(arc, beam_healing_amax))
458  {
459  GiveResourceWithLimit(trace_ent, RES_ARMOR, (rootarmor * coefficient), WEP_CVAR(arc, beam_healing_amax));
460  trace_ent.pauserotarmor_finished = max(
461  trace_ent.pauserotarmor_finished,
463  );
464  }
465  }
466  if(roothealth || rootarmor)
467  new_beam_type = ARC_BT_HEAL;
468  }
469  else if(trace_ent.takedamage && (is_player || WEP_CVAR(arc, beam_nonplayerdamage)))
470  {
471  // calculate our own hit origin as trace_endpos tends to jump around annoyingly (to player origin?)
472  // NO. trace_endpos should be just fine. If not,
473  // that's an engine bug that needs proper debugging.
474  vector hitorigin = trace_endpos;
475 
476  float falloff = ExponentialFalloff(
477  WEP_CVAR(arc, beam_falloff_mindist),
478  WEP_CVAR(arc, beam_falloff_maxdist),
479  WEP_CVAR(arc, beam_falloff_halflifedist),
481  );
482 
483  float rootdamage;
484  if(is_player)
485  {
486  if(burst)
487  { rootdamage = WEP_CVAR(arc, burst_damage); }
488  else
489  { rootdamage = WEP_CVAR(arc, beam_damage); }
490  }
491  else
492  { rootdamage = WEP_CVAR(arc, beam_nonplayerdamage); }
493 
495  {
496  accuracy_add(
497  own,
498  WEP_ARC,
499  0,
500  rootdamage * coefficient * falloff
501  );
502  }
503 
504  Damage(
505  trace_ent,
506  own,
507  own,
508  rootdamage * coefficient * falloff,
509  WEP_ARC.m_id,
510  weaponentity,
511  hitorigin,
512  WEP_CVAR(arc, beam_force) * new_dir * coefficient * falloff
513  );
514 
515  new_beam_type = ARC_BT_HIT;
516  }
517  break;
518  }
519  else if(trace_fraction != 1)
520  {
521  // we collided with geometry
522  new_beam_type = ARC_BT_WALL;
523  break;
524  }
525  }
526 
527  // te_explosion(trace_endpos);
528 
529  // if we're bursting, use burst visual effects
530  new_beam_type |= burst;
531 
532  // network information: beam type
533  if(new_beam_type != this.beam_type)
534  {
535  this.SendFlags |= ARC_SF_BEAMTYPE;
536  this.beam_type = new_beam_type;
537  }
538 
539  own.(weaponentity).beam_prev = time;
540  this.nextthink = time;
541 }
542 
543 void W_Arc_Beam(float burst, entity actor, .entity weaponentity)
544 {
545 
546  // only play fire sound if 1 sec has passed since player let go the fire button
547  if(time - actor.(weaponentity).beam_prev > 1)
548  sound(actor, CH_WEAPON_A, SND_ARC_FIRE, VOL_BASE, ATTN_NORM);
549 
550  entity beam = actor.(weaponentity).arc_beam = new(W_Arc_Beam);
551  beam.weaponentity_fld = weaponentity;
552  beam.solid = SOLID_NOT;
553  setthink(beam, W_Arc_Beam_Think);
554  beam.owner = actor;
556  beam.bot_dodge = true;
557  IL_PUSH(g_bot_dodge, beam);
558  beam.bot_dodgerating = WEP_CVAR(arc, beam_damage);
559  beam.beam_bursting = burst;
560  Net_LinkEntity(beam, false, 0, W_Arc_Beam_Send);
561 
562  getthink(beam)(beam);
563 }
564 void W_Arc_Attack(Weapon thiswep, entity actor, .entity weaponentity, int fire)
565 {
566  if(!actor.(weaponentity).arc_beam || wasfreed(actor.(weaponentity).arc_beam))
567  {
568  w_ready(thiswep, actor, weaponentity, fire);
569  return;
570  }
571 
572  // attack handled by the beam itself, this is just a loop to keep the attack happening!
573 
574  // NOTE: arc doesn't use a refire
575  //ATTACK_FINISHED(actor, weaponentity) = time + WEP_CVAR_PRI(arc, refire) * W_WeaponRateFactor(actor);
576  actor.(weaponentity).wframe = WFRAME_FIRE1;
577  weapon_thinkf(actor, weaponentity, WFRAME_DONTCHANGE, WEP_CVAR(arc, beam_animtime), W_Arc_Attack);
578 }
579 void Arc_Smoke(Weapon thiswep, entity actor, .entity weaponentity, int fire)
580 {
581  // calculate a rough shot origin to show the effect from TODO: move this to the client side!
582  makevectors(actor.v_angle);
584  vector md = actor.(weaponentity).movedir;
585  vector vecs = ((md.x > 0) ? md : '0 0 0');
586  vector dv = v_forward * vecs.x + v_right * -vecs.y + v_up * vecs.z;
587  w_shotorg = actor.origin + actor.view_ofs + dv;
588  //W_SetupShot_Range(actor,weaponentity,false,0,SND_Null,0,0,0,thiswep.m_id);
589 
590  vector smoke_origin = w_shotorg + actor.velocity*frametime;
591  if ( actor.arc_overheat > time )
592  {
593  if ( random() < actor.(weaponentity).arc_heat_percent )
594  Send_Effect(EFFECT_ARC_SMOKE, smoke_origin, '0 0 0', 1 );
595  if ( (fire & 1) || (fire & 2) )
596  {
597  Send_Effect(EFFECT_ARC_OVERHEAT_FIRE, smoke_origin, w_shotdir, 1 );
598  if ( !actor.arc_smoke_sound )
599  {
600  actor.arc_smoke_sound = 1;
601  sound(actor, CH_SHOTS_SINGLE, SND_ARC_LOOP_OVERHEAT, VOL_BASE, ATTN_NORM);
602  }
603  }
604  }
605  else if ( actor.(weaponentity).arc_beam && WEP_CVAR(arc, overheat_max) > 0 &&
606  actor.(weaponentity).arc_beam.beam_heat > WEP_CVAR(arc, overheat_min) )
607  {
608  if ( random() < (actor.(weaponentity).arc_beam.beam_heat-WEP_CVAR(arc, overheat_min)) /
609  ( WEP_CVAR(arc, overheat_max)-WEP_CVAR(arc, overheat_min) ) )
610  Send_Effect(EFFECT_ARC_SMOKE, smoke_origin, '0 0 0', 1 );
611  }
612 
613  bool attacking = PHYS_INPUT_BUTTON_ATCK(actor) || PHYS_INPUT_BUTTON_ATCK2(actor);
614  bool stop_smoke_sound = actor.arc_overheat <= time || !attacking;
615  if ((actor.arc_smoke_sound && stop_smoke_sound) || actor.(weaponentity).m_switchweapon != thiswep)
616  {
617  actor.arc_smoke_sound = 0;
618  sound(actor, CH_SHOTS_SINGLE, SND_Null, VOL_BASE, ATTEN_NORM);
619  }
620 }
621 
622 METHOD(Arc, wr_aim, void(entity thiswep, entity actor, .entity weaponentity))
623 {
624  if(WEP_CVAR(arc, beam_botaimspeed))
625  {
627  actor,
628  weaponentity,
629  WEP_CVAR(arc, beam_botaimspeed),
630  0,
631  WEP_CVAR(arc, beam_botaimlifetime),
632  false
633  );
634  }
635  else
636  {
638  actor,
639  weaponentity,
640  1000000,
641  0,
642  0.001,
643  false
644  );
645  }
646 }
647 METHOD(Arc, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
648 {
649  Arc_Player_SetHeat(actor, weaponentity);
650  Arc_Smoke(thiswep, actor, weaponentity, fire);
651 
652  bool beam_fire2 = ((fire & 2) && !WEP_CVAR(arc, bolt));
653 
654  if (time >= actor.arc_overheat)
655  if ((fire & 1) || beam_fire2 || actor.(weaponentity).arc_beam.beam_bursting)
656  {
657  #if 0
658  if(actor.(weaponentity).arc_BUTTON_ATCK_prev)
659  {
660  #if 0
661  if(actor.animstate_startframe == actor.anim_shoot.x && actor.animstate_numframes == actor.anim_shoot.y)
662  weapon_thinkf(actor, weaponentity, WFRAME_DONTCHANGE, autocvar_g_balance_arc_primary_animtime, w_ready);
663  else
664  #endif
665  weapon_thinkf(actor, weaponentity, WFRAME_DONTCHANGE, WEP_CVAR(arc, beam_animtime), w_ready);
666  }
667  #endif
668 
669  if((!actor.(weaponentity).arc_beam) || wasfreed(actor.(weaponentity).arc_beam))
670  {
671  if(weapon_prepareattack(thiswep, actor, weaponentity, boolean(beam_fire2), 0))
672  {
673  W_Arc_Beam(boolean(beam_fire2), actor, weaponentity);
674 
675  if(!actor.(weaponentity).arc_BUTTON_ATCK_prev)
676  {
677  actor.(weaponentity).wframe = WFRAME_FIRE1;
678  weapon_thinkf(actor, weaponentity, WFRAME_DONTCHANGE, WEP_CVAR(arc, beam_animtime), W_Arc_Attack);
679  actor.(weaponentity).arc_BUTTON_ATCK_prev = true;
680  }
681  }
682  }
683 
684  return;
685  }
686  else if(fire & 2)
687  {
688  if(weapon_prepareattack(thiswep, actor, weaponentity, true, 0))
689  {
690  if(!thiswep.wr_checkammo2(thiswep, actor, weaponentity))
691  if(!(actor.items & IT_UNLIMITED_AMMO))
692  {
693  W_SwitchWeapon_Force(actor, w_getbestweapon(actor, weaponentity), weaponentity);
694  w_ready(thiswep, actor, weaponentity, fire);
695  return;
696  }
697  float ammo_available = GetResource(actor, thiswep.ammo_type);
698  // We don't want to shoot 3 rounds if there's 2 left in the mag, so we'll use a fraction.
699  // Also keep the fraction <= 1 otherwise we'd mag dump in one burst.
700  float burst_fraction = min(1, ammo_available / WEP_CVAR(arc, bolt_ammo));
701  int to_shoot = floor(WEP_CVAR(arc, bolt_count) * burst_fraction);
702 
703  // We also don't want to use 3 rounds if there's only 2 left.
704  int to_use = min(WEP_CVAR(arc, bolt_ammo), ammo_available);
705  W_DecreaseAmmo(thiswep, actor, to_use, weaponentity);
706 
707  // Bursting counts up to 0 from a negative.
708  actor.(weaponentity).misc_bulletcounter = -to_shoot;
709  W_Arc_Attack_Bolt(thiswep, actor, weaponentity, fire);
710  }
711  }
712 
713  if(actor.(weaponentity).arc_BUTTON_ATCK_prev)
714  {
715  sound(actor, CH_WEAPON_A, SND_ARC_STOP, VOL_BASE, ATTN_NORM);
716  weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR(arc, beam_animtime), w_ready);
717  ATTACK_FINISHED(actor, weaponentity) = time + WEP_CVAR(arc, beam_refire) * W_WeaponRateFactor(actor);
718  }
719  actor.(weaponentity).arc_BUTTON_ATCK_prev = false;
720 
721  #if 0
722  if(fire & 2)
723  if(weapon_prepareattack(thiswep, actor, weaponentity, true, autocvar_g_balance_arc_secondary_refire))
724  {
725  W_Arc_Attack2();
726  actor.arc_count = autocvar_g_balance_arc_secondary_count;
727  weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, autocvar_g_balance_arc_secondary_animtime, w_arc_checkattack);
728  actor.arc_secondarytime = time + autocvar_g_balance_arc_secondary_refire2 * W_WeaponRateFactor(actor);
729  }
730  #endif
731 }
732 METHOD(Arc, wr_init, void(entity thiswep))
733 {
734  if(!arc_shotorigin[0])
735  {
736  arc_shotorigin[0] = shotorg_adjust_values(CL_Weapon_GetShotOrg(WEP_ARC.m_id), false, false, 1);
737  arc_shotorigin[1] = shotorg_adjust_values(CL_Weapon_GetShotOrg(WEP_ARC.m_id), false, false, 2);
738  arc_shotorigin[2] = shotorg_adjust_values(CL_Weapon_GetShotOrg(WEP_ARC.m_id), false, false, 3);
739  arc_shotorigin[3] = shotorg_adjust_values(CL_Weapon_GetShotOrg(WEP_ARC.m_id), false, false, 4);
740  }
741 }
742 METHOD(Arc, wr_checkammo1, bool(entity thiswep, entity actor, .entity weaponentity))
743 {
744  return ((!WEP_CVAR(arc, beam_ammo)) || (GetResource(actor, thiswep.ammo_type) > 0));
745 }
746 METHOD(Arc, wr_checkammo2, bool(entity thiswep, entity actor, .entity weaponentity))
747 {
748  if(WEP_CVAR(arc, bolt))
749  {
750  float ammo_amount = GetResource(actor, thiswep.ammo_type) >= WEP_CVAR(arc, bolt_ammo);
751  ammo_amount += actor.(weaponentity).(weapon_load[WEP_ARC.m_id]) >= WEP_CVAR(arc, bolt_ammo);
752  return ammo_amount;
753  }
754  else
755  return WEP_CVAR(arc, overheat_max) > 0 &&
756  ((!WEP_CVAR(arc, burst_ammo)) || (GetResource(actor, thiswep.ammo_type) > 0));
757 }
758 METHOD(Arc, wr_killmessage, Notification(entity thiswep))
759 {
761  return WEAPON_ARC_MURDER_SPRAY;
762  else
763  return WEAPON_ARC_MURDER;
764 }
765 METHOD(Arc, wr_drop, void(entity thiswep, entity actor, .entity weaponentity))
766 {
767  weapon_dropevent_item.arc_overheat = actor.arc_overheat;
768  weapon_dropevent_item.arc_cooldown = actor.arc_cooldown;
769  actor.arc_overheat = 0;
770  actor.arc_cooldown = 0;
771  actor.(weaponentity).arc_BUTTON_ATCK_prev = false;
772 }
773 METHOD(Arc, wr_pickup, void(entity thiswep, entity actor, .entity weaponentity))
774 {
775  if ( !client_hasweapon(actor, thiswep, weaponentity, false, false) &&
776  weapon_dropevent_item.arc_overheat > time )
777  {
778  actor.arc_overheat = weapon_dropevent_item.arc_overheat;
779  actor.arc_cooldown = weapon_dropevent_item.arc_cooldown;
780  }
781 }
782 METHOD(Arc, wr_resetplayer, void(entity thiswep, entity actor))
783 {
784  actor.arc_overheat = 0;
785  actor.arc_cooldown = 0;
786  for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
787  {
788  .entity weaponentity = weaponentities[slot];
789  actor.(weaponentity).arc_BUTTON_ATCK_prev = false;
790  }
791 }
792 METHOD(Arc, wr_playerdeath, void(entity thiswep, entity actor, .entity weaponentity))
793 {
794  actor.arc_overheat = 0;
795  actor.arc_cooldown = 0;
796  actor.(weaponentity).arc_BUTTON_ATCK_prev = false;
797 }
798 #endif
799 #ifdef CSQC
800 bool autocvar_cl_arcbeam_teamcolor = true;
801 bool autocvar_cl_arcbeam_simple = true;
802 
803 .int beam_slot;
804 
805 METHOD(Arc, wr_impacteffect, void(entity thiswep, entity actor))
806 {
808  {
809  vector org2;
810  org2 = w_org + w_backoff * 6;
811  pointparticles(EFFECT_ELECTRO_IMPACT, org2, w_backoff * 1000, 1);
812  if(!w_issilent) { sound(actor, CH_SHOTS, SND_ELECTRO_IMPACT, VOL_BASE, ATTN_NORM); }
813  }
814 }
815 
816 void Draw_ArcBeam_callback(vector start, vector hit, vector end)
817 {
818  entity beam = Draw_ArcBeam_callback_entity;
819  vector transformed_view_org;
821 
822  // Thickdir shall be perpendicular to the beam and to the view-to-beam direction (WEAPONTODO: WHY)
823  // WEAPONTODO: Wouldn't it be better to be perpendicular to the beam and to the view FORWARD direction?
824  vector thickdir = normalize(cross(normalize(start - hit), transformed_view_org - start));
825 
826  vector hitorigin;
827 
828  // draw segment
829  #if 0
830  if(trace_fraction != 1)
831  {
832  // calculate our own hit origin as trace_endpos tends to jump around annoyingly (to player origin?)
833  hitorigin = start + (Draw_ArcBeam_callback_new_dir * Draw_ArcBeam_callback_segmentdist * trace_fraction);
834  hitorigin = WarpZone_TransformOrigin(WarpZone_trace_transform, hitorigin);
835  }
836  else
837  {
838  hitorigin = hit;
839  }
840  #else
841  hitorigin = hit;
842  #endif
843 
844  // decide upon thickness
845  float thickness = beam.beam_thickness;
846 
847  // draw primary beam render
848  vector top = hitorigin + (thickdir * thickness);
849  vector bottom = hitorigin - (thickdir * thickness);
850 
851  vector last_top = WarpZone_TransformOrigin(WarpZone_trace_transform, Draw_ArcBeam_callback_last_top);
852  vector last_bottom = WarpZone_TransformOrigin(WarpZone_trace_transform, Draw_ArcBeam_callback_last_bottom);
853 
854  if(autocvar_cl_arcbeam_simple)
855  Draw_CylindricLine(start, end, thickness, beam.beam_image, 0.25, -time * 3, beam.beam_color, beam.beam_alpha, DRAWFLAG_NORMAL, transformed_view_org);
856  else
857  {
858  R_BeginPolygon(beam.beam_image, DRAWFLAG_NORMAL, false); // DRAWFLAG_ADDITIVE
859  R_PolygonVertex(
860  top,
861  '0 0.5 0' + ('0 0.5 0' * (thickness / beam.beam_thickness)),
862  beam.beam_color,
863  beam.beam_alpha
864  );
865  R_PolygonVertex(
866  last_top,
867  '0 0.5 0' + ('0 0.5 0' * (Draw_ArcBeam_callback_last_thickness / beam.beam_thickness)),
868  beam.beam_color,
869  beam.beam_alpha
870  );
871  R_PolygonVertex(
872  last_bottom,
873  '0 0.5 0' * (1 - (Draw_ArcBeam_callback_last_thickness / beam.beam_thickness)),
874  beam.beam_color,
875  beam.beam_alpha
876  );
877  R_PolygonVertex(
878  bottom,
879  '0 0.5 0' * (1 - (thickness / beam.beam_thickness)),
880  beam.beam_color,
881  beam.beam_alpha
882  );
883  R_EndPolygon();
884  }
885 
886  // draw trailing particles
887  // NOTES:
888  // - Don't use spammy particle counts here, use a FEW small particles around the beam
889  // - We're not using WarpZone_TrailParticles here because we will handle warpzones ourselves.
890  if(beam.beam_traileffect)
891  {
892  trailparticles(beam, beam.beam_traileffect, start, hitorigin);
893  }
894 
895  // set up for the next
896  Draw_ArcBeam_callback_last_thickness = thickness;
897  Draw_ArcBeam_callback_last_top = WarpZone_UnTransformOrigin(WarpZone_trace_transform, top);
898  Draw_ArcBeam_callback_last_bottom = WarpZone_UnTransformOrigin(WarpZone_trace_transform, bottom);
899 }
900 
901 void Reset_ArcBeam()
902 {
903  entity e;
904  for (e = NULL; (e = findfloat(e, beam_usevieworigin, 1)); ) {
905  e.beam_initialized = false;
906  }
907  for (e = NULL; (e = findfloat(e, beam_usevieworigin, 2)); ) {
908  e.beam_initialized = false;
909  }
910 }
911 
912 void Draw_ArcBeam(entity this)
913 {
914  float dt = time - this.move_time;
915  this.move_time = time;
916  if(dt <= 0) { return; }
917 
918  if(!this.beam_usevieworigin)
919  {
920  InterpolateOrigin_Do(this);
921  }
922 
923  // origin = beam starting origin
924  // v_angle = wanted/aim direction
925  // angles = current direction of beam
926 
927  vector start_pos;
928  vector wantdir; //= view_forward;
929  vector beamdir; //= this.beam_dir;
930 
931  float segments;
932  if(this.beam_usevieworigin)
933  {
934  // WEAPONTODO:
935  // Currently we have to replicate nearly the same method of figuring
936  // out the shotdir that the server does... Ideally in the future we
937  // should be able to acquire this from a generalized function built
938  // into a weapon system for client code.
939 
940  // find where we are aiming
941  vector myviewangle = view_angles;
943  {
945  myviewangle = eX * csqcplayer.v_angle.x + eY * csqcplayer.angles.y;
946  else
947  myviewangle = warpzone_save_view_angles;
948  }
949  vector forward, right, up;
950  MAKE_VECTORS(myviewangle, forward, right, up);
951  entity wepent = viewmodels[this.beam_slot];
952 
953  this.beam_usevieworigin = (autocvar_chase_active) ? 1 : 2;
954 
955  // decide upon start position
956  if(this.beam_usevieworigin == 2)
957  { start_pos = warpzone_save_view_origin; }
958  else if(csqcplayer)
959  { start_pos = csqcplayer.origin + csqcplayer.view_ofs; }
960  else
961  { start_pos = this.origin; }
962 
963  // trace forward with an estimation
965  start_pos,
966  start_pos + forward * this.beam_range,
968  this
969  );
970 
971  int v_shot_idx; // used later
972  (v_shot_idx = gettagindex(wepent, "shot")) || (v_shot_idx = gettagindex(wepent, "tag_shot"));
973  if(v_shot_idx && this.beam_usevieworigin == 2)
974  start_pos = gettaginfo(wepent, v_shot_idx) - '0 0 2';
975 
976  // untransform in case our trace went through a warpzone
978 
979  // un-adjust trueaim if shotend is too close
980  if(vdist(end_pos - start_pos, <, g_trueaim_minrange))
981  end_pos = start_pos + (forward * g_trueaim_minrange);
982 
983  // move shot origin to the actual gun muzzle origin
984  vector origin_offset = '0 0 0';
985  if(!v_shot_idx || this.beam_usevieworigin != 2)
986  {
987  this.beam_shotorigin = wepent.movedir;
988  origin_offset = right * -this.beam_shotorigin.y + up * this.beam_shotorigin.z;
989  }
990  else
991  this.beam_shotorigin = '0 0 0';
992 
993  start_pos = start_pos + origin_offset;
994 
995  // Move it also forward, but only as far as possible without hitting anything. Don't poke into walls!
996  traceline(start_pos, start_pos + forward * this.beam_shotorigin.x, MOVE_NORMAL, this);
997  start_pos = trace_endpos;
998 
999  // calculate the aim direction now
1000  wantdir = normalize(end_pos - start_pos);
1001 
1002  if(!this.beam_initialized)
1003  {
1004  this.beam_dir = wantdir;
1005  this.beam_initialized = true;
1006 
1007  this.beam_muzzleentity.drawmask = MASK_NORMAL; // NOTE: this works around the muzzle entity flashing on the middle of the screen for a frame
1008  }
1009 
1010  if(this.beam_dir != wantdir)
1011  {
1012  // calculate how much we're going to move the end of the beam to the want position
1013  // WEAPONTODO (server and client):
1014  // blendfactor never actually becomes 0 in this situation, which is a problem
1015  // regarding precision... this means that this.beam_dir and w_shotdir approach
1016  // eachother, however they never actually become the same value with this method.
1017  // Perhaps we should do some form of rounding/snapping?
1018  float angle = vlen(wantdir - this.beam_dir) * RAD2DEG;
1019  if(angle && (angle > this.beam_maxangle))
1020  {
1021  // if the angle is greater than maxangle, force the blendfactor to make this the maximum factor
1022  float blendfactor = bound(
1023  0,
1024  (1 - (this.beam_returnspeed * dt)),
1025  min(this.beam_maxangle / angle, 1)
1026  );
1027  this.beam_dir = normalize((wantdir * (1 - blendfactor)) + (this.beam_dir * blendfactor));
1028  }
1029  else
1030  {
1031  // the radius is not too far yet, no worries :D
1032  float blendfactor = bound(
1033  0,
1034  (1 - (this.beam_returnspeed * dt)),
1035  1
1036  );
1037  this.beam_dir = normalize((wantdir * (1 - blendfactor)) + (this.beam_dir * blendfactor));
1038  }
1039 
1040  // calculate how many segments are needed
1041  float max_allowed_segments;
1042 
1043  if(this.beam_distancepersegment)
1044  {
1045  max_allowed_segments = min(
1046  ARC_MAX_SEGMENTS,
1047  1 + (vlen(wantdir / this.beam_distancepersegment))
1048  );
1049  }
1050  else { max_allowed_segments = ARC_MAX_SEGMENTS; }
1051 
1052  if(this.beam_degreespersegment)
1053  {
1054  segments = bound(
1055  1,
1056  (
1057  min(
1058  angle,
1059  this.beam_maxangle
1060  )
1061  /
1062  this.beam_degreespersegment
1063  ),
1064  max_allowed_segments
1065  );
1066  }
1067  else { segments = 1; }
1068  }
1069  else { segments = 1; }
1070 
1071  // set the beam direction which the rest of the code will refer to
1072  beamdir = this.beam_dir;
1073 
1074  // finally, set this.angles to the proper direction so that muzzle attachment points in proper direction
1075  this.angles = fixedvectoangles2(forward, up); // TODO(Samual): is this == warpzone_save_view_angles?
1076  }
1077  else
1078  {
1079  // set the values from the provided info from the networked entity
1080  start_pos = this.origin;
1081  wantdir = this.v_angle;
1082  beamdir = this.angles;
1083 
1084  if(beamdir != wantdir)
1085  {
1086  float angle = vlen(wantdir - beamdir) * RAD2DEG;
1087 
1088  // calculate how many segments are needed
1089  float max_allowed_segments;
1090 
1091  if(this.beam_distancepersegment)
1092  {
1093  max_allowed_segments = min(
1094  ARC_MAX_SEGMENTS,
1095  1 + (vlen(wantdir / this.beam_distancepersegment))
1096  );
1097  }
1098  else { max_allowed_segments = ARC_MAX_SEGMENTS; }
1099 
1100  if(this.beam_degreespersegment)
1101  {
1102  segments = bound(
1103  1,
1104  (
1105  min(
1106  angle,
1107  this.beam_maxangle
1108  )
1109  /
1110  this.beam_degreespersegment
1111  ),
1112  max_allowed_segments
1113  );
1114  }
1115  else { segments = 1; }
1116  }
1117  else { segments = 1; }
1118  }
1119 
1120  setorigin(this, start_pos);
1121  this.beam_muzzleentity.angles_z = random() * 360; // WEAPONTODO: use avelocity instead?
1122 
1123  vector beam_endpos = (start_pos + (beamdir * this.beam_range));
1124  vector beam_controlpoint = start_pos + wantdir * (this.beam_range * (1 - this.beam_tightness));
1125 
1126  Draw_ArcBeam_callback_entity = this;
1127  Draw_ArcBeam_callback_last_thickness = 0;
1128  Draw_ArcBeam_callback_last_top = start_pos;
1129  Draw_ArcBeam_callback_last_bottom = start_pos;
1130 
1131  vector last_origin = start_pos;
1132  vector original_start_pos = start_pos;
1133 
1134  float i;
1135  for(i = 1; i <= segments; ++i)
1136  {
1137  // WEAPONTODO (client):
1138  // In order to do nice fading and pointing on the starting segment, we must always
1139  // have that drawn as a separate triangle... However, that is difficult to do when
1140  // keeping in mind the above problems and also optimizing the amount of segments
1141  // drawn on screen at any given time. (Automatic beam quality scaling, essentially)
1142 
1143  vector new_origin = bezier_quadratic_getpoint(
1144  start_pos,
1145  beam_controlpoint,
1146  beam_endpos,
1147  i / segments);
1148 
1150  last_origin,
1151  '0 0 0',
1152  '0 0 0',
1153  new_origin,
1154  MOVE_NORMAL,
1155  NULL,
1156  NULL,
1157  Draw_ArcBeam_callback
1158  );
1159 
1160  // Do all the transforms for warpzones right now, as we already "are" in the post-trace
1161  // system (if we hit a player, that's always BEHIND the last passed wz).
1162  last_origin = trace_endpos;
1163  start_pos = WarpZone_TransformOrigin(WarpZone_trace_transform, start_pos);
1164  beam_controlpoint = WarpZone_TransformOrigin(WarpZone_trace_transform, beam_controlpoint);
1165  beam_endpos = WarpZone_TransformOrigin(WarpZone_trace_transform, beam_endpos);
1167  Draw_ArcBeam_callback_last_top = WarpZone_TransformOrigin(WarpZone_trace_transform, Draw_ArcBeam_callback_last_top);
1168  Draw_ArcBeam_callback_last_bottom = WarpZone_TransformOrigin(WarpZone_trace_transform, Draw_ArcBeam_callback_last_bottom);
1169 
1170  if(trace_fraction < 1) { break; }
1171  }
1172 
1173  // visual effects for startpoint and endpoint
1174  if(this.beam_hiteffect)
1175  {
1176  // FIXME we really should do this on the server so it actually
1177  // matches gameplay. What this client side stuff is doing is no
1178  // more than guesswork.
1181  this.beam_hiteffect,
1182  last_origin,
1183  beamdir * -1,
1184  dt * 2
1185  );
1186  }
1187  if(this.beam_hitlight[0])
1188  {
1190  last_origin,
1191  this.beam_hitlight[0],
1192  vec3(
1193  this.beam_hitlight[1],
1194  this.beam_hitlight[2],
1195  this.beam_hitlight[3]
1196  )
1197  );
1198  }
1199  if(this.beam_muzzleeffect && autocvar_r_drawviewmodel)
1200  {
1202  this.beam_muzzleeffect,
1203  original_start_pos + wantdir * 20,
1204  wantdir * 1000,
1205  dt * 0.1
1206  );
1207  }
1208  if(this.beam_muzzlelight[0])
1209  {
1211  original_start_pos + wantdir * 20,
1212  this.beam_muzzlelight[0],
1213  vec3(
1214  this.beam_muzzlelight[1],
1215  this.beam_muzzlelight[2],
1216  this.beam_muzzlelight[3]
1217  )
1218  );
1219  }
1220 
1221  // cleanup
1222  Draw_ArcBeam_callback_entity = NULL;
1223  Draw_ArcBeam_callback_last_thickness = 0;
1224  Draw_ArcBeam_callback_last_top = '0 0 0';
1225  Draw_ArcBeam_callback_last_bottom = '0 0 0';
1226 }
1227 
1228 void Remove_ArcBeam(entity this)
1229 {
1230  delete(this.beam_muzzleentity);
1231  sound(this, CH_SHOTS_SINGLE, SND_Null, VOL_BASE, ATTEN_NORM);
1232 }
1233 
1234 NET_HANDLE(ENT_CLIENT_ARC_BEAM, bool isnew)
1235 {
1236  int sf = ReadByte();
1237  int slot = ReadByte();
1238  entity flash;
1239 
1240  this.beam_slot = slot;
1241 
1242  if(isnew)
1243  {
1244  int gunalign = W_GunAlign(viewmodels[slot], STAT(GUNALIGN)) - 1;
1245 
1246  this.beam_shotorigin = arc_shotorigin[gunalign]; // get a starting point
1247 
1248  // set other main attributes of the beam
1249  this.draw = Draw_ArcBeam;
1250  IL_PUSH(g_drawables, this);
1251  this.entremove = Remove_ArcBeam;
1252  this.move_time = time;
1253  loopsound(this, CH_SHOTS_SINGLE, SND_ARC_LOOP, VOL_BASE, ATTEN_NORM);
1254 
1255  flash = new(arc_flash);
1256  flash.owner = this;
1257  flash.effects = EF_ADDITIVE | EF_FULLBRIGHT;
1258  //flash.drawmask = MASK_NORMAL;
1259  flash.solid = SOLID_NOT;
1260  flash.avelocity_z = 5000;
1261  setattachment(flash, this, "");
1262  setorigin(flash, '0 0 0');
1263 
1264  this.beam_muzzleentity = flash;
1265  }
1266  else
1267  {
1268  flash = this.beam_muzzleentity;
1269  }
1270 
1271  if(sf & ARC_SF_SETTINGS) // settings information
1272  {
1273  this.beam_degreespersegment = ReadShort();
1274  this.beam_distancepersegment = ReadShort();
1275  this.beam_maxangle = ReadShort();
1276  this.beam_range = ReadCoord();
1277  this.beam_returnspeed = ReadShort();
1278  this.beam_tightness = (ReadByte() / 10);
1279 
1280  if(ReadByte())
1281  {
1282  this.beam_usevieworigin = (autocvar_chase_active) ? 1 : 2;
1283  }
1284  else
1285  {
1286  this.beam_usevieworigin = 0;
1287  }
1288 
1289  this.sv_entnum = ReadByte();
1290  }
1291 
1292  if(!this.beam_usevieworigin)
1293  {
1294  // this.iflags = IFLAG_ORIGIN | IFLAG_ANGLES | IFLAG_V_ANGLE; // why doesn't this work?
1295  this.iflags = IFLAG_ORIGIN;
1296 
1297  InterpolateOrigin_Undo(this);
1298  }
1299 
1300  if(sf & ARC_SF_START) // starting location
1301  {
1302  this.origin = ReadVector();
1303  }
1304  else if(this.beam_usevieworigin) // infer the location from player location
1305  {
1306  if(this.beam_usevieworigin == 2)
1307  {
1308  // use view origin
1309  this.origin = view_origin;
1310  }
1311  else
1312  {
1313  // use player origin so that third person display still works
1314  this.origin = entcs_receiver(player_localnum).origin + ('0 0 1' * STAT(VIEWHEIGHT));
1315  }
1316  }
1317 
1318  setorigin(this, this.origin);
1319 
1320  if(sf & ARC_SF_WANTDIR) // want/aim direction
1321  {
1322  this.v_angle = ReadVector();
1323  }
1324 
1325  if(sf & ARC_SF_BEAMDIR) // beam direction
1326  {
1327  this.angles = ReadAngleVector();
1328  }
1329 
1330  if(sf & ARC_SF_BEAMTYPE) // beam type
1331  {
1332  this.beam_type = ReadByte();
1333 
1334  vector beamcolor = ((autocvar_cl_arcbeam_teamcolor) ? colormapPaletteColor(entcs_GetClientColors(this.sv_entnum - 1) & 0x0F, true) : '1 1 1');
1335  switch(this.beam_type)
1336  {
1337  case ARC_BT_MISS:
1338  {
1339  this.beam_color = beamcolor;
1340  this.beam_alpha = 0.5;
1341  this.beam_thickness = 8;
1342  this.beam_traileffect = (EFFECT_ARC_BEAM);
1343  this.beam_hiteffect = (EFFECT_ARC_LIGHTNING);
1344  this.beam_hitlight[0] = 0;
1345  this.beam_hitlight[1] = 1;
1346  this.beam_hitlight[2] = 1;
1347  this.beam_hitlight[3] = 1;
1348  this.beam_muzzleeffect = EFFECT_Null;
1349  this.beam_muzzlelight[0] = 0;
1350  this.beam_muzzlelight[1] = 1;
1351  this.beam_muzzlelight[2] = 1;
1352  this.beam_muzzlelight[3] = 1;
1353  this.beam_image = "particles/lgbeam";
1354  if(this.beam_muzzleeffect && autocvar_r_drawviewmodel)
1355  {
1356  setmodel(flash, MDL_ARC_MUZZLEFLASH);
1357  flash.alpha = this.beam_alpha;
1358  flash.colormod = this.beam_color;
1359  flash.scale = 0.35;
1360  }
1361  break;
1362  }
1363  case ARC_BT_WALL: // grenadelauncher_muzzleflash healray_muzzleflash
1364  {
1365  this.beam_color = beamcolor;
1366  this.beam_alpha = 0.5;
1367  this.beam_thickness = 8;
1368  this.beam_traileffect = (EFFECT_ARC_BEAM);
1369  this.beam_hiteffect = (EFFECT_ARC_LIGHTNING);
1370  this.beam_hitlight[0] = 0;
1371  this.beam_hitlight[1] = 1;
1372  this.beam_hitlight[2] = 1;
1373  this.beam_hitlight[3] = 1;
1374  this.beam_muzzleeffect = EFFECT_Null; // (EFFECT_GRENADE_MUZZLEFLASH);
1375  this.beam_muzzlelight[0] = 0;
1376  this.beam_muzzlelight[1] = 1;
1377  this.beam_muzzlelight[2] = 1;
1378  this.beam_muzzlelight[3] = 1;
1379  this.beam_image = "particles/lgbeam";
1380  if(this.beam_muzzleeffect && autocvar_r_drawviewmodel)
1381  {
1382  setmodel(flash, MDL_ARC_MUZZLEFLASH);
1383  flash.alpha = this.beam_alpha;
1384  flash.colormod = this.beam_color;
1385  flash.scale = 0.35;
1386  }
1387  break;
1388  }
1389  case ARC_BT_HEAL:
1390  {
1391  this.beam_color = beamcolor;
1392  this.beam_alpha = 0.5;
1393  this.beam_thickness = 8;
1394  this.beam_traileffect = (EFFECT_ARC_BEAM_HEAL);
1395  this.beam_hiteffect = (EFFECT_ARC_BEAM_HEAL_IMPACT);
1396  this.beam_hitlight[0] = 0;
1397  this.beam_hitlight[1] = 1;
1398  this.beam_hitlight[2] = 1;
1399  this.beam_hitlight[3] = 1;
1400  this.beam_muzzleeffect = EFFECT_Null;
1401  this.beam_muzzlelight[0] = 0;
1402  this.beam_muzzlelight[1] = 1;
1403  this.beam_muzzlelight[2] = 1;
1404  this.beam_muzzlelight[3] = 1;
1405  this.beam_image = "particles/lgbeam";
1406  if(this.beam_muzzleeffect && autocvar_r_drawviewmodel)
1407  {
1408  setmodel(flash, MDL_ARC_MUZZLEFLASH);
1409  flash.alpha = this.beam_alpha;
1410  flash.colormod = this.beam_color;
1411  flash.scale = 0.35;
1412  }
1413  break;
1414  }
1415  case ARC_BT_HIT:
1416  {
1417  this.beam_color = beamcolor;
1418  this.beam_alpha = 0.5;
1419  this.beam_thickness = 8;
1420  this.beam_traileffect = (EFFECT_ARC_BEAM);
1421  this.beam_hiteffect = (EFFECT_ARC_LIGHTNING);
1422  this.beam_hitlight[0] = 20;
1423  this.beam_hitlight[1] = 1;
1424  this.beam_hitlight[2] = 0;
1425  this.beam_hitlight[3] = 0;
1426  this.beam_muzzleeffect = EFFECT_Null;
1427  this.beam_muzzlelight[0] = 50;
1428  this.beam_muzzlelight[1] = 1;
1429  this.beam_muzzlelight[2] = 0;
1430  this.beam_muzzlelight[3] = 0;
1431  this.beam_image = "particles/lgbeam";
1432  if(this.beam_muzzleeffect && autocvar_r_drawviewmodel)
1433  {
1434  setmodel(flash, MDL_ARC_MUZZLEFLASH);
1435  flash.alpha = this.beam_alpha;
1436  flash.colormod = this.beam_color;
1437  flash.scale = 0.35;
1438  }
1439  break;
1440  }
1441  case ARC_BT_BURST_MISS:
1442  {
1443  this.beam_color = beamcolor;
1444  this.beam_alpha = 0.5;
1445  this.beam_thickness = 14;
1446  this.beam_traileffect = (EFFECT_ARC_BEAM);
1447  this.beam_hiteffect = (EFFECT_ARC_LIGHTNING);
1448  this.beam_hitlight[0] = 0;
1449  this.beam_hitlight[1] = 1;
1450  this.beam_hitlight[2] = 1;
1451  this.beam_hitlight[3] = 1;
1452  this.beam_muzzleeffect = EFFECT_Null;
1453  this.beam_muzzlelight[0] = 0;
1454  this.beam_muzzlelight[1] = 1;
1455  this.beam_muzzlelight[2] = 1;
1456  this.beam_muzzlelight[3] = 1;
1457  this.beam_image = "particles/lgbeam";
1458  if(this.beam_muzzleeffect && autocvar_r_drawviewmodel)
1459  {
1460  setmodel(flash, MDL_ARC_MUZZLEFLASH);
1461  flash.alpha = this.beam_alpha;
1462  flash.colormod = this.beam_color;
1463  flash.scale = 0.35;
1464  }
1465  break;
1466  }
1467  case ARC_BT_BURST_WALL:
1468  {
1469  this.beam_color = beamcolor;
1470  this.beam_alpha = 0.5;
1471  this.beam_thickness = 14;
1472  this.beam_traileffect = (EFFECT_ARC_BEAM);
1473  this.beam_hiteffect = (EFFECT_ARC_LIGHTNING);
1474  this.beam_hitlight[0] = 0;
1475  this.beam_hitlight[1] = 1;
1476  this.beam_hitlight[2] = 1;
1477  this.beam_hitlight[3] = 1;
1478  this.beam_muzzleeffect = EFFECT_Null;
1479  this.beam_muzzlelight[0] = 0;
1480  this.beam_muzzlelight[1] = 1;
1481  this.beam_muzzlelight[2] = 1;
1482  this.beam_muzzlelight[3] = 1;
1483  this.beam_image = "particles/lgbeam";
1484  if(this.beam_muzzleeffect && autocvar_r_drawviewmodel)
1485  {
1486  setmodel(flash, MDL_ARC_MUZZLEFLASH);
1487  flash.alpha = this.beam_alpha;
1488  flash.colormod = this.beam_color;
1489  flash.scale = 0.35;
1490  }
1491  break;
1492  }
1493  case ARC_BT_BURST_HEAL:
1494  {
1495  this.beam_color = beamcolor;
1496  this.beam_alpha = 0.5;
1497  this.beam_thickness = 14;
1498  this.beam_traileffect = (EFFECT_ARC_BEAM_HEAL);
1499  this.beam_hiteffect = (EFFECT_ARC_BEAM_HEAL_IMPACT2);
1500  this.beam_hitlight[0] = 0;
1501  this.beam_hitlight[1] = 1;
1502  this.beam_hitlight[2] = 1;
1503  this.beam_hitlight[3] = 1;
1504  this.beam_muzzleeffect = EFFECT_Null;
1505  this.beam_muzzlelight[0] = 0;
1506  this.beam_muzzlelight[1] = 1;
1507  this.beam_muzzlelight[2] = 1;
1508  this.beam_muzzlelight[3] = 1;
1509  this.beam_image = "particles/lgbeam";
1510  if(this.beam_muzzleeffect && autocvar_r_drawviewmodel)
1511  {
1512  setmodel(flash, MDL_ARC_MUZZLEFLASH);
1513  flash.alpha = this.beam_alpha;
1514  flash.colormod = this.beam_color;
1515  flash.scale = 0.35;
1516  }
1517  break;
1518  }
1519  case ARC_BT_BURST_HIT:
1520  {
1521  this.beam_color = beamcolor;
1522  this.beam_alpha = 0.5;
1523  this.beam_thickness = 14;
1524  this.beam_traileffect = (EFFECT_ARC_BEAM);
1525  this.beam_hiteffect = (EFFECT_ARC_LIGHTNING);
1526  this.beam_hitlight[0] = 0;
1527  this.beam_hitlight[1] = 1;
1528  this.beam_hitlight[2] = 1;
1529  this.beam_hitlight[3] = 1;
1530  this.beam_muzzleeffect = EFFECT_Null;
1531  this.beam_muzzlelight[0] = 0;
1532  this.beam_muzzlelight[1] = 1;
1533  this.beam_muzzlelight[2] = 1;
1534  this.beam_muzzlelight[3] = 1;
1535  this.beam_image = "particles/lgbeam";
1536  if(this.beam_muzzleeffect && autocvar_r_drawviewmodel)
1537  {
1538  setmodel(flash, MDL_ARC_MUZZLEFLASH);
1539  flash.alpha = this.beam_alpha;
1540  flash.colormod = this.beam_color;
1541  flash.scale = 0.35;
1542  }
1543  break;
1544  }
1545 
1546  // shouldn't be possible, but lets make it colorful if it does :D
1547  default:
1548  {
1549  this.beam_color = randomvec();
1550  this.beam_alpha = 1;
1551  this.beam_thickness = 8;
1552  this.beam_traileffect = NULL;
1553  this.beam_hiteffect = NULL;
1554  this.beam_hitlight[0] = 0;
1555  this.beam_hitlight[1] = 1;
1556  this.beam_hitlight[2] = 1;
1557  this.beam_hitlight[3] = 1;
1558  this.beam_muzzleeffect = EFFECT_Null;
1559  this.beam_muzzlelight[0] = 0;
1560  this.beam_muzzlelight[1] = 1;
1561  this.beam_muzzlelight[2] = 1;
1562  this.beam_muzzlelight[3] = 1;
1563  this.beam_image = "particles/lgbeam";
1564  if(this.beam_muzzleeffect && autocvar_r_drawviewmodel)
1565  {
1566  setmodel(flash, MDL_ARC_MUZZLEFLASH);
1567  flash.alpha = this.beam_alpha;
1568  flash.colormod = this.beam_color;
1569  flash.scale = 0.35;
1570  }
1571  break;
1572  }
1573  }
1574  }
1575 
1576  if(!this.beam_usevieworigin)
1577  {
1578  InterpolateOrigin_Note(this);
1579  }
1580  return true;
1581 }
1582 
1583 #endif
const float SOLID_NOT
Definition: csprogsdefs.qc:244
#define PHYS_INPUT_BUTTON_ATCK2(s)
Definition: player.qh:148
float autocvar_g_balance_pause_armor_rot
Definition: sv_resources.qh:32
void InterpolateOrigin_Note(entity this)
Definition: interpolate.qc:37
bool bot_aim(entity this,.entity weaponentity, float shotspeed, float shotspeedupward, float maxshottime, float applygravity)
float MOVETYPE_NONE
Definition: progsdefs.qc:246
float weapon_load[REGISTRY_MAX(Weapons)]
Definition: weaponsystem.qh:29
const int HITTYPE_BOUNCE
Definition: all.qh:28
int iflags
Definition: interpolate.qh:26
vector w_shotorg
Definition: tracing.qh:18
void W_SwitchWeapon_Force(Player this, Weapon w,.entity weaponentity)
Definition: selection.qc:243
ERASEABLE float ExponentialFalloff(float mindist, float maxdist, float halflifedist, float d)
Definition: math.qh:244
#define PROJECTILE_MAKETRIGGER(e)
Definition: common.qh:29
const vector eY
Definition: vector.qh:45
void InterpolateOrigin_Undo(entity this)
snap origin to iorigin2 (actual origin)
Definition: interpolate.qc:159
#define adddynamiclight
Definition: post.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)
float trace_dphitq3surfaceflags
int falloff
Definition: impulse.qh:12
vector warpzone_save_view_angles
Definition: client.qh:9
const int MIF_SPLASH
Definition: common.qh:34
void W_SwitchToOtherWeapon(entity this,.entity weaponentity)
Definition: selection.qc:253
#define w_getbestweapon(ent, wepent)
Definition: selection.qh:23
float W_CheckProjectileDamage(entity inflictor, entity projowner, int deathtype, float exception)
Definition: common.qc:49
entity viewmodels[MAX_WEAPONSLOTS]
Definition: view.qh:104
IntrusiveList g_damagedbycontents
Definition: damage.qh:155
#define W_SetupShot_Range(ent, wepent, antilag, recoil, snd, chan, maxdamage, range, deathtype)
Definition: tracing.qh:35
entity() spawn
vector beam_color
Definition: laser.qh:30
float DAMAGE_AIM
Definition: progsdefs.qc:284
vector WarpZone_TransformOrigin(entity wz, vector v)
Definition: common.qc:499
int sv_entnum
Definition: main.qh:155
#define vec3(_x, _y, _z)
Definition: vector.qh:95
const float MOVE_NORMAL
Definition: csprogsdefs.qc:252
float MOVETYPE_BOUNCEMISSILE
Definition: progsdefs.qc:257
vector v_angle
Definition: progsdefs.qc:161
void w_ready(Weapon thiswep, entity actor,.entity weaponentity, int fire)
vector view_origin
Definition: main.qh:93
#define NET_HANDLE(id, param)
Definition: net.qh:12
#define WEP_CVAR(wepname, name)
Definition: all.qh:299
#define IS_MONSTER(v)
Definition: utils.qh:21
vector w_shotdir
Definition: tracing.qh:19
void loopsound(entity e, int ch, Sound samp, float vol, float attn)
Definition: projectile.qc:167
entity weaponentity_fld
Definition: weaponsystem.qh:27
Definition: arc.qh:3
entity to
Definition: self.qh:96
bool weapon_prepareattack_check(Weapon thiswep, entity actor,.entity weaponentity, bool secondary, float attacktime)
origin
Definition: ent_cs.qc:114
#define gettaginfo
Definition: post.qh:32
int W_GunAlign(entity this, int preferred_align)
#define W_SetupProjVelocity_PRE(ent, wepname, prefix)
Definition: tracing.qh:62
#define METHOD(cname, name, prototype)
Definition: oo.qh:257
void CSQCProjectile(entity e, float clientanimate, int type, float docull)
ERASEABLE vector bezier_quadratic_getpoint(vector a, vector b, vector c, float t)
Definition: math.qh:114
vector warpzone_save_view_origin
Definition: client.qh:8
entity owner
Definition: main.qh:73
#define gettagindex
Definition: dpextensions.qh:16
IntrusiveList g_bot_dodge
Definition: api.qh:150
bool autocvar_cl_lockview
Definition: view.qh:20
entity trace_ent
Definition: csprogsdefs.qc:40
void WarpZone_traceline_antilag(entity source, vector v1, vector v2, float nomonst, entity forent, float lag)
Definition: antilag.qc:221
vector WarpZone_UnTransformOrigin(entity wz, vector v)
Definition: common.qc:535
void Reset_ArcBeam()
void TakeResource(entity receiver, Resource res_type, float amount)
Takes an entity some resource.
Definition: cl_resources.qc:31
int weaponslot(.entity weaponentity)
Definition: weapon.qh:16
const float EF_ADDITIVE
Definition: csprogsdefs.qc:300
#define PROJECTILE_TOUCH(e, t)
Definition: common.qh:27
#define setmodel(this, m)
Definition: model.qh:26
const float ATTN_NORM
Definition: csprogsdefs.qc:226
vector view_angles
Definition: csprogsdefs.qc:150
RES_HEALTH
Definition: ent_cs.qc:126
const float EF_FULLBRIGHT
Definition: csprogsdefs.qc:303
#define IS_SPEC(v)
Definition: utils.qh:10
vector movedir
Definition: progsdefs.qc:203
const float MOVE_NOMONSTERS
Definition: csprogsdefs.qc:253
float cnt
Definition: powerups.qc:24
ERASEABLE entity IL_PUSH(IntrusiveList this, entity it)
Push to tail.
const int PROJECTILE_ARC_BOLT
Definition: projectiles.qh:39
void GiveResourceWithLimit(entity receiver, Resource res_type, float amount, float limit)
Gives an entity some resource but not more than a limit.
const int CH_WEAPON_A
Definition: sound.qh:7
void SetResource(entity e, Resource res_type, float amount)
Sets the current amount of resource the given entity will have.
Definition: cl_resources.qc:26
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 RES_LIMIT_NONE
Definition: resources.qh:46
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
float misc_bulletcounter
Definition: common.qh:18
#define pointparticles
Definition: csprogsdefs.qh:13
entity weapon_dropevent_item
Definition: weaponsystem.qh:21
#define NULL
Definition: post.qh:17
float frametime
Definition: csprogsdefs.qc:17
const float DRAWFLAG_NORMAL
Definition: csprogsdefs.qc:317
const float VOL_BASE
Definition: sound.qh:36
vector trace_endpos
Definition: csprogsdefs.qc:37
#define PHYS_INPUT_BUTTON_ATCK(s)
Definition: player.qh:146
void Damage(entity targ, entity inflictor, entity attacker, float damage, int deathtype,.entity weaponentity, vector hitloc, vector force)
Definition: damage.qc:583
#define SAME_TEAM(a, b)
Definition: teams.qh:239
bool Heal(entity targ, entity inflictor, float amount, float limit)
Definition: damage.qc:1063
const int HITTYPE_SECONDARY
Definition: all.qh:25
#define W_SetupShot(ent, wepent, antilag, recoil, snd, chan, maxdamage, deathtype)
Definition: tracing.qh:33
float Q3SURFACEFLAG_NOIMPACT
const float MASK_NORMAL
Definition: csprogsdefs.qc:164
#define IS_DEAD(s)
Definition: utils.qh:26
const float ATTEN_NORM
Definition: sound.qh:30
float nextthink
Definition: csprogsdefs.qc:121
const int CH_SHOTS
Definition: sound.qh:14
float w_deathtype
Definition: damage.qh:97
vector WarpZone_TransformVelocity(entity wz, vector v)
Definition: common.qc:504
vector CL_Weapon_GetShotOrg(int wpn)
Definition: weaponsystem.qc:63
vector(float skel, float bonenum) _skel_get_boneabs_hidden
entity WarpZone_trace_transform
Definition: common.qh:37
IntrusiveList g_projectiles
Definition: common.qh:46
const int IFLAG_ORIGIN
Definition: interpolate.qh:36
float GetResource(entity e, Resource res_type)
Returns the current amount of resource the given entity has.
Definition: cl_resources.qc:10
bool autocvar_r_drawviewmodel
Definition: view.qh:94
float move_time
Definition: movetypes.qh:77
float RAD2DEG
Definition: csprogsdefs.qc:962
const vector eX
Definition: vector.qh:44
#define vdist(v, cmp, f)
Vector distance comparison, avoids sqrt()
Definition: vector.qh:8
void accuracy_add(entity this, Weapon w, float fired, float hit)
Definition: accuracy.qc:83
void WarpZone_TraceLine(vector org, vector end, float nomonsters, entity forent)
Definition: common.qc:338
entity Notification
always last
Definition: all.qh:82
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
bool accuracy_isgooddamage(entity attacker, entity targ)
Definition: accuracy.qc:112
vector v_right
Definition: csprogsdefs.qc:31
float arc_heat_percent
Definition: wepent.qh:12
entity realowner
Definition: common.qh:25
#define MUTATOR_CALLHOOK(id,...)
Definition: base.qh:140
entity weaponentities[MAX_WEAPONSLOTS]
Definition: weapon.qh:14
#define cross(a, b)
Definition: vector.qh:25
setorigin(ent, v)
#define ANTILAG_LATENCY(e)
Definition: antilag.qh:19
#define setthink(e, f)
#define trailparticles
Definition: csprogsdefs.qh:12
#define ATTACK_FINISHED(ent, w)
Definition: weaponsystem.qh:42
vector angles
Definition: csprogsdefs.qc:104
void adaptor_think2use_hittype_splash(entity this)
Definition: common.qc:110
entity csqcplayer
Definition: cl_player.qh:26
#define use
Definition: csprogsdefs.qh:50
const int CH_SHOTS_SINGLE
Definition: sound.qh:15
void W_DecreaseAmmo(Weapon wep, entity actor, float ammo_use,.entity weaponentity)
int autocvar_chase_active
Definition: view.qh:17
#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
bool client_hasweapon(entity this, Weapon wpn,.entity weaponentity, float andammo, bool complain)
Definition: selection.qc:48
float time
Definition: csprogsdefs.qc:16
vector velocity
Definition: csprogsdefs.qc:103
int m_id
Definition: weapon.qh:42
#define makevectors
Definition: post.qh:21
float trace_fraction
Definition: csprogsdefs.qc:36
float W_WeaponRateFactor(entity this)
Definition: weaponsystem.qc:33
void WarpZone_TraceBox_ThroughZone(vector org, vector mi, vector ma, vector end, float nomonsters, entity forent, entity zone, WarpZone_trace_callback_t cb)
Definition: common.qc:202
void InterpolateOrigin_Do(entity this)
set origin based on iorigin1 (old pos), iorigin2 (desired pos), and time
Definition: interpolate.qc:129
float player_localnum
Definition: csprogsdefs.qc:20
IntrusiveList g_drawables
Definition: main.qh:77
void set_movetype(entity this, int mt)
#define IS_PLAYER(v)
Definition: utils.qh:9
#define colormapPaletteColor(c, isPants)
Definition: color.qh:5
var void func_null()
#define fixedvectoangles2(a, b)
float g_trueaim_minrange
Definition: main.qh:140
vector v_forward
Definition: csprogsdefs.qc:31
float DAMAGE_YES
Definition: progsdefs.qc:283
int projectiledeathtype
Definition: common.qh:20