/
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
 */

#include <stdlib.h>
#include <stdio.h>

#include "crimson2.h"
#include "log.h"
#include "mem.h"
#include "queue.h"
#include "str.h"
#include "extra.h"
#include "thing.h"
#include "index.h"
#include "edit.h"
#include "history.h"
#include "socket.h"
#include "base.h"

#define BASELINK_ALLOC_SIZE 256

/* This whole link thing is screwy, if I had been thinking clearer at
   the time that I wrote it, I would have made it so that "ControlLinks"
   were simply a SOCK* field in the Base structure, rather than a special
   type of link... oh well I'm not about to change it now especially since
   it works (saves memory this way anyway... 4 bytes per BASE...)
 */

BYTE *linkTypeList[] = {
  "UNDEFINED",
  "CONTROL",
  "TELEPATHY-SND",
  "TELEPATHY-RCV",
  "HEAR-SND",
  "HEAR-RCV",
  "SEE-SND",
  "SEE-RCV",
  "C4-SND",
  "C4-RCV",
  ""
};

void BaseLinkAlloc(THING *sndThing, THING *rcvThing, WORD lType) {
  BASELINK *link; /* send */
  MEMALLOC(link, BASELINK, BASELINK_ALLOC_SIZE);
  link->lDetail.lThing = rcvThing;
  link->lType = lType;
  link->lNext = Base(sndThing)->bLink;
  Base(sndThing)->bLink = link;
}

void BaseLinkCreate(THING *sndThing, THING *rcvThing, WORD lType) {
  WORD      otherLType;

  if (!sndThing){
    Log(LOG_ERROR, "BaseLinkAlloc(base.c): ACK! NULL sndThing\n"); 
    return;
  }
  if (!rcvThing){
    Log(LOG_ERROR, "BaseLinkAlloc(base.c): ACK! NULL rcvThing\n"); 
    return;
  }
  if (lType%2){
    otherLType = lType-1;
  } else
    otherLType = lType+1;

  if (lType==BL_CONTROL){
    Log(LOG_ERROR, "BaseLinkAlloc(base.c): ACK! Control link attempted\n"); 
    return;
  }

  /* its a link guys... */
  BaseLinkAlloc(sndThing, rcvThing, lType);
  BaseLinkAlloc(rcvThing, sndThing, otherLType);
}

/* find the controlling socket for something, fill in what you know, it doesnt
   need all the parms */
BASELINK *BaseLinkFind(BASELINK *next, WORD lType, THING *thing) {
  BASELINK *i;

  for(i=next; i; i = i->lNext) {
    if (i->lType != BL_CONTROL) {
      if ( (lType == BL_UNDEF || i->lType == lType)
         &&(!thing || i->lDetail.lThing==thing))
        return i;
    }
  }

  return NULL;
}

/* will search and destroy both halves of a link */
void BaseLinkFree(THING *thing, BASELINK *link) {
  BASELINK *i;
  BASELINK *freeLink;
  THING    *otherThing;
  LWORD     otherLType;

  if (!thing){
    Log(LOG_ERROR, "BaseLinkFree(base.c): ACK! NULL thing\n"); 
    return;
  }
  if (!link){
    Log(LOG_ERROR, "BaseLinkFree(base.c): ACK! NULL link\n"); 
    return;
  }

  /* find other side and turf it - except for control links which have only one side */
  if (link->lType != BL_CONTROL) { /* normal link */
    otherThing = link->lDetail.lThing;
    if (link->lType%2){
      otherLType = link->lType-1;
    } else
      otherLType = link->lType+1;
    if (   (Base(otherThing)->bLink->lDetail.lThing == thing)
        && (Base(otherThing)->bLink->lType == otherLType) 
    ) {
      freeLink = Base(otherThing)->bLink;
      Base(otherThing)->bLink = Base(otherThing)->bLink->lNext;
      MEMFREE(freeLink, BASELINK);
    } else {  
      for(i=Base(link->lDetail.lThing)->bLink; i && i->lNext; i=i->lNext)
        if ( (i->lNext->lDetail.lThing == thing)
          && (i->lNext->lType == otherLType) )
          break;
      if (i->lNext) {
        freeLink = i->lNext;
        i->lNext = i->lNext->lNext;
        MEMFREE(freeLink, BASELINK);
      }
    }

  /* set ControlThing field to null now that control field is gone */
  } else {
    link->lDetail.lSock->sControlThing = NULL;
  }
  
  /* ok now do ourselves in... */
  if (Base(thing)->bLink == link) {
    freeLink = Base(thing)->bLink;
    Base(thing)->bLink = Base(thing)->bLink->lNext;
    MEMFREE(freeLink, BASELINK);    
  } else {
    for (i=Base(thing)->bLink; i && i->lNext != link; i=i->lNext);
    if (i) {
      freeLink = i->lNext;
      i->lNext = i->lNext->lNext;
      MEMFREE(freeLink, BASELINK);
    }
  }
      
}


/* free all the links that a base has in preparation to get rid of it */
void BaseFree(THING *thing) {
  STRFREE(Base(thing)->bKey);
  STRFREE(Base(thing)->bLDesc);
  while (Base(thing)->bLink)
    BaseLinkFree(thing, Base(thing)->bLink);
}

/* Set a control link from thing to sock */
void BaseControlAlloc(THING *thing, SOCK *sock) {
  BASELINK *link; 

  if (!thing){
    Log(LOG_ERROR, "BaseLinkAlloc(base.c): ACK! NULL thing\n"); 
    return;
  }
  if (!sock){
    Log(LOG_ERROR, "BaseLinkAlloc(base.c): ACK! NULL sock\n"); 
    return;
  }

  /* special case of a control link which points to a socket */
  MEMALLOC(link, BASELINK, BASELINK_ALLOC_SIZE);
  link->lDetail.lSock = sock;
  link->lType = BL_CONTROL;
  link->lNext = Base(thing)->bLink;
  Base(thing)->bLink = link;

  if (!sock->sHomeThing) {
    sock->sHomeThing = thing;
  }  
  sock->sControlThing = thing;
}


/* find the controlling socket for something */
SOCK *BaseControlFind(THING *thing) {
  BASELINK *i;

  if (!thing) return NULL;

  for(i=Base(thing)->bLink; i; i = i->lNext) {
    if (i->lType==BL_CONTROL)
      return i->lDetail.lSock;
  }
  return NULL;
}

/* find the controlling socket for something */
void BaseControlFree(THING *thing, SOCK *sock) {
  BASELINK *i;
  BASELINK *next;

  if (!thing) return;

  for(i=Base(thing)->bLink; i; i = next) {
    next = i->lNext;
    if (i->lType==BL_CONTROL && i->lDetail.lSock == sock) {
      BaseLinkFree(thing, i);
      sock->sControlThing = NULL;
    }
  }
}