Finding Elevator Tops and Bottoms

Title: Finding FuncPlat Tops and Bottoms
Difficulty: Fairly Difficult
By: Maj.Bitch
Email: peblair@frontier.net
Date: 10-02-99
Note: Please give credit where credit is due.
======================================================
In furtherance of the pathing stuff, it is important to
be able to define the start and stop points (visible)
of any of the func_plats or buttons in the level. I've
put together the following functionality which accomplishes
this. What you end up with (when displaying the pos1 and
pos2 vectors) is a particle entity at the visible bottom
of the func plat and at the visible top of the func plat.
NOTE that buttons have pos1=pos2 and the particles are
displayed right outside the touching part if the button
entity.

Here is the source.

=========================================================

<c code>
int numfuncs=0;

typedef struct {
  int    type;  // CONTENTS_BUTTON, CONTENTS_FUNC
  vec3_t pos1;  // location of TouchPlatCenter start
  vec3_t pos2;  // location of final plat end position
} func_t;

func_t *func;

#define CONTENTS_BUTTON  4
#define CONTENTS_FUNC   64

//========================================================
// Make a call to this from the top of ClientThink
//========================================================
void SplashFuncs(void) {
int i;
  for (i=0;i<numfuncs;i++) {
    G_Spawn_Splash(TE_LASER_SPARKS, 8, 0xd0d1d2d3, func[i].pos1, zvec, func[i].pos1);
    if (func[i].type==CONTENTS_BUTTON) continue;
    G_Spawn_Splash(TE_LASER_SPARKS, 8, 0xd0d1d2d3, func[i].pos2, zvec, func[i].pos2); }
}

//=====================================================
// Add all func_plats and func_buttons to func[] array
//=====================================================
void SetFuncTable(void) {
edict_t *ent;
int k=0;

  numfuncs=0;
  // How many func_t structs are we going to have to allocate?
  for (ent=&g_edicts[0]; ent<&g_edicts[globals.num_edicts]; ent++)
    if (ent && !ent->client && !ent->item && ent->touch)
      numfuncs++;

  // Allocate all the structs we'll need...
  func=(func_t *)gi.TagMalloc(numfuncs*sizeof(func_t),TAG_LEVEL);

  // Grab specific ents and calculate pos1 and pos1 for each one.
  for (ent=&g_edicts[0]; ent<&g_edicts[globals.num_edicts]; ent++)
    if (ent && !ent->client && !ent->item && ent->touch) {
      VectorAdd(ent->absmin,ent->absmax,func[k].pos1);
      VectorScale(func[k].pos1,0.5,func[k].pos1);
      func[k].pos1[2]+=16; // Raise it up a bit
      while (!(gi.pointcontents(func[k].pos1) & CONTENTS_SOLID))
         func[k].pos1[2]-=4; // Work your way downward
      func[k].pos1[2]+=20; // Now, reposition it up again
      VectorCopy(func[k].pos1,func[k].pos2); // pos1=pos2 for buttons
      func[k].type=(ent->use==button_use)?CONTENTSBUTTONCONTENTS_FUNC;
      if (func[k].type==CONTENTS_FUNC)
        func[k].pos2[2]+=abs(ent->enemy->absmax[2]-ent->enemy->absmin[2]);
      k++; }

  gi.dprintf("%d touch entities spawned\n",numfuncs);
}
</c code>
We want to be able to grab all of this information before any of the players
actually join the game. Make a call to SetFuncTable() at the very bottom
of your SpawnEntities() function and, immediately after all the entities are
spawned into the game upon startup, we'll determine which are the ones we
are interested in and grab them right away. A message will be displayed to the
console as to the number of touch entities which have been found. Then we ADD
these new pos1 and pos2 node locations to our node[] array for A*..

The reason for the two nodes is this: Say, for example, that the A* algorithm is
working its way merrily along on a lower level. It works its way over to the
node at bottom of the elevator platform (valid node). It adds this node to the OPEN
array for later searching. When it searches from this node upward, the next node
will be the one at the top of the func plat which it'll add for later searching
because its valid. From the node at the top of the func plat it'll start searching
from there!! This way, it can find valid paths UP and DOWN elevators! And it can
colorcode the node as some kind of PAUSE action or FREEZE action so that the bot
doesn't move while at this node location (bottom one) but moves when it gets to
the top node so it can get off the elevator and continue to the next valid node.

Maj.Bitch