Xonotic QuakeC
The free, fast arena FPS with crisp movement and a wide array of weapons
crylink.qc File Reference
#include "crylink.qh"
#include <common/items/item/ammo.qh>
Include dependency graph for crylink.qc:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

void W_Crylink_Attack (Weapon thiswep, entity actor,.entity weaponentity)
void W_Crylink_Attack2 (Weapon thiswep, entity actor,.entity weaponentity)
void W_Crylink_CheckLinks (entity e)
void W_Crylink_DeleteLink (entity this)
void W_Crylink_Dequeue (entity e)
void W_Crylink_Dequeue_Raw (entity own, entity prev, entity me, entity next)
void W_Crylink_Fadethink (entity this)
void W_Crylink_LinkExplode (entity e, entity e2, entity directhitentity)
vector W_Crylink_LinkJoin (entity e, float jspeed)
void W_Crylink_LinkJoinEffect_Think (entity this)
void W_Crylink_Reset (entity this)
void W_Crylink_Touch (entity this, entity toucher)
bool W_Crylink_Touch_WouldHitFriendly (entity projectile, float rad)

Variables

float w_crylink_linkjoin_time

Function Documentation

◆ W_Crylink_Attack()

void W_Crylink_Attack ( Weapon thiswep,
entity actor,
.entity weaponentity )

Definition at line 281 of file crylink.qc.

