From 2e7724c9d2639957f10241da19b7eb3a416c80e9 Mon Sep 17 00:00:00 2001 From: Rudolf Polzer Date: Thu, 11 Feb 2010 15:22:22 +0100 Subject: [PATCH] MinstaNex now can shoot through warpzones... using warpzone-aware tracebox and trailparticles functions --- data/qcsrc/server/cl_weaponsystem.qc | 6 +-- data/qcsrc/server/g_subs.qc | 27 ++++++++++++-- data/qcsrc/server/w_common.qc | 18 +++++---- data/qcsrc/server/w_crylink.qc | 4 +- data/qcsrc/server/w_laser.qc | 2 +- data/qcsrc/server/w_minstanex.qc | 18 ++++----- data/qcsrc/warpzonelib/client.qc | 32 +++++++--------- data/qcsrc/warpzonelib/common.qc | 24 ++++++++++++ data/qcsrc/warpzonelib/common.qh | 4 ++ data/qcsrc/warpzonelib/server.qc | 56 ++++++++++++++++++++++++++++ data/qcsrc/warpzonelib/server.qh | 5 +++ 11 files changed, 152 insertions(+), 44 deletions(-) diff --git a/data/qcsrc/server/cl_weaponsystem.qc b/data/qcsrc/server/cl_weaponsystem.qc index d2d4141a5..35d45d9c1 100644 --- a/data/qcsrc/server/cl_weaponsystem.qc +++ b/data/qcsrc/server/cl_weaponsystem.qc @@ -140,12 +140,12 @@ void W_SetupShot_Dir_ProjectileSize(entity ent, vector s_forward, vector mi, vec else ent.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_CORPSE; if(antilag) - traceline_antilag(world, ent.origin + ent.view_ofs, ent.origin + ent.view_ofs + s_forward * MAX_SHOT_DISTANCE, MOVE_NORMAL, ent, ANTILAG_LATENCY(ent)); + WarpZone_traceline_antilag(world, ent.origin + ent.view_ofs, ent.origin + ent.view_ofs + s_forward * MAX_SHOT_DISTANCE, MOVE_NORMAL, ent, ANTILAG_LATENCY(ent)); // passing world, because we do NOT want it to touch dphitcontentsmask else - traceline(ent.origin + ent.view_ofs, ent.origin + ent.view_ofs + s_forward * MAX_SHOT_DISTANCE, MOVE_NOMONSTERS, ent); + WarpZone_TraceLine(ent.origin + ent.view_ofs, ent.origin + ent.view_ofs + s_forward * MAX_SHOT_DISTANCE, MOVE_NOMONSTERS, ent); ent.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_CORPSE; - trueaimpoint = trace_endpos; + trueaimpoint = WarpZone_trace_endpos; // warpzone support // track max damage if not(inWarmupStage) { diff --git a/data/qcsrc/server/g_subs.qc b/data/qcsrc/server/g_subs.qc index a88dc7217..2a7a82d46 100644 --- a/data/qcsrc/server/g_subs.qc +++ b/data/qcsrc/server/g_subs.qc @@ -307,7 +307,7 @@ A version of traceline that must be used by SOLID_SLIDEBOX things that want to h Additionally it moves players back into the past before the trace and restores them afterward. ================== */ -void tracebox_antilag_force (entity source, vector v1, vector mi, vector ma, vector v2, float nomonst, entity forent, float lag) +void tracebox_antilag_force_wz (entity source, vector v1, vector mi, vector ma, vector v2, float nomonst, entity forent, float lag, float wz) { local entity player; local float oldsolid; @@ -337,7 +337,10 @@ void tracebox_antilag_force (entity source, vector v1, vector mi, vector ma, vec } // do the trace - tracebox (v1, mi, ma, v2, nomonst, forent); + if(wz) + WarpZone_TraceBox (v1, mi, ma, v2, nomonst, forent); + else + tracebox (v1, mi, ma, v2, nomonst, forent); // restore players to current positions if (lag) @@ -356,7 +359,7 @@ void tracebox_antilag_force (entity source, vector v1, vector mi, vector ma, vec } void traceline_antilag_force (entity source, vector v1, vector v2, float nomonst, entity forent, float lag) { - tracebox_antilag_force(source, v1, '0 0 0', '0 0 0', v2, nomonst, forent, lag); + tracebox_antilag_force_wz(source, v1, '0 0 0', '0 0 0', v2, nomonst, forent, lag, FALSE); } void traceline_antilag (entity source, vector v1, vector v2, float nomonst, entity forent, float lag) { @@ -368,7 +371,23 @@ void tracebox_antilag (entity source, vector v1, vector mi, vector ma, vector v2 { if (cvar("g_antilag") != 2 || source.cvar_cl_noantilag) lag = 0; - tracebox_antilag_force(source, v1, mi, ma, v2, nomonst, forent, lag); + tracebox_antilag_force_wz(source, v1, mi, ma, v2, nomonst, forent, lag, FALSE); +} +void WarpZone_traceline_antilag_force (entity source, vector v1, vector v2, float nomonst, entity forent, float lag) +{ + tracebox_antilag_force_wz(source, v1, '0 0 0', '0 0 0', v2, nomonst, forent, lag, TRUE); +} +void WarpZone_traceline_antilag (entity source, vector v1, vector v2, float nomonst, entity forent, float lag) +{ + if (cvar("g_antilag") != 2 || source.cvar_cl_noantilag) + lag = 0; + WarpZone_traceline_antilag_force(source, v1, v2, nomonst, forent, lag); +} +void WarpZone_tracebox_antilag (entity source, vector v1, vector mi, vector ma, vector v2, float nomonst, entity forent, float lag) +{ + if (cvar("g_antilag") != 2 || source.cvar_cl_noantilag) + lag = 0; + tracebox_antilag_force_wz(source, v1, mi, ma, v2, nomonst, forent, lag, TRUE); } float tracebox_inverted (vector v1, vector mi, vector ma, vector v2, float nomonsters, entity forent) // returns the number of traces done, for benchmarking diff --git a/data/qcsrc/server/w_common.qc b/data/qcsrc/server/w_common.qc index 0f565ad4c..bca4c8b93 100644 --- a/data/qcsrc/server/w_common.qc +++ b/data/qcsrc/server/w_common.qc @@ -21,6 +21,7 @@ void W_GiveWeapon (entity e, float wep, string name) self = oldself; } +.float railgundistance; void FireRailgunBullet (vector start, vector end, float bdamage, float bforce, float mindist, float maxdist, float halflifedist, float forcehalflifedist, float deathtype) { local vector hitloc, force, endpoint, dir; @@ -51,9 +52,9 @@ void FireRailgunBullet (vector start, vector end, float bdamage, float bforce, f while (1) { if(self.antilag_debug) - traceline_antilag (self, start, end, FALSE, self, self.antilag_debug); + WarpZone_traceline_antilag (self, start, end, FALSE, self, self.antilag_debug); else - traceline_antilag (self, start, end, FALSE, self, ANTILAG_LATENCY(self)); + WarpZone_traceline_antilag (self, start, end, FALSE, self, ANTILAG_LATENCY(self)); // if it is world we can't hurt it so stop now if (trace_ent == world || trace_fraction == 1) @@ -63,6 +64,7 @@ void FireRailgunBullet (vector start, vector end, float bdamage, float bforce, f trace_ent.railgunhit = TRUE; trace_ent.railgunhitloc = end; trace_ent.railgunhitsolidbackup = trace_ent.solid; + trace_ent.railgundistance = vlen(WarpZone_trace_endpos - start); // stop if this is a wall if (trace_ent.solid == SOLID_BSP) @@ -117,9 +119,6 @@ void FireRailgunBullet (vector start, vector end, float bdamage, float bforce, f { // get the details we need to call the damage function hitloc = ent.railgunhitloc; - ent.railgunhitloc = '0 0 0'; - ent.railgunhitsolidbackup = SOLID_NOT; - ent.railgunhit = FALSE; //for stats so that team hit will count as a miss if(ent.flags & FL_CLIENT) @@ -130,8 +129,8 @@ void FireRailgunBullet (vector start, vector end, float bdamage, float bforce, f if(ent.team == self.team) hit = 0; - f = ExponentialFalloff(mindist, maxdist, halflifedist, (ent.origin - start) * dir); - ffs = ExponentialFalloff(mindist, maxdist, forcehalflifedist, (ent.origin - start) * dir); + f = ExponentialFalloff(mindist, maxdist, halflifedist, ent.railgundistance); + ffs = ExponentialFalloff(mindist, maxdist, forcehalflifedist, ent.railgundistance); // apply the damage if (ent.takedamage) @@ -141,6 +140,11 @@ void FireRailgunBullet (vector start, vector end, float bdamage, float bforce, f //setorigin (explosion, hitloc); //RadiusDamage (explosion, self, 10, 0, 50, world, 300, deathtype); + ent.railgunhitloc = '0 0 0'; + ent.railgunhitsolidbackup = SOLID_NOT; + ent.railgunhit = FALSE; + ent.railgundistance = 0; + // advance to the next entity ent = findfloat(ent, railgunhit, TRUE); } diff --git a/data/qcsrc/server/w_crylink.qc b/data/qcsrc/server/w_crylink.qc index a7bc0bc5b..2289e0e51 100644 --- a/data/qcsrc/server/w_crylink.qc +++ b/data/qcsrc/server/w_crylink.qc @@ -183,9 +183,9 @@ void W_Crylink_Attack3 (void) self.ammo_cells = self.ammo_cells - cvar("g_balance_crylink_secondary_ammo"); W_SetupShot (self, TRUE, 0, "weapons/crylink_fire2.wav", cvar("g_balance_crylink_secondary_damage")); - traceline_antilag(self, w_shotorg, w_shotorg + w_shotdir * cvar("g_balance_crylink_secondary_radius"), FALSE, self, ANTILAG_LATENCY(self)); + WarpZone_traceline_antilag(self, w_shotorg, w_shotorg + w_shotdir * cvar("g_balance_crylink_secondary_radius"), FALSE, self, ANTILAG_LATENCY(self)); - te_lightning1(self, w_shotorg, trace_endpos); + te_lightning1(self, w_shotorg, WarpZone_trace_endpos); if (trace_fraction < 1) Damage(trace_ent, self, self, cvar("g_balance_crylink_secondary_damage"), WEP_CRYLINK | HITTYPE_SECONDARY, trace_endpos, cvar("g_balance_crylink_secondary_force") * w_shotdir); diff --git a/data/qcsrc/server/w_laser.qc b/data/qcsrc/server/w_laser.qc index a8a097cec..d90c97a38 100644 --- a/data/qcsrc/server/w_laser.qc +++ b/data/qcsrc/server/w_laser.qc @@ -104,7 +104,7 @@ void W_Laser_Attack2 (void) // gauntlet { W_SetupShot (self, TRUE, 0, "weapons/gauntlet_fire.wav", cvar("g_balance_laser_primary_damage")); - traceline_antilag(self, w_shotorg, w_shotorg + w_shotdir * cvar("g_balance_laser_primary_radius"), FALSE, self, ANTILAG_LATENCY(self)); + WarpZone_traceline_antilag(self, w_shotorg, w_shotorg + w_shotdir * cvar("g_balance_laser_primary_radius"), FALSE, self, ANTILAG_LATENCY(self)); pointparticles(particleeffectnum("laser_gauntlet"), w_shotorg + w_shotdir * cvar("g_balance_laser_primary_radius"), '0 0 0', 1); diff --git a/data/qcsrc/server/w_minstanex.qc b/data/qcsrc/server/w_minstanex.qc index 52d099b8f..9240a11f7 100644 --- a/data/qcsrc/server/w_minstanex.qc +++ b/data/qcsrc/server/w_minstanex.qc @@ -47,32 +47,32 @@ void W_MinstaNex_Attack (void) { case COLOR_TEAM1: // Red if(damage_goodhits) - trailparticles(world, particleeffectnum("TE_TEI_G3RED_HIT"), w_shotorg, trace_endpos); + WarpZone_TrailParticles(world, particleeffectnum("TE_TEI_G3RED_HIT"), w_shotorg, WarpZone_trace_endpos); else - trailparticles(world, particleeffectnum("TE_TEI_G3RED"), w_shotorg, trace_endpos); + WarpZone_TrailParticles(world, particleeffectnum("TE_TEI_G3RED"), w_shotorg, WarpZone_trace_endpos); break; case COLOR_TEAM2: // Blue if(damage_goodhits) - trailparticles(world, particleeffectnum("TE_TEI_G3BLUE_HIT"), w_shotorg, trace_endpos); + WarpZone_TrailParticles(world, particleeffectnum("TE_TEI_G3BLUE_HIT"), w_shotorg, WarpZone_trace_endpos); else - trailparticles(world, particleeffectnum("TE_TEI_G3BLUE"), w_shotorg, trace_endpos); + WarpZone_TrailParticles(world, particleeffectnum("TE_TEI_G3BLUE"), w_shotorg, WarpZone_trace_endpos); break; case COLOR_TEAM3: // Yellow if(damage_goodhits) - trailparticles(world, particleeffectnum("TE_TEI_G3YELLOW_HIT"), w_shotorg, trace_endpos); + WarpZone_TrailParticles(world, particleeffectnum("TE_TEI_G3YELLOW_HIT"), w_shotorg, WarpZone_trace_endpos); else - trailparticles(world, particleeffectnum("TE_TEI_G3YELLOW"), w_shotorg, trace_endpos); + WarpZone_TrailParticles(world, particleeffectnum("TE_TEI_G3YELLOW"), w_shotorg, WarpZone_trace_endpos); break; case COLOR_TEAM4: // Pink if(damage_goodhits) - trailparticles(world, particleeffectnum("TE_TEI_G3PINK_HIT"), w_shotorg, trace_endpos); + WarpZone_TrailParticles(world, particleeffectnum("TE_TEI_G3PINK_HIT"), w_shotorg, WarpZone_trace_endpos); else - trailparticles(world, particleeffectnum("TE_TEI_G3PINK"), w_shotorg, trace_endpos); + WarpZone_TrailParticles(world, particleeffectnum("TE_TEI_G3PINK"), w_shotorg, WarpZone_trace_endpos); break; } } else - trailparticles(world, particleeffectnum("TE_TEI_G3"), w_shotorg, trace_endpos); + WarpZone_TrailParticles(world, particleeffectnum("TE_TEI_G3"), w_shotorg, WarpZone_trace_endpos); // flash and burn the wall if (trace_ent.solid == SOLID_BSP && !(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)) diff --git a/data/qcsrc/warpzonelib/client.qc b/data/qcsrc/warpzonelib/client.qc index 664433aa3..987f81f59 100644 --- a/data/qcsrc/warpzonelib/client.qc +++ b/data/qcsrc/warpzonelib/client.qc @@ -6,7 +6,7 @@ void WarpZone_Read(float isnew) self.enemy = spawn(); self.enemy.classname = "warpzone_from"; } - self.classname = "warpzone_to"; + self.classname = "trigger_warpzone"; self.origin_x = ReadCoord(); self.origin_y = ReadCoord(); self.origin_z = ReadCoord(); @@ -53,31 +53,27 @@ void WarpZone_FixView() warpzone_saved_origin = warpzone_fixview_origin; warpzone_saved_angles = warpzone_fixview_angles; - for(e = world; (e = find(e, classname, "warpzone_to")); ) + e = WarpZone_Find(warpzone_fixview_origin, warpzone_fixview_origin); + if(e) { - if(WarpZoneLib_BoxTouchesBrush(warpzone_fixview_origin, warpzone_fixview_origin, e, world)) - { - warpzone_saved = 1; - warpzone_fixview_origin = AnglesTransform_Apply(e.warpzone_transform, warpzone_fixview_origin - e.enemy.oldorigin) + e.oldorigin; - warpzone_fixview_angles = WarpZone_TransformVAngles(e.warpzone_transform, warpzone_fixview_angles); - break; - } + warpzone_saved = 1; + warpzone_fixview_origin = AnglesTransform_Apply(e.warpzone_transform, warpzone_fixview_origin - e.enemy.oldorigin) + e.oldorigin; + warpzone_fixview_angles = WarpZone_TransformVAngles(e.warpzone_transform, warpzone_fixview_angles); + break; } // if we are near any warpzone planes - MOVE AWAY (work around nearclip) float nearclip = 1; - for(e = world; (e = find(e, classname, "warpzone_to")); ) + e = WarpZone_Find(warpzone_fixview_origin - '1 1 1' * nearclip, warpzone_fixview_origin + '1 1 1' * nearclip); + if(e) { - if(WarpZoneLib_BoxTouchesBrush(warpzone_fixview_origin - '1 1 1' * nearclip, warpzone_fixview_origin + '1 1 1' * nearclip, e, world)) + fixedmakevectors(e.enemy.avelocity); + pd = (warpzone_fixview_origin - e.enemy.oldorigin) * v_forward; + if(pd >= 0 && pd < nearclip) { - fixedmakevectors(e.enemy.avelocity); + warpzone_saved = 1; + warpzone_fixview_origin = warpzone_fixview_origin + v_forward * (nearclip - pd); pd = (warpzone_fixview_origin - e.enemy.oldorigin) * v_forward; - if(pd >= 0 && pd < nearclip) - { - warpzone_saved = 1; - warpzone_fixview_origin = warpzone_fixview_origin + v_forward * (nearclip - pd); - pd = (warpzone_fixview_origin - e.enemy.oldorigin) * v_forward; - } } } diff --git a/data/qcsrc/warpzonelib/common.qc b/data/qcsrc/warpzonelib/common.qc index 69c0ca1fd..e5f1be1f7 100644 --- a/data/qcsrc/warpzonelib/common.qc +++ b/data/qcsrc/warpzonelib/common.qc @@ -94,3 +94,27 @@ float WarpZoneLib_BoxTouchesBrush(vector mi, vector ma, entity e, entity ig) return f; } + +entity WarpZone_Find(vector mi, vector ma) +{ + // if we are near any warpzone planes - MOVE AWAY (work around nearclip) + entity e; + for(e = world; (e = find(e, classname, "trigger_warpzone")); ) + if(WarpZoneLib_BoxTouchesBrush(mi, ma, e, world)) + return e; + return world; +} + +void WarpZone_MakeAllSolid() +{ + entity e; + for(e = world; (e = find(e, classname, "trigger_warpzone")); ) + e.solid = SOLID_BSP; +} + +void WarpZone_MakeAllOther() +{ + entity e; + for(e = world; (e = find(e, classname, "trigger_warpzone")); ) + e.solid = SOLID_TRIGGER; +} diff --git a/data/qcsrc/warpzonelib/common.qh b/data/qcsrc/warpzonelib/common.qh index 002e0ee5f..454ac2479 100644 --- a/data/qcsrc/warpzonelib/common.qh +++ b/data/qcsrc/warpzonelib/common.qh @@ -2,3 +2,7 @@ float FL_CAMERA = 8192; vector WarpZone_TransformVAngles(vector t, vector ang); float WarpZoneLib_BoxTouchesBrush(vector mi, vector ma, entity e, entity ig); + +entity WarpZone_Find(vector mi, vector ma); +void WarpZone_MakeAllSolid(); +void WarpZone_MakeAllOther(); diff --git a/data/qcsrc/warpzonelib/server.qc b/data/qcsrc/warpzonelib/server.qc index b084b3198..d3af6d9bd 100644 --- a/data/qcsrc/warpzonelib/server.qc +++ b/data/qcsrc/warpzonelib/server.qc @@ -225,3 +225,59 @@ void WarpZone_InitStep_UpdateTransform() self.flags |= FL_CAMERA; self.view_ofs = self.enemy.warpzone_origin; } + +void WarpZone_TraceBox(vector org, vector mi, vector ma, vector end, float nomonsters, entity forent) +{ + float frac, sol; + vector o0, e0; + o0 = org; + e0 = end; + WarpZone_MakeAllSolid(); + sol = -1; + frac = 0; + for(;;) + { + tracebox(org, mi, ma, end, nomonsters, forent); + if(sol < 0) + sol = trace_startsolid; + if(trace_fraction >= 1) + break; + frac = trace_fraction = frac + (1 - frac) * trace_fraction; + if(trace_ent.classname != "trigger_warpzone") + break; + // we hit a warpzone... so, let's perform the trace after the warp again + org = AnglesTransform_Apply(trace_ent.warpzone_transform, trace_endpos - trace_ent.warpzone_origin) + trace_ent.enemy.warpzone_origin; + end = AnglesTransform_Apply(trace_ent.warpzone_transform, end - trace_ent.warpzone_origin) + trace_ent.enemy.warpzone_origin; + } + WarpZone_MakeAllOther(); + WarpZone_trace_endpos = o0 + (e0 - o0) * trace_fraction; +} + +void WarpZone_TraceLine(vector org, vector end, float nomonsters, entity forent) +{ + WarpZone_TraceBox(org, '0 0 0', '0 0 0', end, nomonsters, forent); +} + +void WarpZone_TrailParticles(entity own, float eff, vector org, vector end) +{ + float frac, sol; + WarpZone_MakeAllSolid(); + sol = -1; + frac = 0; + for(;;) + { + traceline(org, end, MOVE_NOMONSTERS, world); + if(sol < 0) + sol = trace_startsolid; + //print(vtos(org), " to ", vtos(trace_endpos), "\n"); + trailparticles(own, eff, org, trace_endpos); + if(trace_fraction >= 1) + break; + if(trace_ent.classname != "trigger_warpzone") + break; + // we hit a warpzone... so, let's perform the trace after the warp again + org = AnglesTransform_Apply(trace_ent.warpzone_transform, trace_endpos - trace_ent.warpzone_origin) + trace_ent.enemy.warpzone_origin; + end = AnglesTransform_Apply(trace_ent.warpzone_transform, end - trace_ent.warpzone_origin) + trace_ent.enemy.warpzone_origin; + } + WarpZone_MakeAllOther(); +} diff --git a/data/qcsrc/warpzonelib/server.qh b/data/qcsrc/warpzonelib/server.qh index b92296bf5..1c02ab660 100644 --- a/data/qcsrc/warpzonelib/server.qh +++ b/data/qcsrc/warpzonelib/server.qh @@ -8,3 +8,8 @@ void WarpZone_PostTeleportPlayer(entity pl); // server must also define a float called ENT_CLIENT_WARPZONE for the initial byte of WarpZone entities const float ENT_CLIENT_WARPZONE; + +vector WarpZone_trace_endpos; // UNtransformed endpos +void WarpZone_TraceBox(vector org, vector min, vector max, vector end, float nomonsters, entity forent); +void WarpZone_TraceLine(vector org, vector end, float nomonsters, entity forent); +void WarpZone_TrailParticles(entity own, float eff, vector org, vector end); -- 2.39.2