7 const float MAX_SHOCKWAVE_HITS = 10;
11 .entity swing_alreadyhit;
12 .float shockwave_blasttime;
13 entity shockwave_hit[MAX_SHOCKWAVE_HITS];
14 float shockwave_hit_damage[MAX_SHOCKWAVE_HITS];
15 vector shockwave_hit_force[MAX_SHOCKWAVE_HITS];
18 void W_Shockwave_Melee_Think(
entity this)
21 float i, f, swing, swing_factor, swing_damage, meleetime, is_player;
44 swing =
bound(0, (this.
cnt + meleetime -
time) / meleetime, 10);
45 f = ((1 - swing) *
WEP_CVAR(shockwave, melee_traces));
48 for(i=this.swing_prev; i < f; ++i)
50 swing_factor = ((1 - (i /
WEP_CVAR(shockwave, melee_traces))) * 2 - 1);
54 + (
v_up * swing_factor *
WEP_CVAR(shockwave, melee_swing_up))
59 (this.
realowner.origin +
this.realowner.view_ofs),
67 #ifdef DEBUG_SHOCKWAVE 69 te_customflash(targpos, 40, 2,
'1 1 1');
77 && (is_player ||
WEP_CVAR(shockwave, melee_nonplayerdamage)))
82 swing_damage = (
WEP_CVAR(shockwave, melee_damage) *
min(1, swing_factor + 1));
84 swing_damage = (
WEP_CVAR(shockwave, melee_nonplayerdamage) *
min(1, swing_factor + 1));
93 this.weaponentity_fld,
94 (
this.realowner.origin +
this.realowner.view_ofs),
102 #ifdef DEBUG_SHOCKWAVE 104 "MELEE: %s hitting %s with %f damage (factor: %f) at %f time.",
106 target_victim.netname,
114 if(
WEP_CVAR(shockwave, melee_multihit))
116 this.swing_alreadyhit = target_victim;
127 if(
time >= this.
cnt + meleetime)
147 meleetemp.owner = meleetemp.realowner = actor;
148 setthink(meleetemp, W_Shockwave_Melee_Think);
150 meleetemp.weaponentity_fld = weaponentity;
151 W_SetupShot_Range(actor, weaponentity,
true, 0, SND_Null, 0,
WEP_CVAR(shockwave, melee_damage),
WEP_CVAR(shockwave, melee_range), thiswep.
m_id |
HITTYPE_SECONDARY);
155 float W_Shockwave_Attack_CheckSpread(
162 float distance_of_attack =
vlen(sw_shotorg - attack_endpos);
163 float distance_from_line =
vlen(targetorg - nearest_on_line);
165 spreadlimit = (distance_of_attack ?
min(1, (
vlen(sw_shotorg - nearest_on_line) / distance_of_attack)) : 1);
168 (
WEP_CVAR(shockwave, blast_spread_min) * (1 - spreadlimit))
170 (
WEP_CVAR(shockwave, blast_spread_max) * spreadlimit)
174 (spreadlimit && (distance_from_line <= spreadlimit))
178 {
return bound(0, (distance_from_line / spreadlimit), 1); }
183 float W_Shockwave_Attack_IsVisible(
190 vector nearest_to_attacker = head.WarpZone_findradius_nearest;
191 vector center = (head.origin + (head.mins + head.maxs) * 0.5);
196 if(W_Shockwave_Attack_CheckSpread(nearest_to_attacker, nearest_on_line, sw_shotorg, attack_endpos))
203 if(W_Shockwave_Attack_CheckSpread(center, nearest_on_line, sw_shotorg, attack_endpos))
212 corner = get_corner_position(head, i);
213 if(W_Shockwave_Attack_CheckSpread(corner, nearest_on_line, sw_shotorg, attack_endpos))
223 float W_Shockwave_Attack_CheckHit(
229 if(!head) {
return false; }
232 for(i = 0; i <= queue; ++i)
234 if(shockwave_hit[i] == head)
236 if(
vlen2(final_force) >
vlen2(shockwave_hit_force[i])) { shockwave_hit_force[i] = final_force; }
237 if(final_damage > shockwave_hit_damage[i]) { shockwave_hit_damage[i] = final_damage; }
242 shockwave_hit[queue] = head;
243 shockwave_hit_force[queue] = final_force;
244 shockwave_hit_damage[queue] = final_damage;
248 void W_Shockwave_Send(
entity actor)
262 float multiplier, multiplier_from_accuracy, multiplier_from_distance;
264 vector final_force, center, vel;
279 W_Shockwave_Send(actor);
282 WEP_CVAR(shockwave, blast_splash_damage),
283 WEP_CVAR(shockwave, blast_splash_edgedamage),
284 WEP_CVAR(shockwave, blast_splash_radius),
295 WEP_CVAR(shockwave, blast_splash_radius),
296 WEP_CVAR(shockwave, blast_jump_radius)
302 bool noantilag = ((
IS_CLIENT(actor)) ?
CS_CVAR(actor).cvar_cl_noantilag :
false);
314 float distance_to_head =
vlen(attack_hitpos - head.WarpZone_findradius_nearest);
316 if((head == actor) && (distance_to_head <=
WEP_CVAR(shockwave, blast_jump_radius)))
323 multiplier_from_accuracy = (1 -
325 min(1, (distance_to_head /
WEP_CVAR(shockwave, blast_jump_radius)))
330 multiplier_from_distance = (1 -
332 min(1, (distance_to_hit / distance_to_end))
339 WEP_CVAR(shockwave, blast_jump_multiplier_min),
341 (multiplier_from_accuracy *
WEP_CVAR(shockwave, blast_jump_multiplier_accuracy))
343 (multiplier_from_distance *
WEP_CVAR(shockwave, blast_jump_multiplier_distance))
350 (
WEP_CVAR(shockwave, blast_jump_damage) * multiplier)
352 (
WEP_CVAR(shockwave, blast_jump_edgedamage) * (1 - multiplier))
359 bound(0, (
vlen(vel) / autocvar_sv_maxspeed), 1)
361 WEP_CVAR(shockwave, blast_jump_force_velocitybias)
366 final_force *= (
WEP_CVAR(shockwave, blast_jump_force) * multiplier);
367 final_force.z *=
WEP_CVAR(shockwave, blast_jump_force_zscale);
381 #ifdef DEBUG_SHOCKWAVE 383 "SELF HIT: multiplier = %f, damage = %f, force = %f... " 384 "multiplier_from_accuracy = %f, multiplier_from_distance = %f.",
388 multiplier_from_accuracy,
389 multiplier_from_distance
393 else if(distance_to_head <=
WEP_CVAR(shockwave, blast_splash_radius))
400 multiplier_from_accuracy = (1 -
402 min(1, (distance_to_head /
WEP_CVAR(shockwave, blast_splash_radius)))
407 multiplier_from_distance = (1 -
409 min(1, (distance_to_hit / distance_to_end))
416 WEP_CVAR(shockwave, blast_splash_multiplier_min),
418 (multiplier_from_accuracy *
WEP_CVAR(shockwave, blast_splash_multiplier_accuracy))
420 (multiplier_from_distance *
WEP_CVAR(shockwave, blast_splash_multiplier_distance))
427 (
WEP_CVAR(shockwave, blast_splash_damage) * multiplier)
429 (
WEP_CVAR(shockwave, blast_splash_edgedamage) * (1 - multiplier))
438 final_force *= (
WEP_CVAR(shockwave, blast_splash_force) * multiplier);
439 final_force.z *=
WEP_CVAR(shockwave, blast_force_zscale);
442 if(W_Shockwave_Attack_CheckHit(queue, head, final_force, final_damage)) { queue =
min(queue + 1, MAX_SHOCKWAVE_HITS); }
444 #ifdef DEBUG_SHOCKWAVE 446 "SPLASH HIT: multiplier = %f, damage = %f, force = %f... " 447 "multiplier_from_accuracy = %f, multiplier_from_distance = %f.",
451 multiplier_from_accuracy,
452 multiplier_from_distance
464 if((head != actor) && head.takedamage)
477 h =
vlen(center - actor.origin);
484 if((
vdist(head.WarpZone_findradius_dist, <=,
WEP_CVAR(shockwave, blast_distance)))
485 && (W_Shockwave_Attack_IsVisible(actor, head, nearest_on_line,
w_shotorg, attack_endpos)))
488 multiplier_from_accuracy = (1 -
489 W_Shockwave_Attack_CheckSpread(
496 multiplier_from_distance = (1 -
498 min(1, (
vlen(head.WarpZone_findradius_dist) / distance_to_end))
505 WEP_CVAR(shockwave, blast_multiplier_min),
507 (multiplier_from_accuracy *
WEP_CVAR(shockwave, blast_multiplier_accuracy))
509 (multiplier_from_distance *
WEP_CVAR(shockwave, blast_multiplier_distance))
516 (
WEP_CVAR(shockwave, blast_damage) * multiplier)
518 (
WEP_CVAR(shockwave, blast_edgedamage) * (1 - multiplier))
523 final_force =
normalize(center - (nearest_on_line - final_force));
527 final_force *= (
WEP_CVAR(shockwave, blast_force) * multiplier);
528 final_force.z *=
WEP_CVAR(shockwave, blast_force_zscale);
531 if(W_Shockwave_Attack_CheckHit(queue, head, final_force, final_damage)) { queue =
min(queue + 1, MAX_SHOCKWAVE_HITS); }
533 #ifdef DEBUG_SHOCKWAVE 535 "BLAST HIT: multiplier = %f, damage = %f, force = %f... " 536 "multiplier_from_accuracy = %f, multiplier_from_distance = %f.",
540 multiplier_from_accuracy,
541 multiplier_from_distance
549 for(i = 1; i <= queue; ++i)
551 head = shockwave_hit[i-1];
552 final_force = shockwave_hit_force[i-1];
553 final_damage = shockwave_hit_damage[i-1];
569 #ifdef DEBUG_SHOCKWAVE 571 "SHOCKWAVE by %s: damage = %f, force = %f.",
578 shockwave_hit[i-1] =
NULL;
579 shockwave_hit_force[i-1] =
'0 0 0';
580 shockwave_hit_damage[i-1] = 0;
589 if(
vdist(actor.origin - actor.enemy.origin, <=,
WEP_CVAR(shockwave, melee_range)))
598 if(
time >= actor.(weaponentity).shockwave_blasttime)
602 W_Shockwave_Attack(thiswep, actor, weaponentity);
614 weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, 0, W_Shockwave_Melee);
629 return WEAPON_THINKING_WITH_PORTALS;
634 return WEAPON_SHOCKWAVE_MURDER_SLAP;
636 return WEAPON_SHOCKWAVE_MURDER;
642 const float SW_MAXALPHA = 0.5;
643 const float SW_FADETIME = 0.4;
644 const float SW_DISTTOMIN = 200;
645 void Draw_Shockwave(
entity this)
648 float a =
bound(0, (SW_MAXALPHA - ((
time - this.sw_time) / SW_FADETIME)), SW_MAXALPHA);
655 vector endpos = (this.sw_shotorg + (this.sw_shotdir * this.sw_distance));
657 vector _forward, right, up;
658 VECTOR_VECTORS(this.sw_shotdir, _forward, right, up);
661 vector min_end = ((this.sw_shotorg + (this.sw_shotdir * SW_DISTTOMIN)) + (up * this.sw_spread_min));
662 vector max_end = (endpos + (up * this.sw_spread_max));
663 float spread_to_min =
vlen(
normalize(min_end - this.sw_shotorg) - this.sw_shotdir);
664 float spread_to_max =
vlen(
normalize(max_end - min_end) - this.sw_shotdir);
666 vector first_min_end =
'0 0 0', prev_min_end =
'0 0 0', new_min_end =
'0 0 0';
667 vector first_max_end =
'0 0 0', prev_max_end =
'0 0 0', new_max_end =
'0 0 0';
668 float new_max_dist, new_min_dist;
670 vector deviation, angle =
'0 0 0';
671 float counter, divisions = 20;
672 for(counter = 0; counter < divisions; ++counter)
675 makevectors(
'0 360 0' * (0.75 + (counter - 0.5) / divisions));
680 deviation = angle * spread_to_min;
681 deviation = ((this.sw_shotdir + (right * deviation.y) + (up * deviation.z)));
682 new_min_dist = SW_DISTTOMIN;
683 new_min_end = (this.sw_shotorg + (deviation * new_min_dist));
687 deviation = angle * spread_to_max;
688 deviation = ((this.sw_shotdir + (right * deviation.y) + (up * deviation.z)));
689 new_max_dist =
vlen(new_min_end - endpos);
690 new_max_end = (new_min_end + (deviation * new_max_dist));
696 first_min_end = new_min_end;
697 first_max_end = new_max_end;
704 R_PolygonVertex(prev_min_end,
'0 0 0', sw_color, a);
705 R_PolygonVertex(new_min_end,
'0 0 0', sw_color, a);
706 R_PolygonVertex(this.sw_shotorg,
'0 0 0', sw_color, a);
711 R_PolygonVertex(new_min_end,
'0 0 0', sw_color, a);
712 R_PolygonVertex(prev_min_end,
'0 0 0', sw_color, a);
713 R_PolygonVertex(prev_max_end,
'0 0 0', sw_color, a);
714 R_PolygonVertex(new_max_end,
'0 0 0', sw_color, a);
718 prev_min_end = new_min_end;
719 prev_max_end = new_max_end;
722 if((counter + 1) == divisions)
726 R_PolygonVertex(prev_min_end,
'0 0 0', sw_color, a);
727 R_PolygonVertex(first_min_end,
'0 0 0', sw_color, a);
728 R_PolygonVertex(this.sw_shotorg,
'0 0 0', sw_color, a);
733 R_PolygonVertex(first_min_end,
'0 0 0', sw_color, a);
734 R_PolygonVertex(prev_min_end,
'0 0 0', sw_color, a);
735 R_PolygonVertex(prev_max_end,
'0 0 0', sw_color, a);
736 R_PolygonVertex(first_max_end,
'0 0 0', sw_color, a);
742 NET_HANDLE(TE_CSQC_SHOCKWAVEPARTICLE,
bool isNew)
744 Net_ReadShockwaveParticle();
748 void Net_ReadShockwaveParticle()
750 entity shockwave =
new(shockwave_cone);
751 shockwave.draw = Draw_Shockwave;
754 shockwave.sw_shotorg = ReadVector();
755 shockwave.sw_shotdir = ReadVector();
757 shockwave.sw_distance = ReadShort();
758 shockwave.sw_spread_max = ReadByte();
759 shockwave.sw_spread_min = ReadByte();
761 shockwave.sv_entnum = ReadByte();
763 shockwave.sw_time =
time;
#define PHYS_INPUT_BUTTON_ATCK2(s)
bool bot_aim(entity this,.entity weaponentity, float shotspeed, float shotspeedupward, float maxshottime, float applygravity)
const float ALPHA_MIN_VISIBLE
vector WarpZoneLib_NearestPointOnBox(vector mi, vector ma, vector org)
#define W_SetupShot_Range(ent, wepent, antilag, recoil, snd, chan, maxdamage, range, deathtype)
void w_ready(Weapon thiswep, entity actor,.entity weaponentity, int fire)
#define NET_HANDLE(id, param)
#define WEP_CVAR(wepname, name)
#define METHOD(cname, name, prototype)
#define IS_REAL_CLIENT(v)
void WarpZone_traceline_antilag(entity source, vector v1, vector v2, float nomonst, entity forent, float lag)
void antilag_restore_all(entity ignore)
const float MOVE_NOMONSTERS
void W_PlayStrengthSound(entity player)
ERASEABLE entity IL_PUSH(IntrusiveList this, entity it)
Push to tail.
bool weapon_prepareattack(Weapon thiswep, entity actor,.entity weaponentity, bool secondary, float attacktime)
const float DRAWFLAG_NORMAL
#define PHYS_INPUT_BUTTON_ATCK(s)
void Damage(entity targ, entity inflictor, entity attacker, float damage, int deathtype,.entity weaponentity, vector hitloc, vector force)
const int HITTYPE_SECONDARY
#define W_SetupShot(ent, wepent, antilag, recoil, snd, chan, maxdamage, deathtype)
entity WarpZone_FindRadius(vector org, float rad, bool needlineofsight)
#define CENTER_OR_VIEWOFS(ent)
vector(float skel, float bonenum) _skel_get_boneabs_hidden
#define vdist(v, cmp, f)
Vector distance comparison, avoids sqrt()
void accuracy_add(entity this, Weapon w, float fired, float hit)
void WarpZone_TraceLine(vector org, vector end, float nomonsters, entity forent)
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)
bool accuracy_isgooddamage(entity attacker, entity targ)
void Damage_DamageInfo(vector org, float coredamage, float edgedamage, float rad, vector force, int deathtype, float bloodtype, entity dmgowner)
#define new_pure(class)
purely logical entities (.origin doesn't work)
#define ANTILAG_LATENCY(e)
#define REGISTER_NET_TEMP(id)
#define sound(e, c, s, v, a)
fields which are explicitly/manually set are marked with "M", fields set automatically are marked wit...
void antilag_takeback_all(entity ignore, float lag)
float W_WeaponRateFactor(entity this)
IntrusiveList g_drawables