/
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/
/* Dynamic Structure header file */
// 2-char identifier: ds
// ****************************************************************************
// Copyright (C) B. Cameron Lesiuk, 1999. All rights reserved.
// Permission to use/copy this code is granted for non-commercial use only.
// B. Cameron Lesiuk
// Victoria, BC, Canada
// wi961@freenet.victoria.bc.ca
// ****************************************************************************

#include<windows.h>
#include<string.h>
#include<time.h>
#include"moledefs.h"
#include"molem.h"
#include"debug.h"
#include"host.h"
#include"dstruct.h"

/***** Reference Library *****/
/* dsRefFree - clears any attached structures and sets elements to NULL */
void dsRefFree(DSREF *p_ref) {
  if (!p_ref) return;

  while(p_ref->rList) {
    dsStructFree(p_ref->rList);
  }
  p_ref->rState=DS_NS_NOTAVAIL;
  p_ref->rList=NULL;
  if (p_ref->rEditWindow)
    DestroyWindow(p_ref->rEditWindow);
  p_ref->rEditWindow=NULL;
  return;
}

/* Initializes a reference structure to all NULL */
void dsRefClear(DSREF *p_ref) {
  if (!p_ref) return;

  p_ref->rState=DS_NS_NOTAVAIL;
  p_ref->rLoadTime=0L;
  p_ref->rList=NULL;
  p_ref->rFlag=0L;
  p_ref->rEditWindow=NULL;

  return;
}

/***** STRing Library *****/
/* Free a STR */
void dsStrFree(DSSTR *p_str) {
  HGLOBAL l_GlobalTemp;

  if (!p_str) return;

  l_GlobalTemp=p_str->sMemory;
  GlobalUnlock(l_GlobalTemp);
  GlobalFree(l_GlobalTemp);

  dsStrClear(p_str);

  return;
}

/* initialize a STR */
void dsStrClear(DSSTR *p_str) {
  if (!p_str) return;
  p_str->sData=NULL;
  p_str->sMemory=NULL;
  return;
}

/* Allocate memory for specified size str */
unsigned long dsStrAlloc(DSSTR *p_str,unsigned long p_len) {
  HGLOBAL l_GlobalTemp;

  if ((!p_str)||(p_len < 1)) return 0L;
  l_GlobalTemp=GlobalAlloc(GHND|GMEM_NOCOMPACT,p_len);
  if (!l_GlobalTemp)
    return 0L;
  p_str->sData=(char *)GlobalLock(l_GlobalTemp);
  if (!(p_str->sData)) {
    GlobalFree(l_GlobalTemp);
    return 0L;
  }
  p_str->sMemory=l_GlobalTemp;
  return GlobalSize(l_GlobalTemp);
}

/* a dsStrAlloc with a strcpy included */
unsigned long dsStrCreate(DSSTR *p_str,char *p_data) {
  unsigned long l_size;
  if (!p_str)
    return 0L;
  if (!p_data) {
    dsStrClear(p_str);
    return 0L;
  }

  l_size=dsStrAlloc(p_str,strlen(p_data)+1);
  if (l_size) {
    strcpy(p_str->sData,p_data);
  }
  return l_size;
}

/* duplicates a STR - WITHOUT new alloc!!! */
void dsStrCopy(DSSTR *p_src,DSSTR *p_dst) {
  if ((!p_dst)||(!p_src))
    return;

  p_dst->sData=p_src->sData;
  p_dst->sMemory=p_src->sMemory;
}

/* duplicates a STR - WITH new alloc!!! */
unsigned long dsStrReplicate(DSSTR *p_src,DSSTR *p_dst) {
  if ((!p_dst)||(!p_src)||(!p_src->sData))
    return 0L;

  return dsStrCreate(p_dst,p_src->sData);
}

/***** FTL Library *****/

