/
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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#include "crimson2.h"
#include "macro.h"
#include "mem.h"
#include "queue.h"
#include "log.h"
#include "str.h"
#include "ini.h"
#include "extra.h"
#include "file.h"
#include "thing.h"
#include "exit.h"
#include "index.h"
#include "world.h"
#include "edit.h"
#include "history.h"
#include "socket.h"
#include "base.h"
#include "object.h"
#include "char.h"
#include "mobile.h"
#include "player.h"
#include "reset.h"
#include "area.h"


AREALIST *areaList     = NULL;
LWORD     areaListMax  = 0;       /* size in units */
LWORD     areaListByte = 1<<13;    /* size in bytes */

BYTE      areaOfLog;
BYTE      areaReadLog;
BYTE      areaTotalLog;
BYTE      areaWriteBinary;

BYTE *wSystemList[] = {
  "WLDUNSAVED",
  "MOBUNSAVED",
  "OBJUNSAVED",
  "RSTUNSAVED",
  "RSTSHOWN",
  ""
};

void AreaInit(void) {
  FILE *areaFile;
  BYTE buf[256];
  BYTE word[256];
  BYTE tmp[128];

  areaOfLog       = INILWordRead("crimson2.ini", "areaOfLog",       0);
  areaReadLog     = INILWordRead("crimson2.ini", "areaReadLog",     0);
  areaTotalLog    = INILWordRead("crimson2.ini", "areaTotalLog",    0);
  areaWriteBinary = INILWordRead("crimson2.ini", "areaWriteBinary", 0);
  if (areaWriteBinary) {
    Log(LOG_BOOT, "WARNING: BINARY FILE WRITING ENABLED\n");
  }
  areaFile = fopen("area/area.tbl", "rb");
  if (!areaFile) {
    Log(LOG_BOOT, "Unable to read area.tbl file, killing server\n");
    exit(ERROR_BADFILE);
  }

  /* report on initialization */
  sprintf(buf, "Initial areaList allocation of %ld entries\n", areaListByte/sizeof(AREALIST));
  Log(LOG_BOOT, buf);
  WorldInit();
  MobileInit();
  ObjectInit();
  ResetInit();

  /* okay we opened it up so read it.... */
  while (!feof(areaFile)) {
    fscanf(areaFile, " %s", tmp); /* get filename */
    if (tmp[0] == '$' || feof(areaFile))
      break; /* Dikumud file format EOF character */
    if (tmp[0] != '#' && tmp[0] != '*') { /* ignore comments */
      REALLOC("AreaInit(area.c): areaList reallocation\n", areaList, AREALIST, areaListMax+1, areaListByte);
      memset( (void*)&areaList[areaListMax], 0, sizeof(AREALIST)); /* init to zeros */
      areaList[areaListMax].aFileName = STRCREATE(tmp);
      fscanf(areaFile, " %ld", &(areaList[areaListMax].aVirtualMin) ); /* get Min */
      fscanf(areaFile, " %ld ", &(areaList[areaListMax].aVirtualMax) ); /* get Max */
      areaList[areaListMax].aEditor = FileStrRead(areaFile);
      areaList[areaListMax].aDesc   = STRCREATE("No description.");

      /* init the index values (used for binary searches) */
      sprintf(buf, "[%s] WldIndex",areaList[areaListMax].aFileName->sText); 
      IndexInit(&areaList[areaListMax].aWldIndex, 128, buf, 0);

      sprintf(buf, "[%s] MobIndex",areaList[areaListMax].aFileName->sText); 
      IndexInit(&areaList[areaListMax].aMobIndex, 128, buf, 0);

      sprintf(buf, "[%s] ObjIndex",areaList[areaListMax].aFileName->sText); 
      IndexInit(&areaList[areaListMax].aObjIndex, 128, buf, 0);

      areaList[areaListMax].aResetList       = NULL;
      areaList[areaListMax].aResetNum        = 0;
      areaList[areaListMax].aResetByte       = 128;
      areaList[areaListMax].aResetFlag       = 0;
      areaList[areaListMax].aResetDelay      = 0;
      areaList[areaListMax].aResetLast       = 0;

      if (areaReadLog) {
        sprintf(buf,
          "Reading Area:[%-18s] [%5ld-%5ld] [%s]\n",
          StrFirstWord(areaList[areaListMax].aFileName->sText,word),
          areaList[areaListMax].aVirtualMin,
          areaList[areaListMax].aVirtualMax,
          areaList[areaListMax].aEditor->sText
        );
        Log(LOG_BOOT, buf);
      }

      /* load the world file for this area */
      WorldRead(areaListMax);
      /* load the mobile templates for this area */
      MobileRead(areaListMax);
      /* load the object templates for this area */
      ObjectRead(areaListMax);
      /* load the reset files for this area */
      ResetRead(areaListMax);
      
      areaList[areaListMax].aResetThing.tSDesc = StrAlloc(areaList[areaListMax].aFileName);
      areaList[areaListMax].aResetThing.tDesc  = StrAlloc(areaList[areaListMax].aDesc);

      if (areaTotalLog) {
        sprintf(buf,
          "SubTotal for:[%-18s] Wld[%5ld] Mob[%5ld] Obj[%5ld] Rst[%5ld]\n",
          areaList[areaListMax].aFileName->sText,
          areaList[areaListMax].aWldIndex.iNum,
          areaList[areaListMax].aMobIndex.iNum,
          areaList[areaListMax].aObjIndex.iNum,
          areaList[areaListMax].aResetNum
        );
        Log(LOG_BOOT, buf);
      }

      areaListMax++;
    }
  }
  /* all done close up shop */
  fclose(areaFile);

  /* convert virtual references to actual pointers */
  WorldReIndex();
  ResetReIndex();

  sprintf(buf,
    "Totals: Area[%ld] Wld[%5ld] Mob[%5ld] Obj[%5ld] Rst[%5ld]\n\n",
    areaListMax,
    worldNum,
    mobileNum,
    objectNum,
    resetNum
   );
  Log(LOG_BOOT, buf);
}



