X-Git-Url: http://git.xonotic.org/?p=xonotic%2Fxonotic-data.pk3dir.git;a=blobdiff_plain;f=qcsrc%2Fserver%2Fweapons%2Ftracing.qc;h=ef1b6bd68d81880e15f018ec4217e4f3fe81b7d4;hp=99fa2df749eb9215c09789e86ec24bfd22d6fad5;hb=59d3684c3ce95d95c6d3f14e6fc5567a2e6ff2ba;hpb=8f381c9ba44ba9902f385949f99b4a106cb512c8 diff --git a/qcsrc/server/weapons/tracing.qc b/qcsrc/server/weapons/tracing.qc index 99fa2df74..ef1b6bd68 100644 --- a/qcsrc/server/weapons/tracing.qc +++ b/qcsrc/server/weapons/tracing.qc @@ -51,14 +51,14 @@ void W_SetupShot_Dir_ProjectileSize_Range(entity ent, .entity weaponentity, vect WarpZone_TraceLine(ent.origin + ent.view_ofs, ent.origin + ent.view_ofs + s_forward * range, MOVE_NOMONSTERS, ent); ent.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_CORPSE; - vector vf, vr, vu; - vf = v_forward; - vr = v_right; - vu = v_up; + vector forward, right, up; + forward = v_forward; + right = v_right; + up = v_up; w_shotend = WarpZone_UnTransformOrigin(WarpZone_trace_transform, trace_endpos); // warpzone support - v_forward = vf; - v_right = vr; - v_up = vu; + v_forward = forward; + v_right = right; + v_up = up; // un-adjust trueaim if shotend is too close if(vdist(w_shotend - (ent.origin + ent.view_ofs), <, autocvar_g_trueaim_minrange)) @@ -69,27 +69,27 @@ void W_SetupShot_Dir_ProjectileSize_Range(entity ent, .entity weaponentity, vect accuracy_add(ent, wep, maxdamage, 0); if(IS_PLAYER(ent)) - W_HitPlotAnalysis(ent, wep, v_forward, v_right, v_up); + W_HitPlotAnalysis(ent, wep, forward, right, up); vector md = ent.(weaponentity).movedir; vector vecs = ((md.x > 0) ? md : '0 0 0'); // TODO this is broken - see 637056bea7bf7f5c9c0fc6113e94731a2767476 for an attempted fix // which fixes issue #1957 but causes #2129 - vector dv = v_right * -vecs.y + v_up * vecs.z; + vector dv = right * -vecs.y + up * vecs.z; w_shotorg = ent.origin + ent.view_ofs + dv; // now move the shotorg forward as much as requested if possible if(antilag) { if(CS(ent).antilag_debug) - tracebox_antilag(ent, w_shotorg, mi, ma, w_shotorg + v_forward * (vecs.x + nudge), MOVE_NORMAL, ent, CS(ent).antilag_debug); + tracebox_antilag(ent, w_shotorg, mi, ma, w_shotorg + forward * (vecs.x + nudge), MOVE_NORMAL, ent, CS(ent).antilag_debug); else - tracebox_antilag(ent, w_shotorg, mi, ma, w_shotorg + v_forward * (vecs.x + nudge), MOVE_NORMAL, ent, ANTILAG_LATENCY(ent)); + tracebox_antilag(ent, w_shotorg, mi, ma, w_shotorg + forward * (vecs.x + nudge), MOVE_NORMAL, ent, ANTILAG_LATENCY(ent)); } else - tracebox(w_shotorg, mi, ma, w_shotorg + v_forward * (vecs.x + nudge), MOVE_NORMAL, ent); - w_shotorg = trace_endpos - v_forward * nudge; + tracebox(w_shotorg, mi, ma, w_shotorg + forward * (vecs.x + nudge), MOVE_NORMAL, ent); + w_shotorg = trace_endpos - forward * nudge; // calculate the shotdir from the chosen shotorg if(W_DualWielding(ent)) w_shotdir = s_forward; @@ -211,7 +211,18 @@ void W_SetupProjVelocity_Explicit(entity proj, vector dir, vector upDir, float p // Ballistics Tracing // ==================== -void FireRailgunBullet (entity this, .entity weaponentity, vector start, vector end, float bdamage, float bforce, float mindist, float maxdist, float halflifedist, float forcehalflifedist, int deathtype) +bool Headshot(entity targ, entity ent, vector start, vector end) +{ + if(!IS_PLAYER(targ) || IS_DEAD(targ) || STAT(FROZEN, targ) || !targ.takedamage) + return false; + vector org = targ.origin; // antilag is already taken into consideration //antilag_takebackorigin(targ, CS(targ), time - ANTILAG_LATENCY(ent)); + vector headmins = org + '0.6 0 0' * targ.mins_x + '0 0.6 0' * targ.mins_y + '0 0 1' * (1.3 * targ.view_ofs_z - 0.3 * targ.maxs_z); + vector headmaxs = org + '0.6 0 0' * targ.maxs_x + '0 0.6 0' * targ.maxs_y + '0 0 1' * targ.maxs_z; + + return trace_hits_box(start, end, headmins, headmaxs); +} + +void FireRailgunBullet (entity this, .entity weaponentity, vector start, vector end, float bdamage, bool headshot_notify, float bforce, float mindist, float maxdist, float halflifedist, float forcehalflifedist, int deathtype) { vector dir = normalize(end - start); vector force = dir * bforce; @@ -220,6 +231,7 @@ void FireRailgunBullet (entity this, .entity weaponentity, vector start, vector end = end + dir; float totaldmg = 0; + bool headshot = false; // indicates that one of the targets hit was a headshot // trace multiple times until we hit a wall, each obstacle will be made // non-solid so we can hit the next, while doing this we spawn effects and @@ -244,6 +256,9 @@ void FireRailgunBullet (entity this, .entity weaponentity, vector start, vector if (trace_ent == NULL || trace_fraction == 1) break; + if(headshot_notify && !headshot && Headshot(trace_ent, this, start, end)) + headshot = true; + // make the entity non-solid so we can hit the next one IL_PUSH(g_railgunhit, trace_ent); trace_ent.railgunhit = true; @@ -285,7 +300,7 @@ void FireRailgunBullet (entity this, .entity weaponentity, vector start, vector msg_entity = it; // we want this to be very loud when close but fall off quickly -> using max base volume and high attenuation - soundtoat(MSG_ONE, pseudoprojectile, beampos, CH_SHOTS, SND(NEXWHOOSH_RANDOM()), VOL_BASEVOICE, ATTEN_IDLE); + soundtoat(MSG_ONE, pseudoprojectile, beampos, CH_SHOTS, SND(NEXWHOOSH_RANDOM()), VOL_BASEVOICE, ATTEN_IDLE, 0); }); if(pseudoprojectile) delete(pseudoprojectile); @@ -313,6 +328,9 @@ void FireRailgunBullet (entity this, .entity weaponentity, vector start, vector IL_CLEAR(g_railgunhit); + if(headshot) + Send_Notification(NOTIF_ONE, this, MSG_ANNCE, ANNCE_HEADSHOT); + // calculate hits and fired shots for hitscan if(this.(weaponentity)) accuracy_add(this, this.(weaponentity).m_weapon, 0, min(bdamage, totaldmg)); @@ -330,25 +348,19 @@ void fireBullet_trace_callback(vector start, vector hit, vector end) fireBullet_last_hit = NULL; } -void fireBullet(entity this, .entity weaponentity, vector start, vector dir, float spread, float max_solid_penetration, float damage, float force, float dtype, entity tracer_effect) +void fireBullet_antilag(entity this, .entity weaponentity, vector start, vector dir, float spread, float max_solid_penetration, float damage, float headshot_multiplier, float force, float dtype, entity tracer_effect, bool do_antilag) { - vector end; - dir = normalize(dir + randomvec() * spread); - end = start + dir * max_shot_distance; + vector end = start + dir * max_shot_distance; fireBullet_last_hit = NULL; fireBullet_trace_callback_eff = tracer_effect; - float solid_penetration_left = 1; + float solid_penetration_fraction = 1; + float damage_fraction = 1; float total_damage = 0; - float lag = ((IS_REAL_CLIENT(this)) ? ANTILAG_LATENCY(this) : 0); - if(lag < 0.001) - lag = 0; - bool noantilag = ((IS_CLIENT(this)) ? CS(this).cvar_cl_noantilag : false); - if(autocvar_g_antilag == 0 || noantilag) - lag = 0; // only do hitscan, but no antilag + float lag = ((do_antilag) ? antilag_getlag(this) : 0); if(lag) antilag_takeback_all(this, lag); @@ -359,9 +371,9 @@ void fireBullet(entity this, .entity weaponentity, vector start, vector dir, flo WarpZone_trace_forent = this; + bool headshot = false; // indicates that one of the hit targets was a headshot for (;;) { - // TODO also show effect while tracing WarpZone_TraceBox_ThroughZone(start, '0 0 0', '0 0 0', end, false, WarpZone_trace_forent, NULL, fireBullet_trace_callback); dir = WarpZone_TransformVelocity(WarpZone_trace_transform, dir); end = WarpZone_TransformOrigin(WarpZone_trace_transform, end); @@ -399,7 +411,7 @@ void fireBullet(entity this, .entity weaponentity, vector start, vector dir, flo is_weapclip = true; if(!hit || hit.solid == SOLID_BSP || hit.solid == SOLID_SLIDEBOX) - Damage_DamageInfo(start, damage * solid_penetration_left, 0, 0, max(1, force) * dir * solid_penetration_left, dtype, hit.species, this); + Damage_DamageInfo(start, damage * damage_fraction, 0, 0, max(1, force) * dir * damage_fraction, dtype, hit.species, this); if (hit && hit != WarpZone_trace_forent && hit != fireBullet_last_hit) // Avoid self-damage (except after going through a warp); avoid hitting the same entity twice (engine bug). { @@ -407,14 +419,19 @@ void fireBullet(entity this, .entity weaponentity, vector start, vector dir, flo yoda = 0; MUTATOR_CALLHOOK(FireBullet_Hit, this, hit, start, end, damage, this.(weaponentity)); damage = M_ARGV(4, float); + if(headshot_multiplier && Headshot(hit, this, start, end)) + { + damage *= headshot_multiplier; + headshot = true; + } bool gooddamage = accuracy_isgooddamage(this, hit); - Damage(hit, this, this, damage * solid_penetration_left, dtype, weaponentity, start, force * dir * solid_penetration_left); + Damage(hit, this, this, damage * damage_fraction, dtype, weaponentity, start, force * dir * damage_fraction); // calculate hits for ballistic weapons if(gooddamage) { // do not exceed 100% - float added_damage = min(damage - total_damage, damage * solid_penetration_left); - total_damage += damage * solid_penetration_left; + float added_damage = min(damage - total_damage, damage * damage_fraction); + total_damage += damage * damage_fraction; accuracy_add(this, this.(weaponentity).m_weapon, 0, added_damage); } } @@ -436,9 +453,9 @@ void fireBullet(entity this, .entity weaponentity, vector start, vector dir, flo else if(hitstore.ballistics_density < 0) maxdist = vlen(hit.maxs - hit.mins) + 1; // -1: infinite travel distance else if(hitstore.ballistics_density == 0) - maxdist = max_solid_penetration * solid_penetration_left; + maxdist = max_solid_penetration * solid_penetration_fraction; else - maxdist = max_solid_penetration * solid_penetration_left * hitstore.ballistics_density; + maxdist = max_solid_penetration * solid_penetration_fraction / hitstore.ballistics_density; if(maxdist <= autocvar_g_ballistics_mindistance) break; @@ -450,10 +467,10 @@ void fireBullet(entity this, .entity weaponentity, vector start, vector dir, flo break; float dist_taken = max(autocvar_g_ballistics_mindistance, vlen(trace_endpos - start)); - // fraction_used_of_what_is_left = dist_taken / maxdist - // solid_penetration_left = solid_penetration_left - solid_penetration_left * fraction_used_of_what_is_left - solid_penetration_left *= 1 - dist_taken / maxdist; - solid_penetration_left = max(solid_penetration_left, 0); + float fraction_used_of_what_is_left = dist_taken / maxdist; + solid_penetration_fraction -= solid_penetration_fraction * fraction_used_of_what_is_left; + solid_penetration_fraction = max(solid_penetration_fraction, 0); + damage_fraction = pow(solid_penetration_fraction, autocvar_g_ballistics_solidpenetration_exponent); // Only show effect when going through a player (invisible otherwise) if (hit && (hit.solid != SOLID_BSP)) @@ -463,9 +480,12 @@ void fireBullet(entity this, .entity weaponentity, vector start, vector dir, flo start = trace_endpos; if(hit.solid == SOLID_BSP) - Damage_DamageInfo(start, 0, 0, 0, max(1, force) * normalize(dir) * -solid_penetration_left, dtype, 0, this); + Damage_DamageInfo(start, 0, 0, 0, max(1, force) * normalize(dir) * -damage_fraction, dtype, 0, this); } + if(headshot) + Send_Notification(NOTIF_ONE, this, MSG_ANNCE, ANNCE_HEADSHOT); + if(lag) antilag_restore_all(this); @@ -473,3 +493,8 @@ void fireBullet(entity this, .entity weaponentity, vector start, vector dir, flo if(this) this.dphitcontentsmask = oldsolid; } + +void fireBullet(entity this, .entity weaponentity, vector start, vector dir, float spread, float max_solid_penetration, float damage, float headshot_multiplier, float force, float dtype, entity tracer_effect) +{ + fireBullet_antilag(this, weaponentity, start, dir, spread, max_solid_penetration, damage, headshot_multiplier, force, dtype, tracer_effect, true); +}