DSFTL *dsFTLAlloc(char *p_name){
  DSFTL *l_ftl;
  HGLOBAL l_GlobalTemp;
  int l_i;

  l_GlobalTemp=GlobalAlloc(GHND|GMEM_NOCOMPACT,sizeof(DSFTL));
  l_ftl=(DSFTL *)GlobalLock(l_GlobalTemp);
  if ((!l_GlobalTemp)||(!(l_ftl)))
    return NULL;
  l_ftl->fMemory=l_GlobalTemp;
  l_ftl->fNext=NULL;
  l_ftl->fDown=NULL;
  l_ftl->fType=MOLE_LISTTYPE_INVALID;
  l_ftl->fList=MOLE_LIST_INVALID;
  l_i=0;
  if (p_name)
    for (l_i=0;(l_i<DS_FTL_NAMELEN-1)&&(p_name[l_i]);l_i++)
      (l_ftl->fName)[l_i]=p_name[l_i];
  (l_ftl->fName)[l_i]=0;
  return l_ftl;
}

void dsFTLFree(DSFTL **p_FTList){
  DSFTL *l_ftl,*l_nextftl,*l_downftl;
  HGLOBAL l_GlobalTemp;

  if (!p_FTList)
    return;

  l_ftl=*p_FTList;
  while(l_ftl) {
    l_downftl=l_ftl->fDown;
    while(l_ftl) {
      l_nextftl=l_ftl->fNext;
      l_GlobalTemp=l_ftl->fMemory;
      GlobalUnlock(l_GlobalTemp);
      GlobalFree(l_GlobalTemp);
      l_ftl=l_nextftl;
    }
    l_ftl=l_downftl;
  }
  *p_FTList=NULL;
  return;
}

void dsFTLAppendNext(DSFTL **p_FTList,DSFTL *p_newEntry){
  DSFTL *l_ftl;

  if (!p_FTList)
    return;
  l_ftl=*p_FTList;
  if (!l_ftl)
    *p_FTList=p_newEntry;
  else {
    while(l_ftl->fNext)
      l_ftl=l_ftl->fNext;
    l_ftl->fNext=p_newEntry;
  }
  return;
}

void dsFTLAppendDown(DSFTL **p_FTList,DSFTL *p_newEntry) {
  DSFTL *l_ftl;

  if (!p_FTList)
    return;
  l_ftl=*p_FTList;
  if (!l_ftl)
    *p_FTList=p_newEntry;
  else {
    while(l_ftl->fDown)
      l_ftl=l_ftl->fDown;
    l_ftl->fDown=p_newEntry;
  }
  return;
}

DSFTL *dsFTLOf(DSFTL **p_FTList,int p_FTLNum) {
  DSFTL *l_ftl;

  if (!p_FTList)
    return NULL;
  for (l_ftl=*p_FTList;(l_ftl)&&(p_FTLNum);p_FTLNum--,l_ftl=l_ftl->fDown);
  return l_ftl;
}

/***** Structure Library *****/
/* Free a structure and any child structures */
void dsStructFree(DSSTRUCT *p_struct) {
  HGLOBAL l_GlobalTemp;

  if (!p_struct) return;

  /* first, free any child structures, or type-specific attachments */
  if (p_struct->sType>=DS_STYPE_LIST)
    dsStrFree(&(DSSList(p_struct)->lName));

  switch(p_struct->sType) {
    case DS_STYPE_EXIT:
      break;
    case DS_STYPE_PROPERTY: /* Extra & Property structs are identical */
    case DS_STYPE_EXTRA:
      dsStrFree(&(DSSExtra(p_struct)->eKey));
      dsStrFree(&(DSSExtra(p_struct)->eDesc));
      break;
    case DS_STYPE_AREADETAIL:
      dsStrFree(&(DSSAreaDetail(p_struct)->aEditor));
      dsStrFree(&(DSSAreaDetail(p_struct)->aDesc));
      dsRefFree(&(DSSAreaDetail(p_struct)->aProperty));
      break;
    case DS_STYPE_LIST:
      break;
    case DS_STYPE_AREA:
      dsRefFree(&(DSSArea(p_struct)->aOBJ));
      dsRefFree(&(DSSArea(p_struct)->aMOB));
      dsRefFree(&(DSSArea(p_struct)->aWLD));
      dsRefFree(&(DSSArea(p_struct)->aRST));
      dsRefFree(&(DSSArea(p_struct)->aDetail));
      break;
    case DS_STYPE_WORLD:
      dsStrFree(&(DSSWorld(p_struct)->wDesc));
      dsRefFree(&(DSSWorld(p_struct)->wExit));
      dsRefFree(&(DSSWorld(p_struct)->wExtra));
      dsRefFree(&(DSSWorld(p_struct)->wProperty));
      break;
    case DS_STYPE_MOBILE:
      dsStrFree(&(DSSMobile(p_struct)->mKey));
      dsStrFree(&(DSSMobile(p_struct)->mLDesc));
      dsStrFree(&(DSSMobile(p_struct)->mDesc));
      dsRefFree(&(DSSMobile(p_struct)->mExtra));
      dsRefFree(&(DSSMobile(p_struct)->mProperty));
      break;
    case DS_STYPE_OBJECT:
      dsStrFree(&(DSSObject(p_struct)->oKey));
      dsStrFree(&(DSSObject(p_struct)->oLDesc));
      dsStrFree(&(DSSObject(p_struct)->oDesc));
      dsRefFree(&(DSSObject(p_struct)->oExtra));
      dsRefFree(&(DSSObject(p_struct)->oProperty));
      break;
    case DS_STYPE_RESET:
    case DS_STYPE_NONE:
    default:
      break;
  }

  /* now extract this structure from it's list */
  dsStructExtract(p_struct);

  /* close any editing window which may be open */
  if (p_struct->sEditWindow) {
    aaDestroyWindow(p_struct->sEditWindow);
  }

  /* and then free the memory alloc'ed to this structure */
  l_GlobalTemp=p_struct->sMemory;
  GlobalUnlock(l_GlobalTemp);
  GlobalFree(l_GlobalTemp);

  /* and we're done! */
  return;
}

