]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/warpzonelib/common.qc
also expose the last zone
[xonotic/xonotic-data.pk3dir.git] / qcsrc / warpzonelib / common.qc
index 5cf155642bd6019d1d4587f0881093a7466171ca..62e74682090c725e544ce7725e57bc8ba2a06294 100644 (file)
@@ -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;
@@ -58,6 +66,11 @@ void WarpZone_SetUp(entity e, vector my_org, vector my_ang, vector other_org, ve
 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;
@@ -110,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;
@@ -129,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;
@@ -138,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;
 }
@@ -145,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;
 }
@@ -165,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.
@@ -188,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();
@@ -203,7 +262,7 @@ void WarpZone_TraceBox_ThroughZone(vector org, vector mi, vector ma, vector end,
                        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)
@@ -213,14 +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);
@@ -230,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;
@@ -252,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.
@@ -276,7 +371,6 @@ 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(;;)
        {
@@ -290,20 +384,24 @@ void WarpZone_TraceToss_ThroughZone(entity e, entity forent, entity zone, WarpZo
                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);
@@ -341,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;