// area.cpp: implementation of the Carea class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include <fcntl.h>
#include <sys/stat.h>

#include "chitem.h"
#include "area.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

Carea::Carea()
{
  fhandlea=fhandlew=-1;
  startpointa=startpointw=-1;
  fullsizea=fullsizew=-1;
  maxlena=maxlenw=-1;
  actorheaders=NULL;
  triggerheaders=NULL;
  spawnheaders=NULL;
  entranceheaders=NULL;
  containerheaders=NULL;
  itemheaders=NULL;
  ambientheaders=NULL;
  variableheaders=NULL;
  doorheaders=NULL;
  animheaders=NULL;
  mapnoteheaders=NULL;
  pstmapnoteheaders=NULL;
  trapheaders=NULL;
  effects=NULL;
  tileheaders=NULL;
  vertexheaders=NULL;
  explored=NULL;
  credatapointers=NULL;

  overlayheaders=NULL;
  overlaytileheaders=NULL;
  overlaytileindices=NULL;
  weddoorheaders=NULL;
  doortileindices=NULL;
  doorpolygonheaders=NULL;
  wallpolygonheaders=NULL;
  wallgroupindices=NULL;
  polygonindices=NULL;
  wedvertices=NULL;

  searchmap=NULL;
  lightmap=NULL;
  heightmap=NULL;

  actorcount=0;
  triggercount=0;
  spawncount=0;
  entrancecount=0;
  containercount=0;
  itemcount=0;
  ambientcount=0;
  variablecount=0;
  doorcount=0;
  animcount=0;
  mapnotecount=0;
  trapcount=0;
  tilecount=0;
  vertexcount=0;
  exploredsize=0;

  overlaycount=0;
  overlaytilecount=0;
  overlaytileidxcount=0;
  weddoorcount=0;
  doortileidxcount=0;
  wallpolygoncount=0;
  doorpolygoncount=0;
  polygonidxcount=0;
  wedvertexcount=0;

  revision=10;
  m_changed=false;
  wedchanged=true;
  wedavailable=true;
  changedmap[0]=changedmap[1]=changedmap[2]=true;
  memset(&intheader,0,sizeof(intheader) );
  m_smallpalette=true;
}

Carea::~Carea()
{
  new_area();
}

void Carea::new_area()
{
  KillActors();
  KillTriggers();
  KillSpawns();
  KillEntrances();
  KillContainers();
  KillItems();
  KillAmbients();
  KillVariables();
  KillDoors();
  KillAnimations();
  KillMapnotes();
  KillTraps();
  KillEffects();
  KillTiles();
  KillVertices();
  KillVertexList();
  KillWedVertexList();
  KillDoorTileList();
  KillExplored();

  KillOverlays();
  KillOverlaytiles();
  KillWeddoors();
  KillDoortiles();
  KillOverlayindices();
  KillWallgroups();
  KillDoorpolygons();
  KillWallgrouppolygons();
  KillPolygonindices();
  KillWedvertices();
  KillMaps();
  
  wedchanged=true;
  wedavailable=true;
  changedmap[0]=changedmap[1]=changedmap[2]=true;
  the_mos.FreeOverlay(); //clearing up the associated tileset
}

int Carea::adjust_actpointa(long offset)
{
  if(actpointa()==offset) return 0;
  if(maxlena<offset) return -2;
  if(myseeka(offset)!=offset) return -2;
  return 1;
}

int Carea::adjust_actpointw(long offset)
{
  if(actpointw()==offset) return 0;
  if(maxlenw<offset) return -2;
  if(myseekw(offset)!=offset) return -2;
  return 1;
}

void Carea::ShiftVertex(long id, int count, POINTS &point)
{
  area_vertex *poi;
  int i;

  poi=(area_vertex *) vertexheaderlist.GetAt(vertexheaderlist.FindIndex(id));
  for(i=0;i<count;i++)
  {
    poi[i].x=(unsigned short) (poi[i].x+point.x);
    poi[i].y=(unsigned short) (poi[i].y+point.y);
  }
}

void Carea::FlipDoorTile(long id, int count, int width)
{
  short *poi;
  int i;
  int x,y;

  poi=(short *) doortilelist.GetAt(doortilelist.FindIndex(id));
  for(i=0;i<count;i++)
  {
    x=poi[i]%width;
    y=poi[i]/width;
    poi[i]=(unsigned short) ((y+1)*width-x-1);
  }
}

void Carea::FlipWedVertex(long id, int count, int width)
{
  area_vertex *poi;
  int i;

  poi=(area_vertex *) wedvertexheaderlist.GetAt(wedvertexheaderlist.FindIndex(id));
  for(i=0;i<count;i++)
  {
    poi[i].x=(unsigned short) (width-poi[i].x);
  }
}

void Carea::FlipVertex(long id, int count, int width)
{
  area_vertex *poi;
  int i;

  poi=(area_vertex *) vertexheaderlist.GetAt(vertexheaderlist.FindIndex(id));
  for(i=0;i<count;i++)
  {
    poi[i].x=(unsigned short) (width-poi[i].x);
  }
}

void Carea::MergeDoortile(short &offset, int count)
{
  void *poi;

  offset=(short) doortileidxcount;
  poi=doortilelist.RemoveHead();
  memcpy(doortileindices+offset,poi,sizeof(short)*count);
  delete [] poi;
  doortileidxcount+=count;
}

void Carea::MergeWedVertex(long &offset, int count)
{
  void *poi;

  offset=wedvertexcount;
  poi=wedvertexheaderlist.RemoveHead();
  memcpy(wedvertices+offset,poi,sizeof(area_vertex)*count);
  delete [] poi;
  wedvertexcount+=count;
}

void Carea::MergeVertex(long &offset, int count)
{
  void *poi;

  offset=header.vertexcnt;
  poi=vertexheaderlist.RemoveHead();
  memcpy(vertexheaders+offset,poi,sizeof(area_vertex)*count);
  delete [] poi;
  header.vertexcnt=(short) (header.vertexcnt+count);
}

int Carea::ImplodeVertices()
{
  int i;

  KillVertices(); //for safety reasons, we just kill them again
  //first count all the vertices (killvertices zeroes vertexcount)
  for(i=0;i<header.infocnt;i++)
  {
    vertexcount+=triggerheaders[i].vertexcount;
  }
  for(i=0;i<header.containercnt;i++)
  {
    vertexcount+=containerheaders[i].vertexcount;
  }
  for(i=0;i<header.doorcnt;i++)
  {
    vertexcount+=doorheaders[i].countvertexopen;
    vertexcount+=doorheaders[i].countvertexclose;
    vertexcount+=doorheaders[i].countblockopen;
    vertexcount+=doorheaders[i].countblockclose;
  }

  vertexheaders=new area_vertex[vertexcount];
  if(!vertexheaders) return -3;
  //this will sum up header.vertexcnt
  header.vertexcnt=0;
  for(i=0;i<header.infocnt;i++)
  {
    MergeVertex(triggerheaders[i].vertindx,triggerheaders[i].vertexcount);
  }
  for(i=0;i<header.containercnt;i++)
  {
    MergeVertex(containerheaders[i].firstvertex,containerheaders[i].vertexcount);
  }
  for(i=0;i<header.doorcnt;i++)
  {
    MergeVertex(doorheaders[i].firstvertexopen,doorheaders[i].countvertexopen);
    MergeVertex(doorheaders[i].firstvertexclose,doorheaders[i].countvertexclose);
    MergeVertex(doorheaders[i].firstblockopen,doorheaders[i].countblockopen);
    MergeVertex(doorheaders[i].firstblockclose,doorheaders[i].countblockclose);
  }

  if(header.vertexcnt!=vertexcount) return -1; //internal error
  if(vertexheaderlist.GetCount())
  {
    KillVertexList();
    return 1;
  }
  return 0;
}

int Carea::ImplodeWedVertices()
{
  int i;

  KillWedvertices(); //kill them for safety reason

  for(i=0;i<secheader.wallpolycnt;i++)
  {
    wedvertexcount+=wallpolygonheaders[i].countvertex;
  }
  
  for(i=0;i<doorpolygoncount;i++)
  {
    wedvertexcount+=doorpolygonheaders[i].countvertex;
  }
  
  wedvertices=new area_vertex[wedvertexcount];
  if(!wedvertices) return -3;
  wedvertexcount=0;
  for(i=0;i<secheader.wallpolycnt;i++)
  {
    MergeWedVertex(wallpolygonheaders[i].firstvertex,wallpolygonheaders[i].countvertex);
  }
  for(i=0;i<doorpolygoncount;i++)
  {
    MergeWedVertex(doorpolygonheaders[i].firstvertex,doorpolygonheaders[i].countvertex);
  }

  if(wedvertexheaderlist.GetCount())
  {
    KillWedVertexList();
    return 1;
  }
  return 0;
}

int Carea::ImplodeDoortiles()
{
  int i;

  KillDoortiles();

  for(i=0;i<wedheader.doorcnt;i++)
  {
    doortileidxcount+=weddoorheaders[i].countdoortileidx;
  }
  doortileindices=new short[doortileidxcount];
  if(!doortileindices) return -3;
  doortileidxcount=0;
  for(i=0;i<wedheader.doorcnt;i++)
  {
    MergeDoortile(weddoorheaders[i].firstdoortileidx,weddoorheaders[i].countdoortileidx);
  }
  if(doortilelist.GetCount())
  {
    KillDoorTileList();
    return 1;
  }
  return 0;
}

void Carea::HandleVertex(long offset, int count)
{
  area_vertex *newvertices;

  newvertices=new area_vertex[count];
  if(!newvertices) return; //can't allocate, heh
  memcpy(newvertices,vertexheaders+offset,sizeof(area_vertex)*count);
  vertexcount-=count;
  //we store the pointer in the offset field, it needs to be resolved before save
  vertexheaderlist.AddTail(newvertices);
}