282{
283 W_DecreaseAmmo(thiswep, actor, WEP_CVAR_PRI(WEP_CRYLINK, ammo), weaponentity);
284
285 float maxdmg = WEP_CVAR_PRI(WEP_CRYLINK, damage) * WEP_CVAR_PRI(WEP_CRYLINK, shots);
286 maxdmg *= 1 + WEP_CVAR_PRI(WEP_CRYLINK, bouncedamagefactor) * WEP_CVAR_PRI(WEP_CRYLINK, bounces);
287 if (WEP_CVAR_PRI(WEP_CRYLINK, joinexplode))
288 maxdmg += WEP_CVAR_PRI(WEP_CRYLINK, joinexplode_damage);
289
290 W_SetupShot(actor, weaponentity, false, 2, SND_CRYLINK_FIRE, CH_WEAPON_A, maxdmg, thiswep.m_id);
291 vector right = v_right;
292 vector up = v_up;
293
294 int shots = WEP_CVAR_PRI(WEP_CRYLINK, shots);
295 W_MuzzleFlash(thiswep, actor, weaponentity, w_shotorg, w_shotdir);
296 entity proj = NULL, prevproj = NULL, firstproj = NULL;
297 vector s;
298 for (int counter = 0; counter < shots; ++counter)
299 {
300 proj = new(spike);
301 proj.dtor = W_Crylink_DeleteLink;
302 proj.reset = W_Crylink_Reset;
303 proj.realowner = proj.owner = actor;
304 proj.crylink_owner = actor;
305 proj.weaponentity_fld = weaponentity;
306 proj.bot_dodge = true;
307 proj.bot_dodgerating = WEP_CVAR_PRI(WEP_CRYLINK, damage);
308 if (shots == 1)
309 {
310 proj.queuenext = proj;
311 proj.queueprev = proj;
312 }
313 else if (counter == 0) // first projectile, store in firstproj for now
314 firstproj = proj;
315 else if (counter == shots - 1) // last projectile, link up with first projectile
316 {
317 prevproj.queuenext = proj;
318 firstproj.queueprev = proj;
319 proj.queuenext = firstproj;
320 proj.queueprev = prevproj;
321 }
322 else // else link up with previous projectile
323 {
324 prevproj.queuenext = proj;
325 proj.queueprev = prevproj;
326 }
327
328 prevproj = proj;
329
332 proj.projectiledeathtype = thiswep.m_id;
333 //proj.gravity = 0.001;
334
335 setorigin(proj, w_shotorg);
336 setsize(proj, '0 0 0', '0 0 0');
337
338 s = W_CalculateSpreadPattern(1, 0, counter, shots) * WEP_CVAR_PRI(WEP_CRYLINK, spread) * autocvar_g_weaponspreadfactor;
339 W_SetupProjVelocity_Explicit(proj, w_shotdir + right * s.y + up * s.z, v_up, WEP_CVAR_PRI(WEP_CRYLINK, speed), 0, 0, 0, false);
341
343 if (counter == 0)
344 {
345 proj.fade_time = time + WEP_CVAR_PRI(WEP_CRYLINK, middle_lifetime);
346 proj.fade_rate = 1 / WEP_CVAR_PRI(WEP_CRYLINK, middle_fadetime);
347 proj.nextthink = time + WEP_CVAR_PRI(WEP_CRYLINK, middle_lifetime) + WEP_CVAR_PRI(WEP_CRYLINK, middle_fadetime);
348 }
349 else
350 {
351 proj.fade_time = time + WEP_CVAR_PRI(WEP_CRYLINK, other_lifetime);
352 proj.fade_rate = 1 / WEP_CVAR_PRI(WEP_CRYLINK, other_fadetime);
353 proj.nextthink = time + WEP_CVAR_PRI(WEP_CRYLINK, other_lifetime) + WEP_CVAR_PRI(WEP_CRYLINK, other_fadetime);
354 }
355 proj.teleport_time = time + WEP_CVAR_PRI(WEP_CRYLINK, joindelay);
356 proj.cnt = WEP_CVAR_PRI(WEP_CRYLINK, bounces);
357 //proj.scale = 1 + 1 * proj.cnt;
358
359 proj.angles = vectoangles(proj.velocity);
360
361 //proj.glow_size = 20;
362
363 proj.flags = FL_PROJECTILE;
364 IL_PUSH(g_projectiles, proj);
365 IL_PUSH(g_bot_dodge, proj);
366 proj.missile_flags = MIF_SPLASH;
367
368 CSQCProjectile(proj, true, (proj.cnt ? PROJECTILE_CRYLINK_BOUNCING : PROJECTILE_CRYLINK), true);
369
370 MUTATOR_CALLHOOK(EditProjectile, actor, proj);
371 }
372 if (WEP_CVAR_PRI(WEP_CRYLINK, joinspread) != 0 && WEP_CVAR_PRI(WEP_CRYLINK, shots) > 1)
373 {
374 actor.(weaponentity).crylink_lastgroup = proj;
376 actor.(weaponentity).crylink_waitrelease = 1;
377 }
378}
IntrusiveList g_bot_dodge
Definition api.qh:150
#define MUTATOR_CALLHOOK(id,...)
Definition base.qh:143
vector W_CalculateSpreadPattern(int pattern, float bias, int counter, int total)
float autocvar_g_weaponspreadfactor
var entity(vector mins, vector maxs,.entity tofield) findbox_tofield_OrFallback
int m_id
Definition weapon.qh:43
const int FL_PROJECTILE
Definition constants.qh:85
vector v_up
float time
vector v_right
void CSQCProjectile(entity e, float clientanimate, int type, float docull)
float speed
Definition dynlight.qc:9
ERASEABLE entity IL_PUSH(IntrusiveList this, entity it)
Push to tail.
vector vectoangles(vector v)
void set_movetype(entity this, int mt)
Definition movetypes.qc:4
const int MOVETYPE_BOUNCEMISSILE
Definition movetypes.qh:140
#define NULL
Definition post.qh:14
const int PROJECTILE_CRYLINK_BOUNCING
const int PROJECTILE_CRYLINK
Definition projectiles.qh:6
#define setthink(e, f)
vector
Definition self.qh:92
#define settouch(e, f)
Definition self.qh:73
const int MIF_SPLASH
Definition common.qh:46
IntrusiveList g_projectiles
Definition common.qh:58
#define PROJECTILE_MAKETRIGGER(e)
Definition common.qh:34
const int CH_WEAPON_A
Definition sound.qh:7
float ammo
Definition sv_turrets.qh:43
void W_SetupProjVelocity_Explicit(entity proj, vector dir, vector upDir, float pSpeed, float pUpSpeed, float pZSpeed, float spread, float forceAbsolute)
Definition tracing.qc:185
vector w_shotdir
Definition tracing.qh:20
vector w_shotorg
Definition tracing.qh:19
#define W_SetupShot(ent, wepent, antilag, recoil, snd, chan, maxdamage, deathtype)
Definition tracing.qh:34
void W_MuzzleFlash(Weapon thiswep, entity actor,.entity weaponentity, vector shotorg, vector shotdir)
Definition all.qc:715
#define WEP_CVAR_PRI(wep, name)
Definition all.qh:338
void W_DecreaseAmmo(Weapon wep, entity actor, float ammo_use,.entity weaponentity)