/* allocate a new structure and initialize it. */
DSSTRUCT *dsStructAlloc(int p_type) {
  HGLOBAL l_GlobalTemp;
  DSSTRUCT *l_struct;

  switch (p_type) {
    case DS_STYPE_EXIT:
      l_GlobalTemp=GlobalAlloc(GHND|GMEM_NOCOMPACT,sizeof(DSSEXIT));
      break;
    case DS_STYPE_EXTRA:
      l_GlobalTemp=GlobalAlloc(GHND|GMEM_NOCOMPACT,sizeof(DSSEXTRA));
      break;
    case DS_STYPE_PROPERTY:
      l_GlobalTemp=GlobalAlloc(GHND|GMEM_NOCOMPACT,sizeof(DSSPROPERTY));
      break;
    case DS_STYPE_AREADETAIL:
      l_GlobalTemp=GlobalAlloc(GHND|GMEM_NOCOMPACT,sizeof(DSSAREADETAIL));
      break;
    case DS_STYPE_LIST:
      l_GlobalTemp=GlobalAlloc(GHND|GMEM_NOCOMPACT,sizeof(DSSLIST));
      break;
    case DS_STYPE_AREA:
      l_GlobalTemp=GlobalAlloc(GHND|GMEM_NOCOMPACT,sizeof(DSSAREA));
      break;
    case DS_STYPE_WORLD:
      l_GlobalTemp=GlobalAlloc(GHND|GMEM_NOCOMPACT,sizeof(DSSWORLD));
      break;
    case DS_STYPE_MOBILE:
      l_GlobalTemp=GlobalAlloc(GHND|GMEM_NOCOMPACT,sizeof(DSSMOBILE));
      break;
    case DS_STYPE_OBJECT:
      l_GlobalTemp=GlobalAlloc(GHND|GMEM_NOCOMPACT,sizeof(DSSOBJECT));
      break;
    case DS_STYPE_RESET:
      l_GlobalTemp=GlobalAlloc(GHND|GMEM_NOCOMPACT,sizeof(DSSRESET));
      break;
    case DS_STYPE_NONE:
    default:
      p_type=DS_STYPE_NONE;
      l_GlobalTemp=GlobalAlloc(GHND|GMEM_NOCOMPACT,sizeof(DSSTRUCT));
      break;
  }

  l_struct=DSStruct(GlobalLock(l_GlobalTemp));
  if ((!l_GlobalTemp)||(!l_struct))
    return NULL;

  /* now initialize the structure */
  l_struct->sType=p_type;
  l_struct->sState=DS_NS_NOTAVAIL;
  l_struct->sMemory=l_GlobalTemp;
  l_struct->sLoadTime=0L;
  l_struct->sPrevious=l_struct->sNext=NULL;
  l_struct->sUpRef=NULL;
  l_struct->sEditWindow=NULL;

  /* type-specific initializations */
  if (p_type>=DS_STYPE_LIST) {
    dsStrClear(&(DSSList(l_struct)->lName));
    DSSList(l_struct)->lVNum=DSSList(l_struct)->lVNum2=0L;
  }

  switch (p_type) {
    case DS_STYPE_EXIT:
      break;
    case DS_STYPE_PROPERTY: /* property & extra structures are identical */
    case DS_STYPE_EXTRA:
      dsStrClear(&(DSSExtra(l_struct)->eKey));
      dsStrClear(&(DSSExtra(l_struct)->eDesc));
      break;
    case DS_STYPE_AREADETAIL:
      dsStrClear(&(DSSAreaDetail(l_struct)->aEditor));
      dsStrClear(&(DSSAreaDetail(l_struct)->aDesc));
      dsRefClear(&(DSSAreaDetail(l_struct)->aProperty));
      break;
    case DS_STYPE_LIST:
      break;
    case DS_STYPE_AREA:
      dsRefClear(&(DSSArea(l_struct)->aOBJ));
      dsRefClear(&(DSSArea(l_struct)->aMOB));
      dsRefClear(&(DSSArea(l_struct)->aWLD));
      dsRefClear(&(DSSArea(l_struct)->aRST));
      dsRefClear(&(DSSArea(l_struct)->aDetail));
      DSSArea(l_struct)->aFlag=0L;
      break;
    case DS_STYPE_WORLD:
      dsStrClear(&(DSSWorld(l_struct)->wDesc));
      dsRefClear(&(DSSWorld(l_struct)->wExit));
      dsRefClear(&(DSSWorld(l_struct)->wExtra));
      dsRefClear(&(DSSWorld(l_struct)->wProperty));
      break;
    case DS_STYPE_MOBILE:
      dsStrClear(&(DSSMobile(l_struct)->mKey));
      dsStrClear(&(DSSMobile(l_struct)->mLDesc));
      dsStrClear(&(DSSMobile(l_struct)->mDesc));
      dsRefClear(&(DSSMobile(l_struct)->mExtra));
      dsRefClear(&(DSSMobile(l_struct)->mProperty));
      break;
    case DS_STYPE_OBJECT:
      dsStrClear(&(DSSObject(l_struct)->oKey));
      dsStrClear(&(DSSObject(l_struct)->oLDesc));
      dsStrClear(&(DSSObject(l_struct)->oDesc));
      dsRefClear(&(DSSObject(l_struct)->oExtra));
      dsRefClear(&(DSSObject(l_struct)->oProperty));
      break;
    case DS_STYPE_RESET:
    case DS_STYPE_NONE:
    default:
      break;
  }

  return l_struct;
}

