changeset 9:3e7eb65281f4

Shitzor
author Matti Hamalainen <ccr@tnsp.org>
date Fri, 08 Dec 2006 19:31:36 +0000
parents a0dd3254e488
children 4219d4a1c00a
files Makefile.gen README colormap.c diffmap.c maputils.c maputils.h mkbcmap.c mkmap.c
diffstat 8 files changed, 571 insertions(+), 259 deletions(-) [+]
line wrap: on
line diff
--- a/Makefile.gen	Fri Dec 08 19:30:23 2006 +0000
+++ b/Makefile.gen	Fri Dec 08 19:31:36 2006 +0000
@@ -15,11 +15,14 @@
 MKMAP_BIN=$(BINPATH)mkmap$(EXEEXT)
 COLORMAP_BIN=$(BINPATH)colormap$(EXEEXT)
 MAKEBCMAP_BIN=$(BINPATH)mkbcmap$(EXEEXT)
-
-TARGETS=$(MKMAP_BIN) $(COLORMAP_BIN) $(MAKEBCMAP_BIN) votk.html batcity.html batcity.txt lanzia.html
+DIFFMAP_BIN=$(BINPATH)diffmap$(EXEEXT)
 
-MAPFILES=batcity.html batcity.txt tooltip.js votk.html votk.map lanzia.html lanzia.map
-TARFILE=maps.tar
+TARGETS=$(MKMAP_BIN) $(COLORMAP_BIN) $(MAKEBCMAP_BIN) $(DIFFMAP_BIN)	\
+	batmap.html votk.html batcity.html batcity.txt lanzia.html
+
+MAPFILES=batmap.html batmap.txt				\
+	batcity.html batcity.txt tooltip.js		\
+	votk.html votk.map lanzia.html lanzia.map
 
 #
 # Target rules
@@ -32,23 +35,28 @@
 $(MKMAP_BIN): mkmap.c th_args.o th_util.o th_string.o
 	$(COMP) -o $@ $+ $(LDFLAGS)
 
-$(COLORMAP_BIN): colormap.c
+$(COLORMAP_BIN): colormap.c maputils.o
 	$(COMP) -o $@ $+ $(LDFLAGS)
 
-$(MAKEBCMAP_BIN): mkbcmap.c th_util.o th_string.o
+$(MAKEBCMAP_BIN): mkbcmap.c th_util.o th_string.o maputils.o
 	$(COMP) -o $@ $+ $(LDFLAGS)
 
+$(DIFFMAP_BIN): diffmap.c th_util.o th_string.o maputils.o
+	$(COMP) -o $@ $+ $(LDFLAGS)
+
+
 %.cmap: %.raw $(MKMAP_BIN)
 	$(MKMAP_BIN) -o $@ -r 800 -w 21 -h 21 $< -v -m 80
 
 %.map: %.raw $(MKMAP_BIN)
 	$(MKMAP_BIN) -o $@ -r 800 -w 13 -h 7 $< -v -m 70
 
+
 batcity.html: $(MAKEBCMAP_BIN) batcity2.cmap batcity.cnam tooltip.js
-	$(MAKEBCMAP_BIN) "New BatCity map (as of `date +"%d.%m.%Y %R"`) by Ggr Pupunen" batcity2.cmap batcity.cnam > $@
+	$(MAKEBCMAP_BIN) "New BatCity map (as of `date +"%d.%m.%Y"`)" batcity2.cmap batcity.cnam > $@
 
 batcity.txt: $(MAKEBCMAP_BIN) batcity2.cmap batcity.cnam
-	$(MAKEBCMAP_BIN) "New BatCity map (as of `date +"%d.%m.%Y %R"`) by Ggr Pupunen" batcity2.cmap batcity.cnam -ascii > $@
+	$(MAKEBCMAP_BIN) "New BatCity map (as of `date +"%d.%m.%Y"`)" batcity2.cmap batcity.cnam -ascii > $@
 
 
 votk.html: votk.map $(COLORMAP_BIN)
@@ -57,13 +65,16 @@
 lanzia.html: lanzia.map $(COLORMAP_BIN)
 	$(COLORMAP_BIN) "The isle of Lanzia" < $< > $@
 