References ammo, autocvar_g_weaponspreadfactor, CH_WEAPON_A, crylink_lastgroup, crylink_waitrelease, CSQCProjectile(), entity(), FL_PROJECTILE, g_bot_dodge, g_projectiles, IL_PUSH(), Weapon::m_id, MIF_SPLASH, MOVETYPE_BOUNCEMISSILE, MUTATOR_CALLHOOK, NULL, PROJECTILE_CRYLINK, PROJECTILE_CRYLINK_BOUNCING, PROJECTILE_MAKETRIGGER, set_movetype(), setthink, settouch, speed, time, v_right, v_up, vectoangles(), vector, W_CalculateSpreadPattern(), W_Crylink_CheckLinks(), W_Crylink_DeleteLink(), W_Crylink_Fadethink(), W_Crylink_Reset(), W_Crylink_Touch(), W_DecreaseAmmo(), W_MuzzleFlash(), W_SetupProjVelocity_Explicit(), W_SetupShot, w_shotdir, w_shotorg, and WEP_CVAR_PRI.

◆ W_Crylink_Attack2()

void W_Crylink_Attack2 ( Weapon thiswep,
entity actor,
.entity weaponentity )

Definition at line 380 of file crylink.qc.

381{
382 W_DecreaseAmmo(thiswep, actor, WEP_CVAR_SEC(WEP_CRYLINK, ammo), weaponentity);
383
384 float maxdmg = WEP_CVAR_SEC(WEP_CRYLINK, damage) * WEP_CVAR_SEC(WEP_CRYLINK, shots);
385 maxdmg *= 1 + WEP_CVAR_SEC(WEP_CRYLINK, bouncedamagefactor) * WEP_CVAR_SEC(WEP_CRYLINK, bounces);
386 if (WEP_CVAR_SEC(WEP_CRYLINK, joinexplode))
387 maxdmg += WEP_CVAR_SEC(WEP_CRYLINK, joinexplode_damage);
388
389 W_SetupShot(actor, weaponentity, false, 2, SND_CRYLINK_FIRE2, CH_WEAPON_A, maxdmg, thiswep.m_id | HITTYPE_SECONDARY);
390 vector right = v_right;
391 vector up = v_up;
392
393 int shots = WEP_CVAR_SEC(WEP_CRYLINK, shots);
394 W_MuzzleFlash(thiswep, actor, weaponentity, w_shotorg, w_shotdir);
395 entity proj = NULL, prevproj = NULL, firstproj = NULL;
396 vector s;
397 for (int counter = 0; counter < shots; ++counter)
398 {
399 proj = new(spike);
400 proj.dtor = W_Crylink_DeleteLink;
401 proj.weaponentity_fld = weaponentity;
402 proj.reset = W_Crylink_Reset;
403 proj.realowner = proj.owner = actor;
404 proj.crylink_owner = actor;
405 proj.bot_dodge = true;
406 proj.bot_dodgerating = WEP_CVAR_SEC(WEP_CRYLINK, damage);
407 if (shots == 1)
408 {
409 proj.queuenext = proj;
410 proj.queueprev = proj;
411 }
412 else if (counter == 0) // first projectile, store in firstproj for now
413 firstproj = proj;
414 else if (counter == shots - 1) // last projectile, link up with first projectile
415 {
416 prevproj.queuenext = proj;
417 firstproj.queueprev = proj;
418 proj.queuenext = firstproj;
419 proj.queueprev = prevproj;
420 }
421 else // else link up with previous projectile
422 {
423 prevproj.queuenext = proj;
424 proj.queueprev = prevproj;
425 }
426
427 prevproj = proj;
428
431 proj.projectiledeathtype = thiswep.m_id | HITTYPE_SECONDARY;
432 //proj.gravity = 0.001;
433
434 setorigin(proj, w_shotorg);
435 setsize(proj, '0 0 0', '0 0 0');
436
437 if (WEP_CVAR_SEC(WEP_CRYLINK, spreadtype) == 1)
438 {
439 s = W_CalculateSpreadPattern(1, 0, counter, shots) * WEP_CVAR_SEC(WEP_CRYLINK, spread) * autocvar_g_weaponspreadfactor;
440 s = w_shotdir + right * s.y + up * s.z;
441 }
442 else
443 s = w_shotdir + (((counter + 0.5) / shots) * 2 - 1) * v_right * WEP_CVAR_SEC(WEP_CRYLINK, spread) * autocvar_g_weaponspreadfactor;
444
445 W_SetupProjVelocity_Explicit(proj, s, v_up, WEP_CVAR_SEC(WEP_CRYLINK, speed), 0, 0, 0, false);
448 if (counter == (shots - 1) * 0.5)
449 {
450 proj.fade_time = time + WEP_CVAR_SEC(WEP_CRYLINK, middle_lifetime);
451 proj.fade_rate = 1 / WEP_CVAR_SEC(WEP_CRYLINK, middle_fadetime);
452 proj.nextthink = time + WEP_CVAR_SEC(WEP_CRYLINK, middle_lifetime) + WEP_CVAR_SEC(WEP_CRYLINK, middle_fadetime);
453 }
454 else
455 {
456 proj.fade_time = time + WEP_CVAR_SEC(WEP_CRYLINK, other_lifetime);
457 proj.fade_rate = 1 / WEP_CVAR_SEC(WEP_CRYLINK, other_fadetime);
458 proj.nextthink = time + WEP_CVAR_SEC(WEP_CRYLINK, other_lifetime) + WEP_CVAR_SEC(WEP_CRYLINK, other_fadetime);
459 }
460 proj.teleport_time = time + WEP_CVAR_SEC(WEP_CRYLINK, joindelay);
461 proj.cnt = WEP_CVAR_SEC(WEP_CRYLINK, bounces);
462 //proj.scale = 1 + 1 * proj.cnt;
463
464 proj.angles = vectoangles(proj.velocity);
465
466 //proj.glow_size = 20;
467
468 proj.flags = FL_PROJECTILE;
469 IL_PUSH(g_projectiles, proj);
470 IL_PUSH(g_bot_dodge, proj);
471 proj.missile_flags = MIF_SPLASH;
472
473 CSQCProjectile(proj, true, (proj.cnt ? PROJECTILE_CRYLINK_BOUNCING : PROJECTILE_CRYLINK), true);
474
475 MUTATOR_CALLHOOK(EditProjectile, actor, proj);
476 }
477 if (WEP_CVAR_SEC(WEP_CRYLINK, joinspread) != 0 && WEP_CVAR_SEC(WEP_CRYLINK, shots) > 1)
478 {
479 actor.(weaponentity).crylink_lastgroup = proj;
481 actor.(weaponentity).crylink_waitrelease = 2;
482 }
483}
const int HITTYPE_SECONDARY
Definition all.qh:29
#define WEP_CVAR_SEC(wep, name)
Definition all.qh:339