/* extract structure from its list */
void dsStructExtract(DSSTRUCT *p_struct) {
  if (!p_struct) return;

  /* update the sPrevious structure */
  if (p_struct->sPrevious) {
    p_struct->sPrevious->sNext=p_struct->sNext;
  } else if (p_struct->sUpRef) {  /* check if we need to update our sUpRef */
    p_struct->sUpRef->rList=p_struct->sNext;
  } /*else {
    dbPrint ("Structure list has been lost - oops!");
  }   */

  /* update the sNext structure */
  if (p_struct->sNext) {
    p_struct->sNext->sPrevious=p_struct->sPrevious;
  }

  return;
}

/* This inserts p_struct at the start of the list (if p_upref is not NULL) or
 * after p_prev */
/* NOTE that it's always assumed that the REFERENCE points to the START of this
 * structure linked list, not someplace in the middle */
void dsStructInsert(DSREF *p_upref, DSSTRUCT *p_prev, DSSTRUCT *p_struct) {
  if (!p_struct) return;
  if (p_upref) {
    if (p_upref->rList) {
      p_struct->sNext=p_upref->rList;
      (p_upref->rList)->sPrevious=p_struct;
    } else { /* first element in list */
      p_struct->sPrevious=p_struct->sNext=NULL;
    }
    p_upref->rList=p_struct;
    p_struct->sUpRef=p_upref;
  } else if (p_prev) {
    p_struct->sNext=p_prev->sNext;
    p_struct->sPrevious=p_prev;
    p_struct->sUpRef=p_prev->sUpRef;
    if (p_prev->sNext)
      (p_prev->sNext)->sPrevious=p_struct;
    p_prev->sNext=p_struct;
  } else return;
  return;
}