void Carea::HandleWedVertex(long offset, int count)
{
  area_vertex *newvertices;

  newvertices=new area_vertex[count];
  if(!newvertices) return; //can't allocate, heh
  memcpy(newvertices,wedvertices+offset,sizeof(area_vertex)*count);
  wedvertexcount-=count;
  //we store the pointer in the offset field, it needs to be resolved before save
  wedvertexheaderlist.AddTail(newvertices);
}

void Carea::HandleDoortile(long offset, int count)
{
  short *newtiles;

  newtiles=new short[count];
  if(!newtiles) return; //can't allocate, heh
  memcpy(newtiles,doortileindices+offset,sizeof(short)*count);
  doortileidxcount-=count;
  //we store the pointer in the offset field, it needs to be resolved before save
  doortilelist.AddTail(newtiles);
}

int Carea::ExplodeVertices()
{
  int ret;
  int i;

  KillVertexList();
  //move vertices into a list (so we can handle them separately)
  for(i=0;i<header.infocnt;i++)
  {
    HandleVertex(triggerheaders[i].vertindx,triggerheaders[i].vertexcount);
  }
  for(i=0;i<header.containercnt;i++)
  {
    HandleVertex(containerheaders[i].firstvertex,containerheaders[i].vertexcount);
  }
  for(i=0;i<header.doorcnt;i++)
  {
    HandleVertex(doorheaders[i].firstvertexopen,doorheaders[i].countvertexopen);
    HandleVertex(doorheaders[i].firstvertexclose,doorheaders[i].countvertexclose);
    HandleVertex(doorheaders[i].firstblockopen,doorheaders[i].countblockopen);
    HandleVertex(doorheaders[i].firstblockclose,doorheaders[i].countblockclose);
  }

  ret=vertexcount;
  KillVertices();
  return ret?1:0;
}
  
int Carea::ExplodeWedVertices()
{
  int ret;
  int i;

  KillWedVertexList();
  for(i=0;i<secheader.wallpolycnt;i++)
  {
    HandleWedVertex(wallpolygonheaders[i].firstvertex,wallpolygonheaders[i].countvertex);
  }
  for(i=0;i<doorpolygoncount;i++)
  {
    HandleWedVertex(doorpolygonheaders[i].firstvertex,doorpolygonheaders[i].countvertex);
  }
  ret=wedvertexcount;
  KillWedvertices();
  return ret?1:0;
}

int Carea::ExplodeDoorTiles()
{
  int ret;
  int i;

  KillDoorTileList();
  for(i=0;i<wedheader.doorcnt;i++)
  {
    HandleDoortile(weddoorheaders[i].firstdoortileidx, weddoorheaders[i].countdoortileidx);
  }
  ret=doortileidxcount;
  KillDoortiles();
  return ret?1:0;
}

int Carea::WriteMap(const char *suffix, unsigned char *pixels, COLORREF *pal, int palsize)
{
  CString filepath, tmpath;
  unsigned char *buffer=NULL;
  int fhandle;
  int fullsize;
  int bitspercolor;
  int scanline, width, height, x;
  int ret;

  filepath=bgfolder+"override\\"+header.wed+suffix+".BMP";
  tmpath=bgfolder+"override\\"+header.wed+suffix+".TMP";
  fhandle=open(tmpath, O_BINARY|O_RDWR|O_CREAT|O_TRUNC,S_IREAD|S_IWRITE);
  if(fhandle<1)
  {
    return -2;
  }
  ret=0;
  width=m_width/GR_WIDTH;
  height=(m_height+GR_HEIGHT-1)/GR_HEIGHT;
  palsize*=sizeof(COLORREF);
  bitspercolor=palsize==64?4:8;
  scanline=GetScanLineLength(width,bitspercolor);
  fullsize=scanline*height;
  bmp_header header={'B','M',fullsize+sizeof(header)+palsize, 0,
  sizeof(header)+palsize, 40, width, height, (short) 1, (short) bitspercolor, 0, fullsize,
  0xb12, 0xb12,0,0};

  if(write(fhandle,&header,sizeof(header))!=sizeof(header))
  {
    ret=-2;
    goto endofquest;
  }

  if(write(fhandle,pal,palsize)!=palsize)
  {
    ret=-2;
    goto endofquest;
  }
  buffer=new unsigned char[scanline];
  if(!buffer)
  {
    ret=-3;
    goto endofquest;
  }
  memset(buffer,0,scanline);
  pixels+=height*width;
  while(height--)
  {
    pixels-=width;
    if(bitspercolor==8) memcpy(buffer, pixels, scanline);
    else
    {
      for(x=0;x<width;x++)
      {
        if(x&1) buffer[x/2]|=pixels[x];
        else buffer[x/2]=(unsigned char) (pixels[x]<<4);
      }      
    }
    if(write(fhandle,buffer,scanline)!=scanline)
    {
      ret=-2;
      goto endofquest;
    }
  }
endofquest:
  if(buffer) delete [] buffer;
  close(fhandle);
  if(!ret)
  {
    unlink(filepath);
    rename(tmpath,filepath);
  }
  return ret;
}

int Carea::WriteWedToFile(int fh)
{
  int otc, dtc, dpc;
  int tmp, ret;
  int esize;
  int fullsize;
  int i;

  memcpy(&wedheader,"WED V1.3",8);

  if(heightmap)
  {
    if(changedmap[0])
    {
      if(m_smallpalette)
      {
        WriteMap("HT",heightmap,htpal,16);
      }
      else
      {
        WriteMap("HT",heightmap,ht8pal,256);
      }
      changedmap[0]=false;
    }
  }
  if(lightmap)
  {
    if(changedmap[1])
    {
      if(m_night)
      {
        WriteMap("LN",lightmap,lmpal,256);
      }
      else
      {
        WriteMap("LM",lightmap,lmpal,256);
      }
      changedmap[1]=false;
    }
  }
  if(searchmap)
  {
    if(changedmap[2])
    {
      WriteMap("SR",searchmap,srpal,16);
      changedmap[2]=false;
    }
  }
  if(!wedavailable) return -1; //internal error

  //adjusting wallgroups
  RecalcBoundingBoxes();

  fullsize=sizeof(wed_header);
  wedheader.overlayoffset=fullsize;
  fullsize+=wedheader.overlaycnt*sizeof(wed_overlay);
  wedheader.secheaderoffset=fullsize;
  fullsize+=sizeof(wed_secondary_header);
  wedheader.dooroffset=fullsize;
  fullsize+=wedheader.doorcnt*sizeof(wed_door);

  if(wedheader.overlaycnt!=5) return -1;

  otc=0;
  for(i=0;i<wedheader.overlaycnt;i++)
  {
    overlayheaders[i].tilemapoffset=fullsize;    
    otc+=overlayheaders[i].height*overlayheaders[i].width;
    fullsize+=overlayheaders[i].height*overlayheaders[i].width*sizeof(wed_tilemap);
  }
  dtc=0;
  dpc=0;
  wedheader.tilecelloffset=fullsize;
  for(i=0;i<weddoorcount;i++)
  {
    dtc+=weddoorheaders[i].countdoortileidx;
    dpc+=weddoorheaders[i].countpolygonopen+weddoorheaders[i].countpolygonclose;
  }
  fullsize+=dtc*sizeof(short);

  tmp=0;
  if(otc!=overlaytilecount)
  {
    return -1; //internal error
  }

  ImplodeDoortiles();
  ImplodeWedVertices();
  for(i=0;i<wallpolygoncount;i++)
  {
    RecalcBox(i,wallpolygonheaders, wedvertices+wallpolygonheaders[i].firstvertex);
  }
  for(i=0;i<doorpolygoncount;i++)
  {
    RecalcBox(i,doorpolygonheaders, wedvertices+doorpolygonheaders[i].firstvertex);
  }
  for(i=0;i<wedheader.overlaycnt;i++)
  {
    overlayheaders[i].tileidxoffset=fullsize+tmp*sizeof(short);
    tmp+=getotic(i);
  }
  fullsize+=overlaytileidxcount*sizeof(short);
  secheader.wallgroupoffset=fullsize;
  fullsize+=wallgroupidxcount*sizeof(wed_polyidx);
  secheader.polygonoffset=fullsize;
  secheader.wallpolycnt=wallpolygoncount;
  fullsize+=secheader.wallpolycnt*sizeof(wed_polygon);
  for(i=0;i<weddoorcount;i++)
  {
    weddoorheaders[i].offsetpolygonopen=fullsize;
    fullsize+=weddoorheaders[i].countpolygonopen*sizeof(wed_polygon);
    weddoorheaders[i].offsetpolygonclose=fullsize;
    fullsize+=weddoorheaders[i].countpolygonclose*sizeof(wed_polygon);
  }

  secheader.polygonidxoffset=fullsize;
  fullsize+=polygonidxcount*sizeof(short);
  secheader.verticeoffset=fullsize;
  fullsize+=wedvertexcount*sizeof(area_vertex);

  //write it
  fullsizew=sizeof(wed_header)+sizeof(wed_secondary_header);
  if(write(fh,&wedheader,sizeof(wed_header) )!=sizeof(wed_header) )
  {
    ret=-2;
    goto endofquest;
  }
  //writing overlay headers
  fullsizew+=esize=wedheader.overlaycnt*sizeof(wed_overlay);
  //hack for saving a night wed
  if(write(fh,overlayheaders,esize)!=esize)
  {
    ret=-2;
    goto endofquest;
  }

  //writing secondary header
  if(write(fh,&secheader,sizeof(wed_secondary_header) )!=sizeof(wed_secondary_header) )
  {
    ret=-2;
    goto endofquest;
  }
  //writing doorheaders
  fullsizew+=esize=wedheader.doorcnt*sizeof(wed_door);
  if(write(fh,weddoorheaders,esize)!=esize)
  {
    ret=-2;
    goto endofquest;
  }
  //converting back to indices
  ret=ConvertOffsetToIndex(secheader.polygonoffset+secheader.wallpolycnt*sizeof(wed_polygon));
  if(ret<0)
  {
    goto endofquest;
  }

  //writing overlay tileheaders
  fullsizew+=esize=overlaytilecount*sizeof(wed_tilemap);
  if(write(fh, overlaytileheaders, esize)!=esize)
  {
    ret=-2;
    goto endofquest;
  }
  //writing door tileindices
  fullsizew+=esize=dtc*sizeof(short);
  if(write(fh,doortileindices, esize)!=esize)
  {
    ret=-2;
    goto endofquest;
  }
  fullsizew+=esize=overlaytileidxcount*sizeof(short);
  if(write(fh,overlaytileindices, esize)!=esize)
  {
    ret=-2;
    goto endofquest;
  }
  fullsizew+=esize=wallgroupidxcount*sizeof(wed_polyidx);
  if(write(fh,wallgroupindices, esize)!=esize)
  {
    ret=-2;
    goto endofquest;
  }
  fullsizew+=esize=secheader.wallpolycnt*sizeof(wed_polygon);
  if(write(fh,wallpolygonheaders, esize)!=esize)
  {
    ret=-2;
    goto endofquest;
  }
  fullsizew+=esize=doorpolygoncount*sizeof(wed_polygon);
  if(write(fh,doorpolygonheaders, esize)!=esize)
  {
    ret=-2;
    goto endofquest;
  }
  fullsizew+=esize=polygonidxcount*sizeof(short);
  if(write(fh,polygonindices, esize)!=esize)
  {
    ret=-2;
    goto endofquest;
  }
  fullsizew+=esize=wedvertexcount*sizeof(area_vertex);
  if(write(fh,wedvertices, esize)!=esize)
  {
    ret=-2;
    goto endofquest;
  }

  if(fullsizew==fullsize)
  {
    wedchanged=false;
    ret=0;
  }
  else ret=-2;

endofquest:
  ExplodeWedVertices();
  ExplodeDoorTiles();
  return ret;
}

