
#include <stdio.h>
#include <stdint.h>

#define NMAPS			95
#define DATA_OFFSET		0x937B0

typedef struct
{
	char tileset[32];
	char filename[32];
	int scroll_type;
	char background[32];
	char NPCset1[32];
	char NPCset2[32];
	uint8_t bossNo;
	char caption[35];
} MapRecord;

MapRecord MapData[NMAPS];

typedef struct
{
	char files[NMAPS+1][32];
	int nfiles;
} filelist;

int FindFileInList(filelist *list, char *fname)
{
int i;
	for(i=0;i<list->nfiles;i++)
	{
		if (!strcasecmp(list->files[i], fname))
		{
			return i;
		}
	}
	return -1;
}

void AddFileToList(filelist *list, char *fname)
{
	if (FindFileInList(list, fname) != -1) return;
	
	//printf("Added '%s' to list at pos %d\n", fname, list->nfiles);
	strcpy(list->files[list->nfiles], fname);
	list->nfiles++;
}


int main(void)
{
filelist bg, tileset, npcset;
FILE *fp;
int i, j;
char *comma;
char buf[256];
	
	// read data from exe
	fp = fopen("/data/win/Programs/Games/Cave Story Deluxe/CaveStory/Doukutsu.exe", "rb");
	if (!fp) { printf("Failed opening exe\n"); return 1; }
	
	// load raw data into struct
	fseek(fp, DATA_OFFSET, SEEK_SET);
	fread(MapData, sizeof(MapRecord), NMAPS, fp);
	fclose(fp);
	
	// parse tileset and bg info and convert strings to numbers
	memset(&bg, 0, sizeof(bg));
	memset(&tileset, 0, sizeof(tileset));
	memset(&npcset, 0, sizeof(npcset));
	for(i=0;i<NMAPS;i++)
	{
		AddFileToList(&bg, MapData[i].background);
		AddFileToList(&tileset, MapData[i].tileset);
		AddFileToList(&npcset, MapData[i].NPCset1);
		AddFileToList(&npcset, MapData[i].NPCset2);
	}
	
	// output data to .c & .h file
	fp = fopen("../autogen/stagedata.h", "wb");
	
	fprintf(fp, "//auto-generated by extractmapinfo.c\n\n");
	fprintf(fp, "#define NMAPS\t %d\n", NMAPS);
	fprintf(fp, "typedef struct\n");
	fprintf(fp, "{\n");
	fprintf(fp, "\tchar filename[32];\n");
	fprintf(fp, "\tchar stagename[35];\n\n");
	fprintf(fp, "\tuint8_t tileset;\n");
	fprintf(fp, "\tuint8_t bg_no;\n");
	fprintf(fp, "\tuint8_t scroll_type;\n");
	fprintf(fp, "\tuint8_t bossNo;\n");
	fprintf(fp, "\tuint8_t NPCset1;\n");
	fprintf(fp, "\tuint8_t NPCset2;\n");
	fprintf(fp, "} MapRecord;\n\n");
	
	fprintf(fp, "extern MapRecord stages[NMAPS];\n\n");
	
	fprintf(fp, "#define NUM_BACKDROPS		%d\n", bg.nfiles);
	fprintf(fp, "#define NUM_TILESETS		%d\n\n", tileset.nfiles);
	
	fprintf(fp, "extern const char *backdrop_names[];\n");
	fprintf(fp, "extern const char *tileset_names[];\n");
	
	// output the NPC spriteset constants
	fprintf(fp, "\n\n");
	for(i=0;i<npcset.nfiles;i++)
	{
		// make the filename upper-case so it looks like a constant
		for(j=strlen(npcset.files[i])-1;j>=0;j--)
		{
			npcset.files[i][j] = toupper(npcset.files[i][j]);
		}
		
		fprintf(fp, "#define NPCSET_%s\t\t %d\n", npcset.files[i], i);
	}
	
	fprintf(fp, "\n");
	fclose(fp);
	
	
	fp = fopen("../autogen/stagedata.cpp", "wb");
	
	fprintf(fp, "//auto-generated by extractmapinfo.c\n\n");
	
	fprintf(fp, "#include <stdio.h>\n");
	fprintf(fp, "#include <stdint.h>\n");
	fprintf(fp, "#include \"stagedata.h\"\n\n");
	
	// output the backdrop names
	fprintf(fp, "const char *backdrop_names[] = {\n");
	for(i=0;i<bg.nfiles;i++)
	{
		bg.files[i][0] = tolower(bg.files[i][0]);	// fix case-sensitivity issue on UNIX filesystems
		fprintf(fp, "\t\"%s\",\n", bg.files[i]);
	}
	fprintf(fp, "\tNULL\n};\n\n");
	
	// output the tileset names
	fprintf(fp, "const char *tileset_names[] = {\n");
	for(i=0;i<tileset.nfiles;i++) { fprintf(fp, "\t\"%s\",\n", tileset.files[i]); }
	fprintf(fp, "\tNULL\n};\n\n");
	
	// finally output the map records
	fprintf(fp, "MapRecord stages[NMAPS] = {\n");
	
	comma = ",";
	for(i=0;i<NMAPS;i++)
	{
		if (i+1==NMAPS) comma = "";
		
		fprintf(fp, "\"%s\", \"%s\", %d, %d, %d, %d, %d, %d%s\n", \
			MapData[i].filename, \
			MapData[i].caption, \
			FindFileInList(&tileset, MapData[i].tileset), \
			FindFileInList(&bg, MapData[i].background), \
			MapData[i].scroll_type, \
			MapData[i].bossNo, \
			FindFileInList(&npcset, MapData[i].NPCset1), \
			FindFileInList(&npcset, MapData[i].NPCset2), \
			comma);
	}
	
	fprintf(fp, "};\n\n");
	fclose(fp);
	
	return 0;
}