References ammo, autocvar_g_weaponspreadfactor, CH_WEAPON_A, crylink_lastgroup, crylink_waitrelease, CSQCProjectile(), entity(), FL_PROJECTILE, g_bot_dodge, g_projectiles, HITTYPE_SECONDARY, IL_PUSH(), Weapon::m_id, MIF_SPLASH, MOVETYPE_BOUNCEMISSILE, MUTATOR_CALLHOOK, NULL, PROJECTILE_CRYLINK, PROJECTILE_CRYLINK_BOUNCING, PROJECTILE_MAKETRIGGER, set_movetype(), setthink, settouch, speed, time, v_right, v_up, vectoangles(), vector, W_CalculateSpreadPattern(), W_Crylink_CheckLinks(), W_Crylink_DeleteLink(), W_Crylink_Fadethink(), W_Crylink_Reset(), W_Crylink_Touch(), W_DecreaseAmmo(), W_MuzzleFlash(), W_SetupProjVelocity_Explicit(), W_SetupShot, w_shotdir, w_shotorg, and WEP_CVAR_SEC.

◆ W_Crylink_CheckLinks()

void W_Crylink_CheckLinks ( entity e)

Definition at line 5 of file crylink.qc.

6{
7 if (e == NULL)
8 error("W_Crylink_CheckLinks: entity is NULL");
9 if (e.classname != "spike" || wasfreed(e))
10 error(sprintf("W_Crylink_CheckLinks: entity is not a spike but a %s (freed: %d)", e.classname, wasfreed(e)));
11
12 entity p = e;
13 int i;
14 for (i = 0; i < 1000; ++i)
15 {
16 if (p.queuenext.queueprev != p || p.queueprev.queuenext != p)
17 error("W_Crylink_CheckLinks: queue is inconsistent");
18 p = p.queuenext;
19 if (p == e)
20 break;
21 }
22 if (i >= 1000)
23 error("W_Crylink_CheckLinks: infinite chain");
24}
#define error
Definition pre.qh:6