WORD AreaOf(WORD virtual) {
  WORD min;
  WORD mid;
  WORD max;
  BYTE buf[256];

  min = 0;
  max = areaListMax-1;

  if (virtual == -1) /* NOWHERE */
    return -1;

  /* if number is way out choke right off the bat */
  if ( (virtual < areaList[min].aVirtualMin)
     ||(virtual > areaList[max].aVirtualMax)) {
    if (areaOfLog) {
      sprintf(buf, "AreaOf(1): area containing virtual#%d does not exist\n", virtual);
      Log(LOG_ERROR, buf);
    }
    return(-1);
  }

  while (max >= min) {
    mid = (min+max) /2;
    if (virtual < areaList[mid].aVirtualMin)
      max = mid-1;
    else if (virtual > areaList[mid].aVirtualMax)
      min = mid+1;
    else { /* this must be it */
      break;
    }
  }

  /* if number fell in a crack between zones detect it here */
  if ( (virtual < areaList[mid].aVirtualMin)
     ||(virtual > areaList[mid].aVirtualMax)) {
    if (areaOfLog) {
      sprintf(buf, "AreaOf(2): area containing virtual#%hd does not exist\n", virtual);
      Log(LOG_ERROR, buf);
    }
    return(-1);
  }
  return (mid);
}


BYTE AreaHasPlayers(WORD area) {
  LWORD i;
  THING *inside;
  
  for (i=0; i<playerIndex.iNum; i++) {
    inside = Base(playerIndex.iThing[i])->bInside;
    if (   (inside                    ) 
        && (inside->tType == TTYPE_WLD) 
        && (Wld(inside)->wArea==area  )  )
      return TRUE;
  }
  return FALSE;
}

/* Move the virtual if it falls in the old range */
LWORD AreaMove(WORD area, LWORD virtual) {
  if (   areaList[area].aOffset
      && virtual >= areaList[area].aVirtualMin-areaList[area].aOffset
      && virtual <= areaList[area].aVirtualMax-areaList[area].aOffset
  )
    virtual += areaList[area].aOffset;
  return virtual;
}

/* AreaIsEditor - this function will check if the specified
 * 'thing' is a valid editor. This function will return 1 if
 * 'thing' is an editor, but not for 'area'; 2 if 'thing' 
 * is a valid editor for 'area'; 0 if 'thing' is not a
 * valid editor of ANY area.  NOTE: This function does NOT
 * take into account player level. If you wish players of certain
 * levels to have extra privs, you have to check that elsewhere. */
BYTE AreaIsEditor(WORD area, THING *thing) {
  WORD i;
  WORD returnVal;

  returnVal=0;
  if (!thing) 
    return 0;
  if (thing->tType!=TTYPE_PLR)
    return 0;
  for (i=0;i<areaListMax;i++) {
    if (StrIsExactKey(thing->tSDesc->sText, areaList[i].aEditor)) {
      if (area==i) {
        returnVal=2;
        break;
      } else {
        returnVal=1;
      }
    } 
  }
  return returnVal;
}