// "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]));
			}
		}
}
