.entity enemy;
-vector WarpZoneLib_BoxTouchesBrush_mins;
-vector WarpZoneLib_BoxTouchesBrush_maxs;
-entity WarpZoneLib_BoxTouchesBrush_ent;
-entity WarpZoneLib_BoxTouchesBrush_ignore;
-float WarpZoneLib_BoxTouchesBrush_Recurse()
+float WarpZoneLib_BoxTouchesBrush_Recurse(vector mi, vector ma, entity e, entity ig)
{
- float s;
+ float f, s;
entity se;
- float f;
- tracebox('0 0 0', WarpZoneLib_BoxTouchesBrush_mins, WarpZoneLib_BoxTouchesBrush_maxs, '0 0 0', MOVE_NOMONSTERS, WarpZoneLib_BoxTouchesBrush_ignore);
+ tracebox('0 0 0', mi, ma, '0 0 0', MOVE_NOMONSTERS, ig);
#ifdef CSQC
if (trace_networkentity)
{
#endif
if (!trace_ent)
return 0;
- if (trace_ent == WarpZoneLib_BoxTouchesBrush_ent)
+ if (trace_ent == e)
return 1;
se = trace_ent;
s = se.solid;
se.solid = SOLID_NOT;
- f = WarpZoneLib_BoxTouchesBrush_Recurse();
+ setorigin(se, se.origin); // unlink
+ f = WarpZoneLib_BoxTouchesBrush_Recurse(mi, ma, e, ig);
se.solid = s;
+ setorigin(se, se.origin); // relink
return f;
}
float WarpZoneLib_BoxTouchesBrush(vector mi, vector ma, entity e, entity ig)
{
- float f, s;
+ // bones_was_here: TODO: when findbox() builtin is available, use it to
+ // optimise this into a single non-recursive function that only calls tracebox once
- if(!e.modelindex || e.warpzone_isboxy)
- return 1;
+ float f, s;
- s = e.solid;
- e.solid = SOLID_BSP;
- WarpZoneLib_BoxTouchesBrush_mins = mi;
- WarpZoneLib_BoxTouchesBrush_maxs = ma;
- WarpZoneLib_BoxTouchesBrush_ent = e;
- WarpZoneLib_BoxTouchesBrush_ignore = ig;
- f = WarpZoneLib_BoxTouchesBrush_Recurse();
- e.solid = s;
+ if(!e.modelindex || e.warpzone_isboxy)
+ return 1;
+
+ // work around trigger_hurt on geit3ctf1 not being detected by tracebox
+ // bones_was_here: FIXME: WHY do these triggers only have supercontents == 128 ?!
+ if (Q3COMPAT_COMMON && ig != world)
+ ig.dphitcontentsmask |= 128;
+
+ s = e.solid;
+ if (e.solid != SOLID_BSP)
+ {
+ e.solid = SOLID_BSP;
+ setorigin(e, e.origin); // update linking
+ }
+ f = WarpZoneLib_BoxTouchesBrush_Recurse(mi, ma, e, ig);
+ if (e.solid != s) // if we needed to change .solid temporarily
+ {
+ e.solid = s; // restore it
+ setorigin(e, e.origin); // update linking
+ }
- return f;
+ if (Q3COMPAT_COMMON && ig != world)
+ ig.dphitcontentsmask &= ~128;
+
+ return f;
}
entity WarpZone_Find(vector mi, vector ma)
case "weaponentity":
case "exteriorweaponentity":
case "sprite_waypoint":
+ case "waypoint":
case "spawnfunc":
case "weaponchild":
case "chatbubbleentity":
return e;
}
-bool WarpZoneLib_ExactTrigger_Touch(entity this, entity toucher)
+bool WarpZoneLib_ExactTrigger_Touch(entity this, entity toucher, bool touchfunc)
{
vector emin = toucher.absmin, emax = toucher.absmax;
- if(STAT(Q3COMPAT))
+ if (!Q3COMPAT_COMMON)
{
- // DP's tracebox enlarges absolute bounding boxes by a single quake unit
- // we must undo that here to allow accurate touching
- emin += '1 1 1';
- emax -= '1 1 1';
+ // Xonotic and Nexuiz maps assume triggers will be activated by adjacent players
+ // prior to sv_legacy_bbox_expand 0 DP always did this for SVQC and never for CSQC
+ emin -= '1 1 1';
+ emax += '1 1 1';
}
- return !WarpZoneLib_BoxTouchesBrush(emin, emax, this, toucher);
+
+ // if called from a touch func, we can assume the boxes do overlap
+ if (!touchfunc && !boxesoverlap(emin, emax, this.absmin, this.absmax)) // quick
+ return false;
+
+ return WarpZoneLib_BoxTouchesBrush(emin, emax, this, toucher); // accurate
}
}
}
-bool WarpZoneLib_MoveOutOfSolid(entity e)
+int WarpZoneLib_MoveOutOfSolid(entity e)
{
vector o = e.origin;
traceline(o, o, MOVE_WORLDONLY, e);
if (trace_startsolid)
- return false;
+ return 0; // too stuck, giving up
tracebox(o, e.mins, e.maxs, o, MOVE_WORLDONLY, e);
if (!trace_startsolid)
- return true;
+ return -1; // wasn't stuck
vector m0 = e.mins;
vector m1 = e.maxs;
if (trace_startsolid)
{
setorigin(e, o);
- return false;
+ return 0; // can't fix
}
- return true;
+ return 1; // was stuck but is fixed now
}