The mysterious engine killing teleporter
-
- Posts: 399
- Joined: Thu May 15, 2008 10:46 pm
- Location: its a secret
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
We knew the words, we knew the score, we knew what we were fighting for
I cursed like a pirate simply trying to get to that teleport, but porting mh's code above to makaqu (plus Q_malloc)
NOTE- this is not tested except for this specific case, and it didn't seem to break standard teleports in a quick run-through.
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;
}
}
}