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