References entity(), error, and NULL.

Referenced by W_Crylink_Attack(), W_Crylink_Attack2(), W_Crylink_Dequeue_Raw(), and W_Crylink_LinkJoin().

◆ W_Crylink_DeleteLink()

void W_Crylink_DeleteLink ( entity this)

Definition at line 44 of file crylink.qc.

45{
46 if (this.classname != "spike_oktoremove")
48 delete_fn(this);
49}
string classname
var void delete_fn(entity e)

References classname, delete_fn(), entity(), and W_Crylink_Dequeue().

Referenced by W_Crylink_Attack(), and W_Crylink_Attack2().

◆ W_Crylink_Dequeue()

void W_Crylink_Dequeue ( entity e)

Definition at line 39 of file crylink.qc.

40{
41 W_Crylink_Dequeue_Raw(e.crylink_owner, e.queueprev, e, e.queuenext);
42}

References entity(), and W_Crylink_Dequeue_Raw().

Referenced by W_Crylink_DeleteLink().

◆ W_Crylink_Dequeue_Raw()

void W_Crylink_Dequeue_Raw ( entity own,
entity prev,
entity me,
entity next )

Definition at line 26 of file crylink.qc.

27{
29 .entity weaponentity = me.weaponentity_fld;
30 if (me == own.(weaponentity).crylink_lastgroup)
31 own.(weaponentity).crylink_lastgroup = (me == next) ? NULL : next;
32 prev.queuenext = next;
33 next.queueprev = prev;
34 me.classname = "spike_oktoremove";
35 if (me != next)
37}
prev
Definition all.qh:73
next
Definition all.qh:95

References crylink_lastgroup, entity(), next, NULL, prev, and W_Crylink_CheckLinks().

Referenced by W_Crylink_Dequeue().

◆ W_Crylink_Fadethink()

void W_Crylink_Fadethink ( entity this)

Definition at line 276 of file crylink.qc.

277{
278 delete(this);
279}

References entity().

Referenced by W_Crylink_Attack(), and W_Crylink_Attack2().

◆ W_Crylink_LinkExplode()

void W_Crylink_LinkExplode ( entity e,
entity e2,
entity directhitentity )

Definition at line 57 of file crylink.qc.

