11 error(
"W_Crylink_CheckLinks: entity is NULL");
12 if(e.classname !=
"spike" || wasfreed(e))
13 error(sprintf(
"W_Crylink_CheckLinks: entity is not a spike but a %s (freed: %d)", e.classname, wasfreed(e)));
16 for(i = 0; i < 1000; ++i)
18 if(p.queuenext.queueprev != p || p.queueprev.queuenext != p)
19 error(
"W_Crylink_CheckLinks: queue is inconsistent");
25 error(
"W_Crylink_CheckLinks: infinite chain");
31 .entity weaponentity = me.weaponentity_fld;
32 if(me == own.(weaponentity).crylink_lastgroup)
36 me.classname =
"spike_oktoremove";
66 a =
bound(0, 1 - (
time - e.fade_time) * e.fade_rate, 1);
68 .entity weaponentity = e.weaponentity_fld;
69 if(e == e.crylink_owner.(weaponentity).crylink_lastgroup)
74 RadiusDamage(e, e.realowner,
WEP_CVAR_BOTH(WEP_CRYLINK, isprimary, damage) * a,
WEP_CVAR_BOTH(WEP_CRYLINK, isprimary, edgedamage) * a,
WEP_CVAR_BOTH(WEP_CRYLINK, isprimary,
radius),
75 NULL,
NULL,
WEP_CVAR_BOTH(WEP_CRYLINK, isprimary, force) * a, e.projectiledeathtype, e.weaponentity_fld, directhitentity);
79 e.classname =
"spike_oktoremove";
92 vector avg_origin, avg_velocity;
102 avg_origin = e.origin;
103 avg_velocity = e.velocity;
105 for(p = e; (p = p.queuenext) != e; )
111 avg_origin *= (1.0 / n);
112 avg_velocity *= (1.0 / n);
118 avg_dist = (
vlen(e.origin - avg_origin) ** 2);
119 for(p = e; (p = p.queuenext) != e; )
121 avg_dist *= (1.0 / n);
122 avg_dist =
sqrt(avg_dist);
129 e.velocity = avg_velocity;
131 for(p = e; (p = p.queuenext) != e; )
136 targ_origin = avg_origin + 1000000000 *
normalize(avg_velocity);
145 for(p = e; (p = p.queuenext) != e; )
183 for(p = e; (p = p.queuenext) != e; )
198 WEP_CVAR_BOTH(WEP_CRYLINK, isprimary, joinexplode_damage) * n,
199 WEP_CVAR_BOTH(WEP_CRYLINK, isprimary, joinexplode_edgedamage) * n,
200 WEP_CVAR_BOTH(WEP_CRYLINK, isprimary, joinexplode_radius) * n,
203 WEP_CVAR_BOTH(WEP_CRYLINK, isprimary, joinexplode_force) * n,
204 e.projectiledeathtype,
218 float hit_friendly = 0;
225 if(
SAME_TEAM(head, projectile.realowner))
234 return (hit_enemy ?
false : hit_friendly);
252 f =
WEP_CVAR_BOTH(WEP_CRYLINK, isprimary, bouncedamagefactor);
256 float totaldamage =
RadiusDamage(
this, this.
realowner,
WEP_CVAR_BOTH(WEP_CRYLINK, isprimary, damage) * f,
WEP_CVAR_BOTH(WEP_CRYLINK, isprimary, edgedamage) * f,
WEP_CVAR_BOTH(WEP_CRYLINK, isprimary,
radius),
262 if(
this == this.
crylink_owner.(weaponentity).crylink_lastgroup)
291 float counter, shots;
292 entity proj, prevproj, firstproj;
294 vector forward, right, up;
302 maxdmg +=
WEP_CVAR_PRI(WEP_CRYLINK, joinexplode_damage);
311 proj = prevproj = firstproj =
NULL;
312 for(counter = 0; counter < shots; ++counter)
317 proj.realowner = proj.owner = actor;
318 proj.crylink_owner = actor;
319 proj.weaponentity_fld = weaponentity;
320 proj.bot_dodge =
true;
321 proj.bot_dodgerating =
WEP_CVAR_PRI(WEP_CRYLINK, damage);
323 proj.queuenext = proj;
324 proj.queueprev = proj;
326 else if(counter == 0) {
329 else if(counter == shots - 1) {
330 prevproj.queuenext = proj;
331 firstproj.queueprev = proj;
332 proj.queuenext = firstproj;
333 proj.queueprev = prevproj;
336 prevproj.queuenext = proj;
337 proj.queueprev = prevproj;
344 proj.projectiledeathtype = thiswep.
m_id;
348 setsize(proj,
'0 0 0',
'0 0 0');
359 proj.fade_rate = 1 /
WEP_CVAR_PRI(WEP_CRYLINK, middle_fadetime);
365 proj.fade_rate = 1 /
WEP_CVAR_PRI(WEP_CRYLINK, other_fadetime);
395 float counter, shots;
396 entity proj, prevproj, firstproj;
398 vector forward, right, up;
406 maxdmg +=
WEP_CVAR_SEC(WEP_CRYLINK, joinexplode_damage);
415 proj = prevproj = firstproj =
NULL;
416 for(counter = 0; counter < shots; ++counter)
420 proj.weaponentity_fld = weaponentity;
422 proj.realowner = proj.owner = actor;
423 proj.crylink_owner = actor;
424 proj.bot_dodge =
true;
425 proj.bot_dodgerating =
WEP_CVAR_SEC(WEP_CRYLINK, damage);
427 proj.queuenext = proj;
428 proj.queueprev = proj;
430 else if(counter == 0) {
433 else if(counter == shots - 1) {
434 prevproj.queuenext = proj;
435 firstproj.queueprev = proj;
436 proj.queuenext = firstproj;
437 proj.queueprev = prevproj;
440 prevproj.queuenext = proj;
441 proj.queueprev = prevproj;
452 setsize(proj,
'0 0 0',
'0 0 0');
468 if(counter == (shots - 1) / 2)
471 proj.fade_rate = 1 /
WEP_CVAR_SEC(WEP_CRYLINK, middle_fadetime);
477 proj.fade_rate = 1 /
WEP_CVAR_SEC(WEP_CRYLINK, other_fadetime);
515 if (autocvar_g_balance_crylink_reload_ammo
518 thiswep.wr_reload(thiswep, actor, weaponentity);
523 if(actor.(weaponentity).crylink_waitrelease != 1)
531 else if((fire & 2) && autocvar_g_balance_crylink_secondary)
533 if(actor.(weaponentity).crylink_waitrelease != 2)
541 if((actor.(weaponentity).crylink_waitrelease == 1 && !(fire & 1)) || (actor.(weaponentity).crylink_waitrelease == 2 && !(fire & 2)))
543 if(!actor.(weaponentity).crylink_lastgroup ||
time > actor.(weaponentity).crylink_lastgroup.teleport_time)
546 if(actor.(weaponentity).crylink_lastgroup)
550 float isprimary = (actor.(weaponentity).crylink_waitrelease == 1);
554 linkjoineffect =
new(linkjoineffect);
555 linkjoineffect.weaponentity_fld = weaponentity;
558 linkjoineffect.owner = actor;
559 setorigin(linkjoineffect, pos);
562 if(!thiswep.wr_checkammo1(thiswep, actor, weaponentity) && !thiswep.wr_checkammo2(thiswep, actor, weaponentity))
566 actor.cnt = thiswep.m_id;
576 if(actor.(weaponentity).crylink_lastgroup && actor.(weaponentity).crylink_waitrelease)
587 if(actor.(weaponentity).crylink_lastgroup && actor.(weaponentity).crylink_waitrelease)
602 return WEAPON_CRYLINK_SUICIDE;
607 return WEAPON_CRYLINK_MURDER;
638 PAR(_(
"The %s fires bursts of laser-like projectiles, spreading out as they travel away and deflecting off walls. "
639 "If the primary fire is held, when it's released the projectiles will converge before spreading out again, "
640 "which can be utilized to deal more damage to an enemy by making the projectiles converge on them."),
COLORED_NAME(
this));
641 PAR(_(
"Projectiles deal damage on collision but also when they bounce, so with good positioning they can sometimes deal double damage."));
642 PAR(_(
"The secondary fire shoots the projectiles together in a tight group, so it is often the better option in situations where the enemy is an easy target to hit."));
643 PAR(_(
"It consumes %s ammo for each projectile, which is shared by several weapons."),
COLORED_NAME(ITEM_Cells));
644 PAR(_(
"Close to medium range is the ideal time to use the %s, although the secondary fire can be useful for long range combat sometimes."),
COLORED_NAME(
this));
645 PAR(_(
"The %s deals knockback in a unique way, pulling the player from their center to the point of impact. "
646 "This makes it one of the best weapons to slow someone down if you are chasing them, particularly with the secondary fire. "
647 "Another common use of the %s is \"crylink running,\" where you partially angle down and use the secondary fire to pull yourself forwards, in order to gain speed."),
COLORED_NAME(
this),
COLORED_NAME(
this));
bool bot_aim(entity this,.entity weaponentity, float shotspeed, float shotspeedupward, float maxshottime, float applygravity, bool shot_accurate)
IntrusiveList g_bot_dodge
#define MUTATOR_CALLHOOK(id,...)
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
float GetResource(entity e, Resource res_type)
Returns the current amount of resource the given entity has.
fields which are explicitly/manually set are marked with "M", fields set automatically are marked wit...
#define COLORED_NAME(this)
const int IT_UNLIMITED_AMMO
#define PHYS_INPUT_BUTTON_ATCK(s)
#define PHYS_INPUT_BUTTON_ATCK2(s)
void W_Crylink_Reset(entity this)
void W_Crylink_Touch(entity this, entity toucher)
void W_Crylink_Dequeue_Raw(entity own, entity prev, entity me, entity next)
void W_Crylink_LinkExplode(entity e, entity e2, entity directhitentity)
void W_Crylink_DeleteLink(entity this)
void W_Crylink_Attack2(Weapon thiswep, entity actor,.entity weaponentity)
float w_crylink_linkjoin_time
float W_Crylink_Touch_WouldHitFriendly(entity projectile, float rad)
void W_Crylink_Attack(Weapon thiswep, entity actor,.entity weaponentity)
vector W_Crylink_LinkJoin(entity e, float jspeed)
void W_Crylink_CheckLinks(entity e)
void W_Crylink_LinkJoinEffect_Think(entity this)
void W_Crylink_Fadethink(entity this)
void W_Crylink_Dequeue(entity e)
float crylink_waitrelease
void UpdateCSQCProjectile(entity e)
void CSQCProjectile(entity e, float clientanimate, int type, float docull)
float RadiusDamage(entity inflictor, entity attacker, float coredamage, float edgedamage, float rad, entity cantbe, entity mustbe, float forceintensity, int deathtype,.entity weaponentity, entity directhitentity)
const float MAX_DAMAGEEXTRARADIUS
const int HITTYPE_SECONDARY
#define pointparticles(effect, org, vel, howmany)
void Send_Effect(entity eff, vector eff_loc, vector eff_vel, int eff_cnt)
ERASEABLE entity IL_PUSH(IntrusiveList this, entity it)
Push to tail.
vector WarpZone_RefSys_TransformVelocity(entity from, entity to, vector vel)
entity WarpZone_FindRadius(vector org, float rad, bool needlineofsight)
vector WarpZone_RefSys_TransformOrigin(entity from, entity to, vector org)
void set_movetype(entity this, int mt)
const int MOVETYPE_BOUNCEMISSILE
entity Notification
always last
#define METHOD(cname, name, prototype)
const int PROJECTILE_CRYLINK_BOUNCING
const int PROJECTILE_CRYLINK
#define w_getbestweapon(ent, wepent)
#define PROJECTILE_TOUCH(e, t)
IntrusiveList g_projectiles
#define PROJECTILE_MAKETRIGGER(e)
#define sound(e, c, s, v, a)
#define PAR(...)
Adds an individually translatable paragraph to PAGE_TEXT without having to deal with strcat and sprin...
var void delete_fn(entity e)
void W_SetupProjVelocity_Explicit(entity proj, vector dir, vector upDir, float pSpeed, float pUpSpeed, float pZSpeed, float spread, float forceAbsolute)
#define W_SetupShot(ent, wepent, antilag, recoil, snd, chan, maxdamage, deathtype)
string W_Guide_Keybinds(Weapon wep)
string W_Guide_DPS_bothMultishot(string name, string pri, string sec)
void W_MuzzleFlash(Weapon thiswep, entity actor,.entity weaponentity, vector shotorg, vector shotdir)
#define WEP_CVAR_PRI(wep, name)
#define WEP_CVAR_BOTH(wep, isprimary, name)
#define WEP_CVAR_SEC(wep, name)
void W_DecreaseAmmo(Weapon wep, entity actor, float ammo_use,.entity weaponentity)
void W_Reload(entity actor,.entity weaponentity, float sent_ammo_min, Sound sent_sound)
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)
void w_ready(Weapon thiswep, entity actor,.entity weaponentity, int fire)
float weapon_load[REGISTRY_MAX(Weapons)]