/
Crimson2/alias/
Crimson2/area.tmp/
Crimson2/area.tmp/AnomalySpaceDock/
Crimson2/area.tmp/AnomalyStation/
Crimson2/area.tmp/AntHill/
Crimson2/area.tmp/ArcticTerrarium/
Crimson2/area.tmp/BuilderCity/
Crimson2/area.tmp/Dungeon/
Crimson2/area.tmp/MiningDock/
Crimson2/area.tmp/PipeSystem/
Crimson2/area.tmp/RattArea/
Crimson2/area.tmp/RobotFactory/
Crimson2/area.tmp/SilverDale/
Crimson2/area.tmp/StarshipFearless/
Crimson2/area.tmp/StationConduits/
Crimson2/area.tmp/TerrariumAlpha/
Crimson2/area.tmp/TerrariumBeta/
Crimson2/area.tmp/TestArea/
Crimson2/area.tmp/Void/
Crimson2/area/
Crimson2/area/AnomalySpaceDock/
Crimson2/area/AnomalyStation/
Crimson2/area/MiningDock/
Crimson2/area/PipeSystem/
Crimson2/area/SilverDale/
Crimson2/area/StationConduits/
Crimson2/area/Void/
Crimson2/board/
Crimson2/clone/
Crimson2/lib/
Crimson2/mole/
Crimson2/mole/mole_src/HELP/
Crimson2/player/
Crimson2/util/
Crimson2/wldedit/
Crimson2/wldedit/res/
/* Crimson2 Mud Server
 * All source written/copyright Ryan Haksi 1995 *
 * This source code is proprietary. Use in whole or in part without
 * explicity permission by the author is strictly prohibited
 *
 * Current email address(es): cryogen@infoserve.net
 * Phone number: (604) 591-5295
 *
 * C4 Script Language written/copyright Cam Lesiuk 1995
 * Email: clesiuk@engr.uvic.ca
 */

/* exit.c */ #include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "crimson2.h"
#include "macro.h"
#include "log.h"
#include "mem.h"
#include "str.h"
#include "index.h"
#include "extra.h"
#include "thing.h"
#include "exit.h"
#include "world.h"

#define EXIT_BLOCK_SIZE 4096

LWORD exitNum = 0;

BYTE *dirList[] = {
  "north",
  "east",
  "south",
  "west",
  "up",
  "down",
  "out",
  "undefined",
  ""
};

/* the order in which exits will be listed */
LWORD eOrderList[] = {
  EDIR_WEST,
  EDIR_NORTH,
  EDIR_SOUTH,
  EDIR_EAST,
  EDIR_UP,
  EDIR_DOWN,
  EDIR_OUT,
  EDIR_UNDEFINED,
  EDIR_MAX
};

BYTE *eFlagList[] = {
  "ISDOOR",
  "PICKPROOF",
  "LOCKED",
  "CLOSED",
  "HIDDEN",
  "ELECTRONIC",
  "NOPHASE",
  ""
};

BYTE reverseDirList[] = {
  EDIR_SOUTH,
  EDIR_WEST,
  EDIR_NORTH,
  EDIR_EAST,
  EDIR_DOWN,
  EDIR_UP,
  EDIR_UNDEFINED,
  EDIR_UNDEFINED
};

EXIT *ExitAlloc(EXIT *eNext, BYTE eDir, STR *eKey, STR *eDesc, FLAG eFlag, WORD eKeyObj, THING *eWorld) {
  EXIT *exit;

  MEMALLOC(exit, EXIT, EXIT_BLOCK_SIZE);
  exit->eNext = eNext;
  exit->eDir  = eDir;
  exit->eKey  = eKey;
  exit->eDesc = eDesc;
  exit->eFlag = eFlag;
  exit->eKeyObj=eKeyObj;
  exit->eWorld= eWorld;

  exitNum++;
  return exit;
}

