X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fxonotic-data.pk3dir.git;a=blobdiff_plain;f=qcsrc%2Fwarpzonelib%2Fcommon.qc;h=62e74682090c725e544ce7725e57bc8ba2a06294;hp=3f6bb10a2ebe872b77bc88e45f44558beced4bb1;hb=cc5c1bc7cac5740f36f9057a8c2aaaa89bb67fe6;hpb=58b26c0a303456441dbb82e608213d2f86d695d8 diff --git a/qcsrc/warpzonelib/common.qc b/qcsrc/warpzonelib/common.qc index 3f6bb10a2..62e746820 100644 --- a/qcsrc/warpzonelib/common.qc +++ b/qcsrc/warpzonelib/common.qc @@ -1,3 +1,6 @@ +float trace_dphitcontents; +.float dphitcontentsmask; + void WarpZone_Accumulator_Clear(entity acc) { acc.warpzone_transform = '0 0 0'; @@ -25,6 +28,11 @@ var float autocvar_cl_warpzone_usetrace = 1; vector WarpZone_camera_transform(vector org, vector ang) { vector vf, vr, vu; + if(self.warpzone_fadestart) + if(vlen(org - self.origin - 0.5 * (self.mins + self.maxs)) > self.warpzone_fadeend + 400) + return org; + // don't transform if zone faded out (plus 400qu safety margin for typical speeds and latencies) + // unneeded on client, on server this helps a lot vf = v_forward; vr = v_right; vu = v_up; @@ -55,6 +63,26 @@ void WarpZone_SetUp(entity e, vector my_org, vector my_ang, vector other_org, ve e.camera_transform = WarpZone_camera_transform; } +vector WarpZone_Camera_camera_transform(vector org, vector ang) +{ + // a fixed camera view + if(self.warpzone_fadestart) + if(vlen(org - self.origin - 0.5 * (self.mins + self.maxs)) > self.warpzone_fadeend + 400) + return org; + // don't transform if zone faded out (plus 400qu safety margin for typical speeds and latencies) + // unneeded on client, on server this helps a lot + trace_endpos = self.warpzone_origin; + makevectors(self.warpzone_angles); + return self.warpzone_origin; +} + +void WarpZone_Camera_SetUp(entity e, vector my_org, vector my_ang) // we assume that e.oldorigin and e.avelocity point to view origin and direction +{ + e.warpzone_origin = my_org; + e.warpzone_angles = my_ang; + e.camera_transform = WarpZone_Camera_camera_transform; +} + .entity enemy; vector WarpZoneLib_BoxTouchesBrush_mins; @@ -95,7 +123,7 @@ float WarpZoneLib_BoxTouchesBrush(vector mi, vector ma, entity e, entity ig) { float f, s; - if not(e.modelindex) + if(!e.modelindex || e.warpzone_isboxy) return 1; s = e.solid; @@ -114,6 +142,8 @@ entity WarpZone_Find(vector mi, vector ma) { // if we are near any warpzone planes - MOVE AWAY (work around nearclip) entity e; + if(!warpzone_warpzones_exist) + return world; for(e = world; (e = find(e, classname, "trigger_warpzone")); ) if(WarpZoneLib_BoxTouchesBrush(mi, ma, e, world)) return e; @@ -123,6 +153,8 @@ entity WarpZone_Find(vector mi, vector ma) void WarpZone_MakeAllSolid() { entity e; + if(!warpzone_warpzones_exist) + return; for(e = world; (e = find(e, classname, "trigger_warpzone")); ) e.solid = SOLID_BSP; } @@ -130,6 +162,8 @@ void WarpZone_MakeAllSolid() void WarpZone_MakeAllOther() { entity e; + if(!warpzone_warpzones_exist) + return; for(e = world; (e = find(e, classname, "trigger_warpzone")); ) e.solid = SOLID_TRIGGER; } @@ -150,20 +184,60 @@ void WarpZone_Trace_AddTransform(entity wz) void WarpZone_TraceBox_ThroughZone(vector org, vector mi, vector ma, vector end, float nomonsters, entity forent, entity zone, WarpZone_trace_callback_t cb) { + float nomonsters_adjusted; float frac, sol, i; + float contentshack; vector o0, e0; entity wz; vector vf, vr, vu; + + WarpZone_trace_firstzone = world; + WarpZone_trace_lastzone = world; + WarpZone_Trace_InitTransform(); + if(!warpzone_warpzones_exist) + { + if(nomonsters == MOVE_NOTHING) + { + trace_endpos = end; + trace_fraction = 1; + if(cb) + cb(org, trace_endpos, end); + return; + } + else + { + tracebox(org, mi, ma, end, nomonsters, forent); + if(cb) + cb(org, trace_endpos, end); + return; + } + } + vf = v_forward; vr = v_right; vu = v_up; o0 = org; e0 = end; - WarpZone_Trace_InitTransform(); + + switch(nomonsters) + { + case MOVE_WORLDONLY: + case MOVE_NOTHING: + nomonsters_adjusted = MOVE_NOMONSTERS; + break; + default: + nomonsters_adjusted = nomonsters; + break; + } + if((contentshack = (forent.dphitcontentsmask && !(forent.dphitcontentsmask & DPCONTENTS_SOLID)))) + forent.dphitcontentsmask |= DPCONTENTS_SOLID; + // if starting in warpzone, first transform wz = WarpZone_Find(org + mi, org + ma); if(wz) { + WarpZone_trace_firstzone = wz; + WarpZone_trace_lastzone = wz; if(zone && wz != zone) { // we are in ANOTHER warpzone. This is bad. Make a zero length trace and return. @@ -173,7 +247,7 @@ void WarpZone_TraceBox_ThroughZone(vector org, vector mi, vector ma, vector end, goto fail; } WarpZone_Trace_AddTransform(wz); - org = WarpZone_TransformOrigin(wz, trace_endpos); + org = WarpZone_TransformOrigin(wz, org); end = WarpZone_TransformOrigin(wz, end); } WarpZone_MakeAllSolid(); @@ -185,9 +259,10 @@ void WarpZone_TraceBox_ThroughZone(vector org, vector mi, vector ma, vector end, if(--i < 1) { dprint("Too many warpzones in sequence, aborting trace.\n"); + trace_ent = world; break; } - tracebox(org, mi, ma, end, nomonsters, forent); + tracebox(org, mi, ma, end, nomonsters_adjusted, forent); if(cb) cb(org, trace_endpos, end); if(sol < 0) @@ -197,13 +272,28 @@ void WarpZone_TraceBox_ThroughZone(vector org, vector mi, vector ma, vector end, if(trace_fraction >= 1) break; if(trace_ent.classname != "trigger_warpzone") + { + if((nomonsters == MOVE_NOTHING) || ((nomonsters == MOVE_WORLDONLY) && trace_ent) || (contentshack && (trace_dphitcontents & forent.dphitcontentsmask) == DPCONTENTS_SOLID)) + { + // continue the trace, ignoring this hit (we only care for warpzones) + org = trace_endpos + normalize(end - org); + continue; + // we cannot do an inverted trace here, as we do care for further warpzones inside that "solid" to be found + // otherwise, players could block entrances that way + } break; + } if(trace_ent == wz) { + // FIXME can this check be removed? Do we really need it? dprint("I transformed into the same zone again, wtf, aborting the trace\n"); + trace_ent = world; break; } wz = trace_ent; + if(!WarpZone_trace_firstzone) + WarpZone_trace_firstzone = wz; + WarpZone_trace_lastzone = wz; if(zone && wz != zone) break; WarpZone_Trace_AddTransform(wz); @@ -213,6 +303,8 @@ void WarpZone_TraceBox_ThroughZone(vector org, vector mi, vector ma, vector end, } WarpZone_MakeAllOther(); :fail + if(contentshack) + forent.dphitcontentsmask &~= DPCONTENTS_SOLID; trace_startsolid = sol; v_forward = vf; v_right = vr; @@ -235,16 +327,36 @@ void WarpZone_TraceToss_ThroughZone(entity e, entity forent, entity zone, WarpZo vector vf, vr, vu, v0, o0; entity wz; - vf = v_forward; - vr = v_right; - vu = v_up; o0 = e.origin; v0 = e.velocity; + + WarpZone_trace_firstzone = world; + WarpZone_trace_lastzone = world; WarpZone_Trace_InitTransform(); + WarpZone_tracetoss_time = 0; + if(!warpzone_warpzones_exist) + { + tracetoss(e, forent); + if(cb) + cb(e.origin, trace_endpos, trace_endpos); + dt = vlen(e.origin - o0) / vlen(e.velocity); + WarpZone_tracetoss_time += dt; + e.velocity_z -= dt * g; + WarpZone_tracetoss_velocity = e.velocity; + e.velocity = v0; + return; + } + + vf = v_forward; + vr = v_right; + vu = v_up; + // if starting in warpzone, first transform wz = WarpZone_Find(e.origin + e.mins, e.origin + e.maxs); if(wz) { + WarpZone_trace_firstzone = wz; + WarpZone_trace_lastzone = wz; if(zone && wz != zone) { // we are in ANOTHER warpzone. This is bad. Make a zero length trace and return. @@ -259,32 +371,37 @@ void WarpZone_TraceToss_ThroughZone(entity e, entity forent, entity zone, WarpZo } WarpZone_MakeAllSolid(); g = cvar("sv_gravity") * e.gravity; - WarpZone_tracetoss_time = 0; i = 16; for(;;) { if(--i < 1) { dprint("Too many warpzones in sequence, aborting trace.\n"); + trace_ent = world; break; } tracetoss(e, forent); if(cb) cb(e.origin, trace_endpos, trace_endpos); e.origin = trace_endpos; - e.velocity_z -= WarpZone_tracetoss_time * g; dt = vlen(e.origin - o0) / vlen(e.velocity); WarpZone_tracetoss_time += dt; + e.velocity_z -= dt * g; if(trace_fraction >= 1) break; if(trace_ent.classname != "trigger_warpzone") break; if(trace_ent == wz) { + // FIXME can this check be removed? Do we really need it? dprint("I transformed into the same zone again, wtf, aborting the trace\n"); + trace_ent = world; break; } wz = trace_ent; + if(!WarpZone_trace_firstzone) + WarpZone_trace_firstzone = wz; + WarpZone_trace_lastzone = wz; if(zone && wz != zone) break; WarpZone_Trace_AddTransform(wz); @@ -322,6 +439,24 @@ void WarpZone_TrailParticles(entity own, float eff, vector org, vector end) WarpZone_TraceBox_ThroughZone(org, '0 0 0', '0 0 0', end, MOVE_NOMONSTERS, world, world, WarpZone_TrailParticles_trace_callback); } +#ifdef CSQC +float WarpZone_TrailParticles_trace_callback_f; +float WarpZone_TrailParticles_trace_callback_flags; +void WarpZone_TrailParticles_WithMultiplier_trace_callback(vector from, vector endpos, vector to) +{ + boxparticles(WarpZone_TrailParticles_trace_callback_eff, WarpZone_TrailParticles_trace_callback_own, from, endpos, WarpZone_TrailParticles_trace_callback_own.velocity, WarpZone_TrailParticles_trace_callback_own.velocity, WarpZone_TrailParticles_trace_callback_f, WarpZone_TrailParticles_trace_callback_flags); +} + +void WarpZone_TrailParticles_WithMultiplier(entity own, float eff, vector org, vector end, float f, float boxflags) +{ + WarpZone_TrailParticles_trace_callback_own = own; + WarpZone_TrailParticles_trace_callback_eff = eff; + WarpZone_TrailParticles_trace_callback_f = f; + WarpZone_TrailParticles_trace_callback_flags = boxflags; + WarpZone_TraceBox_ThroughZone(org, '0 0 0', '0 0 0', end, MOVE_NOMONSTERS, world, world, WarpZone_TrailParticles_WithMultiplier_trace_callback); +} +#endif + float WarpZone_PlaneDist(entity wz, vector v) { return (v - wz.warpzone_origin) * wz.warpzone_forward;