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)));
14 for (i = 0; i < 1000; ++i)
16 if (p.queuenext.queueprev != p || p.queueprev.queuenext != p)
17 error(
"W_Crylink_CheckLinks: queue is inconsistent");
23 error(
"W_Crylink_CheckLinks: infinite chain");
29 .entity weaponentity = me.weaponentity_fld;
30 if (me == own.(weaponentity).crylink_lastgroup)
34 me.classname =
"spike_oktoremove";
62 float a =
bound(0, 1 - (
time - e.fade_time) * e.fade_rate, 1);
64 .entity weaponentity = e.weaponentity_fld;
65 if (e == e.crylink_owner.(weaponentity).crylink_lastgroup)
76 e.projectiledeathtype,
83 e.classname =
"spike_oktoremove";
102 vector avg_org = e.origin;
103 vector avg_vel = e.velocity;
105 for (p = e; (p = p.queuenext) != e; )
118 float avg_dist =
vlen2(e.origin - avg_org);
119 for (p = e; (p = p.queuenext) != e; )
121 avg_dist =
sqrt(avg_dist * (1.0 / n));
129 e.velocity = avg_vel;
131 for (p = e; (p = p.queuenext) != e; )
136 targ_origin = avg_org + 1000000000 *
normalize(avg_vel);
145 for (p = e; (p = p.queuenext) != e; )
181 for (
entity p = e; (p = p.queuenext) != e; )
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),
197 n *
WEP_CVAR_BOTH(WEP_CRYLINK, is_primary, joinexplode_force),
198 e.projectiledeathtype,
217 bool hit_friendly =
false;
218 for (; head; head = head.chain)
220 if (
SAME_TEAM(head, projectile.realowner))
237 float f = (finalhit ? 1 :
WEP_CVAR_BOTH(WEP_CRYLINK, is_primary, bouncedamagefactor));
255 ||
WEP_CVAR_BOTH(WEP_CRYLINK, is_primary, linkexplode) == 2))
258 if (
this == this.
crylink_owner.(weaponentity).crylink_lastgroup)
292 maxdmg +=
WEP_CVAR_PRI(WEP_CRYLINK, joinexplode_damage);
302 for (
int counter = 0; counter < shots; ++counter)
308 proj.realowner = proj.owner = actor;
309 proj.crylink_owner = actor;
310 proj.weaponentity_fld = weaponentity;
311 proj.bot_dodge =
true;
312 proj.bot_dodgerating =
WEP_CVAR_PRI(WEP_CRYLINK, damage);
315 proj.queuenext = proj;
316 proj.queueprev = proj;
318 else if (counter == 0)
320 else if (counter == shots - 1)
322 prevproj.queuenext = proj;
323 firstproj.queueprev = proj;
324 proj.queuenext = firstproj;
325 proj.queueprev = prevproj;
329 prevproj.queuenext = proj;
330 proj.queueprev = prevproj;
337 proj.projectiledeathtype = thiswep.
m_id;
341 setsize(proj,
'0 0 0',
'0 0 0');
351 proj.fade_rate = 1 /
WEP_CVAR_PRI(WEP_CRYLINK, middle_fadetime);
357 proj.fade_rate = 1 /
WEP_CVAR_PRI(WEP_CRYLINK, other_fadetime);
392 maxdmg +=
WEP_CVAR_SEC(WEP_CRYLINK, joinexplode_damage);
402 for (
int counter = 0; counter < shots; ++counter)
407 proj.weaponentity_fld = weaponentity;
409 proj.realowner = proj.owner = actor;
410 proj.crylink_owner = actor;
411 proj.bot_dodge =
true;
412 proj.bot_dodgerating =
WEP_CVAR_SEC(WEP_CRYLINK, damage);
415 proj.queuenext = proj;
416 proj.queueprev = proj;
418 else if (counter == 0)
420 else if (counter == shots - 1)
422 prevproj.queuenext = proj;
423 firstproj.queueprev = proj;
424 proj.queuenext = firstproj;
425 proj.queueprev = prevproj;
429 prevproj.queuenext = proj;
430 proj.queueprev = prevproj;
441 setsize(proj,
'0 0 0',
'0 0 0');
454 if (counter == (shots - 1) * 0.5)
457 proj.fade_rate = 1 /
WEP_CVAR_SEC(WEP_CRYLINK, middle_fadetime);
463 proj.fade_rate = 1 /
WEP_CVAR_SEC(WEP_CRYLINK, other_fadetime);
501 if (autocvar_g_balance_crylink_reload_ammo
504 thiswep.wr_reload(thiswep, actor, weaponentity);
507 if (actor.(weaponentity).crylink_waitrelease != 1
514 else if ((fire & 2) && autocvar_g_balance_crylink_secondary)
516 if (actor.(weaponentity).crylink_waitrelease != 2
524 if ((actor.(weaponentity).crylink_waitrelease == 1 && !(fire & 1))
525 || (actor.(weaponentity).crylink_waitrelease == 2 && !(fire & 2)))
527 if (!actor.(weaponentity).crylink_lastgroup ||
time > actor.(weaponentity).crylink_lastgroup.teleport_time)
530 if (actor.(weaponentity).crylink_lastgroup)
532 bool is_primary = (actor.(weaponentity).crylink_waitrelease == 1);
535 entity linkjoineffect =
new(linkjoineffect);
536 linkjoineffect.weaponentity_fld = weaponentity;
539 linkjoineffect.owner = actor;
540 setorigin(linkjoineffect, pos);
543 if (!thiswep.wr_checkammo1(thiswep, actor, weaponentity) && !thiswep.wr_checkammo2(thiswep, actor, weaponentity)
547 actor.cnt = thiswep.m_id;
557 if (actor.(weaponentity).crylink_lastgroup && actor.(weaponentity).crylink_waitrelease)
568 if (actor.(weaponentity).crylink_lastgroup && actor.(weaponentity).crylink_waitrelease)
583 return WEAPON_CRYLINK_SUICIDE;
588 return WEAPON_CRYLINK_MURDER;
619 PAR(_(
"The %s fires bursts of laser-like projectiles, spreading out as they travel away and deflecting off walls. "
620 "If the primary fire is held, when it's released the projectiles will converge before spreading out again, "
621 "which can be utilized to deal more damage to an enemy by making the projectiles converge on them."),
COLORED_NAME(
this));
622 PAR(_(
"Projectiles deal damage on collision but also when they bounce, so with good positioning they can sometimes deal double damage."));
623 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."));
624 PAR(_(
"It consumes %s ammo for each projectile, which is shared by several weapons."),
COLORED_NAME(ITEM_Cells));
625 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));
626 PAR(_(
"The %s deals knockback in a unique way, pulling the player from their center to the point of impact. "
627 "This makes it one of the best weapons to slow someone down if you are chasing them, particularly with the secondary fire. "
628 "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)
bool W_Crylink_Touch_WouldHitFriendly(entity projectile, float rad)
void W_Crylink_DeleteLink(entity this)
void W_Crylink_Attack2(Weapon thiswep, entity actor,.entity weaponentity)
float w_crylink_linkjoin_time
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)
bool W_Crylink_Touch_WouldHitFriendly_cond(entity e)
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_BOUNCE
set manually after projectile has bounced
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.
entity WarpZone_SearchInRadius(vector org, float rad, float nomonsters, WarpZone_FindRadius_cond_callback_t cb)
Modified findradius aware of warpzones, that only includes entities that meet the "cb" criteria.
vector WarpZone_RefSys_TransformVelocity(entity from, entity to, vector vel)
Transform velocity vel in from's reference into to's reference.
vector WarpZone_RefSys_TransformOrigin(entity from, entity to, vector org)
Transform origin org in from's reference into to's reference.
void WarpZone_RefSys_Copy(entity me, entity from)
Copies the warpzone reference of from onto me.
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)]