void Carea::ConsolidateItems()
{
  area_item *newitems;
  int i,cnt,curcnt;

  cnt=0;
  for(i=0;i<containercount;i++)
  {
    cnt+=containerheaders[i].itemcount;
  }
  newitems = new area_item[cnt];
  if(!newitems)
  {
    return;
  }
  cnt=0;
  for(i=0;i<containercount;i++)
  {
    curcnt=containerheaders[i].itemcount;
    memcpy(newitems+cnt, itemheaders+containerheaders[i].firstitem, curcnt*sizeof(area_item));
    containerheaders[i].firstitem=cnt;
    cnt+=curcnt;
  }
  if(the_area.itemheaders)
  {
    delete [] the_area.itemheaders;
  }
  the_area.itemheaders=newitems;
  itemcount=cnt;
  header.itemcnt=(short) cnt;
}

int Carea::WriteAreaToFile(int fh, int calculate)
{
  int esize;
  int fullsize;
  int ret;
  int i;

  ImplodeVertices();
  ConsolidateItems();
  fullsize=sizeof(area_header);
  if(revision==91)
  {
    fullsize+=sizeof(iwd2_header);
    memcpy(header.filetype,"AREAV9.1",8);
  }
  else
  {
    memcpy(header.filetype,"AREAV1.0",8);
  }

  header.actoroffset=fullsize;
  fullsize+=header.actorcnt*sizeof(area_actor);             //actor headers
  for(i=0;i<actorcount;i++)                                 //actor data
  {
    if (actorheaders[i].cresize)
    {
      actorheaders[i].creoffset=fullsize;
    }
    else
    {
      actorheaders[i].creoffset=0;
    }
    fullsize+=actorheaders[i].cresize;
  }
  header.infooffset=fullsize;
  fullsize+=header.infocnt*sizeof(area_trigger);            //trigger (infopoint)
  header.spawnoffset=fullsize; 
  fullsize+=header.spawncnt*sizeof(area_spawn);             //spawn
  header.entranceoffset=fullsize; 
  fullsize+=header.entrancecnt*sizeof(area_entrance);       //entrance
  header.containeroffset=fullsize;
  fullsize+=header.containercnt*sizeof(area_container);     //container
  header.itemoffset=fullsize;
  fullsize+=header.itemcnt*sizeof(area_item);               //item
  header.ambioffset=fullsize;
  fullsize+=header.ambicnt*sizeof(area_ambient);            //ambient
  header.variableoffset=fullsize;
  fullsize+=header.variablecnt*sizeof(area_variable);       //variable
  header.exploredoffset=fullsize;
  fullsize+=header.exploredsize;                            //explored
  header.dooroffset=fullsize;
  fullsize+=header.doorcnt*sizeof(area_door);               //door
  header.tileoffset=fullsize;
  fullsize+=header.tilecnt*sizeof(area_tile);               //tiled objects
  header.vertexoffset=fullsize;
  fullsize+=header.vertexcnt*sizeof(area_vertex);           //vertex
  header.animationoffset=fullsize;
  fullsize+=header.animationcnt*sizeof(area_anim);          //animation
  //set these only when needed
  if(header.songoffset) header.songoffset=fullsize;
  fullsize+=sizeof(area_song);                              //song
  //set this only when needed
  if(header.intoffset) header.intoffset=fullsize;
  fullsize+=sizeof(area_int);                               //interruption
  if(header.mapnotecnt)
  {
    header.mapnoteoffset=fullsize;
    fullsize+=header.mapnotecnt*sizeof(area_mapnote);       //mapnotes
  }
  if(header.trapcnt && !pst_compatible_var())               //traps are not compatible with pst
  {
    for(i=0;i<trapcount;i++)
    {
      trapheaders[i].offset=fullsize;
      fullsize += trapheaders[i].size;                      //trap effects
    }
    header.pstmapnotecnt=fullsize;
    fullsize+=header.trapcnt*sizeof(area_trap);             //trap projectiles
  }

  if(calculate)
  {
    ExplodeVertices();
    return fullsize;
  }
  ret=0;
  if(fh<1)
  {
    ret=-1;
    goto endofquest;
  }
//header
  if(revision==91)
  { //iwd2 area format sucks (the new, empty unknowns come before the offsets)
    esize=(BYTE *) &header.actoroffset-(BYTE *) header.filetype;
    if(write(fh,&header,esize)!=esize)
    {
      ret=-2;
      goto endofquest;
    }
    if(write(fh,&iwd2header,sizeof(iwd2_header) )!=sizeof(iwd2_header) )
    {
      ret=-2;
      goto endofquest;
    }
    esize=sizeof(area_header)-esize;
    if(write(fh,&header.actoroffset,esize)!=esize)
    {
      ret=-2;
      goto endofquest;
    }
  }
  else
  {
    if(pst_compatible_var()) //quick hack for shifting the mapnotes in place
    {
      header.pstmapnotecnt=header.mapnotecnt;
      header.mapnotecnt=header.mapnoteoffset;
      header.mapnoteoffset=~0;
    }
    if(write(fh,&header,sizeof(area_header) )!=sizeof(area_header) )
    {	
      ret=-2;
      goto endofquest;
    }
    if(pst_compatible_var()) //quick hack for shifting the mapnotes in place
    {
      header.mapnoteoffset=header.mapnotecnt;
      header.mapnotecnt=header.pstmapnotecnt;
    }
  }
//actor
  esize=header.actorcnt*sizeof(area_actor);
  if(write(fh,actorheaders,esize )!=esize )
  {	
    ret=-2;
    goto endofquest;
  }
  for(i=0;i<actorcount;i++)
  {
    esize=actorheaders[i].cresize;
    if(write(fh,credatapointers[i],esize)!=esize)
    {
      ret=-2;
      goto endofquest;
    }
  }
  //trigger (infopoint)
  esize=header.infocnt*sizeof(area_trigger);
  if(write(fh,triggerheaders,esize )!=esize )
  {	
    ret=-2;
    goto endofquest;
  }
  //spawnpoint
  esize=header.spawncnt*sizeof(area_spawn);
  if(write(fh,spawnheaders,esize )!=esize )
  {	
    ret=-2;
    goto endofquest;
  }
  //entrances
  esize=header.entrancecnt*sizeof(area_entrance);
  if(write(fh,entranceheaders,esize )!=esize )
  {	
    ret=-2;
    goto endofquest;
  }
  //container
  esize=header.containercnt*sizeof(area_container);
  if(write(fh,containerheaders,esize )!=esize )
  {	
    ret=-2;
    goto endofquest;
  }
  
  //items
  esize=header.itemcnt*sizeof(area_item);
  if(write(fh,itemheaders,esize )!=esize )
  {	
    ret=-2;
    goto endofquest;
  }
  
  //ambients
  esize=header.ambicnt*sizeof(area_ambient);
  if(write(fh,ambientheaders,esize )!=esize )
  {	
    ret=-2;
    goto endofquest;
  }
  
  //variable
  esize=header.variablecnt*sizeof(area_variable);
  if(write(fh,variableheaders,esize )!=esize )
  {	
    ret=-2;
    goto endofquest;
  }
  
  //explored
  if(write(fh,explored,header.exploredsize )!=header.exploredsize )
  {	
    ret=-2;
    goto endofquest;
  }
  
  //door
  esize=header.doorcnt*sizeof(area_door);
  if(write(fh,doorheaders,esize )!=esize )
  {	
    ret=-2;
    goto endofquest;
  }
  
  //tiled
  esize=header.tilecnt*sizeof(area_tile);
  if(write(fh,tileheaders,esize )!=esize )
  {	
    ret=-2;
    goto endofquest;
  }
  
  //vertices
  esize=header.vertexcnt*sizeof(area_vertex);
  if(write(fh,vertexheaders,esize )!=esize )
  {	
    ret=-2;
    goto endofquest;
  }
  
  //animation
  esize=header.animationcnt*sizeof(area_anim);
  if(write(fh,animheaders,esize )!=esize )
  {	
    ret=-2;
    goto endofquest;
  }
  
  //song
  if(header.songoffset)
  {/*
    for(int i=0;i<sizeof(songheader.unused);i+=4) {
      memcpy(songheader.unused+i, &songheader.songflag,4);
    }
    */
    if(write(fh,&songheader,sizeof(area_song) )!=sizeof(area_song) )
    {	
      ret=-2;
      goto endofquest;
    }
  }
  
//interruption
  if(header.intoffset)
  {
    if(write(fh,&intheader,sizeof(area_int) )!=sizeof(area_int) )
    {	
      ret=-2;
      goto endofquest;
    }
  }
  
  if(pst_compatible_var())
  {
    ConvertToPstMapnote();
    esize=header.mapnotecnt*sizeof(pst_area_mapnote);
    if(write(fh,pstmapnoteheaders,esize )!=esize )
    {
      delete[] pstmapnoteheaders;
      pstmapnoteheaders=NULL;
      ret=-2;
      goto endofquest;
    }
    delete[] pstmapnoteheaders;
    pstmapnoteheaders=NULL;
    m_changed=false;
  }
  else
  {
    esize=header.mapnotecnt*sizeof(area_mapnote);
    if(write(fh,mapnoteheaders,esize )!=esize )
    {
      ret=-2;
      goto endofquest;
    }
    int cnt, i;

    cnt = 0;
    for(i=0;i<trapcount;i++)
    {
      esize=trapheaders[i].size;
      if(write(fh,effects+cnt, esize)!=esize )
      {
        ret=-2;
        goto endofquest;
      }
      cnt +=esize/sizeof(creature_effect);
    }
    esize=header.trapcnt*sizeof(area_trap);
    if(write(fh,trapheaders,esize )!=esize )
    {
      ret=-2;
      goto endofquest;
    }
    m_changed=false;
  }
  
endofquest:
  ExplodeVertices();
  return ret;
}

