X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fxonotic-data.pk3dir.git;a=blobdiff_plain;f=qcsrc%2Fserver%2Fweapons%2Ftracing.qc;h=772809d658dde2d8ad7c95bdbce39077634cf06b;hp=1417717e834e33270ed355d891a450bb73767938;hb=9e8ea75b9aacffc5cfa18c8852c4dd9ffdbd3192;hpb=9e84ff8daa3826ef32e2891a7c5224a7cd436d23 diff --git a/qcsrc/server/weapons/tracing.qc b/qcsrc/server/weapons/tracing.qc index 1417717e83..772809d658 100644 --- a/qcsrc/server/weapons/tracing.qc +++ b/qcsrc/server/weapons/tracing.qc @@ -1,5 +1,7 @@ #include "tracing.qh" +#include + #include "accuracy.qh" #include "common.qh" #include "hitplot.qh" @@ -14,6 +16,7 @@ #include #include +#include #include #include @@ -21,14 +24,17 @@ // this function calculates w_shotorg and w_shotdir based on the weapon model // offset, trueaim and antilag, and won't put w_shotorg inside a wall. // make sure you call makevectors first (FIXME?) -void W_SetupShot_Dir_ProjectileSize_Range(entity ent, .entity weaponentity, vector s_forward, vector mi, vector ma, float antilag, float recoil, Sound snd, float chan, float maxdamage, float range) +void W_SetupShot_Dir_ProjectileSize_Range(entity ent, .entity weaponentity, vector s_forward, vector mi, vector ma, float antilag, float recoil, Sound snd, float chan, float maxdamage, float range, int deathtype) { TC(Sound, snd); float nudge = 1; // added to traceline target and subtracted from result TOOD(divVerent): do we still need this? Doesn't the engine do this now for us? - float oldsolid; - vector vecs, dv; - oldsolid = ent.dphitcontentsmask; - if (IS_PLAYER(ent) && ent.(weaponentity).m_weapon == WEP_RIFLE) + float oldsolid = ent.dphitcontentsmask; + Weapon wep = DEATH_WEAPONOF(deathtype); + if (wep == WEP_Null) + wep = ent.(weaponentity).m_weapon; // TODO: don't fall back, if the attack isn't a weapon we don't want it to affect the user's held weapon! + if(!IS_CLIENT(ent)) + antilag = false; // no antilag for non-clients! + if (IS_PLAYER(ent) && (wep.spawnflags & WEP_FLAG_PENETRATEWALLS)) ent.dphitcontentsmask = DPCONTENTS_BODY | DPCONTENTS_CORPSE; else ent.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_CORPSE; @@ -54,18 +60,15 @@ void W_SetupShot_Dir_ProjectileSize_Range(entity ent, .entity weaponentity, vect // track max damage if (IS_PLAYER(ent) && accuracy_canbegooddamage(ent)) - accuracy_add(ent, ent.(weaponentity).m_weapon.m_id, maxdamage, 0); + accuracy_add(ent, wep.m_id, maxdamage, 0); if(IS_PLAYER(ent)) - W_HitPlotAnalysis(ent, weaponentity, v_forward, v_right, v_up); + W_HitPlotAnalysis(ent, wep, v_forward, v_right, v_up); vector md = ent.(weaponentity).movedir; - if(md.x > 0) - vecs = md; - else - vecs = '0 0 0'; + vector vecs = ((md.x > 0) ? md : '0 0 0'); - dv = v_right * -vecs.y + v_up * vecs.z; + vector dv = v_right * -vecs.y + v_up * vecs.z; w_shotorg = ent.origin + ent.view_ofs + dv; // now move the shotorg forward as much as requested if possible @@ -87,7 +90,7 @@ void W_SetupShot_Dir_ProjectileSize_Range(entity ent, .entity weaponentity, vect //vector prevend = w_shotend; if (antilag) - if (!ent.cvar_cl_noantilag) + if (!CS(ent).cvar_cl_noantilag) { if (autocvar_g_antilag == 1) // switch to "ghost" if not hitting original { @@ -108,10 +111,10 @@ void W_SetupShot_Dir_ProjectileSize_Range(entity ent, .entity weaponentity, vect else if(autocvar_g_antilag == 3) // client side hitscan { // this part MUST use prydon cursor - if (ent.cursor_trace_ent) // client was aiming at someone - if (ent.cursor_trace_ent != ent) // just to make sure - if (ent.cursor_trace_ent.takedamage) // and that person is killable - if (IS_PLAYER(ent.cursor_trace_ent)) // and actually a player + if (CS(ent).cursor_trace_ent) // client was aiming at someone + if (CS(ent).cursor_trace_ent != ent) // just to make sure + if (CS(ent).cursor_trace_ent.takedamage) // and that person is killable + if (IS_PLAYER(CS(ent).cursor_trace_ent)) // and actually a player { // verify that the shot would miss without antilag // (avoids an issue where guns would always shoot at their origin) @@ -119,11 +122,11 @@ void W_SetupShot_Dir_ProjectileSize_Range(entity ent, .entity weaponentity, vect if (!trace_ent.takedamage) { // verify that the shot would hit if altered - traceline(w_shotorg, ent.cursor_trace_ent.origin, MOVE_NORMAL, ent); - if (trace_ent == ent.cursor_trace_ent) - w_shotdir = normalize(ent.cursor_trace_ent.origin - w_shotorg); + traceline(w_shotorg, CS(ent).cursor_trace_ent.origin, MOVE_NORMAL, ent); + if (trace_ent == CS(ent).cursor_trace_ent) + w_shotdir = normalize(CS(ent).cursor_trace_ent.origin - w_shotorg); else - LOG_INFO("antilag fail\n"); + LOG_INFO("antilag fail"); } } } @@ -135,7 +138,7 @@ void W_SetupShot_Dir_ProjectileSize_Range(entity ent, .entity weaponentity, vect ent.punchangle_x = recoil * -1; if (snd != SND_Null) { - sound (ent, chan, snd, VOL_BASE, ATTN_NORM); + sound (ent, chan, snd, (W_DualWielding(ent) ? VOL_BASE * 0.7 : VOL_BASE), ATTN_NORM); W_PlayStrengthSound(ent); } @@ -186,7 +189,7 @@ void W_SetupProjVelocity_Explicit(entity proj, vector dir, vector upDir, float p #if 0 mspercallsum += gettime(GETTIME_HIRES); mspercallcount += 1; - LOG_INFO("avg: ", ftos(mspercallcount / mspercallsum), " per sec\n"); + LOG_INFO("avg: ", ftos(mspercallcount / mspercallsum), " per sec"); #endif proj.velocity = W_CalculateProjectileVelocity(proj.owner, proj.owner.velocity, pSpeed * dir, forceAbsolute); @@ -199,33 +202,21 @@ void W_SetupProjVelocity_Explicit(entity proj, vector dir, vector upDir, float p void FireRailgunBullet (entity this, .entity weaponentity, vector start, vector end, float bdamage, float bforce, float mindist, float maxdist, float halflifedist, float forcehalflifedist, int deathtype) { - vector hitloc, force, endpoint, dir; - entity ent, endent; - float endq3surfaceflags; - float totaldmg; - entity o; - - float length; - vector beampos; - string snd; - entity pseudoprojectile; - float f, ffs; + entity pseudoprojectile = NULL; - pseudoprojectile = NULL; - - dir = normalize(end - start); - length = vlen(end - start); - force = dir * bforce; + vector dir = normalize(end - start); + float length = vlen(end - start); + vector force = dir * bforce; // go a little bit into the wall because we need to hit this wall later end = end + dir; - totaldmg = 0; + float totaldmg = 0; // 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 // note down which entities were hit so we can damage them later - o = this; + entity o = this; while (1) { if(CS(this).antilag_debug) @@ -246,6 +237,7 @@ void FireRailgunBullet (entity this, .entity weaponentity, vector start, vector break; // make the entity non-solid so we can hit the next one + IL_PUSH(g_railgunhit, trace_ent); trace_ent.railgunhit = true; trace_ent.railgunhitloc = end; trace_ent.railgunhitsolidbackup = trace_ent.solid; @@ -260,18 +252,15 @@ void FireRailgunBullet (entity this, .entity weaponentity, vector start, vector trace_ent.solid = SOLID_NOT; } - endpoint = trace_endpos; - endent = trace_ent; - endq3surfaceflags = trace_dphitq3surfaceflags; + vector endpoint = trace_endpos; + entity endent = trace_ent; + float endq3surfaceflags = trace_dphitq3surfaceflags; // find all the entities the railgun hit and restore their solid state - ent = findfloat(NULL, railgunhit, true); - while (ent) + IL_EACH(g_railgunhit, it.railgunhit, { - // restore their solid type - ent.solid = ent.railgunhitsolidbackup; - ent = findfloat(ent, railgunhit, true); - } + it.solid = it.railgunhitsolidbackup; + }); // spawn a temporary explosion entity for RadiusDamage calls //explosion = spawn(); @@ -279,59 +268,57 @@ void FireRailgunBullet (entity this, .entity weaponentity, vector start, vector // Find all non-hit players the beam passed close by if(deathtype == WEP_VAPORIZER.m_id || deathtype == WEP_VORTEX.m_id) { - FOREACH_CLIENT(IS_REAL_CLIENT(it) && it != this, LAMBDA( + FOREACH_CLIENT(IS_REAL_CLIENT(it) && it != this, { if(!it.railgunhit) if(!(IS_SPEC(it) && it.enemy == this)) { msg_entity = it; // nearest point on the beam - beampos = start + dir * bound(0, (msg_entity.origin - start) * dir, length); + vector beampos = start + dir * bound(0, (msg_entity.origin - start) * dir, length); - f = bound(0, 1 - vlen(beampos - msg_entity.origin) / 512, 1); + float f = bound(0, 1 - vlen(beampos - msg_entity.origin) / 512, 1); if(f <= 0) continue; - snd = SND(NEXWHOOSH_RANDOM()); - if(!pseudoprojectile) pseudoprojectile = spawn(); // we need this so the sound uses the "entchannel4" volume - soundtoat(MSG_ONE, pseudoprojectile, beampos, CH_SHOTS, snd, VOL_BASE * f, ATTEN_NONE); + soundtoat(MSG_ONE, pseudoprojectile, beampos, CH_SHOTS, SND(NEXWHOOSH_RANDOM()), VOL_BASE * f, ATTEN_NONE); } - )); + }); if(pseudoprojectile) delete(pseudoprojectile); } // find all the entities the railgun hit and hurt them - ent = findfloat(NULL, railgunhit, true); - while (ent) + IL_EACH(g_railgunhit, it.railgunhit, { + // removal from the list is handled below + // get the details we need to call the damage function - hitloc = ent.railgunhitloc; + vector hitloc = it.railgunhitloc; - f = ExponentialFalloff(mindist, maxdist, halflifedist, ent.railgundistance); - ffs = ExponentialFalloff(mindist, maxdist, forcehalflifedist, ent.railgundistance); + float foff = ExponentialFalloff(mindist, maxdist, halflifedist, it.railgundistance); + float ffs = ExponentialFalloff(mindist, maxdist, forcehalflifedist, it.railgundistance); - if(accuracy_isgooddamage(this, ent)) - totaldmg += bdamage * f; + if(accuracy_isgooddamage(this, it)) + totaldmg += bdamage * foff; // apply the damage - if (ent.takedamage) - Damage (ent, this, this, bdamage * f, deathtype, hitloc, ent.railgunforce * ffs); + if (it.takedamage) + Damage (it, this, this, bdamage * foff, deathtype, weaponentity, hitloc, it.railgunforce * ffs); // create a small explosion to throw gibs around (if applicable) //setorigin(explosion, hitloc); //RadiusDamage (explosion, this, 10, 0, 50, NULL, NULL, 300, deathtype); - ent.railgunhitloc = '0 0 0'; - ent.railgunhitsolidbackup = SOLID_NOT; - ent.railgunhit = false; - ent.railgundistance = 0; + it.railgunhitloc = '0 0 0'; + it.railgunhitsolidbackup = SOLID_NOT; + it.railgunhit = false; + it.railgundistance = 0; + }); - // advance to the next entity - ent = findfloat(ent, railgunhit, true); - } + IL_CLEAR(g_railgunhit); // calculate hits and fired shots for hitscan accuracy_add(this, this.(weaponentity).m_weapon.m_id, 0, min(bdamage, totaldmg)); @@ -354,7 +341,7 @@ void fireBullet(entity this, .entity weaponentity, vector start, vector dir, flo vector end; dir = normalize(dir + randomvec() * spread); - end = start + dir * MAX_SHOT_DISTANCE; + end = start + dir * max_shot_distance; fireBullet_last_hit = NULL; float solid_penetration_left = 1; @@ -367,21 +354,14 @@ void fireBullet(entity this, .entity weaponentity, vector start, vector dir, flo else fireBullet_trace_callback_eff = EFFECT_BULLET; - float lag = ANTILAG_LATENCY(this); + float lag = ((IS_REAL_CLIENT(this)) ? ANTILAG_LATENCY(this) : 0); if(lag < 0.001) lag = 0; - if (!IS_REAL_CLIENT(this)) - lag = 0; - if(autocvar_g_antilag == 0 || this.cvar_cl_noantilag) + 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 if(lag) - { - FOREACH_CLIENT(IS_PLAYER(it) && it != this, antilag_takeback(it, CS(it), time - lag)); - IL_EACH(g_monsters, it != this, - { - antilag_takeback(it, it, time - lag); - }); - } + antilag_takeback_all(this, lag); // change shooter to SOLID_BBOX so the shot can hit corpses int oldsolid = this.dphitcontentsmask; @@ -399,6 +379,10 @@ void fireBullet(entity this, .entity weaponentity, vector start, vector dir, flo start = trace_endpos; entity hit = trace_ent; + // traced up to max_shot_distance and didn't hit anything at all + if (trace_fraction == 1.0) + break; + // When hitting sky, stop. if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY) break; @@ -432,10 +416,10 @@ void fireBullet(entity this, .entity weaponentity, vector start, vector dir, flo { fireBullet_last_hit = hit; yoda = 0; - MUTATOR_CALLHOOK(FireBullet_Hit, this, hit, start, end, damage); + MUTATOR_CALLHOOK(FireBullet_Hit, this, hit, start, end, damage, this.(weaponentity)); damage = M_ARGV(4, float); float g = accuracy_isgooddamage(this, hit); - Damage(hit, this, this, damage * solid_penetration_left, dtype, start, force * dir * solid_penetration_left); + Damage(hit, this, this, damage * solid_penetration_left, dtype, weaponentity, start, force * dir * solid_penetration_left); // calculate hits for ballistic weapons if(g) { @@ -455,16 +439,17 @@ void fireBullet(entity this, .entity weaponentity, vector start, vector dir, flo break; float maxdist; + entity hitstore = IS_PLAYER(hit) ? PS(hit) : hit; if(max_solid_penetration < 0) break; - else if(hit.ballistics_density < -1) + else if(hitstore.ballistics_density < -1) break; // -2: no solid penetration, ever - else if(hit.ballistics_density < 0) + else if(hitstore.ballistics_density < 0) maxdist = vlen(hit.maxs - hit.mins) + 1; // -1: infinite travel distance - else if(hit.ballistics_density == 0) + else if(hitstore.ballistics_density == 0) maxdist = max_solid_penetration * solid_penetration_left; else - maxdist = max_solid_penetration * solid_penetration_left * hit.ballistics_density; + maxdist = max_solid_penetration * solid_penetration_left * hitstore.ballistics_density; if(maxdist <= autocvar_g_ballistics_mindistance) break; @@ -493,13 +478,7 @@ void fireBullet(entity this, .entity weaponentity, vector start, vector dir, flo } if(lag) - { - FOREACH_CLIENT(IS_PLAYER(it) && it != this, antilag_restore(it, CS(it))); - IL_EACH(g_monsters, it != this, - { - antilag_restore(it, it); - }); - } + antilag_restore_all(this); // restore shooter solid type if(this)