3 /* WEP_##id */ CRYLINK,
4 /* function */ w_crylink,
5 /* ammotype */ IT_CELLS,
7 /* flags */ WEP_FLAG_NORMAL | WEP_FLAG_RELOADABLE | WEP_TYPE_SPLASH,
8 /* rating */ BOT_PICKUP_RATING_MID,
10 /* netname */ "crylink",
11 /* fullname */ _("Crylink")
14 #define CRYLINK_SETTINGS(weapon) \
15 WEP_ADD_CVAR(weapon, MO_BOTH, ammo) \
16 WEP_ADD_CVAR(weapon, MO_BOTH, animtime) \
17 WEP_ADD_CVAR(weapon, MO_BOTH, damage) \
18 WEP_ADD_CVAR(weapon, MO_BOTH, edgedamage) \
19 WEP_ADD_CVAR(weapon, MO_BOTH, radius) \
20 WEP_ADD_CVAR(weapon, MO_BOTH, force) \
21 WEP_ADD_CVAR(weapon, MO_BOTH, spread) \
22 WEP_ADD_CVAR(weapon, MO_BOTH, refire) \
23 WEP_ADD_CVAR(weapon, MO_BOTH, speed) \
24 WEP_ADD_CVAR(weapon, MO_BOTH, shots) \
25 WEP_ADD_CVAR(weapon, MO_BOTH, bounces) \
26 WEP_ADD_CVAR(weapon, MO_BOTH, bouncedamagefactor) \
27 WEP_ADD_CVAR(weapon, MO_BOTH, middle_lifetime) \
28 WEP_ADD_CVAR(weapon, MO_BOTH, middle_fadetime) \
29 WEP_ADD_CVAR(weapon, MO_BOTH, other_lifetime) \
30 WEP_ADD_CVAR(weapon, MO_BOTH, other_fadetime) \
31 WEP_ADD_CVAR(weapon, MO_BOTH, linkexplode) \
32 WEP_ADD_CVAR(weapon, MO_BOTH, joindelay) \
33 WEP_ADD_CVAR(weapon, MO_BOTH, joinspread) \
34 WEP_ADD_CVAR(weapon, MO_BOTH, jointime) \
35 WEP_ADD_CVAR(weapon, MO_BOTH, joinexplode) \
36 WEP_ADD_CVAR(weapon, MO_BOTH, joinexplode_damage) \
37 WEP_ADD_CVAR(weapon, MO_BOTH, joinexplode_edgedamage) \
38 WEP_ADD_CVAR(weapon, MO_BOTH, joinexplode_radius) \
39 WEP_ADD_CVAR(weapon, MO_BOTH, joinexplode_force) \
40 WEP_ADD_CVAR(weapon, MO_SEC, spreadtype) \
41 WEP_ADD_PROP(weapon, reloading_ammo, reload_ammo) \
42 WEP_ADD_PROP(weapon, reloading_time, reload_time) \
43 WEP_ADD_PROP(weapon, switchdelay_raise, switchdelay_raise) \
44 WEP_ADD_PROP(weapon, switchdelay_drop, switchdelay_drop)
47 CRYLINK_SETTINGS(crylink)
48 void spawnfunc_weapon_crylink() { weapon_defaultspawnfunc(WEP_CRYLINK); }
50 .float crylink_waitrelease;
51 .entity crylink_lastgroup;
59 void W_Crylink_CheckLinks(entity e)
65 error("W_Crylink_CheckLinks: entity is world");
66 if(e.classname != "spike" || wasfreed(e))
67 error(sprintf("W_Crylink_CheckLinks: entity is not a spike but a %s (freed: %d)", e.classname, wasfreed(e)));
70 for(i = 0; i < 1000; ++i)
72 if(p.queuenext.queueprev != p || p.queueprev.queuenext != p)
73 error("W_Crylink_CheckLinks: queue is inconsistent");
79 error("W_Crylink_CheckLinks: infinite chain");
82 void W_Crylink_Dequeue_Raw(entity own, entity prev, entity me, entity next)
84 W_Crylink_CheckLinks(next);
85 if(me == own.crylink_lastgroup)
86 own.crylink_lastgroup = ((me == next) ? world : next);
87 prev.queuenext = next;
88 next.queueprev = prev;
89 me.classname = "spike_oktoremove";
91 W_Crylink_CheckLinks(next);
94 void W_Crylink_Dequeue(entity e)
96 W_Crylink_Dequeue_Raw(e.realowner, e.queueprev, e, e.queuenext);
99 void W_Crylink_Reset(void)
101 W_Crylink_Dequeue(self);
105 // force projectile to explode
106 void W_Crylink_LinkExplode (entity e, entity e2)
113 a = bound(0, 1 - (time - e.fade_time) * e.fade_rate, 1);
115 if(e == e.realowner.crylink_lastgroup)
116 e.realowner.crylink_lastgroup = world;
118 float isprimary = !(e.projectiledeathtype & HITTYPE_SECONDARY);
120 RadiusDamage(e, e.realowner, WEP_CVAR_BOTH(crylink, isprimary, damage) * a, WEP_CVAR_BOTH(crylink, isprimary, edgedamage) * a, WEP_CVAR_BOTH(crylink, isprimary, radius), world, world, WEP_CVAR_BOTH(crylink, isprimary, force) * a, e.projectiledeathtype, other);
122 W_Crylink_LinkExplode(e.queuenext, e2);
124 e.classname = "spike_oktoremove";
128 // adjust towards center
129 // returns the origin where they will meet... and the time till the meeting is
130 // stored in w_crylink_linkjoin_time.
131 // could possibly network this origin and time, and display a special particle
132 // effect when projectiles meet there :P
133 // jspeed: MINIMUM jing speed
134 // jtime: MAXIMUM jing time (0: none)
135 float w_crylink_linkjoin_time;
136 vector W_Crylink_LinkJoin(entity e, float jspeed, float jtime)
138 vector avg_origin, avg_velocity;
143 // FIXME remove this debug code
144 W_Crylink_CheckLinks(e);
146 w_crylink_linkjoin_time = 0;
148 avg_origin = e.origin;
149 avg_velocity = e.velocity;
151 for(p = e; (p = p.queuenext) != e; )
153 avg_origin += WarpZone_RefSys_TransformOrigin(p, e, p.origin);
154 avg_velocity += WarpZone_RefSys_TransformVelocity(p, e, p.velocity);
157 avg_origin *= (1.0 / n);
158 avg_velocity *= (1.0 / n);
161 return avg_origin; // nothing to do
163 // yes, mathematically we can do this in ONE step, but beware of 32bit floats...
164 avg_dist = pow(vlen(e.origin - avg_origin), 2);
165 for(p = e; (p = p.queuenext) != e; )
166 avg_dist += pow(vlen(WarpZone_RefSys_TransformOrigin(p, e, p.origin) - avg_origin), 2);
167 avg_dist *= (1.0 / n);
168 avg_dist = sqrt(avg_dist);
171 return avg_origin; // no change needed
173 if(jspeed == 0 && jtime == 0)
175 e.velocity = avg_velocity;
176 UpdateCSQCProjectile(e);
177 for(p = e; (p = p.queuenext) != e; )
179 p.velocity = WarpZone_RefSys_TransformVelocity(e, p, avg_velocity);
180 UpdateCSQCProjectile(p);
182 targ_origin = avg_origin + 1000000000 * normalize(avg_velocity); // HUUUUUUGE
189 w_crylink_linkjoin_time = min(jtime, avg_dist / jspeed);
191 w_crylink_linkjoin_time = jtime;
194 w_crylink_linkjoin_time = avg_dist / jspeed;
195 targ_origin = avg_origin + w_crylink_linkjoin_time * avg_velocity;
197 e.velocity = (targ_origin - e.origin) * (1.0 / w_crylink_linkjoin_time);
198 UpdateCSQCProjectile(e);
199 for(p = e; (p = p.queuenext) != e; )
201 p.velocity = WarpZone_RefSys_TransformVelocity(e, p, (targ_origin - WarpZone_RefSys_TransformOrigin(p, e, p.origin)) * (1.0 / w_crylink_linkjoin_time));
202 UpdateCSQCProjectile(p);
206 // jspeed -> +infinity:
207 // w_crylink_linkjoin_time -> +0
208 // targ_origin -> avg_origin
209 // p->velocity -> HUEG towards center
211 // w_crylink_linkjoin_time -> +/- infinity
212 // targ_origin -> avg_velocity * +/- infinity
213 // p->velocity -> avg_velocity
214 // jspeed -> -infinity:
215 // w_crylink_linkjoin_time -> -0
216 // targ_origin -> avg_origin
217 // p->velocity -> HUEG away from center
220 W_Crylink_CheckLinks(e);
225 void W_Crylink_LinkJoinEffect_Think()
227 // is there at least 2 projectiles very close?
230 e = self.owner.crylink_lastgroup;
234 if(vlen(e.origin - self.origin) < vlen(e.velocity) * frametime)
236 for(p = e; (p = p.queuenext) != e; )
238 if(vlen(p.origin - self.origin) < vlen(p.velocity) * frametime)
243 float isprimary = !(e.projectiledeathtype & HITTYPE_SECONDARY);
245 if(WEP_CVAR_BOTH(crylink, isprimary, joinexplode))
247 n /= WEP_CVAR_BOTH(crylink, isprimary, shots);
248 RadiusDamage(e, e.realowner, WEP_CVAR_BOTH(crylink, isprimary, joinexplode_damage) * n,
249 WEP_CVAR_BOTH(crylink, isprimary, joinexplode_edgedamage) * n,
250 WEP_CVAR_BOTH(crylink, isprimary, joinexplode_radius) * n, e.realowner, world,
251 WEP_CVAR_BOTH(crylink, isprimary, joinexplode_force) * n, e.projectiledeathtype, other);
252 pointparticles(particleeffectnum("crylink_joinexplode"), self.origin, '0 0 0', n);
259 float W_Crylink_Touch_WouldHitFriendly(entity projectile, float rad)
261 entity head = WarpZone_FindRadius((projectile.origin + (projectile.mins + projectile.maxs) * 0.5), rad + MAX_DAMAGEEXTRARADIUS, FALSE);
262 float hit_friendly = 0;
267 if((head.takedamage != DAMAGE_NO) && (head.deadflag == DEAD_NO))
269 if(IsDifferentTeam(head, projectile.realowner))
278 return (hit_enemy ? FALSE : hit_friendly);
281 // NO bounce protection, as bounces are limited!
282 void W_Crylink_Touch (void)
286 float isprimary = !(self.projectiledeathtype & HITTYPE_SECONDARY);
290 a = bound(0, 1 - (time - self.fade_time) * self.fade_rate, 1);
292 finalhit = ((self.cnt <= 0) || (other.takedamage != DAMAGE_NO));
296 f = WEP_CVAR_BOTH(crylink, isprimary, bouncedamagefactor);
300 float totaldamage = RadiusDamage(self, self.realowner, WEP_CVAR_BOTH(crylink, isprimary, damage) * f, WEP_CVAR_BOTH(crylink, isprimary, edgedamage) * f, WEP_CVAR_BOTH(crylink, isprimary, radius), world, world, WEP_CVAR_BOTH(crylink, isprimary, force) * f, self.projectiledeathtype, other);
302 if(totaldamage && ((WEP_CVAR_BOTH(crylink, isprimary, linkexplode) == 2) || ((WEP_CVAR_BOTH(crylink, isprimary, linkexplode) == 1) && !W_Crylink_Touch_WouldHitFriendly(self, WEP_CVAR_BOTH(crylink, isprimary, radius)))))
304 if(self == self.realowner.crylink_lastgroup)
305 self.realowner.crylink_lastgroup = world;
306 W_Crylink_LinkExplode(self.queuenext, self);
307 self.classname = "spike_oktoremove";
314 W_Crylink_Dequeue(self);
318 self.cnt = self.cnt - 1;
319 self.angles = vectoangles(self.velocity);
321 self.projectiledeathtype |= HITTYPE_BOUNCE;
322 // commented out as it causes a little hitch...
324 // CSQCProjectile(proj, TRUE, PROJECTILE_CRYLINK, TRUE);
327 void W_Crylink_Fadethink (void)
329 W_Crylink_Dequeue(self);
333 void W_Crylink_Attack (void)
335 float counter, shots;
336 entity proj, prevproj, firstproj;
338 vector forward, right, up;
341 W_DecreaseAmmo(ammo_cells, autocvar_g_balance_crylink_primary_ammo, autocvar_g_balance_crylink_reload_ammo);
343 maxdmg = WEP_CVAR_PRI(crylink, damage) * WEP_CVAR_PRI(crylink, shots);
344 maxdmg *= 1 + WEP_CVAR_PRI(crylink, bouncedamagefactor) * WEP_CVAR_PRI(crylink, bounces);
345 if(WEP_CVAR_PRI(crylink, joinexplode))
346 maxdmg += WEP_CVAR_PRI(crylink, joinexplode_damage);
348 W_SetupShot (self, FALSE, 2, "weapons/crylink_fire.wav", CH_WEAPON_A, maxdmg);
353 shots = WEP_CVAR_PRI(crylink, shots);
354 pointparticles(particleeffectnum("crylink_muzzleflash"), w_shotorg, w_shotdir * 1000, shots);
355 proj = prevproj = firstproj = world;
356 for(counter = 0; counter < shots; ++counter)
359 proj.reset = W_Crylink_Reset;
360 proj.realowner = proj.owner = self;
361 proj.classname = "spike";
362 proj.bot_dodge = TRUE;
363 proj.bot_dodgerating = WEP_CVAR_PRI(crylink, damage);
365 proj.queuenext = proj;
366 proj.queueprev = proj;
368 else if(counter == 0) { // first projectile, store in firstproj for now
371 else if(counter == shots - 1) { // last projectile, link up with first projectile
372 prevproj.queuenext = proj;
373 firstproj.queueprev = proj;
374 proj.queuenext = firstproj;
375 proj.queueprev = prevproj;
377 else { // else link up with previous projectile
378 prevproj.queuenext = proj;
379 proj.queueprev = prevproj;
384 proj.movetype = MOVETYPE_BOUNCEMISSILE;
385 PROJECTILE_MAKETRIGGER(proj);
386 proj.projectiledeathtype = WEP_CRYLINK;
387 //proj.gravity = 0.001;
389 setorigin (proj, w_shotorg);
390 setsize(proj, '0 0 0', '0 0 0');
398 makevectors('0 360 0' * (0.75 + (counter - 0.5) / (shots - 1)));
402 s = s * WEP_CVAR_PRI(crylink, spread) * g_weaponspreadfactor;
403 W_SetupProjectileVelocityEx(proj, w_shotdir + right * s_y + up * s_z, v_up, WEP_CVAR_PRI(crylink, speed), 0, 0, 0, FALSE);
404 proj.touch = W_Crylink_Touch;
406 proj.think = W_Crylink_Fadethink;
409 proj.fade_time = time + WEP_CVAR_PRI(crylink, middle_lifetime);
410 proj.fade_rate = 1 / WEP_CVAR_PRI(crylink, middle_fadetime);
411 proj.nextthink = time + WEP_CVAR_PRI(crylink, middle_lifetime) + WEP_CVAR_PRI(crylink, middle_fadetime);
415 proj.fade_time = time + WEP_CVAR_PRI(crylink, other_lifetime);
416 proj.fade_rate = 1 / WEP_CVAR_PRI(crylink, other_fadetime);
417 proj.nextthink = time + WEP_CVAR_PRI(crylink, other_lifetime) + WEP_CVAR_PRI(crylink, other_fadetime);
419 proj.teleport_time = time + WEP_CVAR_PRI(crylink, joindelay);
420 proj.cnt = WEP_CVAR_PRI(crylink, bounces);
421 //proj.scale = 1 + 1 * proj.cnt;
423 proj.angles = vectoangles (proj.velocity);
425 //proj.glow_size = 20;
427 proj.flags = FL_PROJECTILE;
428 proj.missile_flags = MIF_SPLASH;
430 CSQCProjectile(proj, TRUE, (proj.cnt ? PROJECTILE_CRYLINK_BOUNCING : PROJECTILE_CRYLINK), TRUE);
432 other = proj; MUTATOR_CALLHOOK(EditProjectile);
434 if(WEP_CVAR_PRI(crylink, joinspread) != 0 || WEP_CVAR_PRI(crylink, jointime) != 0)
436 self.crylink_lastgroup = proj;
437 W_Crylink_CheckLinks(proj);
438 self.crylink_waitrelease = 1;
442 void W_Crylink_Attack2 (void)
444 float counter, shots;
445 entity proj, prevproj, firstproj;
447 vector forward, right, up;
450 W_DecreaseAmmo(ammo_cells, autocvar_g_balance_crylink_secondary_ammo, autocvar_g_balance_crylink_reload_ammo);
452 maxdmg = WEP_CVAR_SEC(crylink, damage) * WEP_CVAR_SEC(crylink, shots);
453 maxdmg *= 1 + WEP_CVAR_SEC(crylink, bouncedamagefactor) * WEP_CVAR_SEC(crylink, bounces);
454 if(WEP_CVAR_SEC(crylink, joinexplode))
455 maxdmg += WEP_CVAR_SEC(crylink, joinexplode_damage);
457 W_SetupShot (self, FALSE, 2, "weapons/crylink_fire2.wav", CH_WEAPON_A, maxdmg);
462 shots = WEP_CVAR_SEC(crylink, shots);
463 pointparticles(particleeffectnum("crylink_muzzleflash"), w_shotorg, w_shotdir * 1000, shots);
464 proj = prevproj = firstproj = world;
465 for(counter = 0; counter < shots; ++counter)
468 proj.reset = W_Crylink_Reset;
469 proj.realowner = proj.owner = self;
470 proj.classname = "spike";
471 proj.bot_dodge = TRUE;
472 proj.bot_dodgerating = WEP_CVAR_SEC(crylink, damage);
474 proj.queuenext = proj;
475 proj.queueprev = proj;
477 else if(counter == 0) { // first projectile, store in firstproj for now
480 else if(counter == shots - 1) { // last projectile, link up with first projectile
481 prevproj.queuenext = proj;
482 firstproj.queueprev = proj;
483 proj.queuenext = firstproj;
484 proj.queueprev = prevproj;
486 else { // else link up with previous projectile
487 prevproj.queuenext = proj;
488 proj.queueprev = prevproj;
493 proj.movetype = MOVETYPE_BOUNCEMISSILE;
494 PROJECTILE_MAKETRIGGER(proj);
495 proj.projectiledeathtype = WEP_CRYLINK | HITTYPE_SECONDARY;
496 //proj.gravity = 0.001;
498 setorigin (proj, w_shotorg);
499 setsize(proj, '0 0 0', '0 0 0');
501 if(WEP_CVAR_SEC(crylink, spreadtype) == 1)
508 makevectors('0 360 0' * (0.75 + (counter - 0.5) / (shots - 1)));
512 s = s * WEP_CVAR_SEC(crylink, spread) * g_weaponspreadfactor;
513 s = w_shotdir + right * s_y + up * s_z;
517 s = (w_shotdir + (((counter + 0.5) / shots) * 2 - 1) * v_right * WEP_CVAR_SEC(crylink, spread) * g_weaponspreadfactor);
520 W_SetupProjectileVelocityEx(proj, s, v_up, WEP_CVAR_SEC(crylink, speed), 0, 0, 0, FALSE);
521 proj.touch = W_Crylink_Touch;
522 proj.think = W_Crylink_Fadethink;
523 if(counter == (shots - 1) / 2)
525 proj.fade_time = time + WEP_CVAR_SEC(crylink, middle_lifetime);
526 proj.fade_rate = 1 / WEP_CVAR_SEC(crylink, middle_fadetime);
527 proj.nextthink = time + WEP_CVAR_SEC(crylink, middle_lifetime) + WEP_CVAR_SEC(crylink, middle_fadetime);
531 proj.fade_time = time + WEP_CVAR_SEC(crylink, other_lifetime);
532 proj.fade_rate = 1 / WEP_CVAR_SEC(crylink, other_fadetime);
533 proj.nextthink = time + WEP_CVAR_SEC(crylink, other_lifetime) + WEP_CVAR_SEC(crylink, other_fadetime);
535 proj.teleport_time = time + WEP_CVAR_SEC(crylink, joindelay);
536 proj.cnt = WEP_CVAR_SEC(crylink, bounces);
537 //proj.scale = 1 + 1 * proj.cnt;
539 proj.angles = vectoangles (proj.velocity);
541 //proj.glow_size = 20;
543 proj.flags = FL_PROJECTILE;
544 proj.missile_flags = MIF_SPLASH;
546 CSQCProjectile(proj, TRUE, (proj.cnt ? PROJECTILE_CRYLINK_BOUNCING : PROJECTILE_CRYLINK), TRUE);
548 other = proj; MUTATOR_CALLHOOK(EditProjectile);
550 if(WEP_CVAR_SEC(crylink, joinspread) != 0 || WEP_CVAR_SEC(crylink, jointime) != 0)
552 self.crylink_lastgroup = proj;
553 W_Crylink_CheckLinks(proj);
554 self.crylink_waitrelease = 2;
558 float w_crylink(float req)
566 self.BUTTON_ATCK = bot_aim(WEP_CVAR_PRI(crylink, speed), 0, WEP_CVAR_PRI(crylink, middle_lifetime), FALSE);
568 self.BUTTON_ATCK2 = bot_aim(WEP_CVAR_SEC(crylink, speed), 0, WEP_CVAR_SEC(crylink, middle_lifetime), FALSE);
574 if(autocvar_g_balance_crylink_reload_ammo && self.clip_load < min(autocvar_g_balance_crylink_primary_ammo, autocvar_g_balance_crylink_secondary_ammo)) // forced reload
575 WEP_ACTION(self.weapon, WR_RELOAD);
577 if (self.BUTTON_ATCK)
579 if (self.crylink_waitrelease != 1)
580 if (weapon_prepareattack(0, WEP_CVAR_PRI(crylink, refire)))
583 weapon_thinkf(WFRAME_FIRE1, WEP_CVAR_PRI(crylink, animtime), w_ready);
587 if(self.BUTTON_ATCK2 && autocvar_g_balance_crylink_secondary)
589 if (self.crylink_waitrelease != 2)
590 if (weapon_prepareattack(1, WEP_CVAR_SEC(crylink, refire)))
593 weapon_thinkf(WFRAME_FIRE2, WEP_CVAR_SEC(crylink, animtime), w_ready);
597 if ((self.crylink_waitrelease == 1 && !self.BUTTON_ATCK) || (self.crylink_waitrelease == 2 && !self.BUTTON_ATCK2))
599 if (!self.crylink_lastgroup || time > self.crylink_lastgroup.teleport_time)
601 // fired and released now!
602 if(self.crylink_lastgroup)
605 entity linkjoineffect;
606 float isprimary = (self.crylink_waitrelease == 1);
608 pos = W_Crylink_LinkJoin(self.crylink_lastgroup, WEP_CVAR_BOTH(crylink, isprimary, joinspread) * WEP_CVAR_BOTH(crylink, isprimary, speed), WEP_CVAR_BOTH(crylink, isprimary, jointime));
610 linkjoineffect = spawn();
611 linkjoineffect.think = W_Crylink_LinkJoinEffect_Think;
612 linkjoineffect.classname = "linkjoineffect";
613 linkjoineffect.nextthink = time + w_crylink_linkjoin_time;
614 linkjoineffect.owner = self;
615 setorigin(linkjoineffect, pos);
617 self.crylink_waitrelease = 0;
618 if(!w_crylink(WR_CHECKAMMO1) && !w_crylink(WR_CHECKAMMO2))
619 if not(self.items & IT_UNLIMITED_WEAPON_AMMO)
622 self.cnt = WEP_CRYLINK;
623 self.switchweapon = w_getbestweapon(self);
632 precache_model ("models/weapons/g_crylink.md3");
633 precache_model ("models/weapons/v_crylink.md3");
634 precache_model ("models/weapons/h_crylink.iqm");
635 precache_sound ("weapons/crylink_fire.wav");
636 precache_sound ("weapons/crylink_fire2.wav");
637 precache_sound ("weapons/crylink_linkjoin.wav");
638 WEP_SET_PROPS(CRYLINK_SETTINGS(crylink), WEP_CRYLINK)
643 self.current_ammo = ammo_cells;
648 // don't "run out of ammo" and switch weapons while waiting for release
649 if(self.crylink_lastgroup && self.crylink_waitrelease)
652 ammo_amount = self.ammo_cells >= autocvar_g_balance_crylink_primary_ammo;
653 ammo_amount += self.(weapon_load[WEP_CRYLINK]) >= autocvar_g_balance_crylink_primary_ammo;
658 // don't "run out of ammo" and switch weapons while waiting for release
659 if(self.crylink_lastgroup && self.crylink_waitrelease)
662 ammo_amount = self.ammo_cells >= autocvar_g_balance_crylink_secondary_ammo;
663 ammo_amount += self.(weapon_load[WEP_CRYLINK]) >= autocvar_g_balance_crylink_secondary_ammo;
668 WEP_CONFIG_SETTINGS(CRYLINK_SETTINGS(crylink))
673 W_Reload(min(autocvar_g_balance_crylink_primary_ammo, autocvar_g_balance_crylink_secondary_ammo), autocvar_g_balance_crylink_reload_ammo, autocvar_g_balance_crylink_reload_time, "weapons/reload.wav");
676 case WR_SUICIDEMESSAGE:
678 return WEAPON_CRYLINK_SUICIDE;
682 return WEAPON_CRYLINK_MURDER;
689 float w_crylink(float req)
693 case WR_IMPACTEFFECT:
696 org2 = w_org + w_backoff * 2;
697 if(w_deathtype & HITTYPE_SECONDARY)
699 pointparticles(particleeffectnum("crylink_impact"), org2, '0 0 0', 1);
701 sound(self, CH_SHOTS, "weapons/crylink_impact2.wav", VOL_BASE, ATTN_NORM);
705 pointparticles(particleeffectnum("crylink_impactbig"), org2, '0 0 0', 1);
707 sound(self, CH_SHOTS, "weapons/crylink_impact.wav", VOL_BASE, ATTN_NORM);
714 precache_sound("weapons/crylink_impact2.wav");
715 precache_sound("weapons/crylink_impact.wav");