Mercurial > hg > batmud > maputils
view maputils.c @ 945:81184d58133c aprilli2011
Sync.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Fri, 14 May 2010 11:18:20 +0000 |
parents | 066fed52348d |
children | 82469eecbae7 |
line wrap: on
line source
/* * maputils - Generic functions/tables for maputils package * Programmed by Matti 'ccr' Hämäläinen (Ggr Pupunen) * (C) Copyright 2006-2008 Tecnic Software productions (TNSP) */ #include <string.h> #include "maputils.h" #include "th_util.h" const color_t mapColors[] = { { 0x00, 0x00, 0x00, 30, ANSI_OFF }, { 0x00, 0x00, 0xbb, 34, ANSI_OFF }, { 0xbb, 0x00, 0x00, 31, ANSI_OFF }, { 0xbb, 0xbb, 0x00, 33, ANSI_OFF }, { 0x00, 0xbb, 0x00, 32, ANSI_OFF }, { 0xbb, 0xbb, 0xbb, 37, ANSI_OFF }, { 0x00, 0xff, 0xff, 36, ANSI_OFF }, { 0x77, 0x00, 0x77, 35, ANSI_OFF }, { 0x77, 0x77, 0x77, 30, ANSI_BOLD }, { 0x00, 0x00, 0xff, 34, ANSI_BOLD }, { 0xee, 0x00, 0x00, 31, ANSI_BOLD }, { 0xff, 0xff, 0x00, 33, ANSI_BOLD }, { 0x00, 0xff, 0x00, 32, ANSI_BOLD }, { 0xff, 0xff, 0xff, 37, ANSI_BOLD }, { 0x00, 0xff, 0xff, 36, ANSI_BOLD }, { 0xff, 0x00, 0xff, 35, ANSI_BOLD }, /* extra colors */ { 0xff, 0x80, 0x00, 31, ANSI_BOLD }, }; const int nmapColors = (sizeof(mapColors) / sizeof(mapColors[0])); const mappiece_t mapPieces[] = { { '!', "Mountain Peak", 0xcc,0xff,0xff, col_white, -1, -1, NULL }, { '#', "Ruins", 0x88,0x88,0x88, col_light_black, -1, -1, NULL }, { '%', "Special Location", 0xff,0xff,0xff, col_light_white, -1, -1, NULL }, { '+', "Crossing", 0x33,0x33,0x33, col_light_black, -1, -1, NULL }, { '-', "Road", 0x33,0x33,0x33, col_light_black, -1, -1, NULL }, { '|', "Road", 0x33,0x33,0x33, col_light_black, -1, -1, NULL }, { '/', "Road", 0x33,0x33,0x33, col_light_black, -1, -1, NULL }, { '\\',"Road", 0x33,0x33,0x33, col_light_black, -1, -1, NULL }, { '.', "Plains", 0x55,0x92,0x00, col_green, -1, col_light_black, "Road" }, { -1, NULL, 0x33,0x33,0x33, -1, 'p', col_light_green, "Plains" }, { '=', "Bridge", 0x33,0x33,0x33, col_light_black, -1, -1, NULL }, { '?', "Scenic Location", 0xff,0xff,0xff, col_light_white, -1, -1, NULL }, { '@', "Flowing Lava", 0xff,0x99,0x3f, col_very_light_red, -1, -1, NULL }, { 'C', "Player City", 0x88,0x88,0x88, col_light_black, -1, -1, NULL }, { 'F', "Deep Forest", 0x00,0x88,0x00, col_green, -1, -1, NULL }, { 'H', "Highlands", 0x66,0x3f,0x00, col_magenta, -1, -1, NULL }, { 'L', "Lava Lake", 0xff,0x50,0x00, col_very_light_red, -1, -1, NULL }, { 'R', "Deep River", 0x33,0x66,0xff, col_blue, -1, -1, NULL }, { 'V', "Volcano", 0xff,0x33,0x00, col_red, -1, -1, NULL }, { '^', "Mountain", 0x71,0x82,0x92, col_light_magenta, -1, -1, NULL }, { 'b', "Beach", 0xcf,0xc4,0xa5, col_yellow, -1, -1, NULL }, { 'c', "City", 0x88,0x88,0x88, col_light_black, -1, -1, NULL }, { 'd', "Desert", 0xee,0xbb,0x22, col_yellow, -1, -1, NULL }, { 'f', "Forest", 0x00,0xb6,0x00, col_light_green, -1, -1, NULL }, { 'h', "Hills", 0x99,0x66,0x00, col_magenta, -1, -1, NULL }, { 'i', "Ice", 0xee,0xee,0xff, col_light_blue, -1, col_magenta, "???" }, { 'j', "Jungle", 0x13,0x96,0x36, col_green, -1, -1, NULL }, { 'l', "Lake", 0x21,0x33,0xcc, col_light_blue, -1, -1, NULL }, { 'r', "River", 0x66,0x99,0xff, col_light_blue, -1, -1, NULL }, { 's', "Swamp", 0x9d,0xa8,0x0a, col_light_red, -1, -1, NULL }, { 't', "Tundra", 0x61,0xc3,0xa2, col_white, -1, -1, NULL }, { 'v', "Valley", 0x22,0xdd,0x22, col_light_green, -1, -1, NULL }, { 'w', "Waterfall", 0x77,0xaa,0xff, col_light_cyan, -1, -1, NULL }, { 'x', "Badlands", 0x8a,0x83,0x60, col_light_red, -1, -1, NULL }, { 'y', "Fields", 0xa7,0xcc,0x14, col_yellow, -1, -1, NULL }, { 'z', "Shore", 0xa7,0xcc,0x14, col_light_yellow, -1, -1, NULL }, { ',', "Muddy Trail", 0x8c,0x57,0x38, col_light_yellow, -1, -1, NULL }, { '&', "Monster", 0xff,0x00,0x00, col_light_red, -1, -1, NULL }, #ifndef SECRET_MAP_DATA_FORMAT { 'S', "Shallows", 0x44,0xcc,0xcc, col_light_cyan, -1, -1, NULL }, { '~', "Sea", 0x11,0x88,0xdd, col_blue, -1, -1, NULL }, #else { '~', "Sea 1", 0x00,0x11,0x88, col_blue, -1, -1, NULL }, { '"', "Sea 2", 0x11,0x22,0x99, col_blue, -1, -1, NULL }, { '\'',"Sea 3", 0x11,0x33,0xaa, col_blue, -1, -1, NULL }, { '`', "Shallows?", 0x11,0x66,0xdd, col_blue, -1, -1, NULL }, { 'p', "Plains?", 0x55,0x92,0x00, col_green, -1, -1, NULL }, { 'S', "Swamp?", 0x77,0x77,0x33, col_yellow, -1, -1, NULL }, #endif }; const int nmapPieces = (sizeof(mapPieces) / sizeof(mapPieces[0])); const mappiece_t mapCityPieces[] = { { '.', "Street", 0x00,0x00,0x00, col_yellow, -1, col_white, NULL }, { '-', "Door/Gate", 0x00,0x00,0x00, col_light_yellow, -1, col_yellow, NULL }, { '|', "Door/Gate", 0x00,0x00,0x00, col_light_yellow, -1, col_yellow, NULL }, { '=', "Bridge/Gate", 0x00,0x00,0x00, col_yellow, -1, -1, NULL }, { '*', "Fountain", 0x00,0x00,0x00, col_light_blue, -1, col_light_white,"???" }, { '@', "???", 0x00,0x00,0x00, col_light_yellow, -1, -1, NULL }, { '$', "Tree", 0x00,0x00,0x00, col_green, -1, -1, NULL }, { '#', "Wall", 0x00,0x00,0x00, col_light_black, -1, -1, NULL }, { '"', "Grass", 0x00,0x00,0x00, col_green, -1, -1, NULL }, { ':', "???", 0x00,0x00,0x00, col_white, -1, -1, NULL }, { 'z', "Shore", 0xa7,0xcc,0x14, col_yellow, -1, -1, NULL }, /* { '.', "", 0x00,0x00,0x00, col_, -1, -1, NULL }, */ }; const int nmapCityPieces = (sizeof(mapCityPieces) / sizeof(mapCityPieces[0])); typedef struct { char c; char *ent; } html_entity_t; static const html_entity_t HTMLEntities[] = { { '&', "amp" }, { '<', "lt" }, { '>', "gt" }, { '"', "quot" }, { 'ä', "#228" }, { 'ö', "#246" }, { 'Ä', "#196" }, { 'Ö', "#214" }, }; static const int numHTMLEntities = (sizeof(HTMLEntities) / sizeof(HTMLEntities[0])); void fprinte(FILE *outFile, char *fmt) { char *s = fmt; if (fmt == NULL) return; while (*s) { int i; BOOL found = FALSE; for (i = 0; i < numHTMLEntities; i++) if (HTMLEntities[i].c == *s) { fprintf(outFile, "&%s;", HTMLEntities[i].ent); found = TRUE; break; } if (!found) fputc(*s, outFile); s++; } } void fprintve(FILE *outFile, char *fmt, va_list ap) { int n, bufsize = strlen(fmt) * 2; char *buf, *tmp; if ((buf = th_malloc(bufsize)) == NULL) return; while (1) { va_list tap; va_copy(tap, ap); n = vsnprintf(buf, bufsize, fmt, tap); va_end(tap); if (n > -1 && n < bufsize) { /* String fit the buffer, print it out and return */ fprinte(outFile, buf); th_free(buf); return; } /* Didn't fit, try reallocating some more space */ if (n > -1) bufsize = n + 1; else bufsize *= 2; if ((tmp = th_realloc(buf, bufsize)) == NULL) { th_free(buf); return; } else buf = tmp; } } void fprintfe(FILE *outFile, char *fmt, ...) { va_list ap; va_start(ap, fmt); fprintve(outFile, fmt, ap); va_end(ap); } char *mcGetCSS(int c) { static char tmpStr[32]; assert(c >= 0); assert(c < nmapColors); snprintf(tmpStr, sizeof(tmpStr), "#%02x%02x%02x", mapColors[c].r, mapColors[c].g, mapColors[c].b); return tmpStr; } int mcGetPieceFromList(const mappiece_t pieces[], const int npieces, int symbol, BOOL getOld) { int i; if (getOld) { for (i = 0; i < npieces; i++) if (pieces[i].oldSymbol == symbol) return i; } for (i = 0; i < npieces; i++) if (pieces[i].symbol == symbol) return i; return -1; } int mcGet(int symbol, BOOL getOld, BOOL getCity) { int n; if (getCity && (n = mcGetPieceFromList(mapCityPieces, nmapCityPieces, symbol, getOld)) >= 0) return n; return mcGetPieceFromList(mapPieces, nmapPieces, symbol, getOld); } int mcGetColorFromList(const mappiece_t pieces[], const int npieces, int symbol, BOOL getOld) { int i; if (getOld) { for (i = 0; i < npieces; i++) if (pieces[i].oldSymbol == symbol) { if (pieces[i].oldColor >= 0) return pieces[i].oldColor; else return pieces[i].color; } } for (i = 0; i < npieces; i++) if (pieces[i].symbol == symbol) { if (getOld && pieces[i].oldColor >= 0) return pieces[i].oldColor; else return pieces[i].color; } return -1; } int mcGetColor(int symbol, BOOL getOld, BOOL getCity) { int n; if (getCity && (n = mcGetColorFromList(mapCityPieces, nmapCityPieces, symbol, getOld)) >= 0) return n; if ((n = mcGetColorFromList(mapPieces, nmapPieces, symbol, getOld)) >= 0) return n; else return 0; } void mcXHTMLhead(FILE *outFile, char *title) { static const char *strCharSet = "utf-8"; assert(outFile != NULL); /* Output XHTML header */ fprintf(outFile, "<?xml version=\"1.0\" encoding=\"%s\"?>\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" " <meta http-equiv=\"Content-Type\" content=\"text/html; charset=%s\" />\n", strCharSet, strCharSet ); if (title) { fprintf(outFile, " <title>"); fprinte(outFile, title); fprintf(outFile, "</title>\n"); } } void mcXHTMLcolors(FILE *outFile, char *tagName, char *propName, char *extra) { int n; assert(outFile != NULL); for (n = 0; n < nmapColors; n++) { fprintf(outFile, " %s.%c { %s: #%02x%02x%02x;%s }\n", tagName, 'a'+n, propName ? propName : "color", mapColors[n].r, mapColors[n].g, mapColors[n].b, extra ? extra : ""); } } /* Map block handling */ mapblock_t * allocBlock(int blockW, int blockH) { mapblock_t *blockRes; /* Check arguments */ if (blockW <= 0 || blockH <= 0) return NULL; /* Allocate struct and data */ blockRes = (mapblock_t *) th_calloc(1, sizeof(mapblock_t)); if (!blockRes) return NULL; blockRes->d = (unsigned char *) th_calloc(blockH * blockW, sizeof(char)); if (!blockRes->d) { th_free(blockRes); return NULL; } blockRes->w = blockW; blockRes->h = blockH; return blockRes; } void freeBlock(mapblock_t *b) { if (b) { if (b->d) th_free(b->d); b->d = NULL; th_free(b); } } /* Parse single arbitrary sized block from given mapfile */ mapblock_t * parseFile(char *mapFilename, BOOL isDiff) { FILE *inFile; mapblock_t *res; unsigned char *o; long pos = 0L; BOOL flag; int x, y, resW, resH, c; assert(mapFilename != NULL); /* Open file */ if ((inFile = fopen(mapFilename, "rb")) == NULL) { THERR("Could not open mapfile '%s' for reading.\n", mapFilename); return NULL; } if (isDiff) { char buf[128]; int ver; fgets(buf, sizeof(buf), inFile); if (sscanf(buf, DIFF_MAGIC "%d\n", &ver) != 1) { fclose(inFile); THERR("Not a DIFF format file '%s'.\n", mapFilename); return NULL; } if (ver != DIFF_VERSION) { fclose(inFile); THERR("Not a correct DIFF format version (%d != %d) '%s'.\n", ver, DIFF_VERSION, mapFilename); return NULL; } pos = ftell(inFile); } /* Probe map width */ resH = 1; resW = -1; x = 0; flag = FALSE; while ((c = fgetc(inFile)) != EOF) { if ((!isDiff && c == '\n') || (isDiff && c == 0xff)) { if (x > resW) resW = x; flag = TRUE; } else { if (flag) { x = 0; resH++; flag = FALSE; } x++; } } /* Seek back */ if (fseek(inFile, pos, SEEK_SET) == -1) { fclose(inFile); THERR("Could not rewind file '%s'.\n", mapFilename); return NULL; } /* 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 = 0; x = 0; flag = FALSE; while ((c = fgetc(inFile)) != EOF && (y < res->h)) { if ((!isDiff && c == '\n') || (isDiff && c == 0xff)) { if (x != res->w) { THERR("Broken block in '%s', line #%d width %d < %d!\n", mapFilename, y, x, res->w); fclose(inFile); freeBlock(res); return NULL; } flag = TRUE; } else { if (flag) { x = 0; y++; flag = FALSE; } *(o++) = c; x++; } } /* Close file */ fclose(inFile); if (y >= res->h) { THERR("Broken block in '%s', height %d >= %d\n", mapFilename, y, res->h); freeBlock(res); return NULL; } return res; } /* Print block to given output stream */ void printBlock(FILE *f, mapblock_t *map) { unsigned char *c; int x, y; assert(f != NULL); assert(map != NULL); c = map->d; for (y = 0; y < map->h; y++) { for (x = 0; x < map->w; x++) { if (*c > 0) fputc(*c, f); else fputc(' ', f); c++; } fprintf(f, "\n"); } } /* Blit a block into another, assume that memory has been allocated * in sufficient way and other preparations are done. */ int putBlockDo(mapblock_t *map, mapblock_t *b, int ox, int oy) { int x, y; assert(map != NULL); assert(b != NULL); for (y = 0; y < b->h; y++) for (x = 0; x < b->w; x++) { int dx = (ox + x); int dy = (oy + y); if (dx >= 0 && dx < map->w && dy >= 0 && dy < map->h) { char c = b->d[(y * b->w) + x]; if (c != 0) map->d[(dy * map->w) + dx] = c; } else return -1; } b->mark = TRUE; return 0; } int putBlock(mapblock_t **map, mapblock_t *b, int ox, int oy) { mapblock_t *tmp; int x0, y0, x1, y1, mx, my; assert(map != NULL); assert(*map != NULL); assert(b != NULL); /* Determine new block size */ x0 = mx = y0 = my = 0; x1 = (*map)->w - 1; y1 = (*map)->h - 1; if (ox < 0) { x0 = ox; mx = -ox; ox = 0; } if (oy < 0) { y0 = oy; my = -oy; oy = 0; } if ((x0 + ox + b->w - 1) > x1) x1 = (x0 + ox + b->w - 1); if ((y0 + oy + b->h - 1) > y1) y1 = (y0 + oy + b->h - 1); /* Allocate new block */ if ((tmp = allocBlock((x1 - x0 + 1), (y1 - y0 + 1))) == NULL) return -1; /* Copy data */ if (putBlockDo(tmp, *map, mx, my) < 0) { th_free(tmp); return -2; } if (putBlockDo(tmp, b, ox, oy) < 0) { th_free(tmp); return -3; } tmp->x = -mx; tmp->y = -my; /* Out with the old, in with the new */ freeBlock(*map); *map = tmp; return 0; } /* Clean given block from position markers and whitespaces */ void cleanBlock(mapblock_t *map, char *symbols) { int x, y; unsigned char *c; assert(map != NULL); assert(symbols != NULL); c = map->d; for (y = 0; y < map->h; y++) for (x = 0; x < map->w; x++) { if (strchr(symbols, *c) != NULL) *c = 0; c++; } } void printBlockRaw(FILE *f, mapblock_t *map) { unsigned char *c = map->d; int x, y; assert(f != NULL); assert(map != NULL); for (y = 0; y < map->h; y++) { for (x = 0; x < map->w; x++) { fputc(*c, f); c++; } fputc(0xff, f); } }