]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/lib/warpzone/common.qc
Allow multiple traces through the same warpzone, let the recursive warpzone lightshow...
[xonotic/xonotic-data.pk3dir.git] / qcsrc / lib / warpzone / common.qc
index 5a9b2abf975879fc8cd71cf00f7c5a4b1c08afdf..78d51cf0bc4fa4c6f050b6c137978eb130695d16 100644 (file)
@@ -4,7 +4,7 @@
     #include <common/t_items.qh>
 #elif defined(MENUQC)
 #elif defined(SVQC)
-    #include <common/weapons/all.qh>
+    #include <common/weapons/_all.qh>
 #endif
 
 void WarpZone_Accumulator_Clear(entity acc)
@@ -37,27 +37,26 @@ void WarpZone_Accumulator_AddInverse(entity acc, entity wz)
        WarpZone_Accumulator_AddInverseTransform(acc, wz.warpzone_transform, wz.warpzone_shift);
 }
 
-.vector(vector, vector) camera_transform;
 float autocvar_cl_warpzone_usetrace = 1;
-vector WarpZone_camera_transform(vector org, vector ang)
-{SELFPARAM();
+vector WarpZone_camera_transform(entity this, vector org, vector ang)
+{
        vector vf, vr, vu;
-       if(self.warpzone_fadestart)
-               if(vdist(org - self.origin - 0.5 * (self.mins + self.maxs), >, self.warpzone_fadeend + 400))
+       if(this.warpzone_fadestart)
+               if(vdist(org - this.origin - 0.5 * (this.mins + this.maxs), >, this.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;
-       org = WarpZone_TransformOrigin(self, org);
-       vf = WarpZone_TransformVelocity(self, vf);
-       vr = WarpZone_TransformVelocity(self, vr);
-       vu = WarpZone_TransformVelocity(self, vu);
+       org = WarpZone_TransformOrigin(this, org);
+       vf = WarpZone_TransformVelocity(this, vf);
+       vr = WarpZone_TransformVelocity(this, vr);
+       vu = WarpZone_TransformVelocity(this, vu);
        if(autocvar_cl_warpzone_usetrace)
-               traceline(self.warpzone_targetorigin, org, MOVE_NOMONSTERS, world);
+               traceline(this.warpzone_targetorigin, org, MOVE_NOMONSTERS, NULL);
        else
-               trace_endpos = self.warpzone_targetorigin;
+               trace_endpos = this.warpzone_targetorigin;
        v_forward = vf;
        v_right = vr;
        v_up = vu;
@@ -74,27 +73,27 @@ void WarpZone_SetUp(entity e, vector my_org, vector my_ang, vector other_org, ve
        e.warpzone_targetangles = other_ang;
        fixedmakevectors(my_ang); e.warpzone_forward = v_forward;
        fixedmakevectors(other_ang); e.warpzone_targetforward = v_forward;
-       e.camera_transform = WarpZone_camera_transform;
+       setcamera_transform(e, WarpZone_camera_transform);
 }
 
-vector WarpZone_Camera_camera_transform(vector org, vector ang)
-{SELFPARAM();
+vector WarpZone_Camera_camera_transform(entity this, vector org, vector ang)
+{
        // a fixed camera view
-       if(self.warpzone_fadestart)
-               if(vdist(org - self.origin - 0.5 * (self.mins + self.maxs), >, self.warpzone_fadeend + 400))
+       if(this.warpzone_fadestart)
+               if(vdist(org - this.origin - 0.5 * (this.mins + this.maxs), >, this.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;
+       trace_endpos = this.warpzone_origin;
+       makevectors(this.warpzone_angles);
+       return this.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;
+       setcamera_transform(e, WarpZone_Camera_camera_transform);
 }
 
 .entity enemy;
@@ -113,7 +112,7 @@ float WarpZoneLib_BoxTouchesBrush_Recurse()
 #ifdef CSQC
        if (trace_networkentity)
        {
-               LOG_TRACE("hit a network ent, cannot continue WarpZoneLib_BoxTouchesBrush\n");
+               LOG_TRACE("hit a network ent, cannot continue WarpZoneLib_BoxTouchesBrush");
                // we cannot continue, as a player blocks us...
                // so, abort
                return 0;
@@ -155,39 +154,40 @@ float WarpZoneLib_BoxTouchesBrush(vector mi, vector ma, entity e, entity ig)
 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;
-       return world;
+               return NULL;
+       IL_EACH(g_warpzones, WarpZoneLib_BoxTouchesBrush(mi, ma, it, NULL),
+       {
+               return it;
+       });
+       return NULL;
 }
 
 void WarpZone_MakeAllSolid()
 {
-       entity e;
        if(!warpzone_warpzones_exist)
                return;
-       for(e = world; (e = find(e, classname, "trigger_warpzone")); )
-               e.solid = SOLID_BSP;
+       IL_EACH(g_warpzones, true,
+       {
+               it.solid = SOLID_BSP;
+       });
 }
 
 void WarpZone_MakeAllOther()
 {
-       entity e;
        if(!warpzone_warpzones_exist)
                return;
-       for(e = world; (e = find(e, classname, "trigger_warpzone")); )
-               e.solid = SOLID_TRIGGER;
+       IL_EACH(g_warpzones, true,
+       {
+               it.solid = SOLID_TRIGGER;
+       });
 }
 
 void WarpZone_Trace_InitTransform()
 {
        if(!WarpZone_trace_transform)
        {
-               WarpZone_trace_transform = new(warpzone_trace_transform);
-               make_pure(WarpZone_trace_transform);
+               WarpZone_trace_transform = new_pure(warpzone_trace_transform);
        }
        WarpZone_Accumulator_Clear(WarpZone_trace_transform);
 }
@@ -206,8 +206,8 @@ void WarpZone_TraceBox_ThroughZone(vector org, vector mi, vector ma, vector end,
        vector vf, vr, vu;
 
        WarpZone_trace_forent = forent;
-       WarpZone_trace_firstzone = world;
-       WarpZone_trace_lastzone = world;
+       WarpZone_trace_firstzone = NULL;
+       WarpZone_trace_lastzone = NULL;
        WarpZone_Trace_InitTransform();
        if(!warpzone_warpzones_exist)
        {
@@ -273,8 +273,8 @@ void WarpZone_TraceBox_ThroughZone(vector org, vector mi, vector ma, vector end,
        {
                if(--i < 1)
                {
-                       LOG_TRACE("Too many warpzones in sequence, aborting trace.\n");
-                       trace_ent = world;
+                       LOG_TRACE("Too many warpzones in sequence, aborting trace.");
+                       trace_ent = NULL;
                        break;
                }
                tracebox(org, mi, ma, end, nomonsters_adjusted, WarpZone_trace_forent);
@@ -298,13 +298,13 @@ void WarpZone_TraceBox_ThroughZone(vector org, vector mi, vector ma, vector end,
                        }
                        break;
                }
-               if(trace_ent == wz)
+               /*if(trace_ent == wz)
                {
                        // FIXME can this check be removed? Do we really need it?
-                       LOG_TRACE("I transformed into the same zone again, wtf, aborting the trace\n");
-                       trace_ent = world;
+                       LOG_TRACE("I transformed into the same zone again, wtf, aborting the trace");
+                       trace_ent = NULL;
                        break;
-               }
+               }*/
                wz = trace_ent;
                if(!WarpZone_trace_firstzone)
                        WarpZone_trace_firstzone = wz;
@@ -321,7 +321,7 @@ void WarpZone_TraceBox_ThroughZone(vector org, vector mi, vector ma, vector end,
                org = trace_endpos;
        }
        WarpZone_MakeAllOther();
-:fail
+LABEL(fail)
        if(contentshack)
                BITCLR_ASSIGN(WarpZone_trace_forent.dphitcontentsmask, DPCONTENTS_SOLID);
        trace_startsolid = sol;
@@ -332,7 +332,7 @@ void WarpZone_TraceBox_ThroughZone(vector org, vector mi, vector ma, vector end,
 
 void WarpZone_TraceBox(vector org, vector mi, vector ma, vector end, float nomonsters, entity forent)
 {
-       WarpZone_TraceBox_ThroughZone(org, mi, ma, end, nomonsters, forent, world, WarpZone_trace_callback_t_null);
+       WarpZone_TraceBox_ThroughZone(org, mi, ma, end, nomonsters, forent, NULL, WarpZone_trace_callback_t_null);
 }
 
 void WarpZone_TraceLine(vector org, vector end, float nomonsters, entity forent)
@@ -351,8 +351,8 @@ void WarpZone_TraceToss_ThroughZone(entity e, entity forent, entity zone, WarpZo
        g = cvar("sv_gravity") * e.gravity;
 
        WarpZone_trace_forent = forent;
-       WarpZone_trace_firstzone = world;
-       WarpZone_trace_lastzone = world;
+       WarpZone_trace_firstzone = NULL;
+       WarpZone_trace_lastzone = NULL;
        WarpZone_Trace_InitTransform();
        WarpZone_tracetoss_time = 0;
        if(!warpzone_warpzones_exist)
@@ -397,8 +397,8 @@ void WarpZone_TraceToss_ThroughZone(entity e, entity forent, entity zone, WarpZo
        {
                if(--i < 1)
                {
-                       LOG_TRACE("Too many warpzones in sequence, aborting trace.\n");
-                       trace_ent = world;
+                       LOG_TRACE("Too many warpzones in sequence, aborting trace.");
+                       trace_ent = NULL;
                        break;
                }
                tracetoss(e, WarpZone_trace_forent);
@@ -415,8 +415,8 @@ void WarpZone_TraceToss_ThroughZone(entity e, entity forent, entity zone, WarpZo
                if(trace_ent == wz)
                {
                        // FIXME can this check be removed? Do we really need it?
-                       LOG_TRACE("I transformed into the same zone again, wtf, aborting the trace\n");
-                       trace_ent = world;
+                       LOG_TRACE("I transformed into the same zone again, wtf, aborting the trace");
+                       trace_ent = NULL;
                        break;
                }
                wz = trace_ent;
@@ -439,7 +439,7 @@ void WarpZone_TraceToss_ThroughZone(entity e, entity forent, entity zone, WarpZo
                e.velocity = -e.velocity;
        }
        WarpZone_MakeAllOther();
-:fail
+LABEL(fail)
        WarpZone_tracetoss_velocity = e.velocity;
        v_forward = vf;
        v_right = vr;
@@ -451,7 +451,7 @@ void WarpZone_TraceToss_ThroughZone(entity e, entity forent, entity zone, WarpZo
 
 void WarpZone_TraceToss(entity e, entity forent)
 {
-       WarpZone_TraceToss_ThroughZone(e, forent, world, WarpZone_trace_callback_t_null);
+       WarpZone_TraceToss_ThroughZone(e, forent, NULL, WarpZone_trace_callback_t_null);
 }
 
 entity WarpZone_TrailParticles_trace_callback_own;
@@ -465,7 +465,7 @@ void WarpZone_TrailParticles(entity own, float eff, vector org, vector end)
 {
        WarpZone_TrailParticles_trace_callback_own = own;
        WarpZone_TrailParticles_trace_callback_eff = eff;
-       WarpZone_TraceBox_ThroughZone(org, '0 0 0', '0 0 0', end, MOVE_NOMONSTERS, world, world, WarpZone_TrailParticles_trace_callback);
+       WarpZone_TraceBox_ThroughZone(org, '0 0 0', '0 0 0', end, MOVE_NOMONSTERS, NULL, NULL, WarpZone_TrailParticles_trace_callback);
 }
 
 #ifdef CSQC
@@ -482,7 +482,7 @@ void WarpZone_TrailParticles_WithMultiplier(entity own, float eff, vector org, v
        WarpZone_TrailParticles_trace_callback_eff = eff;
        WarpZone_TrailParticles_trace_callback_f = f;
        WarpZone_TrailParticles_trace_callback_flags = boxflags | PARTICLES_DRAWASTRAIL;
-       WarpZone_TraceBox_ThroughZone(org, '0 0 0', '0 0 0', end, MOVE_NOMONSTERS, world, world, WarpZone_TrailParticles_WithMultiplier_trace_callback);
+       WarpZone_TraceBox_ThroughZone(org, '0 0 0', '0 0 0', end, MOVE_NOMONSTERS, NULL, NULL, WarpZone_TrailParticles_WithMultiplier_trace_callback);
 }
 #endif
 
@@ -573,8 +573,8 @@ vector WarpZoneLib_NearestPointOnBox(vector mi, vector ma, vector org)
 
 bool WarpZoneLib_BadEntity(entity e)
 {
-       string s = e.classname;
        if (is_pure(e)) return true;
+       string s = e.classname;
        switch (s)
        {
                // case "net_linked": // actually some real entities are linked without classname, fail
@@ -591,68 +591,62 @@ bool WarpZoneLib_BadEntity(entity e)
 
 .float WarpZone_findradius_hit;
 .entity WarpZone_findradius_next;
-void WarpZone_FindRadius_Recurse(vector org, float rad,        vector org0,               vector transform, vector shift, float needlineofsight)
-//                               blast origin of current search   original blast origin   how to untransform (victim to blast system)
-{
-       vector org_new;
-       vector org0_new;
-       vector shift_new, transform_new;
-       vector p;
-       entity e, e0;
-       entity wz;
-       if(rad <= 0)
-               return;
-       e0 = findradius(org, rad);
-       wz = world;
-
-       for(e = e0; e; e = e.chain)
-       {
-               if(WarpZoneLib_BadEntity(e))
-                       continue;
-               p = WarpZoneLib_NearestPointOnBox(e.origin + e.mins, e.origin + e.maxs, org0);
-               if(needlineofsight)
+void WarpZone_FindRadius_Recurse(
+    /** blast origin of current search */
+    vector org,
+    float rad,
+    /** original blast origin */
+    vector org0,
+    /** how to untransform (victim to blast system) */
+    vector transform,
+    vector shift,
+    bool needlineofsight)
+{
+       if (rad <= 0) return;
+       entity wz = NULL;
+       FOREACH_ENTITY_RADIUS(org, rad, !WarpZoneLib_BadEntity(it), {
+               vector p = WarpZoneLib_NearestPointOnBox(it.origin + it.mins, it.origin + it.maxs, org0);
+               if (needlineofsight)
                {
-                       traceline(org, p, MOVE_NOMONSTERS, e);
-                       if(trace_fraction < 1)
-                               continue;
+                       traceline(org, p, MOVE_NOMONSTERS, it);
+                       if (trace_fraction < 1) continue;
                }
-               if(!e.WarpZone_findradius_hit || vlen2(e.WarpZone_findradius_dist) > vlen2(org0 - p))
+               if (!it.WarpZone_findradius_hit || vlen2(it.WarpZone_findradius_dist) > vlen2(org0 - p))
                {
-                       e.WarpZone_findradius_nearest = p;
-                       e.WarpZone_findradius_dist = org0 - p;
-                       e.WarpZone_findradius_findorigin = org;
-                       e.WarpZone_findradius_findradius = rad;
-                       if(e.classname == "warpzone_refsys")
+                       it.WarpZone_findradius_nearest = p;
+                       it.WarpZone_findradius_dist = org0 - p;
+                       it.WarpZone_findradius_findorigin = org;
+                       it.WarpZone_findradius_findradius = rad;
+                       if (it.classname == "warpzone_refsys")
                        {
                                // ignore, especially: do not overwrite the refsys parameters
                        }
-                       else if(e.classname == "trigger_warpzone")
+                       else if (it.classname == "trigger_warpzone")
                        {
-                               e.WarpZone_findradius_next = wz;
-                               wz = e;
-                               e.WarpZone_findradius_hit = 1;
-                               e.enemy.WarpZone_findradius_dist = '0 0 0'; // we don't want to go through this zone ever again
-                               e.enemy.WarpZone_findradius_hit = 1;
+                               it.WarpZone_findradius_next = wz;
+                               wz = it;
+                               it.WarpZone_findradius_hit = 1;
+                               it.enemy.WarpZone_findradius_dist = '0 0 0'; // we don't want to go through this zone ever again
+                               it.enemy.WarpZone_findradius_hit = 1;
                        }
                        else
                        {
-                               e.warpzone_transform = transform;
-                               e.warpzone_shift = shift;
-                               e.WarpZone_findradius_hit = 1;
+                               it.warpzone_transform = transform;
+                               it.warpzone_shift = shift;
+                               it.WarpZone_findradius_hit = 1;
                        }
                }
-       }
-       for(e = wz; e; e = e.WarpZone_findradius_next)
+    });
+       for(entity e = wz; e; e = e.WarpZone_findradius_next)
        {
-               if(WarpZoneLib_BadEntity(e))
-                       continue;
+               if (WarpZoneLib_BadEntity(e)) continue;
 
-               org0_new = WarpZone_TransformOrigin(e, org);
+               vector org0_new = WarpZone_TransformOrigin(e, org);
                traceline(e.warpzone_targetorigin, org0_new, MOVE_NOMONSTERS, e);
-               org_new = trace_endpos;
+               vector org_new = trace_endpos;
 
-               transform_new = AnglesTransform_Multiply(e.warpzone_transform, transform);
-               shift_new = AnglesTransform_Multiply_GetPostShift(e.warpzone_transform, e.warpzone_shift, transform, shift);
+               vector transform_new = AnglesTransform_Multiply(e.warpzone_transform, transform);
+               vector shift_new = AnglesTransform_Multiply_GetPostShift(e.warpzone_transform, e.warpzone_shift, transform, shift);
                WarpZone_FindRadius_Recurse(
                        org_new,
                        bound(0, rad - vlen(org_new - org0_new), rad - 8),
@@ -663,23 +657,23 @@ void WarpZone_FindRadius_Recurse(vector org, float rad,        vector org0,
                e.enemy.WarpZone_findradius_hit = 0;
        }
 }
-entity WarpZone_FindRadius(vector org, float rad, float needlineofsight)
+entity WarpZone_FindRadius(vector org, float rad, bool needlineofsight)
 {
-       entity e0, e;
+    // FIXME: why can't we do this? (sometimes finds nothing, breaking explosions)
+    // if (!warpzone_warpzones_exist && !needlineofsight) return findradius(org, rad);
        WarpZone_FindRadius_Recurse(org, rad, org, '0 0 0', '0 0 0', needlineofsight);
-       e0 = findchainfloat(WarpZone_findradius_hit, 1);
-       for(e = e0; e; e = e.chain)
-               e.WarpZone_findradius_hit = 0;
-       return e0;
+       entity list_first = findchainfloat(WarpZone_findradius_hit, 1);
+       FOREACH_LIST(list, chain, true, it.WarpZone_findradius_hit = 0);
+       return list_first;
 }
 
 .entity WarpZone_refsys;
-void WarpZone_RefSys_GC()
-{SELFPARAM();
+void WarpZone_RefSys_GC(entity this)
+{
        // garbage collect unused reference systems
-       self.nextthink = time + 1;
-       if(self.owner.WarpZone_refsys != self)
-               remove(self);
+       this.nextthink = time + 1;
+       if(this.owner.WarpZone_refsys != this)
+               delete(this);
 }
 void WarpZone_RefSys_CheckCreate(entity me)
 {
@@ -687,7 +681,7 @@ void WarpZone_RefSys_CheckCreate(entity me)
        {
                me.WarpZone_refsys = new(warpzone_refsys);
                me.WarpZone_refsys.owner = me;
-               me.WarpZone_refsys.think = WarpZone_RefSys_GC;
+               setthink(me.WarpZone_refsys, WarpZone_RefSys_GC);
                me.WarpZone_refsys.nextthink = time + 1;
                WarpZone_Accumulator_Clear(me.WarpZone_refsys);
        }
@@ -696,8 +690,8 @@ void WarpZone_RefSys_Clear(entity me)
 {
        if(me.WarpZone_refsys)
        {
-               remove(me.WarpZone_refsys);
-               me.WarpZone_refsys = world;
+               delete(me.WarpZone_refsys);
+               me.WarpZone_refsys = NULL;
        }
 }
 void WarpZone_RefSys_AddTransform(entity me, vector t, vector s)
@@ -793,9 +787,9 @@ entity WarpZone_RefSys_SpawnSameRefSys(entity me)
        return e;
 }
 
-float WarpZoneLib_ExactTrigger_Touch()
-{SELFPARAM();
-       return !WarpZoneLib_BoxTouchesBrush(other.absmin, other.absmax, self, other);
+float WarpZoneLib_ExactTrigger_Touch(entity this, entity toucher)
+{
+       return !WarpZoneLib_BoxTouchesBrush(toucher.absmin, toucher.absmax, this, toucher);
 }
 
 
@@ -809,7 +803,7 @@ void WarpZoneLib_MoveOutOfSolid_Expand(entity e, vector by)
        {
                // hit something
                // adjust origin in the other direction...
-               setorigin(e,e.origin - by * (1 - trace_fraction));
+               setorigin(e, e.origin - by * (1 - trace_fraction));
        }
 }