+batmap.txt:
+	wget -q -O batmap.txt http://www.bat.org/maps/batmap.txt
+	/bin/cp batmap.txt batmap-`date +"%d-%m-%Y"`.txt
+
+batmap.html: batmap.txt $(COLORMAP_BIN)
+	$(COLORMAP_BIN) "BatMUD World Map in colour" < $< > $@
 
 #
 # Special targets
 #
-tar: $(MAPFILES)
-	tar -cf $(TARFILE) $+ && gzip -9 $(TARFILE) && scp $(TARFILE).gz mhamalai@students.oamk.fi:public_html/
-
 upload: $(MAPFILES)
 	scp $+ mhamalai@students.oamk.fi:public_html/bat/
 
--- a/README	Fri Dec 08 19:30:23 2006 +0000
+++ b/README	Fri Dec 08 19:31:36 2006 +0000
@@ -1,14 +1,49 @@
 MapUtils
 ========
-Programmed by Matti 'ccr' Hämäläinen (Ggr Pupunen)
+Programmed by Matti Hämäläinen (aka Ggr Pupunen @ BatMUD)
 (C) Copyright 2006 Tecnic Software productions (TNSP)
 
-Miscellaneous utilities for processing ASCII map data.
+Miscellaneous utilities for processing ASCII map data from
+BatMUD in various interesting ways.
+
+mkmap
+-----
+Given an input with "map pieces" and sufficient parameters
+for interpreting, this utility tries to semi-heuristically
+"stitch" together a bigger map from the pieces. This process
+is quite fragile, and can go wrong if the parameters are not
+chosen carefully, or if the map data gives "room for error"
+(several too similar map pieces).
+
+Usage of this utility is not trivial.
+
+See 'mkmap --help' and Makefile.gen for more information.
+
 
+colormap
+--------
+Converts given input BatMUD ASCII world (also some sub-areas) map
+into a XHTML+CSS coloured version.
+
+Can also create coloured maps from binary output of 'diffmap'
+utility, when used with -diff option.
+
+$ colormap ["Map title" [-diff]] < inputfile > outputfile
+
+
+diffmap
+-------
+Compute a 'diff' between two ASCII maps of equivalent size.
+Output is a specially formatted binary file, which can be
+converted to HTML with 'colormap' utility.
+
+$ diffmap mapfile1 mapfile2 > outputfile
+
+
+Miscellaneous information
+-------------------------
 ...
-
 To be documented later.
-
 ...
 
 /def -i prmove_peer = @%{1};say pfs;map
--- a/colormap.c	Fri Dec 08 19:30:23 2006 +0000
+++ b/colormap.c	Fri Dec 08 19:31:36 2006 +0000
@@ -3,175 +3,116 @@
  * Programmed by Matti 'ccr' Hämäläinen (Ggr Pupunen)
  * (C) Copyright 2006 Tecnic Software productions (TNSP)
  */
-#include <stdio.h>
-#include <string.h>
-
-typedef struct {
-	char c;
-	char *desc;
-	int col;
-} mappiece_t;
-
-
-typedef struct {
-	int col;
-	char *css;
-} color_t;
-
+#include "maputils.h"
 
