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