/* This proc will insert a DS_STYPE_LIST or subtype into a list */
/* The list is sorted according to the lVNum virtual number.    */
void dsStructInsertList(DSREF *p_upref, DSSTRUCT *p_struct) {
  DSSTRUCT *l_curstruct,*l_prevstruct;

  if (!p_struct) return;

  if (p_upref->rList) {
    l_prevstruct=NULL;
    l_curstruct=p_upref->rList;
    while(l_curstruct && (DSSList(l_curstruct)->lVNum<DSSList(p_struct)->lVNum)) {
      l_prevstruct=l_curstruct;
      l_curstruct=l_curstruct->sNext;
    }
    if (l_prevstruct) {
      dsStructInsert(NULL,l_prevstruct,p_struct);
    } else {
      /* it belongs at the start */
      dsStructInsert(p_upref,NULL,p_struct);
    }

  } else { /* first element in list */
    dsStructInsert(p_upref,NULL,p_struct);
  }
  return;
}

/* Copy struct - note both p_src and p_dst MUST be already alloc'ed and
 * both must be of the same sType!!!
 * WARNING WARNING: This proc should be used with caution.
 *   This proc does not copy the structure verbatim. It selectively
 *   transfers SOME information, NOT ALL. This is because this
 *   proc isn't intended to be a complete re-hasher, re-sorter, etc.
 *   IT IS INTENDED TO COPY PERTINENT USER-RELATED DATA for Cut/Paste
 *   type operations. USE WITH CAUTION!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
 *   !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
 *   !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
/*   -------======<<<<< USE WITH CAUTION >>>>>=====------------ */
/*   -------======<<<<< USE WITH CAUTION >>>>>=====------------ */
void dsStructCopy(DSSTRUCT *p_src,DSSTRUCT *p_dst) {
  int l_i;

  if ((!p_src)||(!p_dst))
    return;

  if (p_src->sType!=p_dst->sType)
    return;

  if (p_src->sState!=DS_NS_AVAIL)
    return;

  /* Ok, let's copy! */
  /* DSSTRUCT common */
  p_dst->sState=DS_NS_AVAIL; /* note this may cause confusion if a load from the server is pending! */
  p_dst->sLoadTime=time(NULL);
  switch (p_src->sType) {
    case DS_STYPE_NONE:
      break;
    case DS_STYPE_RESET:
      DSSReset(p_dst)->rCmd=DSSReset(p_src)->rCmd;
      DSSReset(p_dst)->rIf=DSSReset(p_src)->rIf;
      DSSReset(p_dst)->rArg1=DSSReset(p_src)->rArg1;
      DSSReset(p_dst)->rArg2=DSSReset(p_src)->rArg2;
      DSSReset(p_dst)->rArg3=DSSReset(p_src)->rArg3;
      DSSReset(p_dst)->rArg4=DSSReset(p_src)->rArg4;
      break;
    case DS_STYPE_EXTRA:
      dsStrFree(&(DSSExtra(p_dst)->eKey));
      dsStrReplicate(&(DSSExtra(p_dst)->eKey),&(DSSExtra(p_src)->eKey));
      dsStrFree(&(DSSExtra(p_dst)->eDesc));
      dsStrReplicate(&(DSSExtra(p_dst)->eDesc),&(DSSExtra(p_src)->eDesc));
      break;
    case DS_STYPE_PROPERTY:
      dsStrFree(&(DSSProperty(p_dst)->pKey));
      dsStrReplicate(&(DSSProperty(p_dst)->pKey),
        &(DSSProperty(p_src)->pKey));
      dsStrFree(&(DSSProperty(p_dst)->pDesc));
      dsStrReplicate(&(DSSProperty(p_dst)->pDesc),
        &(DSSProperty(p_src)->pDesc));
      break;
    case DS_STYPE_EXIT:
      dsStrFree(&(DSSExit(p_dst)->eKey));
      dsStrReplicate(&(DSSExit(p_dst)->eKey),&(DSSExit(p_src)->eKey));
      dsStrFree(&(DSSExit(p_dst)->eDesc));
      dsStrReplicate(&(DSSExit(p_dst)->eDesc),&(DSSExit(p_src)->eDesc));
      DSSExit(p_dst)->eKeyObj=DSSExit(p_src)->eKeyObj;
      DSSExit(p_dst)->eFlag=DSSExit(p_src)->eFlag;
      DSSExit(p_dst)->eWorld=DSSExit(p_src)->eWorld;
      DSSExit(p_dst)->eDir=DSSExit(p_src)->eDir;
      break;
    case DS_STYPE_AREADETAIL:
      dsStrFree(&(DSSAreaDetail(p_dst)->aEditor));
      dsStrReplicate(&(DSSAreaDetail(p_dst)->aEditor),
        &(DSSAreaDetail(p_src)->aEditor));
      dsStrFree(&(DSSAreaDetail(p_dst)->aDesc));
      dsStrReplicate(&(DSSAreaDetail(p_dst)->aDesc),
        &(DSSAreaDetail(p_src)->aDesc));
      break;
    case DS_STYPE_LIST:
    case DS_STYPE_AREA:
    case DS_STYPE_WORLD:
    case DS_STYPE_MOBILE:
    case DS_STYPE_OBJECT:
      dsStrFree(&(DSSList(p_dst)->lName));
      dsStrReplicate(&(DSSList(p_dst)->lName),
        &(DSSList(p_src)->lName));
      /* DON'T TOUCH lVNum or lVNum2!! */
      switch (p_src->sType) {
        case DS_STYPE_AREA:
          DSSArea(p_dst)->aFlag=DSSArea(p_src)->aFlag;
          break;
        case DS_STYPE_WORLD:
          dsStrFree(&(DSSWorld(p_dst)->wDesc));
          dsStrReplicate(&(DSSWorld(p_dst)->wDesc),
            &(DSSWorld(p_src)->wDesc));
          /* don't copy exits, extras, or properties */
          DSSWorld(p_dst)->wFlag=DSSWorld(p_src)->wFlag;
          DSSWorld(p_dst)->wType=DSSWorld(p_dst)->wType;
          break;
        case DS_STYPE_MOBILE:
          dsStrFree(&(DSSMobile(p_dst)->mKey));
          dsStrReplicate(&(DSSMobile(p_dst)->mKey),
            &(DSSMobile(p_src)->mKey));
          dsStrFree(&(DSSMobile(p_dst)->mLDesc));
          dsStrReplicate(&(DSSMobile(p_dst)->mLDesc),
            &(DSSMobile(p_src)->mLDesc));
          dsStrFree(&(DSSMobile(p_dst)->mDesc));
          dsStrReplicate(&(DSSMobile(p_dst)->mDesc),
            &(DSSMobile(p_src)->mDesc));
          /* don't copy extras or properties */
          DSSMobile(p_dst)->mAct=DSSMobile(p_src)->mAct;
          DSSMobile(p_dst)->mAffect=DSSMobile(p_src)->mAffect;
          DSSMobile(p_dst)->mAura=DSSMobile(p_src)->mAura;
          DSSMobile(p_dst)->mLevel=DSSMobile(p_src)->mLevel;
          DSSMobile(p_dst)->mHitBonus=DSSMobile(p_src)->mHitBonus;
          DSSMobile(p_dst)->mArmor=DSSMobile(p_src)->mArmor;
          DSSMobile(p_dst)->mHPDiceNum=DSSMobile(p_src)->mHPDiceNum;
          DSSMobile(p_dst)->mHPDiceSize=DSSMobile(p_src)->mHPDiceSize;
          DSSMobile(p_dst)->mHPBonus=DSSMobile(p_src)->mHPBonus;
          DSSMobile(p_dst)->mDamDiceNum=DSSMobile(p_src)->mDamDiceNum;
          DSSMobile(p_dst)->mDamDiceSize=DSSMobile(p_src)->mDamDiceSize;
          DSSMobile(p_dst)->mDamBonus=DSSMobile(p_src)->mDamBonus;
          DSSMobile(p_dst)->mMoney=DSSMobile(p_src)->mMoney;
          DSSMobile(p_dst)->mExp=DSSMobile(p_src)->mExp;
          DSSMobile(p_dst)->mPos=DSSMobile(p_src)->mPos;
          DSSMobile(p_dst)->mType=DSSMobile(p_src)->mType;
          DSSMobile(p_dst)->mSex=DSSMobile(p_src)->mSex;
          DSSMobile(p_dst)->mWeight=DSSMobile(p_src)->mWeight;
          break;
        case DS_STYPE_OBJECT:
          dsStrFree(&(DSSObject(p_dst)->oKey));
          dsStrReplicate(&(DSSObject(p_dst)->oKey),
            &(DSSObject(p_src)->oKey));
          dsStrFree(&(DSSObject(p_dst)->oLDesc));
          dsStrReplicate(&(DSSObject(p_dst)->oLDesc),
            &(DSSObject(p_src)->oLDesc));
          dsStrFree(&(DSSObject(p_dst)->oDesc));
          dsStrReplicate(&(DSSObject(p_dst)->oDesc),
            &(DSSObject(p_src)->oDesc));
          /* don't copy extras or properties */
          DSSObject(p_dst)->oType=DSSObject(p_src)->oType;
          DSSObject(p_dst)->oAct=DSSObject(p_src)->oAct;
          DSSObject(p_dst)->oWear=DSSObject(p_src)->oWear;
          DSSObject(p_dst)->oWeight=DSSObject(p_src)->oWeight;
          DSSObject(p_dst)->oValue=DSSObject(p_src)->oValue;
          DSSObject(p_dst)->oRent=DSSObject(p_src)->oRent;
          for (l_i=0;l_i<16;l_i++)
            DSSObject(p_dst)->oDetail[l_i]=DSSObject(p_src)->oDetail[l_i];
          for (l_i=0;l_i<DS_OBJECT_MAX_APPLY;l_i++) {
            DSSObject(p_dst)->oApplyType[l_i]=DSSObject(p_src)->oApplyType[l_i];
            DSSObject(p_dst)->oApplyValue[l_i]=DSSObject(p_src)->oApplyValue[l_i];
          }
          break;
        default:
          break;
      }
      break;
    default:
      break;
  }

  return;
}