//looks for entryname in the area opened
int Carea::CheckDestination(int fh, long ml, CString entryname)
{
  int flg, ret;
  int esize;
  int i;
  CString tmpdestination;
  
  ret=0;
  fhandlea=fh;
  if(ml==-1) maxlena=filelength(fhandlea);
  else maxlena=ml;
  if(maxlena<1) return -1; //short file, invalid item
  startpointa=tell(fhandlea);
  esize=(BYTE *) &header.actoroffset-(BYTE *) header.filetype;
  if(read(fhandlea,&header,esize )!=esize )
  {	
  	return -2; // short file, invalid item
  }
  if(memcmp(header.filetype,"AREA",4) )
  {
	  return -2;
  }
  if(header.revision[0]!='V')
  {
	  return -2;
  }
  if(memcmp(header.revision,"V1.0",4) )
  {
    if(memcmp(header.revision,"V9.1",4) )
    {
      return -2;
    }
    else
    {
      if(read(fhandlea,&iwd2header,sizeof(iwd2header))!=sizeof(iwd2header) )
      {
        return -2;
      }
      revision=91;
    }
  }
  else revision=10;

  //reading the second part of the main area header (offsets)
  esize=sizeof(area_header)-esize;
  if(read(fhandlea,&header.actoroffset,esize )!=esize )
  {	
  	return -2; // short file, invalid item
  }

  flg=adjust_actpointa(header.entranceoffset);
  if(flg<0)
  {
    return flg;
  }
  if(entrancecount!=header.entrancecnt)
  {
    KillEntrances();
    entranceheaders=new area_entrance[header.entrancecnt];
    if(!entranceheaders) return -3;
    entrancecount=header.entrancecnt;
  }
  esize=header.entrancecnt*sizeof(area_entrance);
  if(read(fhandlea,entranceheaders,esize )!=esize )
  {
    return -2;
  }
  for(i=0;i<header.entrancecnt;i++)
  {
    RetrieveVariable(tmpdestination,entranceheaders[i].entrancename);
    if(entryname==tmpdestination) return 0;
  }
  return 1; //cannot find it
}

CString Carea::RetrieveMosRef(int fh)
{
  CString tmpstr;
  int required;

  if(fh<1) return "";
  required=(BYTE *) &header.wed-(BYTE *) &header+8;
  if(read(fh, &header, required)!=required)
  {
    close(fh);
    return "";
  }
  close(fh);
  RetrieveResref(tmpstr,header.wed);
  return tmpstr;
}

//looks for entryname in the area opened
int Carea::FillDestination(int fh, long ml, CComboBox *cb)
{
  int flg, ret;
  int esize;
  int i;
  CString tmpdestination;

  cb->ResetContent();
  ret=0;
  fhandlea=fh;
  if(ml==-1) maxlena=filelength(fhandlea);
  else maxlena=ml;
  if(maxlena<1) return -1; //short file, invalid item
  startpointa=tell(fhandlea);
  esize=(BYTE *) &header.actoroffset-(BYTE *) header.filetype;
  if(read(fhandlea,&header,esize )!=esize )
  {	
  	return -2; // short file, invalid item
  }
  if(memcmp(header.filetype,"AREA",4) )
  {
	  return -2;
  }
  if(header.revision[0]!='V')
  {
	  return -2;
  }
  if(memcmp(header.revision,"V1.0",4) )
  {
    if(memcmp(header.revision,"V9.1",4) )
    {
      return -2;
    }
    else
    {
      if(read(fhandlea,&iwd2header,sizeof(iwd2header))!=sizeof(iwd2header) )
      {
        return -2;
      }
      revision=91;
    }
  }
  else revision=10;

  //reading the second part of the main area header (offsets)
  esize=sizeof(area_header)-esize;
  if(read(fhandlea,&header.actoroffset,esize )!=esize )
  {	
  	return -2; // short file, invalid item
  }

  flg=adjust_actpointa(header.entranceoffset);
  if(flg<0)
  {
    return flg;
  }
  if(entrancecount!=header.entrancecnt)
  {
    KillEntrances();
    entranceheaders=new area_entrance[header.entrancecnt];
    if(!entranceheaders) return -3;
    entrancecount=header.entrancecnt;
  }
  esize=header.entrancecnt*sizeof(area_entrance);
  if(read(fhandlea,entranceheaders,esize )!=esize )
  {
    return -2;
  }
  for(i=0;i<header.entrancecnt;i++)
  {
    RetrieveVariable(tmpdestination,entranceheaders[i].entrancename);
    cb->AddString(tmpdestination);
  }
  return 0;
}

void Carea::MirrorMap(unsigned char *poi)
{
  int maxx,maxy;
  int x,y;
  unsigned char tmp;

  maxx=m_width/GR_WIDTH;
  maxy=(m_height+GR_HEIGHT-1)/GR_HEIGHT;
  for(y=0;y<maxy;y++)
  {
    for(x=0;x<maxx/2;x++)
    {
      tmp=poi[y*maxx+x];
      poi[y*maxx+x]=poi[(y+1)*maxx-x-1];
      poi[(y+1)*maxx-x-1]=tmp;
    }
  }
}

//door = -1 don't calculate vertex offset

void Carea::RecalcBox(int pos, wed_polygon *header, area_vertex *vertices)
{
  POINTS tmp, min, max;
  int count;
  int i;

  count=header[pos].countvertex;
  if(!count)
  {
    header[pos].maxx=-1;
    header[pos].maxy=-1;
    header[pos].minx=-1;
    header[pos].miny=-1;
    return;
  }
  
  min=max=(POINTS &) vertices[0];
  for(i=1;i<count;i++)
  {
    tmp=(POINTS &) vertices[i];
    if(max.x<tmp.x) max.x=tmp.x;
    if(max.y<tmp.y) max.y=tmp.y;
    if(min.x>tmp.x) min.x=tmp.x;
    if(min.y>tmp.y) min.y=tmp.y;
  }
  header[pos].maxx=max.x;
  header[pos].maxy=max.y;
  header[pos].minx=min.x;
  header[pos].miny=min.y;
}

