// (3.5, [0.2..2.3])
// (4, 1)
}
+
+.float FindConnectedComponent_processing;
+void FindConnectedComponent(entity e, .entity fld, findNextEntityNearFunction_t nxt, isConnectedFunction_t iscon, entity pass)
+{
+ entity queue_start, queue_end;
+
+ // we build a queue of to-be-processed entities.
+ // queue_start is the next entity to be checked for neighbors
+ // queue_end is the last entity added
+
+ if(e.FindConnectedComponent_processing)
+ error("recursion or broken cleanup");
+
+ // start with a 1-element queue
+ queue_start = queue_end = e;
+ queue_end.fld = world;
+ queue_end.FindConnectedComponent_processing = 1;
+
+ // for each queued item:
+ for(; queue_start; queue_start = queue_start.fld)
+ {
+ // find all neighbors of queue_start
+ entity t;
+ for(t = world; (t = nxt(t, queue_start, pass)); )
+ {
+ if(t.FindConnectedComponent_processing)
+ continue;
+ if(iscon(t, queue_start, pass))
+ {
+ // it is connected? ADD IT. It will look for neighbors soon too.
+ queue_end.fld = t;
+ queue_end = t;
+ queue_end.fld = world;
+ queue_end.FindConnectedComponent_processing = 1;
+ }
+ }
+ }
+
+ // unmark
+ for(queue_start = e; queue_start; queue_start = queue_start.fld)
+ queue_start.FindConnectedComponent_processing = 0;
+}
}
-float EntitiesTouching(entity e1, entity e2)
+entity LinkDoors_nextent(entity cur, entity near, entity pass)
{
- if (e1.absmin_x > e2.absmax_x)
+ while((cur = find(cur, classname, self.classname)) && ((cur.spawnflags & 4) || cur.enemy))
+ {
+ }
+ return cur;
+}
+
+float LinkDoors_isconnected(entity e1, entity e2, entity pass)
+{
+ float DELTA = 4;
+ if (e1.absmin_x > e2.absmax_x + DELTA)
return FALSE;
- if (e1.absmin_y > e2.absmax_y)
+ if (e1.absmin_y > e2.absmax_y + DELTA)
return FALSE;
- if (e1.absmin_z > e2.absmax_z)
+ if (e1.absmin_z > e2.absmax_z + DELTA)
return FALSE;
- if (e1.absmax_x < e2.absmin_x)
+ if (e2.absmin_x > e1.absmax_x + DELTA)
return FALSE;
- if (e1.absmax_y < e2.absmin_y)
+ if (e2.absmin_y > e1.absmax_y + DELTA)
return FALSE;
- if (e1.absmax_z < e2.absmin_z)
+ if (e2.absmin_z > e1.absmax_z + DELTA)
return FALSE;
return TRUE;
}
-
/*
=============
LinkDoors
*/
void LinkDoors()
{
- entity t, starte;
+ entity t;
vector cmins, cmaxs;
if (self.enemy)
return; // don't want to link this door
}
- cmins = self.absmin;
- cmaxs = self.absmax;
-
- starte = self;
- t = self;
+ FindConnectedComponent(self, enemy, LinkDoors_nextent, LinkDoors_isconnected, world);
- do
+ // set owner, and make a loop of the chain
+ dprint("LinkDoors: linking doors:");
+ for(t = self; ; t = t.enemy)
{
- self.owner = starte; // master door
-
- if (self.health)
- starte.health = self.health;
- IFTARGETED
- starte.targetname = self.targetname;
- if (self.message != "")
- starte.message = self.message;
-
- t = find(t, classname, self.classname);
- if (!t)
+ dprint(" ", etos(t));
+ t.owner = self;
+ if(t.enemy == world)
{
- self.enemy = starte; // make the chain a loop
-
- // shootable, or triggered doors just needed the owner/enemy links,
- // they don't spawn a field
-
- self = self.owner;
+ t.enemy = self;
+ break;
+ }
+ }
+ dprint("\n");
- if (self.health)
- return;
- IFTARGETED
- return;
- if (self.items)
- return;
+ // collect health, targetname, message, size
+ cmins = self.absmin;
+ cmaxs = self.absmax;
+ for(t = self; ; t = t.enemy)
+ {
+ if(t.health && !self.health)
+ self.health = t.health;
+ if(t.targetname && !self.targetname)
+ self.targetname = t.targetname;
+ if(t.message != "" && self.message == "")
+ self.message = t.message;
+ if (t.absmin_x < cmins_x)
+ cmins_x = t.absmin_x;
+ if (t.absmin_y < cmins_y)
+ cmins_y = t.absmin_y;
+ if (t.absmin_z < cmins_z)
+ cmins_z = t.absmin_z;
+ if (t.absmax_x > cmaxs_x)
+ cmaxs_x = t.absmax_x;
+ if (t.absmax_y > cmaxs_y)
+ cmaxs_y = t.absmax_y;
+ if (t.absmax_z > cmaxs_z)
+ cmaxs_z = t.absmax_z;
+ if(t.enemy == self)
+ break;
+ }
- self.owner.trigger_field = spawn_field(cmins, cmaxs);
+ // distribute health, targetname, message
+ for(t = self; t; t = t.enemy)
+ {
+ t.health = self.health;
+ t.targetname = self.targetname;
+ t.message = self.message;
+ if(t.enemy == self)
+ break;
+ }
- return;
- }
+ // shootable, or triggered doors just needed the owner/enemy links,
+ // they don't spawn a field
- if (EntitiesTouching(self,t))
- {
- if (t.enemy)
- objerror ("cross connected doors");
-
- self.enemy = t;
- self = t;
-
- if (t.absmin_x < cmins_x)
- cmins_x = t.absmin_x;
- if (t.absmin_y < cmins_y)
- cmins_y = t.absmin_y;
- if (t.absmin_z < cmins_z)
- cmins_z = t.absmin_z;
- if (t.absmax_x > cmaxs_x)
- cmaxs_x = t.absmax_x;
- if (t.absmax_y > cmaxs_y)
- cmaxs_y = t.absmax_y;
- if (t.absmax_z > cmaxs_z)
- cmaxs_z = t.absmax_z;
- }
- } while (1 );
+ if (self.health)
+ return;
+ IFTARGETED
+ return;
+ if (self.items)
+ return;
+ self.trigger_field = spawn_field(cmins, cmaxs);
}