58{
59 if (e == e2)
60 return;
61
62 float a = bound(0, 1 - (time - e.fade_time) * e.fade_rate, 1);
63
64 .entity weaponentity = e.weaponentity_fld;
65 if (e == e.crylink_owner.(weaponentity).crylink_lastgroup)
66 e.crylink_owner.(weaponentity).crylink_lastgroup = NULL;
67
68 bool is_primary = !(e.projectiledeathtype & HITTYPE_SECONDARY);
69 RadiusDamage(e, e.realowner,
70 a * WEP_CVAR_BOTH(WEP_CRYLINK, is_primary, damage),
71 a * WEP_CVAR_BOTH(WEP_CRYLINK, is_primary, edgedamage),
72 WEP_CVAR_BOTH(WEP_CRYLINK, is_primary, radius),
73 NULL,
74 NULL,
75 a * WEP_CVAR_BOTH(WEP_CRYLINK, is_primary, force),
76 e.projectiledeathtype,
77 e.weaponentity_fld,
78 directhitentity
79 );
80
81 W_Crylink_LinkExplode(e.queuenext, e2, directhitentity);
82
83 e.classname = "spike_oktoremove";
84 delete(e);
85}
float radius
Definition impulse.qh:11
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
float bound(float min, float value, float max)
#define WEP_CVAR_BOTH(wep, isprimary, name)
Definition all.qh:340

References bound(), crylink_lastgroup, entity(), HITTYPE_SECONDARY, NULL, radius, RadiusDamage(), time, W_Crylink_LinkExplode(), and WEP_CVAR_BOTH.

Referenced by W_Crylink_LinkExplode(), and W_Crylink_Touch().

◆ W_Crylink_LinkJoin()

vector W_Crylink_LinkJoin ( entity e,
float jspeed )

Definition at line 94 of file crylink.qc.

95{
96 // FIXME remove this debug code
98
100
101 entity p;
102 vector avg_org = e.origin;
103 vector avg_vel = e.velocity;
104 float n = 1;
105 for (p = e; (p = p.queuenext) != e; )
106 {
107 avg_org += WarpZone_RefSys_TransformOrigin(p, e, p.origin);
108 avg_vel += WarpZone_RefSys_TransformVelocity(p, e, p.velocity);
109 ++n;
110 }
111 avg_org *= 1.0 / n;
112 avg_vel *= 1.0 / n;
113
114 if (n < 2)
115 return avg_org; // nothing to do
116
117 // yes, mathematically we can do this in ONE step, but beware of 32bit floats...
118 float avg_dist = vlen2(e.origin - avg_org);
119 for (p = e; (p = p.queuenext) != e; )
120 avg_dist += vlen2(WarpZone_RefSys_TransformOrigin(p, e, p.origin) - avg_org);
121 avg_dist = sqrt(avg_dist * (1.0 / n));
122
123 if (avg_dist == 0)
124 return avg_org; // no change needed
125
126 vector targ_origin;
127 if (jspeed == 0)
128 {
129 e.velocity = avg_vel;
131 for (p = e; (p = p.queuenext) != e; )
132 {
133 p.velocity = WarpZone_RefSys_TransformVelocity(e, p, avg_vel);
135 }
136 targ_origin = avg_org + 1000000000 * normalize(avg_vel); // HUUUUUUGE
137 }
138 else
139 {
140 w_crylink_linkjoin_time = avg_dist / jspeed;
141 targ_origin = avg_org + w_crylink_linkjoin_time * avg_vel;
142
143 e.velocity = (targ_origin - e.origin) * (1.0 / w_crylink_linkjoin_time);
145 for (p = e; (p = p.queuenext) != e; )
146 {
147 p.velocity = WarpZone_RefSys_TransformVelocity(e, p, (targ_origin - WarpZone_RefSys_TransformOrigin(p, e, p.origin)) * (1.0 / w_crylink_linkjoin_time));
149 }
150
151 // analysis:
152 // jspeed -> +infinity:
153 // w_crylink_linkjoin_time -> +0
154 // targ_origin -> avg_org
155 // p->velocity -> HUEG towards center
156 // jspeed -> 0:
157 // w_crylink_linkjoin_time -> +/- infinity
158 // targ_origin -> avg_vel * +/- infinity
159 // p->velocity -> avg_vel
160 // jspeed -> -infinity:
161 // w_crylink_linkjoin_time -> -0
162 // targ_origin -> avg_org
163 // p->velocity -> HUEG away from center
164 }
165
167
168 return targ_origin;
169}
void UpdateCSQCProjectile(entity e)
vector WarpZone_RefSys_TransformVelocity(entity from, entity to, vector vel)
Definition common.qc:771
vector WarpZone_RefSys_TransformOrigin(entity from, entity to, vector org)
Definition common.qc:763
float sqrt(float f)
vector normalize(vector v)
#define vlen2(v)
Definition vector.qh:4