//recalculate all bounding boxes for area_polygons
//sorting wallpolygons into wallgroups
int Carea::RecalcBoundingBoxes()
{
  int wgx, wgy;
  int minx,miny, maxx,maxy;
  int x,y;
  POSITION pos;
  void *poi;
  int count;
  int i;

  pos = wedvertexheaderlist.GetHeadPosition();
  //this is being done for all polygons
  for(i=0;i<wedvertexheaderlist.GetCount();i++)
  {
    if(i<secheader.wallpolycnt)
    {
      RecalcBox(i, wallpolygonheaders, (area_vertex *) wedvertexheaderlist.GetNext(pos) );
    }
    else
    {
      RecalcBox(i-secheader.wallpolycnt,doorpolygonheaders, (area_vertex *) wedvertexheaderlist.GetNext(pos) );
    }
  }
  wgx=(overlayheaders[0].width+9)/10;
  wgy=(overlayheaders[0].height*2+14)/15;
  wallgroupidxcount=wgx*wgy;
  if(wallgroupindices) 
  {
    delete [] wallgroupindices;
  }
  wallgroupindices=new wed_polyidx[wallgroupidxcount];
  if(!wallgroupindices) return -3;
  memset(wallgroupindices,0,wallgroupidxcount*sizeof(wed_polyidx) );
  pos = wedvertexheaderlist.GetHeadPosition();
//  for(i=0;i<secheader.wallpolycnt;i++)
  for(i=0;i<wedvertexheaderlist.GetCount();i++)
  {
    poi = wedvertexheaderlist.GetNext(pos);
    if(i<secheader.wallpolycnt)
    {
      minx=wallpolygonheaders[i].minx/640;
      maxx=wallpolygonheaders[i].maxx/640;
      miny=wallpolygonheaders[i].miny/480;
      maxy=wallpolygonheaders[i].maxy/480;
      count=wallpolygonheaders[i].countvertex;
    }
    else
    {
      minx=doorpolygonheaders[i-secheader.wallpolycnt].minx/640;
      maxx=doorpolygonheaders[i-secheader.wallpolycnt].maxx/640;
      miny=doorpolygonheaders[i-secheader.wallpolycnt].miny/480;
      maxy=doorpolygonheaders[i-secheader.wallpolycnt].maxy/480;
      count=doorpolygonheaders[i-secheader.wallpolycnt].countvertex;
    }
    if (minx<0) minx=0;
    if (miny<0) miny=0;
    if (maxx>=wgx) maxx=wgx-1;
    for(x=minx;x<=maxx;x++) for(y=miny;y<=maxy;y++)
    {
      if(PolygonInBox( (area_vertex *) poi, count, CRect(minx*640, miny*480, (minx+1)*640, (miny+1)*480) ) )
      {
        if (x>=wgx) continue;
        if (y>=wgy) continue;
        wallgroupindices[y*wgx+x].count++;
      }
    }
  }
  polygonidxcount=0;
  for(i=0;i<wallgroupidxcount;i++)
  {
    wallgroupindices[i].index=(short) polygonidxcount;
    polygonidxcount+=wallgroupindices[i].count;
    wallgroupindices[i].count=0;
  }
  if(polygonindices)
  {
    delete [] polygonindices;
  }
  polygonindices=new short[polygonidxcount];
  pos = wedvertexheaderlist.GetHeadPosition();
//  for(i=0;i<secheader.wallpolycnt;i++)
  for(i=0;i<wedvertexheaderlist.GetCount();i++)
  {
    poi = wedvertexheaderlist.GetNext(pos);
    if(i<secheader.wallpolycnt)
    {
      minx=wallpolygonheaders[i].minx/640;
      maxx=wallpolygonheaders[i].maxx/640;
      miny=wallpolygonheaders[i].miny/480;
      maxy=wallpolygonheaders[i].maxy/480;
      count=wallpolygonheaders[i].countvertex;
    }
    else
    {
      minx=doorpolygonheaders[i-secheader.wallpolycnt].minx/640;
      maxx=doorpolygonheaders[i-secheader.wallpolycnt].maxx/640;
      miny=doorpolygonheaders[i-secheader.wallpolycnt].miny/480;
      maxy=doorpolygonheaders[i-secheader.wallpolycnt].maxy/480;
      count=doorpolygonheaders[i-secheader.wallpolycnt].countvertex;
    }
    for(x=minx;x<=maxx;x++) for(y=miny;y<=maxy;y++)
    {
      if(PolygonInBox((area_vertex *) poi, count, CRect(minx*640, miny*480, (minx+1)*640, (miny+1)*480) ) )
      {
        if (x>=wgx) continue;
        if (y>=wgy) continue;
        wed_polyidx *wgi=wallgroupindices+y*wgx+x;
        polygonindices[wgi->index+wgi->count++]=(short) i;
      }
    }
  }
  return 0;
}

int Carea::ConvertOffsetToIndex(int polyoffset)
{
  int i;
  int dpc;

  dpc=0;
  for(i=0;i<weddoorcount;i++)
  {
    weddoorheaders[i].offsetpolygonopen=(weddoorheaders[i].offsetpolygonopen-polyoffset)/sizeof(wed_polygon);
    if(weddoorheaders[i].offsetpolygonopen!=dpc)
    {
      return -1;
    }
    dpc+=weddoorheaders[i].countpolygonopen;
    weddoorheaders[i].offsetpolygonclose=(weddoorheaders[i].offsetpolygonclose-polyoffset)/sizeof(wed_polygon);
    if(weddoorheaders[i].offsetpolygonclose!=dpc)
    {
      return -1;
    }
    dpc+=weddoorheaders[i].countpolygonclose;
  }
  return dpc;
}

int Carea::getotc(int overlay)
{
  int i, otc;

  otc=0;
  for(i=0;i<overlay;i++)
  {
    otc+=overlayheaders[i].height*overlayheaders[i].width;
  }
  return otc;
}

int Carea::getfoti(int overlay) //first overlay tile index
{
  int i, otc, foti;

  otc=getotc(overlay);
  foti=0;
  for(i=0;i<otc;i++)
  {    
    foti+=overlaytileheaders[i].counttileprimary;
  }
  return foti;
}

int Carea::getotic(int overlay) //overlay tile index count
{
  int i, otc, otic, first;

  first=getotc(overlay);
  otc=overlayheaders[overlay].height*overlayheaders[overlay].width;
  otic=0;
  for(i=0;i<otc;i++)
  {    
    otic+=overlaytileheaders[i+first].counttileprimary;
  }
  return otic;
}

int Carea::ReadMap(const char *Suffix, unsigned char *&Storage, COLORREF *Palette, int size)
{
  Cbam tmpbam;
  CString resname;
  int mapsize;
  int ret;

  RetrieveResref(resname,header.wed);
  resname+=Suffix;
  if(read_bmp(resname, &tmpbam, 0)) return -2;
  if(tmpbam.GetFrameCount()!=1) return -2;
  //if(size<tmpbam.m_palettesize) return -2;
  if(Storage)
  {
    delete [] Storage;
    Storage=NULL;
  }
  memset(Palette,0,size);
  if(size>tmpbam.m_palettesize) size=tmpbam.m_palettesize;
  memcpy(Palette, tmpbam.m_palette, size);
  mapsize=(m_width/GR_WIDTH)*((m_height+GR_HEIGHT-1)/GR_HEIGHT);
  Storage = new unsigned char[mapsize];
  if(!Storage) return -3;
  memset(Storage, 0, mapsize);
  ret = 0;
  if(tmpbam.m_palettesize!=size) ret = 1;
  size = tmpbam.GetFrameDataSize(0);
  if(size<mapsize)
  {
    mapsize=size;
    ret = 1;
  }
  memcpy(Storage, tmpbam.GetFrameData(0), mapsize);
  return ret;
}