-enum {
-	col_black = 0,
-	col_blue,
-	col_red,
-	col_yellow,
-	col_green,
-	col_white,
-	col_cyan,
-	col_magenta,
-	col_light_black,
-	col_light_blue,
-	col_light_red,
-	col_light_yellow,
-	col_light_green,
-	col_light_white,
-	col_light_cyan,
-	col_light_magenta,
-};
-
-
-color_t colors[] = {
-{ col_black,		"#000000" },
-{ col_blue,		"#0000bb" },
-{ col_red,		"#bb0000" },
-{ col_yellow,		"#bbbb00" },
-{ col_green,		"#00bb00" },
-{ col_white,		"#bbbbbb" },
-{ col_cyan,		"#00ffff" },
-{ col_magenta,		"#770077" },
-
-{ col_light_black,	"#777777" },
-{ col_light_blue,	"#0000ff" },
-{ col_light_red,	"#ff0000" },
-{ col_light_yellow,	"#ffff00" },
-{ col_light_green,	"#00ff00" },
-{ col_light_white,	"#ffffff" },
-{ col_light_cyan,	"#00ffff" },
-{ col_light_magenta,	"#ff00ff" },
-};
-
-const int ncolors = (sizeof(colors) / sizeof(color_t));
-
+void processNormal(FILE *inFile, FILE *outFile)
+{
+	DINT k, c, p;
 
-mappiece_t mapPieces[] = {
-{ '~', "sea",			col_blue },
-{ 'r', "river",			col_blue },
-{ 'l', "lake",			col_light_blue },
-{ 'V', "volcano",		col_red },
-{ 's', "swamp",			col_light_red },
-{ '^', "mountain",		col_light_magenta },
-{ 'b', "beach",			col_light_yellow },
-{ '-', "east-west road",	col_light_black },
-{ 'y', "field",			col_light_yellow },
-{ 'j', "jungle",		col_green },
-{ '%', "special location",	col_light_white },
-{ 'C', "playercity",		col_light_black },
-{ '#', "ruins",			col_light_black },
-{ 'R', "deepriver",		col_blue },
-{ '?', "scenic location",	col_light_white },
-{ 'i', "highlands",		col_magenta },
-{ 'd', "desert",		col_yellow },
-{ '+', "crossing",		col_light_black },
-{ 'p', "plain",			col_light_green },
-{ 'x', "badlands",		col_light_red },
-{ 't', "tundra",		col_white },
-{ '=', "bridge",		col_light_black },
-{ '!', "peak",			col_white },
-{ '/', "sw-ne road",		col_light_black },
-{ 'w', "waterfall",		col_light_cyan },
-{ '|', "north-south road",	col_light_black },
-{ 'z', "shore",			col_light_yellow },
-{ 'S', "shallow",		col_cyan },
-{ 'h', "hills",			col_magenta },
-{ 'f', "forest",		col_light_green },
-{ 'F', "deep forest",		col_green },
-{ '\\', "nw-se road",		col_light_black },
-{ 'v', "valley",		col_light_green },
-{ 'c', "city",			col_light_black },
-};
-
-const int nmapPieces = (sizeof(mapPieces) / sizeof(mappiece_t));
-
-
-int mcget(int c)
-{
-	int i;
+	c = p = -1;
+	while ((k = fgetc(inFile)) != EOF) {
+		if (k == '\n') {
+			if (p != -1)
+				fprintf(outFile, "</span>");
+			
+			fprintf(outFile, "\n");
+			c = -1;
+		} else {
+			c = mcgetc(k);
+			if (c != p) {
+				if (p != -1) {
+					fprintf(outFile, "</span>");
+				}
 	
-	for (i = 0; i < nmapPieces; i++)
-		if (mapPieces[i].c == c)
-			return i;
-
-	return -1;
-}
-
-
-void mkend(FILE *f, int c, int p)
-{
-	int i;
-	
-	if (p != -1) {
-		fprintf(f, "</span>");
-	}
-	
-	if (c > 0) {
-		i = mcget(c);
-		if (i >= 0)
-			i = mapPieces[i].col;
-		else
-			i = 0;
+				if (k > 0) {
+					fprintf(outFile,
+					"<span class=\"c%d\">%c", c, k);
+				}
+			} else
+				fprintf(outFile, "%c", k);
+		}
 		
-		fprintf(f,
-		"<span class=\"c%d\">%c", i, c);
+		p = c;
 	}
 }
 
 
-int main(int argc, char *argv[])
+void processDiff(FILE *inFile, FILE *outFile)
 {
-	FILE *i, *o;
-	int c, p, n;
+	DINT c, p;
+
+	c = p = -1;
+	while ((c = fgetc(inFile)) != EOF) {
+		if (c == 0xff) {
+			if (p != -1)
+				fprintf(outFile, "</span>");
+			
+			fprintf(outFile, "\n");
+			c = -1;
+		} else {
+			if (c != p) {
+				if (p != -1) {
+					fprintf(outFile, "</span>");
+				}
 	
-	i = stdin;
-	o = stdout;
+				if (c >= 0) {
+					DINT t = (c / 64), q = (c % 64);
+					if (t > 0) {
+						fprintf(outFile,
+						"<span style=\"color:%s;background:%s\">",
+						mapColors[mapPieces[q].col].css,
+						mapColors[t].css);
+					} else {
+						fprintf(outFile,
+						"<span class=\"c%d\">",
+						mapPieces[q].col);
+					}
+					
+					fprintf(outFile, "%c", mapPieces[q].c);
+				}
+			} else {
+				fprintf(outFile, "%c",
+				mapPieces[c % 64].c);
+			}
+		}
+		
+		p = c;
+	}
+}
+
+
+DINT main(DINT argc, DCHAR *argv[])
+{
+	FILE *inFile, *outFile;
+	DBOOL optDiff;
 	
+	inFile = stdin;
+	outFile = stdout;
+	
+	fprintf(stderr,
+		"Usage: %s [\"title\" [-diff]] < input > output\n",
+		argv[0]);
+		
 	/* Output XHTML header */
-	fprintf(o,
-	"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
-	"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n"
-	"<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"en\" xml:lang=\"en\">\n"
-	"<head>\n"
-	);
+	if (argc >= 2)
+		mcXHTMLhead(outFile, argv[1]);
+	else
+		mcXHTMLhead(outFile, NULL);
 	
-	/* Optional title -tag */
-	if (argc >= 2) {
-		fprintf(o,
-		" <title>%s</title>\n",
-		argv[1]);
-	}
-	
+	if (argc >= 3 && !strcmp(argv[2], "-diff"))
+		optDiff = TRUE;
+	else
+		optDiff = FALSE;
+		
 	/* Output CSS style information */
-	fprintf(o,
+	fprintf(outFile,
 	" <style type=\"text/css\">\n"
 	"  body	{ background: black; color: white; }\n"
 	);
 
-	for (n = 0; n < ncolors; n++) {
-		fprintf(o,
-		"  span.c%d { color: %s; }\n",
-		colors[n].col, colors[n].css
-		);
-	}
+	mcXHTMLcolors(outFile);
 	
-	fprintf(o,
+	fprintf(outFile,
 	" </style>\n"
 	"</head>\n"
 	"<body>\n"
@@ -179,25 +120,13 @@
 	);
 	
 	/* Process input, convert to map */
-	c = p = -1;
-	while ((c = fgetc(i)) != EOF) {
-		if (c == '\n') {
-			if (p != -1)
-				fprintf(o, "</span>");
-			c = -1;
-			fprintf(o, "\n");
-		} else
-		if (c != p) {
-			mkend(o, c, p);
-		} else {
-			fprintf(o, "%c", c);
-		}
-		
-		p = c;
-	}
+	if (optDiff)
+		processDiff(inFile, outFile);
+	else
+		processNormal(inFile, outFile);
 	
 	/* XHTML document end tags */
-	fprintf(o,
+	fprintf(outFile,
 	"</pre>\n"
 	"</body>\n"
 	"</html>\n"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/diffmap.c	Fri Dec 08 19:31:36 2006 +0000
@@ -0,0 +1,221 @@
+/*
+ * diffmap - Compute 'diff' between two maps, output XHTML+CSS
+ * Programmed by Matti 'ccr' Hämäläinen (Ggr Pupunen)
+ * (C) Copyright 2006 Tecnic Software productions (TNSP)
+ */
+#include <string.h>
+#include "maputils.h"
+#include "th_util.h"
+
+
+typedef struct {
+	DCHAR *d;
+	DINT w, h;
+} mapblock_t;
+
+
+/* Map block handling
+ */
+mapblock_t * allocBlock(DINT blockW, DINT blockH)
+{
+	mapblock_t *res;
+	
+	/* Check arguments */
+	if ((blockW <= 0) || (blockH <= 0))
+		return NULL;
+	
+	/* Allocate struct and data */
+	res = (mapblock_t *) th_malloc(sizeof(mapblock_t));
+	if (!res) return NULL;
+	
+	res->d = (DCHAR *) th_calloc(blockH * blockW, sizeof(DCHAR));
+	if (!res->d) {
+		th_free(res);
+		return NULL;
+	}
+	
+	res->w = blockW;
+	res->h = blockH;
+
+	return res;
+}
+
+
+void freeBlock(mapblock_t *b)
+{
+	if (b) {
+		if (b->d)
+			th_free(b->d);
+		b->d = NULL;
+		th_free(b);
+	}
+}
+
+
+void printBlock(FILE *f, mapblock_t *map)
+{
+	DCHAR *c;
+	DINT x, y;
+
+	c = map->d;
+	
+	for (y = 0; y < map->h; y++) {
+		for (x = 0; x < map->w; x++) {
+			fputc(*c, f);
+			c++;
+		}
+		fputc(0xff, f);
+	}
+}
+
+
+mapblock_t * diffBlocks(mapblock_t *map1, mapblock_t *map2)
+{
+	DINT x, y;
+	mapblock_t *res;
+	DCHAR *p1, *p2, *pd;
+	
+	if (map1->w != map2->w || map1->h != map2->h) {
+		THERR("Mapblock size mismatch (%d, %d) vs (%d, %d)\n",
+			map1->w, map1->h,
+			map2->w, map2->h);
+		return NULL;
+	}
+	
+	if ((res = allocBlock(map1->w, map1->h)) == NULL) {
+		THERR("Could not allocate mapblock (%d, %d)\n",
+			map1->w, map1->h);
+		return NULL;
+	}
+	
+	p1 = map1->d; p2 = map2->d;
+	pd = res->d;
+	
+	for (y = 0; y < map1->h; y++)
+	for (x = 0; x < map1->w; x++) {
+		if (*p1 != *p2)
+			*pd = mcget(*p2) + 0x40;
+		else
+			*pd = mcget(*p1);
+
+		p1++; p2++; pd++;
+	}
+	
+	return res;
+}
+
+mapblock_t * parseFile(DCHAR *mapFilename)
+{
+	FILE *inFile;
+	mapblock_t *res;
+	DCHAR *o;
+	DINT x, y, resW, resH, maxW, c;
+	
+	/* Open file */
+	if ((inFile = fopen(mapFilename, "rb")) == NULL) {
+		THERR("Could not open mapfile '%s' for reading.\n",
+			mapFilename);
+		return NULL;
+	}
+
+	/* Probe map width */
+	resH = 0; resW = -1; maxW = 0;
+	while ((c = fgetc(inFile)) != EOF) {
+		if (c == '\n' || c == '\r') {
+			if (maxW > resW)
+				resW = maxW;
+			maxW = 0;
+			resH++;
+		} else
+			maxW++;
+	}
+	
+	/* Seek back */
+	if (fseek(inFile, 0L, SEEK_SET) == -1) {
+		fclose(inFile);
+		THERR("Could not rewind file '%s'.\n",
+			mapFilename);
+		return NULL;
+	}
+	
+	THPRINT(0, "'%s' w=%d, h=%d\n", mapFilename, resW, resH);
+	
+	/* Allocate block */
+	if ((res = allocBlock(resW, resH)) == NULL) {
+		fclose(inFile);
+		THERR("Could not allocate mapblock (%d, %d) for '%s'.\n",
+			resW, resH, mapFilename);
+		return NULL;
+	}
+	
+	/* Read data */
+	o = res->d;
+	y = x = 0;
+	while ((c = fgetc(inFile)) != EOF && (y < res->h)) {
+		if (c == '\n' || c == '\r') {
+			if (x != res->w) {
+				THERR("Broken block, line width %d < %d!\n",
+					x, res->w);
+				fclose(inFile);
+				freeBlock(res);
+				return NULL;
+			}
+			
+			x = 0;
+			y++;
+		} else {
+			*o = c;
+			x++;
+			o++;
+		}
+	}
+	
+	/* Close file */
+	fclose(inFile);
+	
+	if (y != res->h) {
+		THERR("Broken block, height %d < %d\n",
+			y, res->h);
+		freeBlock(res);
+		return NULL;
+	}
+	
+	return res;
+}
+
+
+
+DINT main(DINT argc, DCHAR *argv[])
+{
+	mapblock_t *map1, *map2, *res;
+	
+	if (argc < 3) {
+		fprintf(stderr,
+		"Usage: %s mapfile1 mapfile2 > outfile\n",
+		argv[0]);
+		return 0;
+	}
+	
+	/* Read mapfiles */
+	if ((map1 = parseFile(argv[1])) == NULL) {
+		THERR("Could not parse input file #1: '%s'\n",
+			argv[1]);
+		return 1;
+	}
+
+	if ((map2 = parseFile(argv[2])) == NULL) {
+		THERR("Could not parse input file #2: '%s'\n",
+			argv[2]);
+		return 1;
+	}
+	
+	/* Compute and output data */
+	if ((res = diffBlocks(map1, map2)) == NULL) {
+		THERR("Could not create diff between inputs!\n");
+		return 1;
+	}
+	
+	printBlock(stdout, res);
+
+	return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/maputils.c	Fri Dec 08 19:31:36 2006 +0000
@@ -0,0 +1,122 @@
+/*
+ * maputils - Generic functions/tables for maputils package
+ * Programmed by Matti 'ccr' Hämäläinen (Ggr Pupunen)
+ * (C) Copyright 2006 Tecnic Software productions (TNSP)
+ */
+#include "maputils.h"
+
+color_t mapColors[] = {
+{ "#000000" },
+{ "#0000bb" },
+{ "#bb0000" },
+{ "#bbbb00" },
+
+{ "#00bb00" },
+{ "#bbbbbb" },
+{ "#00ffff" },
+{ "#770077" },
+
+{ "#777777" },
+{ "#0000ff" },
+{ "#ff0000" },
+{ "#ffff00" },
+
+{ "#00ff00" },
+{ "#ffffff" },
+{ "#00ffff" },
+{ "#ff00ff" },
+};
+
+const DINT nmapColors = (sizeof(mapColors) / sizeof(color_t));
+
+
+mappiece_t mapPieces[] = {
+{ '~', "sea",			col_blue },
+{ 'r', "river",			col_blue },
+{ 'l', "lake",			col_light_blue },
+{ 'V', "volcano",		col_red },
+
+{ 's', "swamp",			col_light_red },
+{ '^', "mountain",		col_light_magenta },
+{ 'b', "beach",			col_light_yellow },
+{ '-', "east-west road",	col_light_black },
+
+{ 'y', "field",			col_light_yellow },
+{ 'j', "jungle",		col_green },
+{ '%', "special location",	col_light_white },
+{ 'C', "playercity",		col_light_black },
+
+{ '#', "ruins",			col_light_black },
+{ 'R', "deepriver",		col_blue },
+{ '?', "scenic location",	col_light_white },
+{ 'i', "highlands",		col_magenta },
+
+{ 'd', "desert",		col_yellow },
+{ '+', "crossing",		col_light_black },
+{ 'p', "plain",			col_light_green },
+{ 'x', "badlands",		col_light_red },
+
+{ 't', "tundra",		col_white },
+{ '=', "bridge",		col_light_black },
+{ '!', "peak",			col_white },
+{ '/', "sw-ne road",		col_light_black },
+
+{ 'w', "waterfall",		col_light_cyan },
+{ '|', "north-south road",	col_light_black },
+{ 'z', "shore",			col_light_yellow },
+{ 'S', "shallow",		col_cyan },
+
+{ 'h', "hills",			col_magenta },
+{ 'f', "forest",		col_light_green },
+{ 'F', "deep forest",		col_green },
+{ '\\', "nw-se road",		col_light_black },
+
+{ 'v', "valley",		col_light_green },
+{ 'c', "city",			col_light_black },
+};
+
+const DINT nmapPieces = (sizeof(mapPieces) / sizeof(mappiece_t));
+
+
+DINT mcget(DINT c)
+{
+	DINT i;
+	for (i = 0; i < nmapPieces; i++)
+		if (mapPieces[i].c == c)
+			return i;
+	return -1;
+}
+
+DINT mcgetc(DINT c)
+{
+	DINT i;
+	for (i = 0; i < nmapPieces; i++)
+		if (mapPieces[i].c == c)
+			return mapPieces[i].col;
+	return 0;
+}
+
+void mcXHTMLcolors(FILE *o)
+{
+	DINT n;
+	
+	for (n = 0; n < nmapColors; n++) {
+		fprintf(o,
+		"  span.c%d { color: %s; }\n",
+		n, mapColors[n].css);
+	}
+	
+}
+
+
+void mcXHTMLhead(FILE *outFile, DCHAR *title)
+{
+	fprintf(outFile,
+	"<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n"
+	"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n"
+	"<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"en\" xml:lang=\"en\">\n"
+	"<head>\n");
+	
+	if (title)
+	fprintf(outFile, "  <title>%s</title>\n", title);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/maputils.h	Fri Dec 08 19:31:36 2006 +0000
@@ -0,0 +1,57 @@
+#ifndef _MAPUTIL_H
+#define _MAPUTIL_H
+#include "th_types.h"
+#include <stdio.h>
+
+
+/* Typedefs
+ */
+typedef struct {
+	DCHAR c;
+	DCHAR *desc;
+	DINT col;
+} mappiece_t;
+
+
+typedef struct {
+	DCHAR *css;
+} color_t;
+
+
+enum {
+	col_black = 0,
+	col_blue,
+	col_red,
+	col_yellow,
+	col_green,
+	col_white,
+	col_cyan,
+	col_magenta,
+	col_light_black,
+	col_light_blue,
+	col_light_red,
+	col_light_yellow,
+	col_light_green,
+	col_light_white,
+	col_light_cyan,
+	col_light_magenta,
+};
+
+
+/* Tables
+ */
+extern color_t mapColors[];
+extern const DINT nmapColors;
+
+extern mappiece_t mapPieces[];
+extern const DINT nmapPieces;
+
+
+/* Functions
+ */
+DINT	mcget(DINT);
+DINT	mcgetc(DINT);
+void	mcXHTMLcolors(FILE *);
+void	mcXHTMLhead(FILE *, DCHAR *);
+
+#endif
--- a/mkbcmap.c	Fri Dec 08 19:30:23 2006 +0000
+++ b/mkbcmap.c	Fri Dec 08 19:31:36 2006 +0000
@@ -3,11 +3,9 @@
  * Programmed by Matti 'ccr' Hämäläinen (Ggr Pupunen)
  * (C) Copyright 2006 Tecnic Software productions (TNSP)
  */
-#include <stdio.h>
-#include "th_util.h"
+#include <string.h>
+#include "maputils.h"
 #include "th_string.h"
-#include <string.h>
-#include <strings.h>
 
 
 typedef struct {
@@ -17,55 +15,6 @@
 } location_t;
 
 
-typedef struct {
-	DINT col;
-	DCHAR *css;
-} color_t;
-
-
-enum {
-	col_black = 0,
-	col_blue,
-	col_red,
-	col_yellow,
-	col_green,
-	col_white,
-	col_cyan,
-	col_magenta,
-	col_light_black,
-	col_light_blue,
-	col_light_red,
-	col_light_yellow,
-	col_light_green,
-	col_light_white,
-	col_light_cyan,
-	col_light_magenta,
-};
-
-
-color_t colors[] = {
-{ col_black,		"#000000" },
-{ col_blue,		"#0000bb" },
-{ col_red,		"#bb0000" },
-{ col_yellow,		"#bbbb00" },
-{ col_green,		"#00bb00" },
-{ col_white,		"#bbbbbb" },
-{ col_cyan,		"#00ffff" },
-{ col_magenta,		"#770077" },
-
-{ col_light_black,	"#777777" },
-{ col_light_blue,	"#0000ff" },
-{ col_light_red,	"#ff0000" },
-{ col_light_yellow,	"#ffff00" },
-{ col_light_green,	"#00ff00" },
-{ col_light_white,	"#ffffff" },
-{ col_light_cyan,	"#00ffff" },
-{ col_light_magenta,	"#ff00ff" },
-};
-
-
-const DINT ncolors = (sizeof(colors) / sizeof(color_t));
-
 #define MAX_LOC		(256)
 DINT nlocations = 0;
 location_t locations[MAX_LOC];
@@ -268,16 +217,8 @@
 
 void outputHTML(FILE *outFile, FILE *inFile, DCHAR *mapTitle)
 {
-	DINT n;
-	
 	/* Output XHTML header */
-	fprintf(outFile,
-	"<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n"
-	"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n"
-	"<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"en\" xml:lang=\"en\">\n"
-	"<head>\n"
-	" <title>%s</title>\n",
-		mapTitle);
+	mcXHTMLhead(outFile, mapTitle);
 	
 	/* Output CSS style information */
 	fprintf(outFile,
@@ -295,12 +236,7 @@
 	"  * html .holder { display: inline-block; position: relative; margin-right: -400px; }\n"
 	);
 
-	for (n = 0; n < ncolors; n++) {
-		fprintf(outFile,
-		"  span.c%d { color: %s; }\n",
-		colors[n].col, colors[n].css
-		);
-	}
+	mcXHTMLcolors(outFile);
 	
 	fprintf(outFile,
 	" </style>\n"
--- a/mkmap.c	Fri Dec 08 19:30:23 2006 +0000
+++ b/mkmap.c	Fri Dec 08 19:31:36 2006 +0000
@@ -161,12 +161,12 @@
 		return NULL;
 	
 	/* Allocate struct and data */
-	blockRes = (mapblock_t *) calloc(1, sizeof(mapblock_t));
+	blockRes = (mapblock_t *) th_calloc(1, sizeof(mapblock_t));
 	if (!blockRes) return NULL;
 	
-	blockRes->d = (char *) calloc(blockH * blockW, sizeof(char));
+	blockRes->d = (char *) th_calloc(blockH * blockW, sizeof(char));
 	if (!blockRes->d) {
-		free(blockRes);
+		th_free(blockRes);
 		return NULL;
 	}
 	
@@ -181,9 +181,9 @@
 {
 	if (b) {
 		if (b->d)
-			free(b->d);
+			th_free(b->d);
 		b->d = NULL;
-		free(b);
+		th_free(b);
 	}
 }
 
@@ -292,14 +292,14 @@
 	
 	/* Copy data */
 	if (putBlockDo(tmp, *map, mx, my) < 0) {
-		free(tmp);
+		th_free(tmp);
 		return -2;
 	}
 
 //fprintf(stderr, "(%d,%d - %d,%d)\n--- map[%d,%d]\n", x0, y0, x1, y1, mx, my);printBlock(stderr, tmp);
 
 	if (putBlockDo(tmp, b, ox, oy) < 0) {
-		free(tmp);
+		th_free(tmp);
 		return -3;
 	}
 	
@@ -323,6 +323,7 @@
 		switch (map->d[o]) {
 		case ' ':
 		case '*':
+		case '@':
 			map->d[o] = 0;
 			break;
 		case 'X':
@@ -419,7 +420,7 @@
 	mapblock_t **mapBlocks = NULL;
 
 	progName = argv[0];
-	th_init("mkmap", "ASCII Map Auto-Stitcher", "0.2", NULL, NULL);
+	th_init("mkmap", "ASCII Map Auto-Stitcher", "0.3", NULL, NULL);
 	th_verbosityLevel = 1;
 	
 	/* Parse arguments */
@@ -443,7 +444,7 @@
 		while (!feof(tmpFile)) {
 			if ((tmp = parseBlock(tmpFile, optBlockW, optBlockH)) != NULL) {
 				nmapBlocks++;
-				mapBlocks = (mapblock_t **) realloc(mapBlocks, sizeof(mapblock_t *) * nmapBlocks);
+				mapBlocks = (mapblock_t **) th_realloc(mapBlocks, sizeof(mapblock_t *) * nmapBlocks);
 				if (!mapBlocks) {
 					THERR("Could not allocate/extend mapblock pointer structure (#%d)\n", nmapBlocks);
 					exit(3);