EXIT *ExitCreate(EXIT *eNext, BYTE eDir, BYTE *eKey, BYTE *eDesc, FLAG eFlag, WORD eKeyObj, THING *eWorld) {
  STR *sKey;
  STR *sDesc;

  /* Check to see if an exit in this direction already exists */
  if (ExitDir(eNext,eDir))
    return NULL;

  sKey = STRCREATE(eKey);
  sDesc = STRCREATE(eDesc);
  return ExitAlloc(eNext, eDir, sKey, sDesc, eFlag, eKeyObj, eWorld);
}


EXIT *ExitFind(EXIT *eList, BYTE *eKey) {
  EXIT *exit;
  LWORD i;

  if (!eKey) return NULL;
  exit = NULL;
  i = TYPEFIND(eKey, dirList);
  if (i != -1) {
    for (exit = eList; exit && (exit->eDir != i); exit = exit->eNext);
  }
  /* if we havent found a matching dir then search on keyword */
  if (exit==NULL) {
    for (exit = eList; exit && !StrIsKey(eKey, exit->eKey); exit = exit->eNext);
  }
  return exit; /* exit will be either the found exit or Null */
}

EXIT *ExitDir(EXIT *eList, BYTE eDir) {
  EXIT *exit;

  if (eDir == EDIR_UNDEFINED)
    return NULL;
  for (exit = eList; exit && (exit->eDir != eDir); exit = exit->eNext);
  return exit; /* exit will be either the found exit or Null */
}

/* Find the exit that points back to us */
EXIT *ExitReverse(THING *world, EXIT *exit) {
  EXIT *eList;
  EXIT *reverse = NULL;

  if (!exit) return NULL;
  if (!(exit->eWorld)) return NULL;

  /* look for the obvious choice - a return path back along the opposite direction */
  if (exit->eDir!=EDIR_UNDEFINED) { 
    eList = Wld(exit->eWorld)->wExit;
    reverse = ExitDir(eList, reverseDirList[exit->eDir]);
    if (reverse && reverse->eWorld == world)
      return reverse;
  }

  /* look for a return exit with a corner in it */
  for (reverse = eList; reverse && (reverse->eWorld != world); reverse = reverse->eNext);
  return reverse; /* exit will be either the found exit or Null */
}

/* this esoteric piece of code determines if there is a bend in a pair of exits
   ie if you leave north from one room and come in from the west into the destination
   we could reasonably assume that there is a corner in the way

   This is important since weapons cannot fire around corners!
*/
LWORD ExitIsCorner(EXIT *exit, EXIT *reverse) {
  if (exit && reverse) {
    if (exit->eDir == EDIR_UNDEFINED || reverse->eDir == EDIR_UNDEFINED)
      return TRUE;
    if (exit->eDir == reverseDirList[reverse->eDir])
      return TRUE;
  }
  return FALSE;
}

EXIT *ExitFree(EXIT *eList, EXIT *exit) {
  EXIT *i;
  EXIT *eFree;

  if (!exit) return eList;
  exitNum -= 1;

  while (IndexFind(&eventThingIndex, exit, NULL))
    IndexDelete(&eventThingIndex, exit, NULL);

  if (eList == exit) {
    eFree = eList;
    eList = eList->eNext;
    STRFREE(eFree->eKey);
    STRFREE(eFree->eDesc);
    MEMFREE(eFree, EXIT);
    return eList;
  }

  for (i = eList; i && i->eNext != exit; i = i->eNext);
  if (i) { /* found it */
    eFree = i->eNext;
    i->eNext = eFree->eNext;
    STRFREE(eFree->eKey);
    STRFREE(eFree->eDesc);
    MEMFREE(eFree, EXIT);
  } else {
    eFree = exit;
    STRFREE(eFree->eKey);
    STRFREE(eFree->eDesc);
    MEMFREE(eFree, EXIT);
  }
  return eList;
}

BYTE *ExitGetName(EXIT *exit, BYTE *buf) {
  if (exit->eDir != EDIR_UNDEFINED) {
    strcpy(buf, dirList[exit->eDir]);
  } else {
    StrOneWord(exit->eKey->sText, buf);
  }
  return buf;
}