5 void W_Crylink_CheckLinks(
entity e)
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");
30 W_Crylink_CheckLinks(next);
31 .entity weaponentity = me.weaponentity_fld;
32 if(me == own.(weaponentity).crylink_lastgroup)
33 own.(weaponentity).crylink_lastgroup = ((me ==
next) ?
NULL :
next);
35 next.queueprev =
prev;
36 me.classname =
"spike_oktoremove";
38 W_Crylink_CheckLinks(next);
41 void W_Crylink_Dequeue(
entity e)
43 W_Crylink_Dequeue_Raw(e.crylink_owner, e.queueprev, e, e.queuenext);
46 void W_Crylink_DeleteLink(
entity this)
49 W_Crylink_Dequeue(
this);
53 void W_Crylink_Reset(
entity this)
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)
70 e.crylink_owner.(weaponentity).crylink_lastgroup =
NULL;
74 RadiusDamage(e, e.realowner,
WEP_CVAR_BOTH(crylink, isprimary, damage) * a,
WEP_CVAR_BOTH(crylink, isprimary, edgedamage) * a,
WEP_CVAR_BOTH(crylink, isprimary,
radius),
75 NULL,
NULL,
WEP_CVAR_BOTH(crylink, isprimary, force) * a, e.projectiledeathtype, e.weaponentity_fld, directhitentity);
77 W_Crylink_LinkExplode(e.queuenext, e2, directhitentity);
79 e.classname =
"spike_oktoremove";
89 float w_crylink_linkjoin_time;
92 vector avg_origin, avg_velocity;
98 W_Crylink_CheckLinks(e);
100 w_crylink_linkjoin_time = 0;
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);
140 w_crylink_linkjoin_time = avg_dist / jspeed;
141 targ_origin = avg_origin + w_crylink_linkjoin_time * avg_velocity;
143 e.velocity = (targ_origin - e.origin) * (1.0 / w_crylink_linkjoin_time);
145 for(p = e; (p = p.queuenext) != e; )
166 W_Crylink_CheckLinks(e);
171 void W_Crylink_LinkJoinEffect_Think(
entity this)
177 e = this.
owner.(weaponentity).crylink_lastgroup;
183 for(p = e; (p = p.queuenext) != e; )
199 WEP_CVAR_BOTH(crylink, isprimary, joinexplode_edgedamage) * n,
204 e.projectiledeathtype,
208 Send_Effect(EFFECT_CRYLINK_JOINEXPLODE, this.
origin,
'0 0 0', n);
215 float W_Crylink_Touch_WouldHitFriendly(
entity projectile,
float rad)
218 float hit_friendly = 0;
225 if(
SAME_TEAM(head, projectile.realowner))
234 return (hit_enemy ?
false : hit_friendly);
248 finalhit = ((this.
cnt <= 0) || (toucher.takedamage !=
DAMAGE_NO));
256 float totaldamage =
RadiusDamage(
this, this.
realowner,
WEP_CVAR_BOTH(crylink, isprimary, damage) * f,
WEP_CVAR_BOTH(crylink, isprimary, edgedamage) * f,
WEP_CVAR_BOTH(crylink, isprimary,
radius),
262 if(
this == this.crylink_owner.(weaponentity).crylink_lastgroup)
263 this.crylink_owner.(weaponentity).crylink_lastgroup =
NULL;
264 W_Crylink_LinkExplode(this.queuenext,
this, toucher);
284 void W_Crylink_Fadethink(
entity this)
291 float counter, shots;
292 entity proj, prevproj, firstproj;
294 vector forward, right, up;
311 proj = prevproj = firstproj =
NULL;
312 for(counter = 0; counter < shots; ++counter)
315 proj.dtor = W_Crylink_DeleteLink;
316 proj.reset = W_Crylink_Reset;
317 proj.realowner = proj.owner = actor;
318 proj.crylink_owner = actor;
319 proj.weaponentity_fld = weaponentity;
320 proj.bot_dodge =
true;
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');
356 makevectors(
'0 360 0' * (0.75 + (counter - 0.5) / (shots - 1)));
362 settouch(proj, W_Crylink_Touch);
364 setthink(proj, W_Crylink_Fadethink);
368 proj.fade_rate = 1 /
WEP_CVAR_PRI(crylink, middle_fadetime);
374 proj.fade_rate = 1 /
WEP_CVAR_PRI(crylink, other_fadetime);
385 proj.flags = FL_PROJECTILE;
396 actor.(weaponentity).crylink_lastgroup = proj;
397 W_Crylink_CheckLinks(proj);
398 actor.(weaponentity).crylink_waitrelease = 1;
404 float counter, shots;
405 entity proj, prevproj, firstproj;
407 vector forward, right, up;
424 proj = prevproj = firstproj =
NULL;
425 for(counter = 0; counter < shots; ++counter)
428 proj.dtor = W_Crylink_DeleteLink;
429 proj.weaponentity_fld = weaponentity;
430 proj.reset = W_Crylink_Reset;
431 proj.realowner = proj.owner = actor;
432 proj.crylink_owner = actor;
433 proj.bot_dodge =
true;
436 proj.queuenext = proj;
437 proj.queueprev = proj;
439 else if(counter == 0) {
442 else if(counter == shots - 1) {
443 prevproj.queuenext = proj;
444 firstproj.queueprev = proj;
445 proj.queuenext = firstproj;
446 proj.queueprev = prevproj;
449 prevproj.queuenext = proj;
450 proj.queueprev = prevproj;
461 setsize(proj,
'0 0 0',
'0 0 0');
470 makevectors(
'0 360 0' * (0.75 + (counter - 0.5) / (shots - 1)));
483 settouch(proj, W_Crylink_Touch);
484 setthink(proj, W_Crylink_Fadethink);
485 if(counter == (shots - 1) / 2)
488 proj.fade_rate = 1 /
WEP_CVAR_SEC(crylink, middle_fadetime);
494 proj.fade_rate = 1 /
WEP_CVAR_SEC(crylink, other_fadetime);
505 proj.flags = FL_PROJECTILE;
516 actor.(weaponentity).crylink_lastgroup = proj;
517 W_Crylink_CheckLinks(proj);
518 actor.(weaponentity).crylink_waitrelease = 2;
532 thiswep.wr_reload(thiswep, actor, weaponentity);
537 if(actor.(weaponentity).crylink_waitrelease != 1)
540 W_Crylink_Attack(thiswep, actor, weaponentity);
545 if((fire & 2) && autocvar_g_balance_crylink_secondary)
547 if(actor.(weaponentity).crylink_waitrelease != 2)
550 W_Crylink_Attack2(thiswep, actor, weaponentity);
555 if((actor.(weaponentity).crylink_waitrelease == 1 && !(fire & 1)) || (actor.(weaponentity).crylink_waitrelease == 2 && !(fire & 2)))
557 if(!actor.(weaponentity).crylink_lastgroup ||
time > actor.(weaponentity).crylink_lastgroup.teleport_time)
560 if(actor.(weaponentity).crylink_lastgroup)
564 float isprimary = (actor.(weaponentity).crylink_waitrelease == 1);
566 pos = W_Crylink_LinkJoin(actor.(weaponentity).crylink_lastgroup,
WEP_CVAR_BOTH(crylink, isprimary, joinspread) *
WEP_CVAR_BOTH(crylink, isprimary,
speed));
568 linkjoineffect =
new(linkjoineffect);
569 linkjoineffect.weaponentity_fld = weaponentity;
570 setthink(linkjoineffect, W_Crylink_LinkJoinEffect_Think);
571 linkjoineffect.nextthink =
time + w_crylink_linkjoin_time;
572 linkjoineffect.owner = actor;
575 actor.(weaponentity).crylink_waitrelease = 0;
576 if(!thiswep.wr_checkammo1(thiswep, actor, weaponentity) && !thiswep.wr_checkammo2(thiswep, actor, weaponentity))
577 if(!(actor.items & IT_UNLIMITED_AMMO))
580 actor.cnt = thiswep.m_id;
581 actor.(weaponentity).m_switchweapon =
w_getbestweapon(actor, weaponentity);
589 if(actor.(weaponentity).crylink_lastgroup && actor.(weaponentity).crylink_waitrelease)
599 if(actor.(weaponentity).crylink_lastgroup && actor.(weaponentity).crylink_waitrelease)
612 return WEAPON_CRYLINK_SUICIDE;
616 return WEAPON_CRYLINK_MURDER;
623 org2 = w_org + w_backoff * 2;
#define WEP_CVAR_PRI(wepname, name)
#define PHYS_INPUT_BUTTON_ATCK2(s)
bool bot_aim(entity this,.entity weaponentity, float shotspeed, float shotspeedupward, float maxshottime, float applygravity)
#define WEP_CVAR_SEC(wepname, name)
float weapon_load[REGISTRY_MAX(Weapons)]
const int PROJECTILE_CRYLINK
#define PROJECTILE_MAKETRIGGER(e)
#define w_getbestweapon(ent, wepent)
float MOVETYPE_BOUNCEMISSILE
void w_ready(Weapon thiswep, entity actor,.entity weaponentity, int fire)
var void delete_fn(entity e)
#define METHOD(cname, name, prototype)
void CSQCProjectile(entity e, float clientanimate, int type, float docull)
vector WarpZone_RefSys_TransformVelocity(entity from, entity to, vector vel)
const int PROJECTILE_CRYLINK_BOUNCING
IntrusiveList g_bot_dodge
#define PROJECTILE_TOUCH(e, t)
vector WarpZone_RefSys_TransformOrigin(entity from, entity to, vector org)
void W_SetupProjVelocity_Explicit(entity proj, vector dir, vector upDir, float pSpeed, float pUpSpeed, float pZSpeed, float spread, float forceAbsolute)
ERASEABLE entity IL_PUSH(IntrusiveList this, entity it)
Push to tail.
void UpdateCSQCProjectile(entity e)
bool weapon_prepareattack(Weapon thiswep, entity actor,.entity weaponentity, bool secondary, float attacktime)
#define WEP_CVAR_BOTH(wepname, isprimary, name)
#define PHYS_INPUT_BUTTON_ATCK(s)
const int HITTYPE_SECONDARY
#define W_SetupShot(ent, wepent, antilag, recoil, snd, chan, maxdamage, deathtype)
entity WarpZone_FindRadius(vector org, float rad, bool needlineofsight)
vector(float skel, float bonenum) _skel_get_boneabs_hidden
float autocvar_g_weaponspreadfactor
IntrusiveList g_projectiles
float GetResource(entity e, Resource res_type)
Returns the current amount of resource the given entity has.
entity Notification
always last
void weapon_thinkf(entity actor,.entity weaponentity, WFRAME fr, float t, void(Weapon thiswep, entity actor,.entity weaponentity, int fire) func)
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
#define MUTATOR_CALLHOOK(id,...)
void W_DecreaseAmmo(Weapon wep, entity actor, float ammo_use,.entity weaponentity)
#define sound(e, c, s, v, a)
fields which are explicitly/manually set are marked with "M", fields set automatically are marked wit...
void set_movetype(entity this, int mt)
void W_Reload(entity actor,.entity weaponentity, float sent_ammo_min, Sound sent_sound)