The mysterious engine killing teleporter

Discuss programming topics for the various GPL'd game engine sources.
metlslime
Posts: 316
Joined: Tue Feb 05, 2008 11:03 pm

Post by metlslime »

note, tyr-glquake does not break on White Room, so Tyrann must have more to his fix than the code snippet from above.
MeTcHsteekle
Posts: 399
Joined: Thu May 15, 2008 10:46 pm
Location: its a secret

Post by MeTcHsteekle »

metlslime wrote: So I guess the more robust method of FTE and DP is the way to go.
Damn, the tough way around eh?
bah
mh
Posts: 2292
Joined: Sat Jan 12, 2008 1:38 am

Post by mh »

Here's the more robust version as it's currently coded in DirectQ. Any other engine's allocators are going to be different of course, and the C++ stuff won't be usable, but it should nonetheless be straightforward to port.

Code: Select all

void SV_TouchLinks (edict_t *ent, areanode_t *node)
{
	link_t	       *l, *next;
	edict_t	       *touch;
	int	       old_self, old_other, touched = 0, i;

	// Static due to recursive function
	static edict_t **list = NULL;

	if (!list)
	{
		// alloc first time (to keep it off the stack - 256K - ouch!)
		list = (edict_t **) Pool_Permanent->Alloc (MAX_EDICTS * sizeof (edict_t *));
	}

loc0:;
	// ensure
	touched = 0;

	// Build a list of touched edicts since linked list may change during touch
	for (l = node->trigger_edicts.next; l != &node->trigger_edicts; l = l->next)
	{
		touch = EDICT_FROM_AREA(l);

		if (touch == ent) continue;
		if (touch->free) continue;
		if (!touch->v.touch || touch->v.solid != SOLID_TRIGGER) continue;

		if (ent->v.absmin[0] > touch->v.absmax[0] || ent->v.absmin[1] > touch->v.absmax[1] || ent->v.absmin[2] > touch->v.absmax[2] ||
			ent->v.absmax[0] < touch->v.absmin[0] || ent->v.absmax[1] < touch->v.absmin[1] || ent->v.absmax[2] < touch->v.absmin[2])
			continue;

		list[touched++] = touch;

		if (touched == MAX_EDICTS)
		{
			Con_DPrintf ("SV_TouchLinks: ");
			Con_DPrintf ("too many touched trigger_edicts (max = %d)\n", MAX_EDICTS);
			break;
		}
	}

	// touch linked edicts
	for (i = 0; i < touched; ++i)
	{
		int ednum;

		touch = list[i];

		ednum = GetNumberForEdict(touch);

		old_self = SVProgs->GlobalStruct->self;
		old_other = SVProgs->GlobalStruct->other;

		SVProgs->GlobalStruct->self = EDICT_TO_PROG(touch);
		SVProgs->GlobalStruct->other = EDICT_TO_PROG(ent);
		SVProgs->GlobalStruct->time = SV_TIME;
		SVProgs->ExecuteProgram (touch->v.touch);

		SVProgs->GlobalStruct->self = old_self;
		SVProgs->GlobalStruct->other = old_other;
	}

	// recurse down both sides
	if (node->axis == -1)
		return;

	if (ent->v.absmax[node->axis] > node->dist)
	{
		// order reversed to reduce code
		if (ent->v.absmin[node->axis] < node->dist) SV_TouchLinks(ent, node->children[1]);
		node = node->children[0];
		goto loc0;
	}
	else
	{
		if (ent->v.absmin[node->axis] < node->dist)
		{
			node = node->children[1];
			goto loc0;
		}
	}
}
We had the power, we had the space, we had a sense of time and place
We knew the words, we knew the score, we knew what we were fighting for
qbism
Posts: 1236
Joined: Thu Nov 04, 2004 5:51 am
Contact:

Post by qbism »

I cursed like a pirate simply trying to get to that teleport, but porting mh's code above to makaqu (plus Q_malloc)

Code: Select all

void SV_TouchLinks ( edict_t *ent, areanode_t *node )
{
	link_t		*l, *next;
	edict_t		*touch;
	int			old_self, old_other, touched = 0, i; 

   // Static due to recursive function
   static edict_t **list = NULL;

   if (!list)
   {
      // alloc first time (to keep it off the stack - 256K - ouch!)
      list = (edict_t **) Q_malloc (MAX_EDICTS * sizeof (edict_t *));
   }
loc0:;
   // ensure
   touched = 0;

   // Build a list of touched edicts since linked list may change during touch
   for (l = node->trigger_edicts.next; l != &node->trigger_edicts; l = l->next)
   {
      touch = EDICT_FROM_AREA(l);

      if (touch == ent) continue;
      if (touch->free) continue;
      if (!touch->v.touch || touch->v.solid != SOLID_TRIGGER) continue;

      if (ent->v.absmin[0] > touch->v.absmax[0] || ent->v.absmin[1] > touch->v.absmax[1] || ent->v.absmin[2] > touch->v.absmax[2] ||
         ent->v.absmax[0] < touch->v.absmin[0] || ent->v.absmax[1] < touch->v.absmin[1] || ent->v.absmax[2] < touch->v.absmin[2])
         continue;

      list[touched++] = touch;

      if (touched == MAX_EDICTS)
      {
         Con_DPrintf ("SV_TouchLinks: ");
         Con_DPrintf ("too many touched trigger_edicts (max = %d)\n", MAX_EDICTS);
         break;
      }
   }

   // touch linked edicts
   for (i = 0; i < touched; ++i)
   {
      int ednum;

      touch = list[i];

      ednum = NUM_FOR_EDICT(touch);

 		old_self = pr_global_struct->self;
		old_other = pr_global_struct->other;

      pr_global_struct->self = EDICT_TO_PROG(touch);
      pr_global_struct->other = EDICT_TO_PROG(ent);
      pr_global_struct->time = sv.time;
      PR_ExecuteProgram (touch->v.touch);

      pr_global_struct->self = old_self;
      pr_global_struct->other = old_other;
   }

   // recurse down both sides
   if (node->axis == -1)
      return;

   if (ent->v.absmax[node->axis] > node->dist)
   {
      // order reversed to reduce code
      if (ent->v.absmin[node->axis] < node->dist) SV_TouchLinks(ent, node->children[1]);
      node = node->children[0];
      goto loc0;
   }
   else
   {
      if (ent->v.absmin[node->axis] < node->dist)
      {
         node = node->children[1];
         goto loc0;
      }
   }
}
NOTE- this is not tested except for this specific case, and it didn't seem to break standard teleports in a quick run-through.
Post Reply