int Carea::ReadWedFromFile(int fh, long ml)
{
  int flg, ret;
  int esize;
  int otc, dtc, otic, ootic;
  int dpc, wgc, wgpc;
  int wvc;
  int pos;
  int i;

  fhandlew=fh;
  if(ml==-1) maxlenw=filelength(fhandlew);
  else maxlenw=ml;
  if(maxlenw<1) return -1; //short file, invalid item
  startpointw=tell(fhandlew);
  fullsizew=sizeof(wedheader);
  if(read(fhandlew,&wedheader,fullsizew )!=fullsizew )
  {	
  	return -2; // short file, invalid item
  }
  if(memcmp(wedheader.filetype,"WED ",4) )
  {
	  return -2;
  }

  //wed overlays
  if(wedheader.overlayoffset!=fullsizew)
  {
    return -2;
  }
  otc=0;
  wgc=0;
  if(overlaycount!=wedheader.overlaycnt)
  {
    KillOverlays();
    overlayheaders=new wed_overlay[wedheader.overlaycnt];
    if(!overlayheaders)
    {
      return -3;
    }
    overlaycount=wedheader.overlaycnt;
  }  
  esize=wedheader.overlaycnt*sizeof(wed_overlay);
  if(read(fhandlew,overlayheaders,esize )!=esize )
  {
    return -2;
  }
  if(wedheader.overlaycnt)
  {
    m_width=(unsigned short) (overlayheaders[0].width*64);
    m_height=(unsigned short) (overlayheaders[0].height*64);
  }
  else m_width=m_height=0;
  if(m_night)
  {
    ReadMap("LN", lightmap, lmpal, sizeof(lmpal) );
  }
  else
  {
    ReadMap("LM", lightmap, lmpal, sizeof(lmpal) );
  }
  ReadMap("SR", searchmap, srpal, sizeof(srpal) );
  m_smallpalette=true;
  ret = ReadMap("HT", heightmap, htpal, sizeof(htpal) );
  if(ret==1)
  {
    m_smallpalette=false;
    ReadMap("HT", heightmap, ht8pal, sizeof(ht8pal) );
  }
  wedchanged=false;
  for(ret=0;ret<3;ret++) changedmap[ret]=false;
  ret=0;

  fullsizew+=esize;
  //precalculating the size of the overlaytilemap
  for(i=0;i<overlaycount;i++)
  {
    otc+=overlayheaders[i].width*overlayheaders[i].height;
  }
  if(otc!=overlaytilecount)
  {
    KillOverlaytiles();
    overlaytileheaders=new wed_tilemap[otc];
    if(!overlaytileheaders)
    {
      return -3;
    }
    overlaytilecount=otc;
  }

  if(wedheader.secheaderoffset!=fullsizew )
  {
    return -2;
  }
  if(read(fhandlew,&secheader,sizeof(secheader) )!=sizeof(secheader) )
  {	
  	return -2; // short file, invalid item
  }
  fullsizew+=sizeof(secheader);

  //wed doors
  if(wedheader.dooroffset!=fullsizew)
  {
    return -2;
  }
  if(weddoorcount!=wedheader.doorcnt)
  {
    KillWeddoors();
    weddoorheaders=new wed_door[wedheader.doorcnt];
    if(!weddoorheaders)
    {
      return -3;
    }
    weddoorcount=wedheader.doorcnt;
  }

  esize=wedheader.doorcnt*sizeof(wed_door);
  if(read(fhandlew,weddoorheaders,esize )!=esize )
  {
    return -2;
  }
  fullsizew+=esize;
  //precalculating the number of door tile indices, doorpolygonheaders
  
  dpc=ConvertOffsetToIndex(secheader.polygonoffset+secheader.wallpolycnt*sizeof(wed_polygon));
  if(dpc<0) return dpc;

  dtc=0;
  for(i=0;i<weddoorcount;i++)
  {
    dtc+=weddoorheaders[i].countdoortileidx;
  }
  if(dtc!=doortileidxcount)
  {
    KillDoortiles();
    doortileindices=new short[dtc];
    if(!doortileindices)
    {
      return -3;
    }
    doortileidxcount=dtc;
  }

  pos=0;
  for(i=0;i<wedheader.overlaycnt;i++)
  {
    //IETME saves doors first, therefore we need to seek the overlayheaders out
    //we seek each of them one by one to improve flexibility
    flg=adjust_actpointw(overlayheaders[i].tilemapoffset);
    if(flg<0) return flg;
    ret|=flg;
    
    esize=overlayheaders[i].height*overlayheaders[i].width*sizeof(wed_tilemap);
    if(read(fhandlew, overlaytileheaders+pos, esize )!=esize )
    {
      return -2;
    }
    fullsizew+=esize;
    pos+=overlayheaders[i].height*overlayheaders[i].width;    
  }
  if(pos!=otc) return -1; //hmm hmm hmm
  //precalculating overlay tilemap index counter
  otic=0;
  for(i=0;i<otc;i++)
  {
    otic+=overlaytileheaders[i].counttileprimary;
  }
  if(otic!=overlaytileidxcount)
  {
    KillOverlayindices();
    overlaytileindices=new short[otic];
    if(!overlaytileindices) return -3;
    overlaytileidxcount=otic;
  }

  //wed tiles
  flg=adjust_actpointw(wedheader.tilecelloffset);
  if(flg<0) return flg;
  ret|=flg;

  esize=dtc*sizeof(short);
  if(read(fhandlew,doortileindices, esize)!=esize)
  {
    return -2;
  }
  fullsizew+=esize;

  if(!overlaycount)
  {
    return -2;
  }
  pos=0;
  for(i=0;i<overlaycount;i++)
  {
    flg=adjust_actpointw(overlayheaders[i].tileidxoffset);
    if(flg<0) return flg;
    ret|=flg;

    ootic=getotic(i);
    esize=ootic*sizeof(short);
    if(read(fhandlew,overlaytileindices+pos, esize)!=esize)
    {
      return -2;
    }
    fullsizew+=esize;
    pos+=ootic;
    otic-=ootic; //should be 0
    if(otic<0) return -1;
  }
  if(otic) return -1;

  //wallgroups
  flg=adjust_actpointw(secheader.wallgroupoffset);
  if(flg<0) return flg;
  ret|=flg;

  wgc=((overlayheaders[0].width+9)/10)*((overlayheaders[0].height*2+14)/15);
  if(wgc!=wallgroupidxcount)
  {
    KillWallgroups();
    wallgroupindices=new wed_polyidx[wgc];
    if(!wallgroupindices) return -3;
    wallgroupidxcount=wgc;
  }
  esize=wgc*sizeof(wed_polyidx); //similar to POINTS structure (sizeof=4)
  if(read(fhandlew,wallgroupindices, esize)!=esize)
  {
    return -2;
  }
  fullsizew+=esize;

  wgpc=0;
  for(i=0;i<wgc;i++)
  {
    if(wallgroupindices[i].index!=wgpc) //a little consistency check
    {
      ret|=2;
    }
    //we use MAX to get the maximal extent of this region,
    //there could be holes/mixups inside
    wgpc=max(wgpc,wallgroupindices[i].index+wallgroupindices[i].count);
  }

  //allocating door polygons
  flg=adjust_actpointw(secheader.polygonoffset);
  if(flg<0) return flg;
  ret|=flg;

  if(dpc!=doorpolygoncount)
  {
    KillDoorpolygons();
    doorpolygonheaders=new wed_polygon[dpc];
    if(!doorpolygonheaders) return -3;
    doorpolygoncount=dpc;
  }

  //wallgroup polygons
  if(secheader.wallpolycnt!=wallpolygoncount)
  {
    KillWallgrouppolygons();
    wallpolygonheaders=new wed_polygon[secheader.wallpolycnt];
    if(!wallpolygonheaders) return -3;
    wallpolygoncount=secheader.wallpolycnt;
  }
  esize=wallpolygoncount*sizeof(wed_polygon);
  if(read(fhandlew,wallpolygonheaders,esize)!=esize)
  {
    return -2;
  }
  fullsizew+=esize;

  //reading door polygons
  esize=doorpolygoncount*sizeof(wed_polygon);
  if(read(fhandlew,doorpolygonheaders,esize)!=esize)
  {
    return -2;
  }
  fullsizew+=esize;

  //precalculating vertex size
  wvc=0;
  for(i=0;i<wallpolygoncount;i++)
  {
    if(wallpolygonheaders[i].firstvertex!=wvc)
    {
      ret|=1;
    }
    wvc=max(wvc,wallpolygonheaders[i].firstvertex+wallpolygonheaders[i].countvertex);
  }
  //here is the limit between door/wallgroup, normally
  for(i=0;i<doorpolygoncount;i++)
  {
    if(doorpolygonheaders[i].firstvertex!=wvc)
    {
      ret|=1;
    }
    wvc=max(wvc,doorpolygonheaders[i].firstvertex+doorpolygonheaders[i].countvertex);
  }

  flg=adjust_actpointw(secheader.polygonidxoffset);
  if(flg<0) return flg;
  ret|=flg;

  if(wgpc!=polygonidxcount)
  {
    KillPolygonindices();
    polygonindices=new short[wgpc];
    if(!polygonindices) return -3;
    polygonidxcount=wgpc;
  }
  esize=wgpc*sizeof(short);
  if(read(fhandlew,polygonindices,esize)!=esize)
  {
    return -2;
  }
  fullsizew+=esize;

  //finally: vertices
  //we cannot read the vertices separated, because IETME dumps door polygons among
  //wallgroup polygons
  flg=adjust_actpointw(secheader.verticeoffset);
  if(flg<0) return flg;
  ret|=flg;
  if(wvc!=wedvertexcount)
  {
    KillWedvertices();
    wedvertices=new area_vertex[wvc];  //'official' vertex type: short x,y;
    if(!wedvertices) return -3;
    wedvertexcount=wvc;
  }
  esize=wvc*sizeof(area_vertex);
  if(read(fhandlew,wedvertices,esize)!=esize)
  {
    return -2;
  }
  fullsizew+=esize;

  flg=ExplodeDoorTiles();
  if(flg<0) return flg;
  ret|=flg;

  flg=ExplodeWedVertices();
  if(flg<0) return flg;
  ret|=flg;

  wedavailable=true;
  if(fullsizew!=maxlenw)
  {
    ret|=2;
  }
  return ret;
}

int Carea::ReadActorData()
{
  long oldpos;
  int flg;
  int i;

  KillCreDataPointers();
  credatapointers=new char*[actorcount];
  if(!credatapointers) return -3;
  for(i=0;i<actorcount;i++)
  {
    if(actorheaders[i].creoffset && actorheaders[i].cresize)
    {
      credatapointers[i]=new char[actorheaders[i].cresize];
      if(!credatapointers[i]) return -3;
      oldpos=tell(fhandlea);
      if(lseek(fhandlea,actorheaders[i].creoffset,SEEK_SET)==actorheaders[i].creoffset)
      {
        flg=read(fhandlea,credatapointers[i],actorheaders[i].cresize)!=actorheaders[i].cresize;
        lseek(fhandlea,oldpos,SEEK_SET);
      }
      else flg=1;
      if(flg) return -2;
      fullsizea+=actorheaders[i].cresize; 
    }
    else 
    {
      credatapointers[i]=NULL;
      actorheaders[i].creoffset=0;
      actorheaders[i].cresize=0;
    }
  }

  return 0;
}

void Carea::ConvertToPstMapnote()
{
  int i;

  if(pstmapnoteheaders) delete[] pstmapnoteheaders;
  pstmapnoteheaders = new pst_area_mapnote[header.mapnotecnt];
  for(i=0;i<header.mapnotecnt;i++)
  {
    pstmapnoteheaders[i].px=mapnoteheaders[i].px;
    pstmapnoteheaders[i].py=mapnoteheaders[i].py;
    CString tmpstr=resolve_tlk_text(mapnoteheaders[i].strref);
    int len = tmpstr.GetLength();
    if(len>256) len=256;
    strncpy(pstmapnoteheaders[i].text, tmpstr, len);
    pstmapnoteheaders[i].readonly=!!mapnoteheaders[i].colour;
  }
}

void Carea::ConvertFromPstMapnote()
{
  int i;

  if(mapnoteheaders) delete[] mapnoteheaders;
  mapnoteheaders = new area_mapnote[header.mapnotecnt];
  memset(mapnoteheaders,0,header.mapnotecnt*sizeof(area_mapnote) );
  for(i=0;i<header.mapnotecnt;i++)
  {
    mapnoteheaders[i].px=(unsigned short) pstmapnoteheaders[i].px;
    mapnoteheaders[i].py=(unsigned short) pstmapnoteheaders[i].py;
    mapnoteheaders[i].strref=store_tlk_text(-1,pstmapnoteheaders[i].text);
    mapnoteheaders[i].colour=(unsigned short) pstmapnoteheaders[i].readonly;
  }
  delete[] pstmapnoteheaders;
  pstmapnoteheaders=NULL;
}

