示例#1
0
static int engrid_cell(grid * gold, gridindex *index) {
  vector gmin, gmax, gsize;
  flt len;
  int numobj, numcbrt, xs, ys, zs;
  grid * g;
  objectlist **list;
  objectlist * newobj;

  list = &gold->cells[index->z*gold->xsize*gold->ysize + 
                     index->y*gold->xsize  + index->x];

  if (*list == NULL)
    return 0;

  numobj =  cellbound(gold, index, &gmin, &gmax);

  VSub(&gmax, &gmin, &gsize);
  len = 1.0 / (MYMAX( MYMAX(gsize.x, gsize.y), gsize.z ));
  gsize.x *= len;  
  gsize.y *= len;  
  gsize.z *= len;  

  if (numobj > 16) {
    numcbrt = (int) cbrt(2*numobj); 
    
    xs = (int) ((flt) numcbrt * gsize.x);
    if (xs < 1) xs = 1;
    ys = (int) ((flt) numcbrt * gsize.y);
    if (ys < 1) ys = 1;
    zs = (int) ((flt) numcbrt * gsize.z);
    if (zs < 1) zs = 1;

    g = (grid *) newgrid(xs, ys, zs, gmin, gmax);
    engrid_objectlist(g, list);

    newobj = (objectlist *) rt_getmem(sizeof(objectlist));    
    newobj->obj = (object *) g;
    newobj->next = *list;
    *list = newobj;

    g->nextobj = gold->objects;
    gold->objects = (object *) g;
  }

  return 1;
}
示例#2
0
int engrid_scene(object ** list) {
  grid * g;
  int numobj, numcbrt;
  vector gmin, gmax;
  gridindex index;
 
  if (*list == NULL)
    return 0;

  numobj = countobj(*list);

  if ( !silent_mode )
    fprintf(stderr, "Scene contains %d bounded objects.\n", numobj);

  if (numobj > 16) {
    numcbrt = (int) cbrt(4*numobj);
    globalbound(list, &gmin, &gmax);

    g = (grid *) newgrid(numcbrt, numcbrt, numcbrt, gmin, gmax);
    engrid_objlist(g, list);

    numobj = countobj(*list);
    g->nextobj = *list;
    *list = (object *) g;

    /* now create subgrids.. */
    for (index.z=0; index.z<g->zsize; index.z++) {
      for (index.y=0; index.y<g->ysize; index.y++) {
        for (index.x=0; index.x<g->xsize; index.x++) {
          engrid_cell(g, &index);
        }
      }
    } 
  }

  return 1;
}
示例#3
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. */
}