/* $Id: map.c,v 1.20 2004/01/07 23:04:32 patty21 Exp $ */ /* map handling, like generate and load maps. */ #include "bomberclone.h" _map map; // put the special items into the field void map_fillitems (int fieldtype, int num) { int nb_try = 100, d, x, y; /* this is the item factor we multiply it with this so we know how much items we want in the game */ float fkt = ((float) (map.size.x * map.size.y)) / (25.0 * 17.0); for (d = 0; d < num * fkt; d++) { x = y = 0; while (map.field[x][y].type != FT_stone && map.field[x][y].special != FT_nothing) { x = ((float) rand () / (float) RAND_MAX) * (map.size.x - 1); y = ((float) rand () / (float) RAND_MAX) * (map.size.y - 1); nb_try--; if (nb_try < 0) break; } if (map.field[x][y].type != FT_tunnel) map.field[x][y].special = fieldtype; } } // loads or generate an map void map_new (char *filename) { int x, y; FILE *fmap; signed char old_maptype = map.type; if (filename) { fmap = fopen (filename, "r"); /* if we can't open the given filename for any reason, reverting to default value else, load the file map */ if (fmap) map_load (fmap); } else fmap = NULL; // Clean and create the field // if (fmap == NULL) map_genrandom (); if (map.type == -1) map.type = s_random (MAPT_max); if (map.type == MAPT_tunnel) { /* insert tunnels */ for (x = 0; x < GAME_MAX_TUNNELS; x++) map.tunnel[x].x = map.tunnel[x].y = -1; map.field[3][3].type = FT_tunnel; map.field[3][3].special = 0; map.field[map.size.x - 4][map.size.y - 4].type = FT_tunnel; map.field[map.size.x - 4][map.size.y - 4].special = 1; if (map.size.y > 12) { map.field[map.size.x - 4][3].type = FT_tunnel; map.field[map.size.x - 4][3].special = 2; map.field[3][map.size.y - 4].type = FT_tunnel; map.field[3][map.size.y - 4].special = 3; map.tunnel[0].x = map.size.x - 4; map.tunnel[0].y = 3; map.tunnel[1].x = 3; map.tunnel[1].y = map.size.y - 4; map.tunnel[2].x = map.size.x - 4; map.tunnel[2].y = map.size.y - 4; map.tunnel[3].x = 3; map.tunnel[3].y = 3; } else { map.tunnel[0].x = map.size.x - 4; map.tunnel[0].y = map.size.y - 4; map.tunnel[1].x = 3; map.tunnel[1].y = 3; } } /* delete the bfield data */ for (x = 0; x < MAX_FIELDSIZE_X; x++) for (y = 0; y < MAX_FIELDSIZE_Y; y++) map.bfield[x][y] = 0; /* Set the Playerinformation */ map_set_playerposition (fmap != NULL); /* put the fire powerups in the field */ map_fillitems (FT_fire, map.fire); /* put the bomb powerups in the field */ map_fillitems (FT_bomb, map.bombs); /* put the shoe powerup in the field */ map_fillitems (FT_shoe, map.shoes); /* put the death ?powerups? in the field */ map_fillitems (FT_death, map.death); /* put the mixed powerrup in the field */ map_fillitems (FT_mixed, map.mixed); /* put the trigger special in the field */ map_fillitems (FT_sp_trigger, map.sp_trigger); /* put the row special in the field */ map_fillitems (FT_sp_row, map.sp_row); /* put the push special in the field */ map_fillitems (FT_sp_push, map.sp_push); map_fillitems (FT_sp_liquid, map.sp_push); map_fillitems (FT_sp_moved, map.sp_push); /* put the push special in the field */ map_fillitems(FT_sp_kick,map.sp_kick); map.type = old_maptype; } void map_genrandom () { int x, y, d; /* if we can't load the map check first the fieldsize settings */ if (map.size.x < MIN_FIELDSIZE_X) map.size.x = MIN_FIELDSIZE_X; if (map.size.x > MAX_FIELDSIZE_X) map.size.x = MAX_FIELDSIZE_X; for (x = 0; x < map.size.x; x++) for (y = 0; y < map.size.y; y++) { if ((y == 0) || (y == map.size.y - 1)) map.field[x][y].type = FT_block; else if ((x == 0) || (x == map.size.x - 1)) map.field[x][y].type = FT_block; else if (((x & 1) == 0) && ((y & 1) == 0)) map.field[x][y].type = FT_block; else { // create random field if ((s_random (256) & 3) == 0) map.field[x][y].type = FT_nothing; else map.field[x][y].type = FT_stone; } for (d = 0; d < 4; d++) map.field[x][y].ex[d].frame = map.field[x][y].ex[d].count = 0; map.field[x][y].ex_nr = -1; map.field[x][y].frame = 0.0f; map.field[x][y].special = FT_nothing; } } /* will set the playerposition but in a way that we won't start on a block */ /* i am just too lazy to write this all again and again */ #define PLX(__i) players[__i].pos.x #define PLY(__i) players[__i].pos.y /* check if there is another player in the near if so delete player pos for another try */ void map_playerpos_check (int pl) { int i, d = MAX_FIELDSIZE_X, dx, dy; for (i = 0; (i < MAX_PLAYERS && d > 1); i++) if (i != pl) { dx = PLX(i) - PLX(pl); if (dx < 0) dx = -dx; dy = PLY(i) - PLY(pl); if (dy < 0) dy = -dy; if (dx < dy) // save the biggest distance in there dx = dy; if (dx < d) d = dx; } if (d < 2) { PLX(pl) = -1; PLY(pl) = -1; } } void map_set_player_way1 (int pl) { _point p, t[4]; int i, j, ok = 0; p.x = s_random (map.size.x - 2) + 1; p.y = s_random (map.size.y - 2) + 1; /* check if there is no block */ if (map.field[p.x][p.y].type != FT_nothing) return; /* check if we can run away somewhere */ for (j = 0; j < 4; j++) { t[j].x = p.x; t[j].y = p.y; } for (i = 0; (i < 10 && ok == 0); i++) { t[left].x -= 1; t[right].x += 1; t[up].y = -1; t[down].y += 1; for (j = 0; j < 4; j++) if (t[j].x > 0 && t[j].x < map.size.x && t[j].y > 0 && t[j].y < map.size.y) { if (map.field[t[j].x][t[j].y].type == FT_nothing) { if ((j == left || j == right) && map.field[t[j].x][t[j].y - 1].type == FT_nothing && map.field[t[j].x][t[j].y + 1].type == FT_nothing) ok = 1; if ((j == up || j == down) && map.field[t[j].x - 1][t[j].y].type == FT_nothing && map.field[t[j].x + 1][t[j].y].type == FT_nothing) ok = 1; } else { /* this field is not free anymore */ t[j].x = -1; t[j].y = -1; } } else { t[j].x = -1; t[j].y = -1; } } if (ok) { PLX(pl) = p.x; PLY(pl) = p.y; } } void map_set_player_way2 (int pl, int hardway) { _point p, t[4]; int i, j, ok = 0; p.x = s_random (map.size.x - 2) + 1; p.y = s_random (map.size.y - 2) + 1; /* check if there is no block */ if ((map.field[p.x][p.y].type != FT_nothing && (!hardway || map.field[p.x][p.y].type != FT_stone)) || map.field[p.x][p.y].special == FT_tunnel) return; /* delete the stone under the player, only in hardway mode */ if (map.field[p.x][p.y].type != FT_stone && hardway) { map.field[p.x][p.y].type = FT_nothing; map.field[p.x][p.y].special = FT_nothing; } /* check if we can run away somewhere */ for (j = 0; j < 4; j++) { t[j].x = p.x; t[j].y = p.y; } if (hardway) // if we using the hard way for playerposition hardway = s_random (4)+1; // then select a side which we use for (i = 0; (i < 10 && ok == 0); i++) { t[left].x -= 1; t[right].x += 1; t[up].y = -1; t[down].y += 1; for (j = 0; j < 4; j++) if (t[j].x > 0 && t[j].x < map.size.x && t[j].y > 0 && t[j].y < map.size.y) { if (hardway && (hardway - 1) == j && map.field[t[j].x][t[j].y].type == FT_stone) { map.field[t[j].x][t[j].y].type = FT_nothing; map.field[t[j].x][t[j].y].special = FT_nothing; } if (map.field[t[j].x][t[j].y].type == FT_nothing) { if (ok == 0 && (j == left || j == right) && (map.field[t[j].x][t[j].y - 1].type == FT_stone || map.field[t[j].x][t[j].y - 1].type == FT_nothing)) { map.field[t[j].x][t[j].y - 1].type = FT_nothing; map.field[t[j].x][t[j].y - 1].special = FT_nothing; ok = 1; } if (ok == 0 && (j == left || j == right) && (map.field[t[j].x][t[j].y + 1].type == FT_stone || map.field[t[j].x][t[j].y + 1].type == FT_nothing)) { map.field[t[j].x][t[j].y + 1].type = FT_nothing; map.field[t[j].x][t[j].y + 1].special = FT_nothing; ok = 1; } if (ok == 0 && (j == up || j == down) && (map.field[t[j].x + 1][t[j].y].type == FT_stone || map.field[t[j].x + 1][t[j].y].type == FT_nothing)) { map.field[t[j].x + 1][t[j].y].type = FT_nothing; map.field[t[j].x + 1][t[j].y].special = FT_nothing; ok = 1; } if (ok == 0 && (j == up || j == down) && (map.field[t[j].x - 1][t[j].y].type == FT_stone || map.field[t[j].x - 1][t[j].y].type == FT_nothing)) { map.field[t[j].x - 1][t[j].y].type = FT_nothing; map.field[t[j].x - 1][t[j].y].special = FT_nothing; ok = 1; } } else { /* this field is not free anymore */ t[j].x = -1; t[j].y = -1; } } else { t[j].x = -1; t[j].y = -1; } } if (ok) { PLX(pl) = p.x; PLY(pl) = p.y; } } void map_set_playerposition (int usermap) { int pl, ready, maxtry; d_printf ("map_set_playerposition\n"); /* try to set every player on a good place */ maxtry = 300; ready = 0; while (!ready && maxtry-- > 0) { ready = 1; for (pl = 0; pl < MAX_PLAYERS; pl++) if (PS_IS_used (players[pl].state) && (PLX (pl) < 0 || PLY (pl) < 0)) { /* set player */ ready = 0; map_set_player_way1 (pl); map_playerpos_check (pl); } } /* every player which is still not set .. set now and delete some normal stones */ maxtry = 200; ready = 0; while (!ready && maxtry-- > 0) { ready = 1; for (pl = 0; pl < MAX_PLAYERS; pl++) if (PS_IS_used (players[pl].state) && (PLX (pl) < 0 || PLY (pl) < 0)) { /* set player */ ready = 0; map_set_player_way2 (pl, 0); if (maxtry > 50) map_playerpos_check (pl); } } /* try another way for setting the players */ maxtry = 200; ready = 0; while (!ready && maxtry-- > 0) { ready = 1; for (pl = 0; pl < MAX_PLAYERS; pl++) if (PS_IS_used (players[pl].state) && (PLX (pl) < 0 || PLY (pl) < 0)) { /* set player */ ready = 0; map_set_player_way2 (pl, 1); if (maxtry > 50) map_playerpos_check (pl); } } /* every player who is still not set ... let them die before they * can play put a warning on the screen */ maxtry = 0; // mark our warning for (pl = 0; pl < MAX_PLAYERS; pl++) if (PS_IS_used (players[pl].state) && (PLX (pl) < 0 || PLY (pl) < 0)) { PLX (pl) = 0.0; PLY (pl) = 0.0; maxtry = 1; } if (maxtry) d_fatal ("Not All Player could been set\n"); }; #undef PLX #undef PLY /* load a random map */ void map_random () { _direntry *destart, *de, *desel; char path[LEN_PATHFILENAME]; int max, sel; sprintf (path, "%s/maps", bman.datapath); desel = destart = s_getdir (path); for (max = 0, de = destart; de != NULL; de = de->next) if ((de->flags & DF_file) == DF_file) max++; sel = s_random (max); for (max = 0, de = destart; max <= sel && de != NULL; de = de->next) if ((de->flags & DF_file) == DF_file) { desel = de; max++; } d_printf ("Random Map %s (%d on %d)\n", desel->name, sel, max); if (desel != NULL) sprintf (map.map, "%s/maps/%s", bman.datapath, desel->name); } // Init the game according to options void init_map_tileset () { if (GT_MP_PTPM || GT_SP) { switch (map.map_selection) { case (0): map_new (map.map); break; case (1): map_random (); map_new (map.map); break; case (2): map_new (NULL); break; } if (map.random_tileset) tileset_random (); } } /* read from an open file map, determine field.x and field.y and fill the field. (# correspond to a bloc and @ correspond to a stone, an espace is nothing ' ' % are commentary at the beginning of the map */ void map_load (FILE * fmap) { size_t length; char *currentline; char tmp[MAX_FIELDSIZE_X]; int sizex = 0; int sizey = 0; int i; int d; while ((currentline = fgets (tmp, MAX_FIELDSIZE_X, fmap))) { length = strlen (currentline); if (currentline[0] == '%') continue; /* now each line correspond to the field */ else if (strstr (currentline, "bombs") == currentline) // bombs map.bombs = atoi (strchr (currentline, '=') + 1); else if (strstr (currentline, "fire") == currentline) // fire map.fire = atoi (strchr (currentline, '=') + 1); else if (strstr (currentline, "shoes") == currentline) // shoes map.shoes = atoi (strchr (currentline, '=') + 1); else if (strstr (currentline, "mixed") == currentline) // mixed map.mixed = atoi (strchr (currentline, '=') + 1); else if (strstr (currentline, "death") == currentline) // death map.death = atoi (strchr (currentline, '=') + 1); else if (strstr (currentline, "sp_trigger") == currentline) // trigger special map.sp_trigger = atoi (strchr (currentline, '=') + 1); else if (strstr (currentline, "sp_push") == currentline) // push special map.sp_push = atoi (strchr (currentline, '=') + 1); else if (strstr (currentline, "sp_row") == currentline) // row special map.sp_row = atoi (strchr (currentline, '=') + 1); else if (currentline[0] == '#') { /* the map itself */ for (i = 0; i < length; i++) { switch (currentline[i]) { case '#': map.field[i][sizey].type = FT_block; break; case '@': map.field[i][sizey].type = FT_stone; break; case ' ': map.field[i][sizey].type = FT_nothing; default: break; } for (d = 0; d < 4; d++) map.field[i][sizey].ex[d].frame = map.field[i][sizey].ex[d].count = 0; map.field[i][sizey].ex_nr = -1; map.field[i][sizey].frame = 0.0f; map.field[i][sizey].special = FT_nothing; } sizey++; if (sizex < length) sizex = length; } } map.size.x = sizex - 1; map.size.y = sizey; /* darw the border so we know everything is right */ for (i = 0; i < map.size.x; i++) map.field[i][0].type = map.field[i][map.size.y - 1].type = FT_block; for (i = 0; i < map.size.y; i++) map.field[0][i].type = map.field[map.size.x - 1][i].type = FT_block; fclose (fmap); };