/* change List to sub-list type and back again */
/* Note this'll kill any edit window attached to p_old */
DSSTRUCT *dsChangeListType(DSSTRUCT *p_old, int p_newtype) {
  DSSTRUCT *l_new;

  if (!p_old)
    return NULL;
  if ((p_newtype<DS_STYPE_LIST)||(p_old->sType<DS_STYPE_LIST))
    return p_old;
  if (p_newtype==p_old->sType)
    return p_old;

  l_new=dsStructAlloc(p_newtype);
  if (!l_new)
    return p_old;
  /* swap in the new structure, swap out the old */
  l_new->sPrevious=p_old->sPrevious;
  l_new->sNext=p_old->sNext;
  if (p_old->sPrevious)
    p_old->sPrevious->sNext=l_new;
  if (p_old->sNext)
    p_old->sNext->sPrevious=l_new;
  l_new->sUpRef=p_old->sUpRef;
  if ((p_old->sUpRef)&&(p_old->sUpRef->rList==p_old))
    p_old->sUpRef->rList=l_new;
  p_old->sNext=p_old->sPrevious=NULL;
  p_old->sUpRef=NULL;
  /* yes, here we actually "trade" the lName field to the new list */
  DSSList(l_new)->lName.sData=DSSList(p_old)->lName.sData;
  DSSList(l_new)->lName.sMemory=DSSList(p_old)->lName.sMemory;
  DSSList(p_old)->lName.sData=NULL;
  DSSList(p_old)->lName.sMemory=NULL;
  DSSList(l_new)->lVNum=DSSList(p_old)->lVNum;
  DSSList(l_new)->lVNum2=DSSList(p_old)->lVNum2;
  /* don't forget the other "minor items" */
  l_new->sState=p_old->sState;
  l_new->sLoadTime=p_old->sLoadTime;
  l_new->sEditWindow=p_old->sEditWindow;
  p_old->sEditWindow=NULL;
  /* we're done. Release the sucker & return the new one */
  dsStructFree(p_old);
  return l_new;
}