int Carea::ReadAreaFromFile(int fh, long ml)
{
  int flg, ret;
  int esize;

  wedavailable=false;
  wedchanged=false;
  m_night=false;
  for(ret=0;ret<3;ret++) changedmap[ret]=false;
  m_changed=false;
  if(overlaycount)
  {
    overlayheaders[0].height=9999;
    overlayheaders[0].width=9999;
  }
  ret=0;
  fhandlea=fh;
  if(ml==-1) maxlena=filelength(fhandlea);
  else maxlena=ml;
  if(maxlena<1) return -1; //short file, invalid item
  startpointa=tell(fhandlea);
  fullsizea=sizeof(header);
  esize=(BYTE *) &header.actoroffset-(BYTE *) header.filetype;
  if(read(fhandlea,&header,esize )!=esize )
  {	
  	return -2; // short file, invalid item
  }
  if(memcmp(header.filetype,"AREA",4) )
  {
	  return -2;
  }
  if(memcmp(header.revision,"V1.0",4) )
  {
    if(memcmp(header.revision,"V9.1",4) )
    {
      return -2;
    }
    else
    {
      if(read(fhandlea,&iwd2header,sizeof(iwd2header))!=sizeof(iwd2header) )
      {
        return -2;
      }
      fullsizea+=sizeof(iwd2header);
      revision=91;
    }
  }
  else revision=10;

  //reading the second part of the main area header (offsets)
  esize=sizeof(area_header)-esize;
  if(read(fhandlea,&header.actoroffset,esize )!=esize )
  {	
  	return -2; // short file, invalid item
  }
  if(pst_compatible_var()) //quick hack for shifting the mapnotes in place
  {
    header.mapnoteoffset=header.mapnotecnt;
    header.mapnotecnt=header.pstmapnotecnt;
  }
  //actors
  if(header.actorcnt)
  {
    flg=adjust_actpointa(header.actoroffset);
    if(flg<0) return flg;
    if(flg) ret|=flg;
  }

  if(actorcount!=header.actorcnt)
  {
    KillActors();
    actorheaders=new area_actor[header.actorcnt];
    if(!actorheaders)
    {
      return -3;
    }
    actorcount=header.actorcnt;
  }
  esize=header.actorcnt*sizeof(area_actor);
  if(read(fhandlea,actorheaders,esize )!=esize )
  {
    return -2;
  }
  fullsizea+=esize;
  flg=ReadActorData();
  if(flg<0) return flg;
  //infopoints
  if(header.infocnt)
  {
    flg=adjust_actpointa(header.infooffset);
    if(flg<0) return flg;
    if(flg) ret|=flg;
  }

  if(triggercount!=header.infocnt)
  {
    KillTriggers();
    triggerheaders=new area_trigger[header.infocnt];
    if(!triggerheaders)
    {
      return -3;
    }
    triggercount=header.infocnt;
  }
  esize=header.infocnt*sizeof(area_trigger);
  if(read(fhandlea,triggerheaders,esize )!=esize )
  {
    return -2;
  }
  fullsizea+=esize;

  //spawns
  if(header.spawncnt)
  {
    flg=adjust_actpointa(header.spawnoffset);
    if(flg<0) return flg;
    if(flg) ret|=flg;
  }

  if(spawncount!=header.spawncnt)
  {
    KillSpawns();
    spawnheaders=new area_spawn[header.spawncnt];
    if(!spawnheaders)
    {
      return -3;
    }
    spawncount=header.spawncnt;
  }
  esize=header.spawncnt*sizeof(area_spawn);
  if(read(fhandlea,spawnheaders,esize )!=esize )
  {
    return -2;
  }
  fullsizea+=esize;

  //entrances
  if(header.entrancecnt)
  {
    flg=adjust_actpointa(header.entranceoffset);
    if(flg<0) return flg;
    if(flg) ret|=flg;
  }

  if(entrancecount!=header.entrancecnt)
  {
    KillEntrances();
    entranceheaders=new area_entrance[header.entrancecnt];
    if(!entranceheaders)
    {
      return -3;
    }
    entrancecount=header.entrancecnt;
  }
  esize=header.entrancecnt*sizeof(area_entrance);
  if(read(fhandlea,entranceheaders,esize )!=esize )
  {
    return -2;
  }
  fullsizea+=esize;

  //containers
  if(header.containercnt)
  {
    flg=adjust_actpointa(header.containeroffset);
    if(flg<0) return flg;
    if(flg) ret|=flg;
  }

  if(containercount!=header.containercnt)
  {
    KillContainers();
    containerheaders=new area_container[header.containercnt];
    if(!containerheaders)
    {
      return -3;
    }
    containercount=header.containercnt;
  }
  esize=header.containercnt*sizeof(area_container);
  if(read(fhandlea,containerheaders,esize )!=esize )
  {
    return -2;
  }
  fullsizea+=esize;

  //items
  if(header.itemcnt)
  {
    flg=adjust_actpointa(header.itemoffset);
    if(flg<0) return flg;
    if(flg) ret|=flg;
  }

  if(itemcount!=header.itemcnt)
  {
    KillItems();
    itemheaders=new area_item[header.itemcnt];
    if(!itemheaders)
    {
      return -3;
    }
    itemcount=header.itemcnt;
  }
  esize=header.itemcnt*sizeof(area_item);
  if(read(fhandlea,itemheaders,esize )!=esize )
  {
    return -2;
  }
  fullsizea+=esize;

  //ambisounds
  if(header.ambicnt)
  {
    flg=adjust_actpointa(header.ambioffset);
    if(flg<0) return flg;
    if(flg) ret|=flg;
  }

  if(ambientcount!=header.ambicnt)
  {
    KillAmbients();
    ambientheaders=new area_ambient[header.ambicnt];
    if(!ambientheaders) return -3;
    ambientcount=header.ambicnt;
  }
  esize=header.ambicnt*sizeof(area_ambient);
  if(read(fhandlea,ambientheaders,esize )!=esize )
  {
    return -2;
  }
  fullsizea+=esize;

  //variables
  if(header.variablecnt)
  {
    flg=adjust_actpointa(header.variableoffset);
    if(flg<0) return flg;
    if(flg) ret|=flg;
  }

  if(variablecount!=header.variablecnt)
  {
    KillVariables();
    variableheaders=new area_variable[header.variablecnt];
    if(!variableheaders) return -3;
    variablecount=header.variablecnt;
  }
  esize=header.variablecnt*sizeof(area_variable);
  if(read(fhandlea,variableheaders,esize )!=esize )
  {
    return -2;
  }
  fullsizea+=esize;

  //explored
  if(header.exploredsize)
  {
    flg=adjust_actpointa(header.exploredoffset);
    if(flg<0) return flg;
    if(flg) ret|=flg;
  }
  
  if(exploredsize!=header.exploredsize)
  {
    KillExplored();
    explored=new char[header.exploredsize];
    if(!explored) return -3;
    exploredsize=header.exploredsize;
  }
  if(read(fhandlea,explored,exploredsize)!=exploredsize)
  {
    return -2;
  }
  fullsizea+=header.exploredsize;

  //door
  if(header.doorcnt)
  {
    flg=adjust_actpointa(header.dooroffset);
    if(flg<0) return flg;
    if(flg) ret|=flg;
  }

  if(doorcount!=header.doorcnt)
  {
    KillDoors();
    doorheaders=new area_door[header.doorcnt];
    if(!doorheaders) return -3;
    doorcount=header.doorcnt;
  }
  esize=header.doorcnt*sizeof(area_door);
  if(read(fhandlea,doorheaders,esize )!=esize )
  {
    return -2;
  }
  fullsizea+=esize;

  //tiled objects
  if(header.tilecnt)
  {
    flg=adjust_actpointa(header.tileoffset);
    if(flg<0) return flg;
    if(flg) ret|=flg;
  }
  
  if(tilecount!=header.tilecnt)
  {
    KillTiles();
    tileheaders=new area_tile[header.tilecnt];
    if(!tileheaders) return -3;
    tilecount=header.tilecnt;
  }
  esize=header.tilecnt*sizeof(area_tile);
  if(read(fhandlea,tileheaders,esize )!=esize )
  {
    return -2;
  }
  fullsizea+=esize;

  //vertices
  if(header.vertexcnt)
  {
    flg=adjust_actpointa(header.vertexoffset);
    if(flg<0) return flg;
    if(flg) ret|=flg;
  }

  if(vertexcount!=header.vertexcnt)
  {
    KillVertices();
    vertexheaders=new area_vertex[header.vertexcnt];
    if(!vertexheaders) return -3;
    vertexcount=header.vertexcnt;
  }
  esize=header.vertexcnt*sizeof(area_vertex);
  if(read(fhandlea,vertexheaders,esize )!=esize )
  {
    return -2;
  }
  fullsizea+=esize;

  //animation
  if(header.animationcnt)
  {
    flg=adjust_actpointa(header.animationoffset);
    if(flg<0) return flg;
    if(flg) ret|=flg;
  }

  if(animcount!=header.animationcnt)
  {
    KillAnimations();
    animheaders=new area_anim[header.animationcnt];
    if(!animheaders) return -3;
    animcount=header.animationcnt;
  }
  esize=header.animationcnt*sizeof(area_anim);
  if(read(fhandlea,animheaders,esize )!=esize )
  {
    return -2;
  }
  fullsizea+=esize;

  //song offset
  if(header.songoffset)
  {
    flg=adjust_actpointa(header.songoffset);
    if(flg<0) return flg;
    if(flg) ret|=flg;

    if(read(fhandlea,&songheader,sizeof(area_song) )!=sizeof(area_song) )
    {
      return -2;
    }
    fullsizea+=sizeof(area_song);
  }

  //interruption
  if(header.intoffset)
  {
    flg=adjust_actpointa(header.intoffset);
    if(flg<0) return flg;
    if(flg) ret|=flg;

    if(read(fhandlea,&intheader,sizeof(area_int) )!=sizeof(area_int) )
    {
      return -2;
    }
    fullsizea+=sizeof(area_int);
  }

  //mapnotes
  if(!header.mapnotecnt)
  {
    if(header.mapnoteoffset)
    {
      header.mapnoteoffset=0;
      ret=1;
    }
  }

  //pst was converted to common format before
  if(header.mapnotecnt)
  {
    flg=adjust_actpointa(header.mapnoteoffset);
    if(flg<0) return flg;
    if(flg) ret|=flg;
  }

  if(pst_compatible_var())
  {
    if(mapnotecount!=header.mapnotecnt)
    {
      KillMapnotes();
      pstmapnoteheaders=new pst_area_mapnote[header.mapnotecnt];
      if(!pstmapnoteheaders) return -3;
      mapnotecount=header.mapnotecnt;
    }
    esize=header.mapnotecnt*sizeof(pst_area_mapnote);
    if(read(fhandlea,pstmapnoteheaders,esize )!=esize )
    {
      return -2;
    }
    ConvertFromPstMapnote();
    fullsizea+=esize;
  }
  else
  {
    if(mapnotecount!=header.mapnotecnt)
    {
      KillMapnotes();
      mapnoteheaders=new area_mapnote[header.mapnotecnt];
      if(!mapnoteheaders) return -3;
      mapnotecount=header.mapnotecnt;
    }
    esize=header.mapnotecnt*sizeof(area_mapnote);
    if(read(fhandlea,mapnoteheaders,esize )!=esize )
    {
      return -2;
    }
    fullsizea+=esize;

    if(header.trapcnt)
    {
      flg=adjust_actpointa(header.pstmapnotecnt); //also trapoffset
      if(flg<0) return flg;
      if(flg) ret|=flg;
    }
    if(trapcount!=header.trapcnt)
    {
      KillTraps();
      trapheaders=new area_trap[header.trapcnt];
      if(!trapheaders) return -3;
      trapcount=header.trapcnt;
    }
    esize=header.trapcnt*sizeof(area_trap);
    if(read(fhandlea,trapheaders,esize )!=esize )
    {
      return -2;
    }
    fullsizea+=esize;

    int i,cnt;
    esize = 0;
    cnt = 0;
    for(i=0;i<trapcount;i++)
    {
      cnt+=trapheaders[i].size/sizeof(creature_effect);
    }
    if(effectcount!=cnt)
    {
      KillEffects();
      effects=new creature_effect[cnt];
      if(!effects) return -3;
      effectcount=cnt;
    }

    cnt = 0;
    for(i=0;i<trapcount;i++)
    {
      flg=adjust_actpointa(trapheaders[i].offset);
      if(flg<0) return flg;
      if(flg) ret|=flg;
      esize = trapheaders[i].size;
      if (esize>(effectcount-cnt)*(int) sizeof(creature_effect))
      {
        return -2;
      }
      if(read(fhandlea,effects+cnt,esize )!=esize )
      {
        return -2;
      }
      cnt+=esize/sizeof(creature_effect);
      fullsizea+=esize;
    }
  }

  if(fullsizea!=maxlena)
  {
    ret=2;
  }
  flg=ExplodeVertices();
  if(flg<0) return flg;
  if(flg) ret|=flg;
  return ret;
}