References entity(), normalize(), sqrt(), UpdateCSQCProjectile(), vector, vlen2, W_Crylink_CheckLinks(), w_crylink_linkjoin_time, WarpZone_RefSys_TransformOrigin(), and WarpZone_RefSys_TransformVelocity().

◆ W_Crylink_LinkJoinEffect_Think()

void W_Crylink_LinkJoinEffect_Think ( entity this)

Definition at line 171 of file crylink.qc.

172{
173 // is there at least 2 projectiles very close?
174 .entity weaponentity = this.weaponentity_fld;
175 entity e = this.owner.(weaponentity).crylink_lastgroup;
176 if (e)
177 {
178 float n = 0;
179 if (vlen2(e.origin - this.origin) < vlen2(e.velocity) * frametime)
180 ++n;
181 for (entity p = e; (p = p.queuenext) != e; )
182 if (vlen2(p.origin - this.origin) < vlen2(p.velocity) * frametime)
183 ++n;
184 if (n >= 2)
185 {
186 bool is_primary = !(e.projectiledeathtype & HITTYPE_SECONDARY);
187
188 if (WEP_CVAR_BOTH(WEP_CRYLINK, is_primary, joinexplode))
189 {
190 n /= WEP_CVAR_BOTH(WEP_CRYLINK, is_primary, shots);
191 RadiusDamage(e, e.realowner,
192 n * WEP_CVAR_BOTH(WEP_CRYLINK, is_primary, joinexplode_damage),
193 n * WEP_CVAR_BOTH(WEP_CRYLINK, is_primary, joinexplode_edgedamage),
194 n * WEP_CVAR_BOTH(WEP_CRYLINK, is_primary, joinexplode_radius),
195 e.realowner,
196 NULL,
197 n * WEP_CVAR_BOTH(WEP_CRYLINK, is_primary, joinexplode_force),
198 e.projectiledeathtype,
199 e.weaponentity_fld,
200 NULL
201 );
202 Send_Effect(EFFECT_CRYLINK_JOINEXPLODE, this.origin, '0 0 0', n);
203 }
204 }
205 }
206 delete(this);
207}
entity owner
Definition main.qh:87
float frametime
vector origin
void Send_Effect(entity eff, vector eff_loc, vector eff_vel, int eff_cnt)
Definition all.qc:120
entity weaponentity_fld

References crylink_lastgroup, entity(), frametime, HITTYPE_SECONDARY, NULL, origin, owner, RadiusDamage(), Send_Effect(), vlen2, weaponentity_fld, and WEP_CVAR_BOTH.

◆ W_Crylink_Reset()

void W_Crylink_Reset ( entity this)

Definition at line 51 of file crylink.qc.

52{
53 delete(this);
54}

References entity().

Referenced by W_Crylink_Attack(), and W_Crylink_Attack2().

◆ W_Crylink_Touch()

void W_Crylink_Touch ( entity this,
entity toucher )

Definition at line 226 of file crylink.qc.

