Beispiel #1
0
CTable::CTable(const std::_tstring & table, bool line)
{
	m_rows.push_back(CLine(GUID_START));
	if (line)
		parse_line(table);
	else
		parse_rows(table);
	m_rows.push_back(CLine(GUID_END));
}
Beispiel #2
0
/* Load the game file. */
int load_game_file(nbstate *state)
{
	FILE *fp;
	int line = 1;
	level *l, *lev = NULL;
	char buf[256], *p;
	int inlevelblock = 0;

	/* Generate the full game file name including the directory: */
	snprintf(buf, 256, "%s/%s", state->gamedir, state->gamefile);

	/* Try to open the game file: */
	if(!(fp = fopen(buf, "r"))) {
		/* It failed, so print an error message and return "failure": */
		GrError("Failed to open game file \"%s\": %s\n",
						buf, strerror(errno));
		return 1;
	}

	/* Read the file one line at a time in a loop: */
	while(fgets(buf, 256, fp)) {

		/* Look for the newline at the end of the line. */
		if(!(p = strchr(buf, '\n'))) {
			/* There wasn't one, which probably means that the
			 * line was longer than 255 characters. */
			GrError("Too long line on line %d of game file "
					"\"%s\"\n", line, state->gamefile);
			return 1;
		}
		*p = 0; /* Get rid of the newline. */

		/* Ignore comments and blank lines: */
		if(*buf == '#' || *buf == 0) {
		/* Compare the line against each of the different keywords: */
		} else if(!memcmp(buf, "TitleBackground ", 16)) {
			if(state->titlebackground) {
				redefinewarning("TitleBackground", line,
						state->gamefile);
				free(state->titlebackground);
			}
			if(!(state->titlebackground = strdup(buf + 16))) {
				oom();
				goto err;
			}
		} else if(!memcmp(buf, "TitleBackgroundTiled ", 21)) {
			/* Check whether the parameter to TitleBackgroundTiled
			 * is "Yes" (1), "No" (0), or something else (parse
			 * error): */
			if(!strcmp(buf + 21, "Yes"))
				state->backgroundtiled = 1;
			else if(!strcmp(buf + 21, "No"))
				state->backgroundtiled = 0;
			else goto parseerr;
		} else if(!memcmp(buf, "TitleSplash ", 12)) {
			if(state->titlesplash) {
				redefinewarning("TitleSplash", line,
						state->gamefile);
				free(state->titlesplash);
			}
			if(!(state->titlesplash = strdup(buf + 12))) {
				oom();
				goto err;
			}
		} else if(!memcmp(buf, "GameWonSplash ", 14)) {
			if(state->gamewonsplash) {
				redefinewarning("GameWonSplash", line,
						state->gamefile);
				free(state->gamewonsplash);
			}
			if(!(state->gamewonsplash = strdup(buf + 14))) {
				oom();
				goto err;
			}
		} else if(!memcmp(buf, "GameLostSplash ", 15)) {
			if(state->gamelostsplash) {
				redefinewarning("GameLostSplash", line,
						state->gamefile);
				free(state->gamelostsplash);
			}
			if(!(state->gamelostsplash = strdup(buf + 15))) {
				oom();
				goto err;
			}
		} else if(!memcmp(buf, "NormalPoints ", 13)) {
			/* Convert the parameter to NormalPoints into a
			 * number: */
			state->normalpoints = strtol(buf + 13, &p, 10);
			if(*p) goto parseerr;
		} else if(!memcmp(buf, "SmallBonusPoints ", 17)) {
			state->smallbonuspoints = strtol(buf + 17, &p, 10);
			if(*p) goto parseerr;
		} else if(!memcmp(buf, "MediumBonusPoints ", 18)) {
			state->mediumbonuspoints = strtol(buf + 18, &p, 10);
			if(*p) goto parseerr;
		} else if(!memcmp(buf, "LargeBonusPoints ", 17)) {
			state->largebonuspoints = strtol(buf + 17, &p, 10);
			if(*p) goto parseerr;
		} else if(!memcmp(buf, "HugeBonusPoints ", 16)) {
			state->hugebonuspoints = strtol(buf + 16, &p, 10);
			if(*p) goto parseerr;
		} else if(!memcmp(buf, "PowerUpPoints ", 14)) {
			state->poweruppoints = strtol(buf + 14, &p, 10);
			if(*p) goto parseerr;
		} else if(!memcmp(buf, "PowerDownPoints ", 16)) {
			state->powerdownpoints = strtol(buf + 16, &p, 10);
			if(*p) goto parseerr;
		} else if(!memcmp(buf, "StartBalls ", 11)) {
			state->startballs = strtol(buf + 11, &p, 10);
			if(*p) goto parseerr;
		} else if(!memcmp(buf, "NewLevelBalls ", 14)) {
			state->newlevelballs = strtol(buf + 14, &p, 10);
			if(*p) goto parseerr;
		} else if(!memcmp(buf, "BallImage ", 10)) {
			/* If the ball sprite has already been defined, print
			 * a warning and destroy the old sprite: */
			if(state->ball.s) {
				redefinewarning("BallImage", line,
						state->gamefile);
				destroy_sprite(state, state->ball.s);
			}
			/* Try to load the ball sprite: */
			if(!(state->ball.s = load_sprite(state, buf + 10,
								-1, -1))) {
				/* That failed so try to make an empty one: */
				if(!(state->ball.s = make_empty_sprite(state,
							buf + 10,
							DEFAULT_BALL_SIZE,
							DEFAULT_BALL_SIZE))) {
					/* That failed too so print an error
					 * message and give up: */
					GrError("Couldn't create "
							"ball sprite on line "
							"%d of game file "
							"\"%s\"\n", line,
							state->gamefile);
					goto err;
				}
				/* Fill in the dummy sprite with a white
				 * circle: */
				GrSetGCForeground(state->gc, GR_COLOR_WHITE);
				GrFillEllipse(state->ball.s->p, state->gc,
							DEFAULT_BALL_SIZE / 2,
							DEFAULT_BALL_SIZE / 2,
						(DEFAULT_BALL_SIZE / 2) - 1,
						(DEFAULT_BALL_SIZE / 2) - 1);
				GrFillEllipse(state->ball.s->a, state->gc,
							DEFAULT_BALL_SIZE / 2,
							DEFAULT_BALL_SIZE / 2,
						(DEFAULT_BALL_SIZE / 2) - 1,
						(DEFAULT_BALL_SIZE / 2) - 1);
			}
		} else if(!memcmp(buf, "SlowBallVelocity ", 17)) {
			state->ball.sv = strtol(buf + 17, &p, 10);
			if(*p) goto parseerr;
		} else if(!memcmp(buf, "NormalBallVelocity ", 19)) {
			state->ball.nv = strtol(buf + 19, &p, 10);
			if(*p) goto parseerr;
		} else if(!memcmp(buf, "FastBallVelocity ", 17)) {
			state->ball.fv = strtol(buf + 17, &p, 10);
			if(*p) goto parseerr;
		} else if(!memcmp(buf, "BatVelocity ", 12)) {
			state->batv = strtol(buf + 12, &p, 10);
			if(*p) goto parseerr;
		} else if(!memcmp(buf, "PowerVelocity ", 14)) {
			state->powerv = strtol(buf + 14, &p, 10);
			if(*p) goto parseerr;
		} else if(!memcmp(buf, "AnimatePeriod ", 14)) {
			state->animateperiod = strtol(buf + 14, &p, 10);
			if(*p) goto parseerr;
		} else if(!memcmp(buf, "BrickWidth ", 11)) {
			state->brickwidth = strtol(buf + 11, &p, 10);
			if(*p) goto parseerr;
		} else if(!memcmp(buf, "BrickHeight ", 12)) {
			state->brickheight = strtol(buf + 12, &p, 10);
			if(*p) goto parseerr;
		} else if(!memcmp(buf, "Brick ", 6)) {
			/* Parse the brick line: */
			if(parse_brick(state, inlevelblock, lev, line, buf + 6))
				goto err;
		} else if(!memcmp(buf, "Width ", 6)) {
			if(lev) {
				GrError("Error: Width must be set "
					"before the first level is defined "
					"(see line %d of game file \"%s\")\n",
					line, state->gamefile);
				goto err;
			}
			state->width = strtol(buf + 6, &p, 10);
			if(*p) goto parseerr;
		} else if(!memcmp(buf, "Height ", 7)) {
			if(lev) {
				GrError("Error: Height must be set "
					"before the first level is defined "
					"(see line %d of game file \"%s\")\n",
					line, state->gamefile);
				goto err;
			}
			state->height = strtol(buf + 7, &p, 10);
			if(*p) goto parseerr;
		} else if(!memcmp(buf, "BatHeight ", 10)) {
			state->batheight = strtol(buf + 10, &p, 10);
			if(*p) goto parseerr;
		} else if(!memcmp(buf, "NormalBatWidth ", 15)) {
			state->batwidths[NORMALBAT] = strtol(buf + 15, &p, 10);
			if(*p) goto parseerr;
		} else if(!memcmp(buf, "SmallBatWidth ", 14)) {
			state->batwidths[SMALLBAT] = strtol(buf + 14, &p, 10);
			if(*p) goto parseerr;
		} else if(!memcmp(buf, "LargeBatWidth ", 14)) {
			state->batwidths[LARGEBAT] = strtol(buf + 14, &p, 10);
			if(*p) goto parseerr;
		} else if(!memcmp(buf, "NormalBat ", 10)) {
			if(state->bats[NORMALBAT]) {
				redefinewarning("NormalBat", line,
						state->gamefile);
				destroy_sprite(state, state->bats[NORMALBAT]);
			}
			if(!(state->bats[NORMALBAT] = load_sprite(state,
					buf + 10, state->batwidths[NORMALBAT],
					state->batheight))) {
				if(!(state->bats[NORMALBAT] =
					make_empty_sprite(state, buf + 10,
						state->batwidths[NORMALBAT],
						state->batheight))) {
					GrError("Couldn't create "
							"normal bat sprite on "
							"line %d of game file "
							"\"%s\"\n", line,
							state->gamefile);
					goto err;
				}
				GrSetGCForeground(state->gc, GR_COLOR_RED);
				GrFillRect(state->bats[NORMALBAT]->p,
						state->gc, 0, 0,
						state->batwidths[NORMALBAT],
						state->batheight);
				GrSetGCForeground(state->gc, GR_COLOR_WHITE);
				GrFillRect(state->bats[NORMALBAT]->a,
						state->gc, 0, 0,
						state->batwidths[NORMALBAT],
						state->batheight);
			}
		} else if(!memcmp(buf, "SmallBat ", 9)) {
			if(state->bats[SMALLBAT]) {
				redefinewarning("SmallBat", line,
						state->gamefile);
				destroy_sprite(state, state->bats[SMALLBAT]);
			}
			if(!(state->bats[SMALLBAT] = load_sprite(state,
					buf + 9, state->batwidths[SMALLBAT],
					state->batheight))) {
				if(!(state->bats[SMALLBAT] =
					make_empty_sprite(state, buf + 9,
						state->batwidths[SMALLBAT],
						state->batheight))) {
					GrError("Couldn't create "
							"small bat sprite on "
							"line %d of game file "
							"\"%s\"\n", line,
							state->gamefile);
					goto err;
				}
				GrSetGCForeground(state->gc, GR_COLOR_RED);
				GrFillRect(state->bats[SMALLBAT]->p,
						state->gc, 0, 0,
						state->batwidths[SMALLBAT],
						state->batheight);
				GrSetGCForeground(state->gc, GR_COLOR_WHITE);
				GrFillRect(state->bats[SMALLBAT]->a,
						state->gc, 0, 0,
						state->batwidths[SMALLBAT],
						state->batheight);
			}
		} else if(!memcmp(buf, "LargeBat ", 9)) {
			if(state->bats[LARGEBAT]) {
				redefinewarning("LargeBat", line,
						state->gamefile);
				destroy_sprite(state, state->bats[LARGEBAT]);
			}
			if(!(state->bats[LARGEBAT] = load_sprite(state,
					buf + 9, state->batwidths[LARGEBAT],
					state->batheight))) {
				if(!(state->bats[LARGEBAT] =
					make_empty_sprite(state, buf + 9,
						state->batwidths[LARGEBAT],
						state->batheight))) {
					GrError("Couldn't create "
							"large bat sprite on "
							"line %d of game file "
							"\"%s\"\n", line,
							state->gamefile);
					goto err;
				}
				GrSetGCForeground(state->gc, GR_COLOR_RED);
				GrFillRect(state->bats[LARGEBAT]->p,
						state->gc, 0, 0,
						state->batwidths[LARGEBAT],
						state->batheight);
				GrSetGCForeground(state->gc, GR_COLOR_WHITE);
				GrFillRect(state->bats[LARGEBAT]->a,
						state->gc, 0, 0,
						state->batwidths[LARGEBAT],
						state->batheight);
			}
		} else if(!memcmp(buf, "PowerSprite ", 12)) {
			/* Parse the PowerSprite line: */
			if(parse_powersprite(state, buf + 12, line)) goto err;
		} else if(!memcmp(buf, "PowerUpTimeout ", 15)) {
			state->poweruptime = strtol(buf + 15, &p, 10);
			if(*p) goto parseerr;
		} else if(!memcmp(buf, "PowerDownTimeout ", 17)) {
			state->powerdowntime = strtol(buf + 17, &p, 10);
			if(*p) goto parseerr;
		} else if(!memcmp(buf, "FadeRate ", 9)) {
			state->faderate = strtol(buf + 9, &p, 10);
			if(*p) goto parseerr;
			if(state->faderate > 255 || state->faderate < 0) {
				GrError("Invalid fade rate on line "
					"%d of game file \"%s\"\n", line,
					state->gamefile);
				goto err;
			}
		} else if(!memcmp(buf, "SolidFloorCheat ", 16)) {
			if(state->cheats[SFCHEAT]) {
				redefinewarning("SolidFloorCheat", line,
						state->gamefile);
				free(state->cheats[SFCHEAT]);
			}
			if(!(state->cheats[SFCHEAT] = strdup(buf + 16))) {
				oom();
				goto err;
			}
			if(strlen(state->cheats[SFCHEAT]) > MAXCHEATLEN) {
				GrError("Cheat sequence too long on "
						"line %d of game file \"%s\"\n",
						line, state->gamefile);
				goto err;
			}
		} else if(!memcmp(buf, "TeleportCheat ", 14)) {
			if(state->cheats[TPCHEAT]) {
				redefinewarning("TeleportCheat", line,
						state->gamefile);
				free(state->cheats[TPCHEAT]);
			}
			if(!(state->cheats[TPCHEAT] = strdup(buf + 14))) {
				oom();
				goto err;
			}
			if(strlen(state->cheats[TPCHEAT]) > MAXCHEATLEN) {
				GrError("Cheat sequence too long on "
						"line %d of game file \"%s\"\n",
						line, state->gamefile);
				goto err;
			}
		} else if(!memcmp(buf, "NoBounceCheat ", 14)) {
			if(state->cheats[NBCHEAT]) {
				redefinewarning("NoBounceCheat", line,
						state->gamefile);
				free(state->cheats[NBCHEAT]);
			}
			if(!(state->cheats[NBCHEAT] = strdup(buf + 14))) {
				oom();
				goto err;
			}
			if(strlen(state->cheats[NBCHEAT]) > MAXCHEATLEN) {
				GrError("Cheat sequence too long on "
						"line %d of game file \"%s\"\n",
						line, state->gamefile);
				goto err;
			}

		} else if(!memcmp(buf, "NoPowerDownCheat ", 17)) {
			if(state->cheats[NPDCHEAT]) {
				redefinewarning("NoPowerDownCheat", line,
						state->gamefile);
				free(state->cheats[NPDCHEAT]);
			}
			if(!(state->cheats[NPDCHEAT] = strdup(buf + 17))) {
				oom();
				goto err;
			}
			if(strlen(state->cheats[NPDCHEAT]) > MAXCHEATLEN) {
				GrError("Cheat sequence too long on "
						"line %d of game file \"%s\"\n",
						line, state->gamefile);
				goto err;
			}

		} else if(!memcmp(buf, "NoPowerUpTimeoutCheat ", 22)) {
			if(state->cheats[NPUTOCHEAT]) {
				redefinewarning("NoPowerUpTimeoutCheat", line,
						state->gamefile);
				free(state->cheats[NPUTOCHEAT]);
			}
			if(!(state->cheats[NPUTOCHEAT] = strdup(buf + 22))) {
				oom();
				goto err;
			}
			if(strlen(state->cheats[NPUTOCHEAT]) > MAXCHEATLEN) {
				GrError("Cheat sequence too long on "
						"line %d of game file \"%s\"\n",
						line, state->gamefile);
				goto err;
			}
		} else if(!memcmp(buf, "BeginLevel", 10)) {

			/* Check to make sure we haven't got another BeginLevel
			 * line while already in a level definition block: */
			if(inlevelblock) {
				GrError("Error: BeginLevel while "
					"already in a level block on line %d "
					"of game file \"%s\"\n", line,
					state->gamefile);
				goto err;
			}
			inlevelblock = 1;

			/* Allocate a new level structure: */
			if(!(lev = malloc(sizeof(level)))) {
				oom();
				goto err;
			}
			/* Fill in the structure members with some defaults: */
			lev->bricks = NULL;
			lev->backgroundname = NULL;
			lev->backgroundtiled = DEFAULT_BACKGROUND_TILED;
			lev->numbricks = 0;
			lev->next = NULL;

			/* Allocate and initialise the level grid: */
			if(!(lev->grid = newgrid(state))) {
				oom();
				goto err;
			}

			/* Link the new level structure onto the end of the
			 * levels list: */
			if(!state->levels) state->levels = lev;
			else {
				for(l = state->levels; l->next; l = l->next);
				l->next = lev;
			}
		} else if(!memcmp(buf, "LevelBackground ", 16)) {
			if(!inlevelblock) {
				notinlevblockerr("LevelBackground", line,
						state->gamefile);
				goto err;
			}
			if(lev->backgroundname) {
				redefinewarning("LevelBackground", line,
						state->gamefile);
				free(lev->backgroundname);
			}
			if(!(lev->backgroundname = strdup(buf + 16))) {
				oom();
				goto err;
			}
		} else if(!memcmp(buf, "LevelBackgroundTiled ", 21)) {
			if(!inlevelblock) {
				notinlevblockerr("LevelBackgroundTiled", line,
						state->gamefile);
				goto err;
			}
			if(!strcmp(buf + 21, "Yes")) lev->backgroundtiled = 1;
			else if(!strcmp(buf + 21, "No"))
				lev->backgroundtiled = 0;
			else goto parseerr;
		} else if(!memcmp(buf, "BeginRows", 9)) {
			if(!inlevelblock) {
				notinlevblockerr("BeginRows", line,
						state->gamefile);
				goto err;
			}
			/* Parse the rows block: */
			if(parse_rows(state, lev, fp, &line)) goto err;
		} else if(!memcmp(buf, "EndRows", 7)) {
			/* We should never see an EndRows here in a valid
			 * level file because parse_rows() consumes it. */
			GrError("Error: EndRows without corresponding "
					"BeginRows on line %d of game file "
					"\"%s\"\n", line, state->gamefile);
			goto err;
		} else if(!memcmp(buf, "BeginPowers", 11)) {
			if(!inlevelblock) {
				notinlevblockerr("BeginPowers", line,
						state->gamefile);
				goto err;
			}
			if(parse_powers(state, lev, fp, &line)) goto err;
		} else if(!memcmp(buf, "EndPowers", 9)) {
			GrError("Error: EndPowers without "
					"corresponding BeginPowers on line %d "
					"of game file \"%s\"\n", line,
					state->gamefile);
			goto err;
		} else if(!memcmp(buf, "EndLevel", 8)) {
			if(!inlevelblock) {
				GrError("Error: EndLevel while not in "
					"in a level block on line %d of game "
					"file \"%s\"\n", line, state->gamefile);
				goto err;
			}
			inlevelblock = 0;
			state->numlevels++;
		} else {
			GrError("Unknown command \"%s\" on line %d "
					"of game file \"%s\"\n", buf,
					line, state->gamefile);
		}
		/* We keep a count of the line we're on so that errors and
		 * warnings can print out the number of the bad line: */
		line++;
	}

	/* Check if the reason fgets() failed was because of an I/O error
	 * instead of simply reaching the end of the file: */
	if(ferror(fp)) {
		GrError("Error reading from game file \"%s\" on line "
				"%d: %s\n", state->gamefile, line,
				strerror(errno));
		goto err;
	}

	/* Allocate and initialise the current game grid: */
	if(!(state->grid = newgrid(state))) {
		oom();
		goto err;
	}

	fclose(fp); /* Close the game file. */

	return 0; /* Success. */

parseerr: /* A parse error occured so print an error message: */
	GrError("Parse error on line %d of game file \"%s\"\n", line,
							state->gamefile);
err: /* Some other error occured and we've already printed the error message. */
	fclose(fp); /* Close the game file (may fail but we don't care). */
	return 1; /* Failure. */
}