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 float curr_ammo = GetResource(own, thiswep.ammo_type);
268 coefficient = min(coefficient, curr_ammo / rootammo);
269 SetResource(own, thiswep.ammo_type, max(0, curr_ammo - rootammo * frametime));
270 }
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 // network information: shot origin and want/aim direction
295 if (this.beam_start != w_shotorg)
296 {
297 this.SendFlags |= ARC_SF_START;
298 this.beam_start = w_shotorg;
299 }
300 if (this.beam_wantdir != w_shotdir)
301 {
303 this.beam_wantdir = w_shotdir;
304 }
305
306 if (!this.beam_initialized)
307 {
308 this.beam_dir = w_shotdir;
309 this.beam_initialized = true;
310 }
311
312 // WEAPONTODO: Detect player velocity so that the beam curves when moving too
313 // idea: blend together this.beam_dir with the inverted direction the player is moving in
314 // might have to make some special accomodation so that it only uses view_right and view_up
315
316 // note that if we do this, it'll always be corrected to a maximum angle by beam_maxangle handling
317
318 float segments = 1;
319 if (this.beam_dir != w_shotdir)
320 {
321 // calculate how much we're going to move the end of the beam to the want position
322 float angle = vlen(w_shotdir - this.beam_dir) * RAD2DEG;
323 if (angle < 0.01) // snap only when very close so it's impossible to notice
324 this.beam_dir = w_shotdir; // snap otherwise vectors will never actually be the same
325 else
326 {
327 float max_blendfactor = 1;
328 if (angle && angle > WEP_CVAR(WEP_ARC, beam_maxangle))
329 max_blendfactor = WEP_CVAR(WEP_ARC, beam_maxangle) / angle;
330 float blendfactor = bound(0, (1 - (WEP_CVAR(WEP_ARC, beam_returnspeed) * frametime)), max_blendfactor);
331 this.beam_dir = normalize((w_shotdir * (1 - blendfactor)) + (this.beam_dir * blendfactor));
332 }
333
334 // network information: beam direction
336
337 // calculate how many segments are needed
338 float max_allowed_segments = ARC_MAX_SEGMENTS;
339 if (WEP_CVAR(WEP_ARC, beam_distancepersegment))
340 {
341 max_allowed_segments = 1 + vlen(w_shotdir) / WEP_CVAR(WEP_ARC, beam_distancepersegment);
342 max_allowed_segments = bound(1, max_allowed_segments, ARC_MAX_SEGMENTS);
343 }
344
345 if (WEP_CVAR(WEP_ARC, beam_degreespersegment))
346 {
347 segments = min(angle, WEP_CVAR(WEP_ARC, beam_maxangle)) / WEP_CVAR(WEP_ARC, beam_degreespersegment);
348 segments = bound(1, segments, max_allowed_segments);
349 }
350 }
351
352 vector beam_endpos = w_shotorg + (this.beam_dir * WEP_CVAR(WEP_ARC, beam_range));
353 float beam_controlpoint_dist = WEP_CVAR(WEP_ARC, beam_range) * bound(0.001, 1 - WEP_CVAR(WEP_ARC, beam_tightness), 1);
354 vector beam_controlpoint = w_shotorg + w_shotdir * beam_controlpoint_dist;
355
356 int new_beam_type = 0;
357 vector last_origin = w_shotorg;
358 vector original_start_pos = 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 );
374
376 own,
377 last_origin,
378 new_origin,
380 NULL,
381 ANTILAG_LATENCY(own)
382 );
383
384 last_origin_prev = last_origin; // used later to calculate damage force direction
385 last_origin = trace_endpos;
386
387 // Do all the transforms for warpzones right now, as we already "are" in the post-trace
388 // system (if we hit a player, that's always BEHIND the last passed wz).
390
391 if (trace_fraction == 1)
392 {
393 beam_controlpoint = WarpZone_TransformOrigin(WarpZone_trace_transform, beam_controlpoint);
394 beam_endpos = WarpZone_TransformOrigin(WarpZone_trace_transform, beam_endpos);
395 continue;
396 }
397
398 if (!trace_ent)
399 {
400 // we collided with geometry
401 new_beam_type = ARC_BT_WALL;
402 break;
403 }
404
405 // we collided with an entity
406 bool is_player = (IS_PLAYER(trace_ent) || trace_ent.classname == "body" || IS_MONSTER(trace_ent));
407 if (trace_ent != own && SAME_TEAM(own, trace_ent))
408 {
409 float roothealth = (burst ? WEP_CVAR(WEP_ARC, burst_healing_hps) : WEP_CVAR(WEP_ARC, beam_healing_hps));
410 float rootarmor = (burst ? WEP_CVAR(WEP_ARC, burst_healing_aps) : WEP_CVAR(WEP_ARC, beam_healing_aps));
411 float hplimit = (IS_PLAYER(trace_ent) ? WEP_CVAR(WEP_ARC, beam_healing_hmax) : RES_LIMIT_NONE);
412 Heal(trace_ent, own, (roothealth * coefficient), hplimit);
413 if (IS_PLAYER(trace_ent) && rootarmor
414 && GetResource(trace_ent, RES_ARMOR) <= WEP_CVAR(WEP_ARC, beam_healing_amax))
415 {
416 GiveResourceWithLimit(trace_ent, RES_ARMOR, (rootarmor * coefficient), WEP_CVAR(WEP_ARC, beam_healing_amax));
417 trace_ent.pauserotarmor_finished = max(trace_ent.pauserotarmor_finished, time + autocvar_g_balance_pause_armor_rot);
418 }
419 if (roothealth || rootarmor)
420 new_beam_type = ARC_BT_HEAL;
421 }
422 else if (trace_ent.takedamage && (is_player || WEP_CVAR(WEP_ARC, beam_nonplayerdamage)))
423 {
424 // calculate our own hit origin as trace_endpos tends to jump around annoyingly (to player origin?)
425 // NO. trace_endpos should be just fine. If not,
426 // that's an engine bug that needs proper debugging.
427 vector hitorigin = trace_endpos;
428 float falloff = 1;
429 if (WEP_CVAR(WEP_ARC, beam_falloff_halflifedist))
431 WEP_CVAR(WEP_ARC, beam_falloff_mindist),
432 WEP_CVAR(WEP_ARC, beam_falloff_maxdist),
433 WEP_CVAR(WEP_ARC, beam_falloff_halflifedist),
434 vlen(WarpZone_UnTransformOrigin(WarpZone_trace_transform, hitorigin) - original_start_pos)
435 );
436
437 float damage;
438 if (is_player)
439 {
440 if (burst)
441 damage = WEP_CVAR(WEP_ARC, burst_damage);
442 else
443 damage = WEP_CVAR(WEP_ARC, beam_damage);
444 }
445 else
446 damage = WEP_CVAR(WEP_ARC, beam_nonplayerdamage);
447 damage *= coefficient * falloff;
448
450 accuracy_add(own, WEP_ARC, 0, damage, 0); // add to hit
451
452 vector new_dir = normalize(new_origin - last_origin_prev);
454 float force = WEP_CVAR(WEP_ARC, beam_force) * coefficient * falloff;
455 Damage(trace_ent, own, own, damage, WEP_ARC.m_id, weaponentity, hitorigin, force * new_dir);
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{
651 return (w_deathtype & HITTYPE_SECONDARY) ? WEAPON_ARC_SUICIDE_BOLT : WEAPON_THINKING_WITH_PORTALS;
652}
653METHOD(Arc, wr_init, void(entity thiswep))
654{
655 if (!arc_shotorigin[0])
656 {
657 vector vecs = CL_Weapon_GetShotOrg(WEP_ARC.m_id);
658 arc_shotorigin[0] = shotorg_adjust(vecs, false, false, 1);
659 arc_shotorigin[1] = shotorg_adjust(vecs, false, false, 2);
660 arc_shotorigin[2] = shotorg_adjust(vecs, false, false, 3);
661 arc_shotorigin[3] = shotorg_adjust(vecs, false, false, 4);
662 }
663}
664METHOD(Arc, wr_checkammo1, bool(entity thiswep, entity actor, .entity weaponentity))
665{
666 return (!WEP_CVAR(WEP_ARC, beam_ammo) || GetResource(actor, thiswep.ammo_type) > 0);
667}
668METHOD(Arc, wr_checkammo2, bool(entity thiswep, entity actor, .entity weaponentity))
669{
670 if (WEP_CVAR(WEP_ARC, bolt))
671 {
672 float ammo_amount = GetResource(actor, thiswep.ammo_type) >= WEP_CVAR(WEP_ARC, bolt_ammo);
673 ammo_amount += actor.(weaponentity).(weapon_load[WEP_ARC.m_id]) >= WEP_CVAR(WEP_ARC, bolt_ammo);
674 return ammo_amount;
675 }
676 else
677 return WEP_CVAR(WEP_ARC, overheat_max) > 0
678 && (!WEP_CVAR(WEP_ARC, burst_ammo) || GetResource(actor, thiswep.ammo_type) > 0);
679}
680METHOD(Arc, wr_killmessage, Notification(entity thiswep))
681{
682 return (w_deathtype & HITTYPE_SECONDARY) ? WEAPON_ARC_MURDER_SPRAY : WEAPON_ARC_MURDER;
683}
684METHOD(Arc, wr_drop, void(entity thiswep, entity actor, .entity weaponentity))
685{
686 weapon_dropevent_item.arc_overheat = actor.arc_overheat;
687 weapon_dropevent_item.arc_cooldown = actor.arc_cooldown;
688 actor.arc_overheat = 0;
689 actor.arc_cooldown = 0;
690 actor.(weaponentity).arc_BUTTON_ATCK_prev = false;
691}
692METHOD(Arc, wr_pickup, void(entity thiswep, entity actor, .entity weaponentity))
693{
694 if (!client_hasweapon(actor, thiswep, weaponentity, false, false)
695 && weapon_dropevent_item.arc_overheat > time)
696 {
697 actor.arc_overheat = weapon_dropevent_item.arc_overheat;
698 actor.arc_cooldown = weapon_dropevent_item.arc_cooldown;
699 }
700}
701METHOD(Arc, wr_resetplayer, void(entity thiswep, entity actor))
702{
703 actor.arc_overheat = 0;
704 actor.arc_cooldown = 0;
705 for (int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
706 {
707 .entity weaponentity = weaponentities[slot];
708 actor.(weaponentity).arc_BUTTON_ATCK_prev = false;
709 }
710}
711METHOD(Arc, wr_playerdeath, void(entity thiswep, entity actor, .entity weaponentity))
712{
713 actor.arc_overheat = 0;
714 actor.arc_cooldown = 0;
715 actor.(weaponentity).arc_BUTTON_ATCK_prev = false;
716}
717
718#endif // SVQC
719#ifdef CSQC
720
722
724
725METHOD(Arc, wr_impacteffect, void(entity thiswep, entity actor))
726{
728 {
729 vector org2 = w_org + w_backoff * 2;
730 pointparticles(EFFECT_ELECTRO_IMPACT, org2, w_backoff * 1000, 1);
731 if (!w_issilent)
732 sound(actor, CH_SHOTS, SND_ARC_BOLT_IMPACT, VOL_BASE, ATTN_NORM);
733 }
734}
735
737{
740
741 vector hitorigin;
742 #if 0
743 if (trace_fraction != 1)
744 {
745 // calculate our own hit origin as trace_endpos tends to jump around annoyingly (to player origin?)
746 hitorigin = start + (Draw_ArcBeam_callback_new_dir * Draw_ArcBeam_callback_segmentdist * trace_fraction);
748 }
749 else
750 hitorigin = hit;
751 #else
752 hitorigin = hit;
753 #endif
754
755 float thickness = beam.beam_thickness;
756
758 Draw_CylindricLine(start, hit, thickness, beam.beam_image, 0.25, time * -3, beam.beam_color, beam.beam_alpha, DRAWFLAG_NORMAL, transformed_view_org);
759 else
760 {
761 // Thickdir shall be perpendicular to the beam and to the view-to-beam direction (WEAPONTODO: WHY)
762 // WEAPONTODO: Wouldn't it be better to be perpendicular to the beam and to the view FORWARD direction?
763 vector thickdir = normalize(cross(normalize(start - hit), transformed_view_org - start));
764
765 // draw primary beam render
766 vector top = hitorigin + (thickdir * thickness);
767 vector bottom = hitorigin - (thickdir * thickness);
768
771
772 // draw segment
773 R_BeginPolygon(beam.beam_image, DRAWFLAG_NORMAL, false); // DRAWFLAG_ADDITIVE
774 R_PolygonVertex(
775 top,
776 '0 0.5 0' + ('0 0.5 0' * (thickness / beam.beam_thickness)),
777 beam.beam_color,
778 beam.beam_alpha
779 );
780 R_PolygonVertex(
781 last_top,
782 '0 0.5 0' + ('0 0.5 0' * (Draw_ArcBeam_callback_last_thickness / beam.beam_thickness)),
783 beam.beam_color,
784 beam.beam_alpha
785 );
786 R_PolygonVertex(
787 last_bottom,
788 '0 0.5 0' * (1 - (Draw_ArcBeam_callback_last_thickness / beam.beam_thickness)),
789 beam.beam_color,
790 beam.beam_alpha
791 );
792 R_PolygonVertex(
793 bottom,
794 '0 0.5 0' * (1 - (thickness / beam.beam_thickness)),
795 beam.beam_color,
796 beam.beam_alpha
797 );
798 R_EndPolygon();
799
800 // set up for the next
804 }
805
806 // draw trailing particles
807 // NOTES:
808 // - Don't use spammy particle counts here, use a FEW small particles around the beam
809 // - We're not using WarpZone_TrailParticles here because we will handle warpzones ourselves.
810 if (beam.beam_traileffect)
811 trailparticles(beam, beam.beam_traileffect, start, hitorigin);
812}
813
815{
816 entity e;
817 for (e = NULL; (e = findfloat(e, beam_usevieworigin, 1)); )
818 e.beam_initialized = false;
819 for (e = NULL; (e = findfloat(e, beam_usevieworigin, 2)); )
820 e.beam_initialized = false;
821}
822
824{
825 float dt = time - this.move_time;
826 this.move_time = time;
827 if (dt <= 0)
828 return;
829
830 // origin = beam starting origin
831 // v_angle = wanted/aim direction
832 // angles = current direction of beam
833
834 vector start_pos;
835 vector wantdir; //= view_forward;
836 vector beamdir; //= this.beam_dir;
837
838 float segments;
839 if (this.beam_usevieworigin)
840 {
841 // WEAPONTODO:
842 // Currently we have to replicate nearly the same method of figuring
843 // out the shotdir that the server does... Ideally in the future we
844 // should be able to acquire this from a generalized function built
845 // into a weapon system for client code.
846
847 // Dr. Jaska: Reply to ^: Do we? If the server would decide where a
848 // client draws a beam it would mean that what the client sees will
849 // always be lagged and not where they are actually hitting in "real
850 // time" after being antilagged. Thus I don't understand the above.
851
852 // find where we are aiming
853 vector myviewangle = view_angles;
855 {
857 myviewangle = eX * csqcplayer.v_angle.x + eY * csqcplayer.angles.y;
858 else
859 myviewangle = warpzone_save_view_angles;
860 }
861 vector forward, right, up;
862 MAKE_VECTORS(myviewangle, forward, right, up);
863 entity wepent = viewmodels[this.beam_slot];
864
866
867 // decide upon start position
868 if (this.beam_usevieworigin == 2)
869 start_pos = warpzone_save_view_origin;
870 else if (csqcplayer)
871 start_pos = csqcplayer.origin + csqcplayer.view_ofs;
872 else
873 start_pos = this.origin;
874
875 vector start_pos_saved = start_pos;
876 int v_shot_idx;
877 (v_shot_idx = gettagindex(wepent, "shot")) || (v_shot_idx = gettagindex(wepent, "tag_shot"));
878 if (v_shot_idx && this.beam_usevieworigin == 2)
879 {
880 start_pos = gettaginfo(wepent, v_shot_idx) - '0 0 2';
881 // ignore our own player model in this traceline otherwise it may be hit with trace_fraction < 1
882 // while crouching / standing up due to view height smoothing (cl_smoothviewheight)
883 traceline(start_pos_saved, start_pos, MOVE_NORMAL, csqcplayer);
884 if (trace_fraction < 1)
885 {
886 // found an obstacle between view origin and shot tag
887 v_shot_idx = 0;
888 start_pos = trace_endpos;
889 start_pos_saved = start_pos;
890 }
891 }
892
893 // trace forward with an estimation
895 start_pos_saved,
896 start_pos_saved + forward * WEP_CVAR(WEP_ARC, beam_range),
898 this
899 );
900
901 // untransform in case our trace went through a warpzone
903
904 // un-adjust trueaim if shotend is too close
905 if (vdist(end_pos - start_pos, <, g_trueaim_minrange))
906 end_pos = start_pos + (forward * g_trueaim_minrange);
907
908 // move shot origin to the actual gun muzzle origin
909 vector origin_offset = '0 0 0';
910 if (!v_shot_idx || this.beam_usevieworigin != 2)
911 {
912 this.beam_shotorigin = wepent.movedir;
913 origin_offset = right * -this.beam_shotorigin.y + up * this.beam_shotorigin.z;
914 }
915 else
916 this.beam_shotorigin = '0 0 0';
917
918 start_pos += origin_offset;
919
920 // Move it also forward, but only as far as possible without hitting anything. Don't poke into walls!
921 traceline(start_pos, start_pos + forward * this.beam_shotorigin.x, MOVE_NORMAL, this);
922 start_pos = trace_endpos;
923
924 // calculate the aim direction now
925 if (vdist(end_pos - start_pos, >, 0.001))
926 wantdir = normalize(end_pos - start_pos);
927 else
928 wantdir = view_forward;
929
930 if (!this.beam_initialized)
931 {
932 this.beam_dir = wantdir;
933 this.beam_initialized = true;
934
935 this.beam_muzzleentity.drawmask = MASK_NORMAL; // NOTE: this works around the muzzle entity flashing on the middle of the screen for a frame
936 }
937
938 segments = 1;
939 if (this.beam_dir != wantdir)
940 {
941 // calculate how much we're going to move the end of the beam to the want position
942 float angle = vlen(wantdir - this.beam_dir) * RAD2DEG;
943 if (angle < 0.01) // snap only when very close so it's impossible to notice
944 this.beam_dir = wantdir; // snap otherwise vectors will never actually be the same
945 else
946 {
947 float max_blendfactor = 1;
948 if (angle && angle > WEP_CVAR(WEP_ARC, beam_maxangle))
949 max_blendfactor = WEP_CVAR(WEP_ARC, beam_maxangle) / angle;
950 float blendfactor = bound(0, (1 - (WEP_CVAR(WEP_ARC, beam_returnspeed) * dt)), max_blendfactor);
951 this.beam_dir = normalize((wantdir * (1 - blendfactor)) + (this.beam_dir * blendfactor));
952
953 // calculate how many segments are needed
954 float max_allowed_segments = ARC_MAX_SEGMENTS;
955 if (WEP_CVAR(WEP_ARC, beam_distancepersegment))
956 {
957 max_allowed_segments = 1 + (vlen(wantdir / WEP_CVAR(WEP_ARC, beam_distancepersegment)));
958 max_allowed_segments = bound(1, max_allowed_segments, ARC_MAX_SEGMENTS);
959 }
960 if (WEP_CVAR(WEP_ARC, beam_degreespersegment))
961 {
962 segments = min(angle, WEP_CVAR(WEP_ARC, beam_maxangle)) / WEP_CVAR(WEP_ARC, beam_degreespersegment);
963 segments = bound(1, segments, max_allowed_segments);
964 }
965 }
966 }
967
968 // set the beam direction which the rest of the code will refer to
969 beamdir = this.beam_dir;
970
971 // finally, set this.angles to the proper direction so that muzzle attachment points in proper direction
972 this.angles = fixedvectoangles2(forward, up); // TODO(Samual): is this == warpzone_save_view_angles?
973 }
974 else // if (!this.beam_usevieworigin)
975 {
977
978 // set the values from the provided info from the networked entity
979 start_pos = this.origin;
980 wantdir = this.v_angle;
981 beamdir = this.angles;
982
983 segments = 1;
984 if (beamdir != wantdir)
985 {
986 float angle = vlen(wantdir - beamdir) * RAD2DEG;
987
988 // calculate how many segments are needed
989 float max_allowed_segments = ARC_MAX_SEGMENTS;
990 if (WEP_CVAR(WEP_ARC, beam_distancepersegment))
991 {
992 max_allowed_segments = 1 + (vlen(wantdir / WEP_CVAR(WEP_ARC, beam_distancepersegment)));
993 max_allowed_segments = bound(1, max_allowed_segments, ARC_MAX_SEGMENTS);
994 }
995
996 if (WEP_CVAR(WEP_ARC, beam_degreespersegment))
997 {
998 segments = min(angle, WEP_CVAR(WEP_ARC, beam_maxangle)) / WEP_CVAR(WEP_ARC, beam_degreespersegment);
999 segments = bound(1, segments, max_allowed_segments);
1000 }
1001 }
1002 }
1003
1004 setorigin(this, start_pos);
1005 this.beam_muzzleentity.angles.z = random() * 360; // WEAPONTODO: use avelocity instead?
1006
1007 vector beam_endpos = start_pos + (beamdir * WEP_CVAR(WEP_ARC, beam_range));
1008 float beam_controlpoint_dist = WEP_CVAR(WEP_ARC, beam_range) * bound(0.001, 1 - WEP_CVAR(WEP_ARC, beam_tightness), 1);
1009 vector beam_controlpoint = start_pos + wantdir * beam_controlpoint_dist;
1010
1013 {
1017 }
1018
1019 vector last_origin = start_pos;
1020 vector original_start_pos = start_pos;
1021
1022 for (int i = 1; i <= segments; ++i)
1023 {
1024 // WEAPONTODO (client):
1025 // In order to do nice fading and pointing on the starting segment, we must always
1026 // have that drawn as a separate triangle... However, that is difficult to do when
1027 // keeping in mind the above problems and also optimizing the amount of segments
1028 // drawn on screen at any given time. (Automatic beam quality scaling, essentially)
1029
1030 vector new_origin = bezier_quadratic_getpoint(
1031 start_pos,
1032 beam_controlpoint,
1033 beam_endpos,
1034 i / segments
1035 );
1036
1038 last_origin,
1039 '0 0 0',
1040 '0 0 0',
1041 new_origin,
1043 NULL,
1044 NULL,
1046 );
1047
1048 last_origin = trace_endpos;
1049
1050 if (trace_fraction < 1)
1051 break; // hit something
1052
1053 // Do all the transforms for warpzones right now, as we already "are" in the post-trace
1054 // system (if we hit a player, that's always BEHIND the last passed wz).
1055 start_pos = WarpZone_TransformOrigin(WarpZone_trace_transform, start_pos);
1056 beam_controlpoint = WarpZone_TransformOrigin(WarpZone_trace_transform, beam_controlpoint);
1057 beam_endpos = WarpZone_TransformOrigin(WarpZone_trace_transform, beam_endpos);
1060 {
1063 }
1064 }
1065
1066 // visual effects for startpoint and endpoint
1069 this.beam_hiteffect,
1070 last_origin,
1072 dt * 2
1073 );
1074
1075 if (this.beam_hitlight[0])
1077 last_origin,
1078 this.beam_hitlight[0],
1079 vec3(
1080 this.beam_hitlight[1],
1081 this.beam_hitlight[2],
1082 this.beam_hitlight[3]
1083 )
1084 );
1085
1088 this.beam_muzzleeffect,
1089 original_start_pos + wantdir * 20,
1090 wantdir * 1000,
1091 dt * 0.1
1092 );
1093
1094 if (this.beam_muzzlelight[0])
1096 original_start_pos + wantdir * 20,
1097 this.beam_muzzlelight[0],
1098 vec3(
1099 this.beam_muzzlelight[1],
1100 this.beam_muzzlelight[2],
1101 this.beam_muzzlelight[3]
1102 )
1103 );
1104
1105 // cleanup
1108 {
1112 }
1113}
1114
1116{
1117 delete(this.beam_muzzleentity);
1118 sound(this, CH_SHOTS_SINGLE, SND_Null, VOL_BASE, ATTEN_NORM);
1119}
1120
1121NET_HANDLE(ENT_CLIENT_ARC_BEAM, bool isNew)
1122{
1123 int sf = ReadByte();
1124 int slot = ReadByte();
1125 entity flash;
1126
1127 this.beam_slot = slot;
1128
1129 if (isNew)
1130 {
1131 int gunalign = W_GunAlign(viewmodels[slot], STAT(GUNALIGN)) - 1;
1132
1133 this.beam_shotorigin = arc_shotorigin[gunalign]; // get a starting point
1134
1135 // set other main attributes of the beam
1136 this.draw = Draw_ArcBeam;
1137 IL_PUSH(g_drawables, this);
1138 this.entremove = Remove_ArcBeam;
1139 this.move_time = time;
1140 loopsound(this, CH_SHOTS_SINGLE, SND_ARC_LOOP, VOL_BASE, ATTEN_NORM);
1141
1142 flash = new(arc_flash);
1143 flash.owner = this;
1144 flash.effects = EF_ADDITIVE | EF_FULLBRIGHT;
1145 //flash.drawmask = MASK_NORMAL;
1146 flash.solid = SOLID_NOT;
1147 flash.avelocity.z = 5000;
1148 setattachment(flash, this, "");
1149 setorigin(flash, '0 0 0');
1150
1151 this.beam_muzzleentity = flash;
1152 }
1153 else
1154 flash = this.beam_muzzleentity;
1155
1156 if (sf & ARC_SF_UPDATE)
1157 {
1158 this.beam_usevieworigin = (ReadByte()) // drawlocal?
1159 ? (autocvar_chase_active ? 1 : 2)
1160 : 0;
1161
1162 this.sv_entnum = ReadByte();
1163 }
1164
1165 if (!this.beam_usevieworigin)
1166 {
1167 // this.iflags = IFLAG_ORIGIN | IFLAG_ANGLES | IFLAG_V_ANGLE; // why doesn't this work?
1168 this.iflags = IFLAG_ORIGIN;
1169
1171 }
1172
1173 if (sf & ARC_SF_START) // starting location
1174 this.origin = ReadVector();
1175 else if (this.beam_usevieworigin) // infer the location from player location
1176 {
1177 if (this.beam_usevieworigin == 2)
1178 {
1179 // use view origin
1180 this.origin = view_origin;
1181 }
1182 else
1183 {
1184 // use player origin so that third person display still works
1185 this.origin = entcs_receiver(player_localnum).origin + ('0 0 1' * STAT(VIEWHEIGHT));
1186 }
1187 }
1188
1189 setorigin(this, this.origin);
1190
1191 if (sf & ARC_SF_WANTDIR) // want/aim direction
1192 this.v_angle = ReadVector();
1193
1194 if (sf & ARC_SF_BEAMDIR) // beam direction
1195 this.angles = ReadAngleVector();
1196
1197 if (sf & ARC_SF_BEAMTYPE) // beam type
1198 {
1199 this.beam_type = ReadByte();
1200
1201 vector beamcolor = '1 1 1';
1203 beamcolor = colormapPaletteColor(entcs_GetClientColors(this.sv_entnum - 1) & 0x0F, true);
1204
1205 switch (this.beam_type)
1206 {
1207 case ARC_BT_MISS:
1208 this.beam_color = beamcolor;
1209 this.beam_alpha = 0.5;
1210 this.beam_thickness = 8;
1211 this.beam_traileffect = (EFFECT_ARC_BEAM);
1212 this.beam_hiteffect = (EFFECT_ARC_LIGHTNING);
1213 this.beam_hitlight[0] = 0;
1214 this.beam_hitlight[1] = 1;
1215 this.beam_hitlight[2] = 1;
1216 this.beam_hitlight[3] = 1;
1217 this.beam_muzzleeffect = EFFECT_Null;
1218 this.beam_muzzlelight[0] = 0;
1219 this.beam_muzzlelight[1] = 1;
1220 this.beam_muzzlelight[2] = 1;
1221 this.beam_muzzlelight[3] = 1;
1222 this.beam_image = "particles/lgbeam";
1224 {
1225 setmodel(flash, MDL_ARC_MUZZLEFLASH);
1226 flash.alpha = this.beam_alpha;
1227 flash.colormod = this.beam_color;
1228 flash.scale = 0.35;
1229 }
1230 break;
1231 case ARC_BT_WALL: // grenadelauncher_muzzleflash healray_muzzleflash
1232 this.beam_color = beamcolor;
1233 this.beam_alpha = 0.5;
1234 this.beam_thickness = 8;
1235 this.beam_traileffect = (EFFECT_ARC_BEAM);
1236 this.beam_hiteffect = (EFFECT_ARC_LIGHTNING);
1237 this.beam_hitlight[0] = 0;
1238 this.beam_hitlight[1] = 1;
1239 this.beam_hitlight[2] = 1;
1240 this.beam_hitlight[3] = 1;
1241 this.beam_muzzleeffect = EFFECT_Null; // (EFFECT_GRENADE_MUZZLEFLASH);
1242 this.beam_muzzlelight[0] = 0;
1243 this.beam_muzzlelight[1] = 1;
1244 this.beam_muzzlelight[2] = 1;
1245 this.beam_muzzlelight[3] = 1;
1246 this.beam_image = "particles/lgbeam";
1248 {
1249 setmodel(flash, MDL_ARC_MUZZLEFLASH);
1250 flash.alpha = this.beam_alpha;
1251 flash.colormod = this.beam_color;
1252 flash.scale = 0.35;
1253 }
1254 break;
1255 case ARC_BT_HEAL:
1256 this.beam_color = beamcolor;
1257 this.beam_alpha = 0.5;
1258 this.beam_thickness = 8;
1259 this.beam_traileffect = (EFFECT_ARC_BEAM_HEAL);
1260 this.beam_hiteffect = (EFFECT_ARC_BEAM_HEAL_IMPACT);
1261 this.beam_hitlight[0] = 0;
1262 this.beam_hitlight[1] = 1;
1263 this.beam_hitlight[2] = 1;
1264 this.beam_hitlight[3] = 1;
1265 this.beam_muzzleeffect = EFFECT_Null;
1266 this.beam_muzzlelight[0] = 0;
1267 this.beam_muzzlelight[1] = 1;
1268 this.beam_muzzlelight[2] = 1;
1269 this.beam_muzzlelight[3] = 1;
1270 this.beam_image = "particles/lgbeam";
1272 {
1273 setmodel(flash, MDL_ARC_MUZZLEFLASH);
1274 flash.alpha = this.beam_alpha;
1275 flash.colormod = this.beam_color;
1276 flash.scale = 0.35;
1277 }
1278 break;
1279 case ARC_BT_HIT:
1280 this.beam_color = beamcolor;
1281 this.beam_alpha = 0.5;
1282 this.beam_thickness = 8;
1283 this.beam_traileffect = (EFFECT_ARC_BEAM);
1284 this.beam_hiteffect = (EFFECT_ARC_LIGHTNING);
1285 this.beam_hitlight[0] = 20;
1286 this.beam_hitlight[1] = 1;
1287 this.beam_hitlight[2] = 0;
1288 this.beam_hitlight[3] = 0;
1289 this.beam_muzzleeffect = EFFECT_Null;
1290 this.beam_muzzlelight[0] = 50;
1291 this.beam_muzzlelight[1] = 1;
1292 this.beam_muzzlelight[2] = 0;
1293 this.beam_muzzlelight[3] = 0;
1294 this.beam_image = "particles/lgbeam";
1296 {
1297 setmodel(flash, MDL_ARC_MUZZLEFLASH);
1298 flash.alpha = this.beam_alpha;
1299 flash.colormod = this.beam_color;
1300 flash.scale = 0.35;
1301 }
1302 break;
1303 case ARC_BT_BURST_MISS:
1304 this.beam_color = beamcolor;
1305 this.beam_alpha = 0.5;
1306 this.beam_thickness = 14;
1307 this.beam_traileffect = (EFFECT_ARC_BEAM);
1308 this.beam_hiteffect = (EFFECT_ARC_LIGHTNING);
1309 this.beam_hitlight[0] = 0;
1310 this.beam_hitlight[1] = 1;
1311 this.beam_hitlight[2] = 1;
1312 this.beam_hitlight[3] = 1;
1313 this.beam_muzzleeffect = EFFECT_Null;
1314 this.beam_muzzlelight[0] = 0;
1315 this.beam_muzzlelight[1] = 1;
1316 this.beam_muzzlelight[2] = 1;
1317 this.beam_muzzlelight[3] = 1;
1318 this.beam_image = "particles/lgbeam";
1320 {
1321 setmodel(flash, MDL_ARC_MUZZLEFLASH);
1322 flash.alpha = this.beam_alpha;
1323 flash.colormod = this.beam_color;
1324 flash.scale = 0.35;
1325 }
1326 break;
1327 case ARC_BT_BURST_WALL:
1328 this.beam_color = beamcolor;
1329 this.beam_alpha = 0.5;
1330 this.beam_thickness = 14;
1331 this.beam_traileffect = (EFFECT_ARC_BEAM);
1332 this.beam_hiteffect = (EFFECT_ARC_LIGHTNING);
1333 this.beam_hitlight[0] = 0;
1334 this.beam_hitlight[1] = 1;
1335 this.beam_hitlight[2] = 1;
1336 this.beam_hitlight[3] = 1;
1337 this.beam_muzzleeffect = EFFECT_Null;
1338 this.beam_muzzlelight[0] = 0;
1339 this.beam_muzzlelight[1] = 1;
1340 this.beam_muzzlelight[2] = 1;
1341 this.beam_muzzlelight[3] = 1;
1342 this.beam_image = "particles/lgbeam";
1344 {
1345 setmodel(flash, MDL_ARC_MUZZLEFLASH);
1346 flash.alpha = this.beam_alpha;
1347 flash.colormod = this.beam_color;
1348 flash.scale = 0.35;
1349 }
1350 break;
1351 case ARC_BT_BURST_HEAL:
1352 this.beam_color = beamcolor;
1353 this.beam_alpha = 0.5;
1354 this.beam_thickness = 14;
1355 this.beam_traileffect = (EFFECT_ARC_BEAM_HEAL);
1356 this.beam_hiteffect = (EFFECT_ARC_BEAM_HEAL_IMPACT2);
1357 this.beam_hitlight[0] = 0;
1358 this.beam_hitlight[1] = 1;
1359 this.beam_hitlight[2] = 1;
1360 this.beam_hitlight[3] = 1;
1361 this.beam_muzzleeffect = EFFECT_Null;
1362 this.beam_muzzlelight[0] = 0;
1363 this.beam_muzzlelight[1] = 1;
1364 this.beam_muzzlelight[2] = 1;
1365 this.beam_muzzlelight[3] = 1;
1366 this.beam_image = "particles/lgbeam";
1368 {
1369 setmodel(flash, MDL_ARC_MUZZLEFLASH);
1370 flash.alpha = this.beam_alpha;
1371 flash.colormod = this.beam_color;
1372 flash.scale = 0.35;
1373 }
1374 break;
1375 case ARC_BT_BURST_HIT:
1376 this.beam_color = beamcolor;
1377 this.beam_alpha = 0.5;
1378 this.beam_thickness = 14;
1379 this.beam_traileffect = (EFFECT_ARC_BEAM);
1380 this.beam_hiteffect = (EFFECT_ARC_LIGHTNING);
1381 this.beam_hitlight[0] = 0;
1382 this.beam_hitlight[1] = 1;
1383 this.beam_hitlight[2] = 1;
1384 this.beam_hitlight[3] = 1;
1385 this.beam_muzzleeffect = EFFECT_Null;
1386 this.beam_muzzlelight[0] = 0;
1387 this.beam_muzzlelight[1] = 1;
1388 this.beam_muzzlelight[2] = 1;
1389 this.beam_muzzlelight[3] = 1;
1390 this.beam_image = "particles/lgbeam";
1392 {
1393 setmodel(flash, MDL_ARC_MUZZLEFLASH);
1394 flash.alpha = this.beam_alpha;
1395 flash.colormod = this.beam_color;
1396 flash.scale = 0.35;
1397 }
1398 break;
1399
1400 // shouldn't be possible, but lets make it colorful if it does :D
1401 default:
1402 this.beam_color = randomvec();
1403 this.beam_alpha = 1;
1404 this.beam_thickness = 8;
1405 this.beam_traileffect = NULL;
1406 this.beam_hiteffect = NULL;
1407 this.beam_hitlight[0] = 0;
1408 this.beam_hitlight[1] = 1;
1409 this.beam_hitlight[2] = 1;
1410 this.beam_hitlight[3] = 1;
1411 this.beam_muzzleeffect = EFFECT_Null;
1412 this.beam_muzzlelight[0] = 0;
1413 this.beam_muzzlelight[1] = 1;
1414 this.beam_muzzlelight[2] = 1;
1415 this.beam_muzzlelight[3] = 1;
1416 this.beam_image = "particles/lgbeam";
1418 {
1419 setmodel(flash, MDL_ARC_MUZZLEFLASH);
1420 flash.alpha = this.beam_alpha;
1421 flash.colormod = this.beam_color;
1422 flash.scale = 0.35;
1423 }
1424 break;
1425 }
1426 }
1427
1428 if (!this.beam_usevieworigin)
1430
1431 return true;
1432}
1433
1434#endif // CSQC
1435#ifdef MENUQC
1437
1438METHOD(Arc, describe, string(Arc this))
1439{
1440 TC(Arc, this);
1442 PAR(_("The %s fires a continuous beam of electricity, steadily dealing damage to any enemies that cross its path."), COLORED_NAME(this));
1443 PAR(_("The secondary fire rapidly shoots electric bolts forward, exploding on impact and dealing some splash damage."));
1444 PAR(_("It consumes %s ammo, steadily churning through your supply to maintain the stream."), COLORED_NAME(ITEM_Cells));
1445 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));
1446 PAR(W_Guide_Keybinds(this));
1447 PAR(W_Guide_DPS_primaryDPS(this.netname, "beam", "bolt"));
1448 return PAGE_TEXT;
1449}
1450
1451#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:721
void Arc_Smoke(Weapon thiswep, entity actor,.entity weaponentity, int fire)
Definition arc.qc:513
void Remove_ArcBeam(entity this)
Definition arc.qc:1115
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:736
void Reset_ArcBeam()
Definition arc.qc:814
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:823
int beam_slot
Definition arc.qc:723
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.
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:189
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:10
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
set manually after projectile has bounced
Definition all.qh:33
const int HITTYPE_SECONDARY
Definition all.qh:31
#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:155
ent angles
Definition ent_cs.qc:146
WriteByte(chan, ent.angles.y/DEC_FACTOR)
SetResourceExplicit(ent, RES_ARMOR, ReadByte() *DEC_FACTOR)) ENTCS_PROP(NAME
#define entcs_receiver(...)
Definition ent_cs.qh:61
int entcs_GetClientColors(int i)
Definition ent_cs.qh:111
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:349
#define ReadAngleVector()
Definition net.qh:351
#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:94
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:192
void WarpZone_TraceLine(vector org, vector end, float nomonsters, entity forent)
Definition common.qc:328
vector WarpZone_TransformVelocity(entity wz, vector v)
Definition common.qc:491
vector WarpZone_UnTransformOrigin(entity wz, vector v)
Definition common.qc:519
vector WarpZone_TransformOrigin(entity wz, vector v)
Definition common.qc:486
entity WarpZone_trace_transform
Definition common.qh:40
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:247
ERASEABLE vector bezier_quadratic_getpoint(vector a, vector b, vector c, float t)
Definition math.qh:114
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)
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:133
const int MOVETYPE_BOUNCEMISSILE
Definition movetypes.qh:144
float move_time
Definition movetypes.qh:81
var void func_null()
entity Notification
always last
Definition all.qh:85
#define METHOD(cname, name, prototype)
Definition oo.qh:274
#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:96
entity entity toucher
Definition self.qh:76
#define settouch(e, f)
Definition self.qh:77
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:651
#define PAR(...)
Adds an individually translatable paragraph to PAGE_TEXT without having to deal with strcat and sprin...
Definition string.qh:657
#define PAGE_TEXT_INIT()
Definition string.qh:650
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:44
#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:43
#define vec3(_x, _y, _z)
Definition vector.qh:100
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)]