text: // "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman
  // Ken Silverman's official web site: "http://www.advsys.net/ken"
  // See the included license file "BUILDLIC.TXT" for license info.
  
  #include <stdio.h>
  #include <string.h>
  #include <fcntl.h>
  #ifdef PLATFORM_DOS
  #include <io.h>
  #include <sys\types.h>
  #include <sys\stat.h>
  #include <dos.h>
  #include "dos_compat.h"
  #else
  #include <sys/types.h>
  #include <sys/stat.h>
  #include <unistd.h>
  #include "unix_compat.h"
  #endif
  
  #define NEWMAPVERSION 7
  #define MAXMENUFILES 1024
  
  #define MAXSECTORS 1024
  #define MAXWALLS 8192
  #define MAXSPRITES 4096
  
  #define MAXSTATUS 1024
  #define MAXTILES 4096
  
  static char menuname[MAXMENUFILES][32];
  static long menunamecnt;
  
  #ifdef PLATFORM_DOS
  #pragma pack(push,1);
  #endif
  
  typedef struct
  {
  	unsigned short wallptr, wallnum;
  	short ceilingpicnum, floorpicnum;
  	short ceilingheinum, floorheinum;
  	long ceilingz, floorz;
  	signed char ceilingshade, floorshade;
  	char ceilingxpanning, floorxpanning;
  	char ceilingypanning, floorypanning;
  	char ceilingstat, floorstat;
  	char ceilingpal, floorpal;
  	char visibility;
  	short lotag, hitag, extra;
  } sectortype;
  
  typedef struct
  {
  	long x, y;
  	short point2, nextsector, nextwall;
  	short picnum, overpicnum;
  	signed char shade;
  	char pal;
  	short cstat;
  	unsigned char xrepeat, yrepeat, xpanning, ypanning;
  	short lotag, hitag, extra;
  } walltype;
  
  typedef struct
  {
  	long x, y, z;
  	short cstat;
  	signed char shade;
  	char pal, clipdist;
  	unsigned char xrepeat, yrepeat;
  	signed char xoffset, yoffset;
  	short picnum, ang, xvel, yvel, zvel, owner;
  	short sectnum, statnum;
  	short lotag, hitag, extra;
  } spritetype;
  
  	//40 bytes
  typedef struct
  {
  	short wallptr, wallnum;
  	long ceilingz, floorz;
  	short ceilingstat, floorstat;
  	short ceilingpicnum, ceilingheinum;
  	signed char ceilingshade;
  	char ceilingpal, ceilingxpanning, ceilingypanning;
  	short floorpicnum, floorheinum;
  	signed char floorshade;
  	char floorpal, floorxpanning, floorypanning;
  	char visibility, filler;
  	short lotag, hitag, extra;
  } newsectortype;
  
  	//32 bytes
  typedef struct
  {
  	long x, y;
  	short point2, nextwall, nextsector, cstat;
  	short picnum, overpicnum;
  	signed char shade;
  	char pal, xrepeat, yrepeat, xpanning, ypanning;
  	short lotag, hitag, extra;
  } newwalltype;
  
  	//44 bytes
  typedef struct
  {
  	long x, y, z;
  	short cstat, picnum;
  	signed char shade;
  	char pal, clipdist, filler;
  	unsigned char xrepeat, yrepeat;
  	signed char xoffset, yoffset;
  	short sectnum, statnum;
  	short ang, owner, xvel, yvel, zvel;
  	short lotag, hitag, extra;
  } newspritetype;
  
  #ifdef PLATFORM_DOS
  #pragma pack(pop);
  #endif
  
  //**************************************************************************
  
  static sectortype sector[MAXSECTORS];
  static walltype wall[MAXWALLS];
  static spritetype sprite[MAXSPRITES];
  
  static newsectortype newsector[MAXSECTORS];
  static newwalltype newwall[MAXWALLS];
  static newspritetype newsprite[MAXSPRITES];
  
  static long posx, posy, posz, mapversion;
  static short ang, cursectnum, numsectors, numwalls, numsprites;
  
  // Function definitions
  void convmap(char *filename);
  int loadoldboard(char *filename);
  int savenewboard(char *filename);
  int getfilenames(char *kind);
  void sortfilenames(void);
  
  int main(int argc, char **argv)
  {
  	long i;
  
  	if (argc != 2)
  	{
  		printf("CONVMAP%d [filespec]                                            by Ken Silverman\n",NEWMAPVERSION);
  		printf("This CONVMAP%d.EXE converts map version %d to map version %d\n",NEWMAPVERSION,NEWMAPVERSION-1,NEWMAPVERSION);
  		exit(0);
  	}
  	menunamecnt = 0;
  	getfilenames(argv[1]);
  	sortfilenames();
  
  	if (menunamecnt == 0)
  	{
  		printf("CONVMAP%d [filespec]                                            by Ken Silverman\n",NEWMAPVERSION);
  		printf("This CONVMAP%d.EXE converts map version %d to map version %d\n",NEWMAPVERSION,NEWMAPVERSION-1,NEWMAPVERSION);
  		printf("File not found\n");
  		exit(0);
  	}
  
  	printf("Converting map version %d to map version %d\n",NEWMAPVERSION-1,NEWMAPVERSION);
  
  	for(i=0;i<menunamecnt;i++)
  		convmap(menuname[i]);
  	return(0);
  }
  
  void convmap(char *filename)
  {
  	long i;
  
  	if (strchr(filename,'.') == 0) strcat(filename,".map");
  	if ((i = loadoldboard(filename)) < 0)
  	{
  		if (i == -1)
  		{
  			printf("%s not found.\n",filename);
  		}
  		if (i == -2)
  		{
  			if (mapversion == NEWMAPVERSION)
  				printf("%s already map version %d.\n",filename,NEWMAPVERSION);
  			else
  				printf("CANNOT CONVERT %s!\n",filename);
  		}
  		return;
  	}
  
  	for(i=0;i<numsectors;i++)
  	{
  		newsector[i].ceilingz = sector[i].ceilingz;
  		newsector[i].floorz = sector[i].floorz;
  		newsector[i].wallptr = sector[i].wallptr;
  		newsector[i].wallnum = sector[i].wallnum;
  		newsector[i].ceilingpicnum = sector[i].ceilingpicnum;
  		newsector[i].ceilingheinum = max(min(((long)sector[i].ceilingheinum)<<5,32767),-32768);
  		if ((sector[i].ceilingstat&2) == 0) newsector[i].ceilingheinum = 0;
  		newsector[i].ceilingshade = sector[i].ceilingshade;
  		newsector[i].ceilingpal = sector[i].ceilingpal;
  		newsector[i].ceilingxpanning = sector[i].ceilingxpanning;
  		newsector[i].ceilingypanning = sector[i].ceilingypanning;
  		newsector[i].floorpicnum = sector[i].floorpicnum;
  		newsector[i].floorheinum = max(min(((long)sector[i].floorheinum)<<5,32767),-32768);
  		if ((sector[i].floorstat&2) == 0) newsector[i].floorheinum = 0;
  		newsector[i].floorshade = sector[i].floorshade;
  		newsector[i].floorpal = sector[i].floorpal;
  		newsector[i].floorxpanning = sector[i].floorxpanning;
  		newsector[i].floorypanning = sector[i].floorypanning;
  		newsector[i].ceilingstat = sector[i].ceilingstat;
  		newsector[i].floorstat = sector[i].floorstat;
  		newsector[i].visibility = sector[i].visibility;
  		newsector[i].filler = 0;
  		newsector[i].lotag = sector[i].lotag;
  		newsector[i].hitag = sector[i].hitag;
  		newsector[i].extra = sector[i].extra;
  	}
  	for(i=0;i<numwalls;i++)
  	{
  		newwall[i].x = wall[i].x;
  		newwall[i].y = wall[i].y;
  		newwall[i].point2 = wall[i].point2;
  		newwall[i].nextwall = wall[i].nextwall;
  		newwall[i].nextsector = wall[i].nextsector;
  		newwall[i].cstat = wall[i].cstat;
  		newwall[i].picnum = wall[i].picnum;
  		newwall[i].overpicnum = wall[i].overpicnum;
  		newwall[i].shade = wall[i].shade;
  		newwall[i].pal = wall[i].pal;
  		newwall[i].xrepeat = wall[i].xrepeat;
  		newwall[i].yrepeat = wall[i].yrepeat;
  		newwall[i].xpanning = wall[i].xpanning;
  		newwall[i].ypanning = wall[i].ypanning;
  		newwall[i].lotag = wall[i].lotag;
  		newwall[i].hitag = wall[i].hitag;
  		newwall[i].extra = wall[i].extra;
  	}
  	for(i=0;i<numsprites;i++)
  	{
  		newsprite[i].x = sprite[i].x;
  		newsprite[i].y = sprite[i].y;
  		newsprite[i].z = sprite[i].z;
  		newsprite[i].cstat = sprite[i].cstat;
  		newsprite[i].picnum = sprite[i].picnum;
  		newsprite[i].shade = sprite[i].shade;
  		newsprite[i].pal = sprite[i].pal;
  		newsprite[i].clipdist = sprite[i].clipdist;
  		newsprite[i].filler = 0;
  		newsprite[i].xrepeat = sprite[i].xrepeat;
  		newsprite[i].yrepeat = sprite[i].yrepeat;
  		newsprite[i].xoffset = sprite[i].xoffset;
  		newsprite[i].yoffset = sprite[i].yoffset;
  		newsprite[i].sectnum = sprite[i].sectnum;
  		newsprite[i].statnum = sprite[i].statnum;
  		newsprite[i].ang = sprite[i].ang;
  		newsprite[i].owner = sprite[i].owner;
  		newsprite[i].xvel = sprite[i].xvel;
  		newsprite[i].yvel = sprite[i].yvel;
  		newsprite[i].zvel = sprite[i].zvel;
  		newsprite[i].lotag = sprite[i].lotag;
  		newsprite[i].hitag = sprite[i].hitag;
  		newsprite[i].extra = sprite[i].extra;
  	}
  
  	mapversion = NEWMAPVERSION;
  	if (savenewboard(filename) == 0)
  		printf("%s successfully converted.\n",filename);
  	else
  		printf("%s NOT converted for some stupid reason.\n",filename);
  }
  
  int loadoldboard(char *filename)
  {
  	long fil;
  
  	if ((fil = open(filename,O_BINARY|O_RDWR,S_IREAD)) == -1)
  		return(-1);
  
  	read(fil,&mapversion,4);
  	if (mapversion != NEWMAPVERSION-1)
  	{
  		close(fil);
  		return(-2);
  	}
  	read(fil,&posx,4);
  	read(fil,&posy,4);
  	read(fil,&posz,4);
  	read(fil,&ang,2);
  	read(fil,&cursectnum,2);
  
  	read(fil,&numsectors,2);
  	read(fil,&sector[0],sizeof(sectortype)*numsectors);
  
  	read(fil,&numwalls,2);
  	read(fil,&wall[0],sizeof(walltype)*numwalls);
  
  	read(fil,&numsprites,2);
  	read(fil,&sprite[0],sizeof(spritetype)*numsprites);
  
  	close(fil);
  	return(0);
  }
  
  int savenewboard(char *filename)
  {
  	long fil;
  
  	if ((fil = open(filename,O_BINARY|O_TRUNC|O_CREAT|O_WRONLY,UC_PERMS)) == -1)
  		return(-1);
  
  		 //Version control
  	write(fil,&mapversion,4);
  
  		 //Starting position
  	write(fil,&posx,4);
  	write(fil,&posy,4);
  	write(fil,&posz,4);
  	write(fil,&ang,2);
  	write(fil,&cursectnum,2);
  
  		//Sectors
  	write(fil,&numsectors,2);
  	write(fil,&newsector[0],sizeof(newsectortype)*numsectors);
  
  		//Walls
  	write(fil,&numwalls,2);
  	write(fil,&newwall[0],sizeof(newwalltype)*numwalls);
  
  		//Sprites
  	write(fil,&numsprites,2);
  	write(fil,&newsprite[0],sizeof(newspritetype)*numsprites);
  
  	close(fil);
  
  	return(0);
  }
  
  int getfilenames(char *kind)
  {
  	short type;
  	struct find_t fileinfo;
  
  	if (strcmp(kind,"SUBD") == 0)
  	{
  		strcpy(kind,"*.*");
  		if (_dos_findfirst(kind,_A_SUBDIR,&fileinfo) != 0)
  			return(-1);
  		type = 1;
  	}
  	else
  	{
  		if (_dos_findfirst(kind,_A_NORMAL,&fileinfo) != 0)
  			return(-1);
  		type = 0;
  	}
  	do
  	{
  		if ((type == 0) || ((fileinfo.attrib&16) > 0))
  			if ((fileinfo.name[0] != '.') || (fileinfo.name[1] != 0))
  			{
  				if (menunamecnt < MAXMENUFILES)
  				{
  					strcpy(menuname[menunamecnt],fileinfo.name);
  					menuname[menunamecnt][16] = type;
  					menunamecnt++;
  				}
  				//else
  				//   printmessage("Too many files! (max=MAXMENUFILES)");
  			}
  	}
  	while (_dos_findnext(&fileinfo) == 0);
  
  	return(0);
  }
  
  void sortfilenames(void)
  {
  	char sortbuffer[32];
  	long i, j, k;
  
  	for(i=1;i<menunamecnt;i++)
  		for(j=0;j<i;j++)
  		{
  			 k = 0;
  			 while ((menuname[i][k] == menuname[j][k]) && (menuname[i][k] != 0) && (menuname[j][k] != 0))
  				 k++;
  			if (menuname[i][k] < menuname[j][k])
  			{
  				memcpy(&sortbuffer[0],&menuname[i][0],sizeof(menuname[0]));
  				memcpy(&menuname[i][0],&menuname[j][0],sizeof(menuname[0]));
  				memcpy(&menuname[j][0],&sortbuffer[0],sizeof(menuname[0]));
  			}
  		}
  }
  