#define DEF_OVERLAY_CNT  5
int Carea::DefaultAreaOverlays()
{
  wedheader.overlaycnt=DEF_OVERLAY_CNT;
  overlaycount=DEF_OVERLAY_CNT;
  overlayheaders=new wed_overlay[wedheader.overlaycnt];
  if(!overlayheaders)
  {
    return -3;
  }
  memset(overlayheaders,0,DEF_OVERLAY_CNT*sizeof(wed_overlay) );
  return 0;
}

int Carea::RemoveDoorPolygon(int first)
{
  wed_polygon *newpolygons;
  POSITION pos;
  int i;

  pos=wedvertexheaderlist.FindIndex(wallpolygoncount+first);
  if(!pos) return -1;
  newpolygons=new wed_polygon[--doorpolygoncount];
  if(!newpolygons)
  {
    doorpolygoncount++;
    return -3;
  }
  for(i=0;i<weddoorcount;i++)
  {
    if(weddoorheaders[i].offsetpolygonopen>first)
    {
      weddoorheaders[i].offsetpolygonopen--;
    }
    if(weddoorheaders[i].offsetpolygonclose>first)
    {
      weddoorheaders[i].offsetpolygonclose--;
    }
  }
  memcpy(newpolygons, doorpolygonheaders, first*sizeof(wed_polygon));
  memcpy(newpolygons+first, doorpolygonheaders+first+1,(doorpolygoncount-first)*sizeof(wed_polygon) );
  delete [] doorpolygonheaders;
  doorpolygonheaders=newpolygons;
  wedvertexheaderlist.RemoveAt(pos);//this also frees the polygon
  return 0;
}

int Carea::AddWedDoor(CString doorid)
{
  int i;
  wed_door *newweddoors;
  wed_polygon *newpolygonheaders;
  area_vertex *newvertex;
  short *newtiles;

  for(i=0;i<the_area.wedheader.doorcnt;i++)
  {
    if(!strnicmp(doorid, the_area.weddoorheaders[i].doorid,8) )
    {
      return 1;
    }
  }

  the_area.wedchanged=true;
  //wed door (TODO)
  newweddoors=new wed_door[++the_area.wedheader.doorcnt];
  if(!newweddoors)
  {
    the_area.wedheader.doorcnt--;
    return -3;
  }
  memcpy(newweddoors, the_area.weddoorheaders, the_area.weddoorcount*sizeof(wed_door) );
  memset(newweddoors+the_area.weddoorcount,0,sizeof(wed_door) );
  StoreResref(doorid,newweddoors[the_area.weddoorcount].doorid);
  newweddoors[the_area.weddoorcount].firstdoortileidx=(short) the_area.doortileidxcount;
  newweddoors[the_area.weddoorcount].closed=1;
  newweddoors[the_area.weddoorcount].countpolygonopen=1;
  newweddoors[the_area.weddoorcount].countpolygonclose=1;
  newweddoors[the_area.weddoorcount].offsetpolygonopen=the_area.doorpolygoncount;
  newweddoors[the_area.weddoorcount].offsetpolygonclose=the_area.doorpolygoncount+1;
  delete [] the_area.weddoorheaders;
  the_area.weddoorheaders= newweddoors;

  //adding 2 empty polygons (open/closed)
  newpolygonheaders = new wed_polygon[the_area.doorpolygoncount+2];
  if(!newpolygonheaders)
  {
    newweddoors[the_area.weddoorcount].countpolygonopen=0;
    newweddoors[the_area.weddoorcount].countpolygonclose=0;
    return -3;
  }
  memcpy(newpolygonheaders, the_area.doorpolygonheaders, the_area.doorpolygoncount*sizeof(wed_polygon) );
  memset(newpolygonheaders+the_area.doorpolygoncount,0,2*sizeof(wed_polygon) );
  newpolygonheaders[the_area.doorpolygoncount].firstvertex=the_area.wedvertexcount;
  newpolygonheaders[the_area.doorpolygoncount+1].firstvertex=the_area.wedvertexcount+1;
  newpolygonheaders[the_area.doorpolygoncount].flags=0x89;
  newpolygonheaders[the_area.doorpolygoncount+1].flags=0x89;
  newpolygonheaders[the_area.doorpolygoncount].unkflags=255;
  newpolygonheaders[the_area.doorpolygoncount+1].unkflags=255;
  delete [] the_area.doorpolygonheaders;
  the_area.doorpolygonheaders=newpolygonheaders;
  the_area.doorpolygoncount+=2;

  newvertex=new area_vertex[0];
  the_area.wedvertexheaderlist.AddTail(newvertex);
  newvertex=new area_vertex[0];
  the_area.wedvertexheaderlist.AddTail(newvertex);  

  the_area.weddoorcount=the_area.wedheader.doorcnt;

  newtiles=new short[0];
  the_area.doortilelist.AddTail(newtiles);
  return 0;
}

int Carea::RemoveWedDoor(char *doorid)
{
  wed_door *newdoors;
  POSITION pos;
  int newcount;
  int i,j;

  newcount=0;
  for(i=0;i<wedheader.doorcnt;i++)
  {
    //the door isn't about to remove
    if(strnicmp(doorid, weddoorheaders[i].doorid,8) )
    {
      newcount++;
    }
  }
  if(newcount==wedheader.doorcnt) return 1; //wed didn't need any change
  newdoors=new wed_door[newcount];
  if(!newdoors) return -3;
  j=0;
  for(i=0;i<wedheader.doorcnt;i++)
  {
    //we keep this door
    if(strnicmp(doorid, weddoorheaders[i].doorid,8) )
    {
      newdoors[j++]=weddoorheaders[i];
    }
    else //we don't keep this door
    {
      ////TODO
      while(weddoorheaders[i].countpolygonopen)
      {
        RemoveDoorPolygon(weddoorheaders[i].offsetpolygonopen);
        weddoorheaders[i].countpolygonopen--;
      }
      while(weddoorheaders[i].countpolygonclose)
      {
        RemoveDoorPolygon(weddoorheaders[i].offsetpolygonclose);
        weddoorheaders[i].countpolygonclose--;
      }
      pos=doortilelist.FindIndex(i);
      if(pos)
      {
        doortilelist.RemoveAt(pos);
      }
    }
  }
  wedchanged=true;
  if(weddoorheaders)
  {
    delete [] weddoorheaders;
  }
  weddoorheaders=newdoors;
  weddoorcount=wedheader.doorcnt=newcount;
  return 0;
}
