/* Read the header bytes of the given solution file. flags receives * the option bytes (bytes 5-6). extra receives any bytes in the * header that this code doesn't recognize. */ static int readsolutionheader(fileinfo *file, int ruleset, int *flags, int *extrasize, unsigned char *extra) { uint32_t sig; uint16_t f; uint8_t n; if (!filereadint32(file, &sig, "not a valid solution file")) return FALSE; if (sig != CSSIG) return fileerr(file, "not a valid solution file"); if (!filereadint8(file, &n, "not a valid solution file")) return FALSE; if (n != ruleset) return fileerr(file, "solution file is for a different ruleset" " than the level set file"); if (!filereadint16(file, &f, "not a valid solution file")) return FALSE; *flags = (int)f; if (!filereadint8(file, &n, "not a valid solution file")) return FALSE; *extrasize = n; if (n) if (!fileread(file, extra, *extrasize, "not a valid solution file")) return FALSE; return TRUE; }
/* Read the puzzle file corresponding to series, and the corresponding * solutions in the answer file, until at least level maps have been * successfully parsed, or the end is reached. The files are opened if * they have not been already. No files are opened if the requested * level has already been loaded into memory. */ int readlevelinseries(gameseries *series, int level) { int n; if (level < 0) return FALSE; if (series->count > level) return TRUE; if (!series->allmapsread) { if (!series->mapfp) { currentfilename = series->filename; series->mapfp = openfileindir(datadir, series->filename, "r"); if (!series->mapfp) return fileerr(NULL); if (!readseriesheader(series)) return fileerr("file contains no maps"); if (*savedir) { series->answerfp = openfileindir(savedir, series->filename, "r"); if (series->answerfp) { savedirchecked = TRUE; series->answersreadonly = TRUE; } } else series->answerfp = NULL; } while (!series->allmapsread && series->count <= level) { while (series->count >= series->allocated) { n = series->allocated ? series->allocated * 2 : 16; if (!(series->games = realloc(series->games, n * sizeof *series->games))) memerrexit(); memset(series->games + series->allocated, 0, (n - series->allocated) * sizeof *series->games); series->allocated = n; } if (readlevelmap(series->mapfp, series->games + series->count)) { series->games[series->count].seriesname = series->name; if (!series->allanswersread) readanswers(series->answerfp, series->games + series->count); ++series->count; } if (feof(series->mapfp)) { fclose(series->mapfp); series->mapfp = NULL; series->allmapsread = TRUE; } if (series->answerfp && feof(series->answerfp)) series->allanswersread = TRUE; } } return series->count > level; }
/* Add data not explicitly defined in the file's representation. * Neighboring WALL cells are "joined" so that they can be drawn in * outline, and every cell that is "inside" is given a FLOOR. Finally, * invisible WALLs are added around the outer edge (so as to insure * that the player is not allowed to leave the map and go walking * through the heap). */ static int improvemap(gamesetup *game) { cell *map; yx initpos; int y, x; initpos = 0; map = game->map; for (y = 0 ; y < game->ysize ; ++y, map += XSIZE) { for (x = 0 ; x < game->xsize ; ++x) { if (map[x] & WALL) continue; map[x] |= FLOOR; if (map[x] & PLAYER) { if (initpos) return fileerr("multiple players in map"); initpos = &map[x] - game->map; } } } if (!initpos) return fileerr("no player in map"); pullflooring(game->map, 0); map = game->map; for (y = 1, map += XSIZE ; y < game->ysize - 1 ; ++y, map += XSIZE) { for (x = 1 ; x < game->xsize - 1 ; ++x) { if (!(map[x] & WALL)) continue; if (map[x + XSIZE] & WALL) map[x + XSIZE] |= EXTENDNORTH; if (map[x - XSIZE] & WALL) map[x - XSIZE] |= EXTENDSOUTH; if (map[x + 1] & WALL) map[x + 1] |= EXTENDWEST; if (map[x - 1] & WALL) map[x - 1] |= EXTENDEAST; } } map = game->map; memset(map, WALL, game->xsize); for (y = 1, map += XSIZE ; y < game->ysize - 1 ; ++y, map += XSIZE) map[0] = map[game->xsize - 1] = WALL; memset(map, WALL, game->xsize); return TRUE; }
static int readppmascrow(fileinfo *file, imageinfo *image) { uchar *rline, *gline, *bline; int r, g, b; int y, x; y = image->height - image->ypos; if (y <= 0) return 0; if (y > squaresize) y = squaresize; rline = image->buf[0]; gline = image->buf[1]; bline = image->buf[2]; while (y--) { for (x = 0 ; x < image->width ; ++x) { if (fscanf(file->fp, "%d %d %d", &r, &g, &b) < 3) { fileerr(file); return -1; } rline[x] = r; gline[x] = g; bline[x] = b; } rline += image->width; gline += image->width; bline += image->width; } return 1; }
static int readppmrawrow(fileinfo *file, imageinfo *image) { uchar *rline, *gline, *bline; int r, g, b; int y, x; y = image->height - image->ypos; if (y <= 0) return 0; if (y > squaresize) y = squaresize; rline = image->buf[0]; gline = image->buf[1]; bline = image->buf[2]; while (y--) { for (x = 0 ; x < image->width ; ++x) { if ((r = fgetc(file->fp)) == EOF || (g = fgetc(file->fp)) == EOF || (b = fgetc(file->fp)) == EOF) { fileerr(file); return -1; } rline[x] = r; gline[x] = g; bline[x] = b; } rline += image->width; gline += image->width; bline += image->width; } return 1; }
static int readpgmrawrow(fileinfo *file, imageinfo *image) { int y; y = image->height - image->ypos; if (y <= 0) return 0; if (y > squaresize) y = squaresize; if ((int)fread(image->buf[0], image->width, y, file->fp) != y) { fileerr(file); return -1; } return 1; }
static int readpgmascrow(fileinfo *file, imageinfo *image) { uchar *line; int pixel; int y, x; y = image->height - image->ypos; if (y <= 0) return 0; if (y > squaresize) y = squaresize; for (line = image->buf[0] ; y ; --y, line += image->width) { for (x = 0 ; x < image->width ; ++x) { if (fscanf(file->fp, "%d", &pixel) < 1) { fileerr(file); return -1; } line[x] = pixel; } } return 1; }
static int readpbmrawrow(fileinfo *file, imageinfo *image) { uchar *line; int byte; int y, x, w; y = image->height - image->ypos; if (y <= 0) return 0; if (y > squaresize) y = squaresize; for (line = image->buf[0] ; y ; --y, line += image->width) { for (x = 0 ; x < image->width ; x += 8) { if ((byte = fgetc(file->fp)) == EOF) { fileerr(file); return -1; } byte ^= 255; for (w = 0 ; w < 8 && x + w < image->width ; ++w, byte <<= 1) line[x + w] = byte & 128 ? 1 : 0; } } return 1; }
/* Read a single map from the current position of fp and use it to * initialize the given gamesetup structure. Maps in the file are * separated by blank lines and/or lines beginning with a semicolon, * equal sign, or single quote. A semicolon appearing inside a line * in a map causes the remainder of the line to be ignored. */ static int readlevelmap(FILE *fp, gamesetup *game) { char buf[256]; char *p, *q; int badmap = FALSE; int y, x, n, ch; game->name[0] = '\0'; memset(game->map, EMPTY, sizeof game->map); game->xsize = 1; for (y = 1 ; y < MAXHEIGHT ; ++y) { ch = fgetc(fp); if (ch == EOF) { if (y > 1) break; else return FALSE; } else if (ch == '\n' || ch == ';' || ch == '=' || ch == '\'') { if (y > 1) { ungetc(ch, fp); break; } --y; if (ch == '\n') continue; n = getnline(fp, buf, sizeof buf); if (n < 0) return FALSE; if (ch == ';' && *buf == ';') { for (x = 1 ; isspace(buf[x]) ; ++x) ; n -= x; if (n >= (int)(sizeof game->name)) n = sizeof game->name - 1; memcpy(game->name, buf + x, n); for (--n ; isspace(game->name[n]) ; --n) ; game->name[n + 1] = '\0'; } continue; } buf[0] = ch; getnline(fp, buf + 1, sizeof buf - 1); if (badmap) continue; x = 1; p = buf; for ( ; x < MAXWIDTH && *p && *p != '\n' && *p != ';' ; ++x, ++p) { if (*p == '\t') { x |= 7; continue; } if (!(q = strchr(filecells, *p))) { fileerr("unrecognized character in level"); badmap = TRUE; break; } game->map[y * XSIZE + x] = q - filecells; } if (game->xsize <= x) { game->xsize = x + 1; if (game->xsize > MAXWIDTH) break; } } game->ysize = y + 1; if (game->ysize > MAXHEIGHT || game->xsize > MAXWIDTH) return fileerr("ignoring map which exceeds maximum dimensions"); if (!improvemap(game)) return FALSE; game->boxcount = 0; game->goalcount = 0; game->storecount = 0; for (n = 0 ; n < game->ysize * XSIZE ; ++n) { if (game->map[n] & PLAYER) game->start = n; else if (game->map[n] & BOX) { ++game->boxcount; if (game->map[n] & GOAL) ++game->storecount; } if (game->map[n] & GOAL) ++game->goalcount; } return TRUE; }