You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
532 lines
15 KiB
532 lines
15 KiB
/* $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);
|
|
};
|