227{
228 bool is_primary = !(this.projectiledeathtype & HITTYPE_SECONDARY);
230
231 float a = bound(0, 1 - (time - this.fade_time) * this.fade_rate, 1);
232 float finalhit = (this.cnt <= 0 || toucher.takedamage != DAMAGE_NO);
233 float f = (finalhit ? 1 : WEP_CVAR_BOTH(WEP_CRYLINK, is_primary, bouncedamagefactor));
234 if (a)
235 f *= a;
236
237 float totaldamage = RadiusDamage(this, this.realowner,
238 f * WEP_CVAR_BOTH(WEP_CRYLINK, is_primary, damage),
239 f * WEP_CVAR_BOTH(WEP_CRYLINK, is_primary, edgedamage),
240 WEP_CVAR_BOTH(WEP_CRYLINK, is_primary, radius),
241 NULL,
242 NULL,
243 f * WEP_CVAR_BOTH(WEP_CRYLINK, is_primary, force),
245 this.weaponentity_fld,
246 toucher
247 );
248
249 if (totaldamage
250 && ((WEP_CVAR_BOTH(WEP_CRYLINK, is_primary, linkexplode) == 1 && !W_Crylink_Touch_WouldHitFriendly(this, WEP_CVAR_BOTH(WEP_CRYLINK, is_primary, radius)))
251 || WEP_CVAR_BOTH(WEP_CRYLINK, is_primary, linkexplode) == 2))
252 {
253 .entity weaponentity = this.weaponentity_fld;
254 if (this == this.crylink_owner.(weaponentity).crylink_lastgroup)
255 this.crylink_owner.(weaponentity).crylink_lastgroup = NULL;
257 this.classname = "spike_oktoremove";
258 delete(this);
259 return;
260 }
261 else if (finalhit)
262 {
263 // just unlink
264 delete(this);
265 return;
266 }
267 --this.cnt;
268 this.angles = vectoangles(this.velocity);
269 this.owner = NULL;
271 // commented out as it causes a little hitch...
272 //if (proj.cnt == 0)
273 // CSQCProjectile(proj, true, PROJECTILE_CRYLINK, true);
274}
float cnt
Definition powerups.qc:24
vector velocity
const int HITTYPE_BOUNCE
Definition all.qh:31
ent angles
Definition ent_cs.qc:121
fade_rate
Definition projectile.qh:14
entity entity toucher
Definition self.qh:72
int projectiledeathtype
Definition common.qh:21
#define PROJECTILE_TOUCH(e, t)
Definition common.qh:28
float fade_time
Definition common.qh:23
const int DAMAGE_NO
Definition subs.qh:79
entity realowner

References angles, bound(), classname, cnt, crylink_lastgroup, crylink_owner, DAMAGE_NO, entity(), fade_rate, fade_time, HITTYPE_BOUNCE, HITTYPE_SECONDARY, NULL, owner, PROJECTILE_TOUCH, projectiledeathtype, queuenext, radius, RadiusDamage(), realowner, time, toucher, vectoangles(), velocity, W_Crylink_LinkExplode(), W_Crylink_Touch_WouldHitFriendly(), weaponentity_fld, and WEP_CVAR_BOTH.

Referenced by W_Crylink_Attack(), and W_Crylink_Attack2().

◆ W_Crylink_Touch_WouldHitFriendly()

bool W_Crylink_Touch_WouldHitFriendly ( entity projectile,
float rad )

Definition at line 209 of file crylink.qc.

210{
211 entity head = WarpZone_FindRadius(projectile.origin + (projectile.mins + projectile.maxs) * 0.5, rad + MAX_DAMAGEEXTRARADIUS, false);
212 bool hit_friendly = false;
213 for (; head; head = head.chain)
214 if (head.takedamage != DAMAGE_NO && !IS_DEAD(head))
215 {
216 if (SAME_TEAM(head, projectile.realowner))
217 hit_friendly = true;
218 else
219 return false;
220 }
221
222 return hit_friendly;
223}
#define IS_DEAD(s)
Definition player.qh:244
const float MAX_DAMAGEEXTRARADIUS
entity WarpZone_FindRadius(vector org, float rad, bool needlineofsight)
Definition common.qc:684
#define SAME_TEAM(a, b)
Definition teams.qh:241

References DAMAGE_NO, entity(), IS_DEAD, MAX_DAMAGEEXTRARADIUS, SAME_TEAM, and WarpZone_FindRadius().

Referenced by W_Crylink_Touch().

Variable Documentation

◆ w_crylink_linkjoin_time

float w_crylink_linkjoin_time

Definition at line 93 of file crylink.qc.

Referenced by W_Crylink_LinkJoin().