/* $Id: field.c,v 1.30 2003/06/07 19:05:55 stpohle Exp $ */ /* field.c - procedures which are needed to control the field */ #include #include #include "bomberclone.h" #include "gfx.h" static _point fieldani[MAX_FILEDANIMATION]; void draw_stone (int x, int y) { _field *stone = &bman.field[x][y]; SDL_Rect dest, src; SDL_Surface *srcimg = NULL; int i, d; if (x < 0 || y < 0 || x > bman.fieldsize.x || y > bman.fieldsize.y) { d_fatal ("Draw Stone out of range [%d,%d]\n", x, y); return; } src.w = dest.w = gfx.block.x; src.h = dest.h = gfx.block.y; dest.x = x * gfx.block.x + gfx.offset.x; dest.y = y * gfx.block.y + gfx.offset.y; src.x = 0; /* draw background if we have a stone, block or nothing */ if (stone->type <= FT_block) { SDL_Rect srcbg; srcbg.w = dest.w; srcbg.h = dest.h; srcbg.x = (x % gfx.field[FT_nothing].frames) * gfx.block.x; srcbg.y = (y % gfx.field[FT_nothing].frames) * gfx.block.y; SDL_BlitSurface (gfx.field[FT_nothing].image, &srcbg, gfx.screen, &dest); } if (stone->type == FT_mixed) { i = stone->mixframe; if (i < FT_death || i >= FT_mixed) i = FT_death; } else i = stone->type; /* animate the stone if needed only for exploding stone */ if (stone->type == FT_stone && stone->frame > 0) { field_animation_add (x, y); if (stone->frame < gfx.field[FT_stone].frames) { src.y = stone->frame * gfx.block.y; srcimg = gfx.field[FT_stone].image; } else { src.y = 0; srcimg = gfx.field[FT_nothing].image; } } else if (stone->type == FT_stone || stone->type == FT_block) { src.y = 0; srcimg = gfx.field[stone->type].image; } /* some powerup so we need to animate this too */ if (i == FT_death) d = PWUP_bad; else if (i >= FT_sp_trigger) d = PWUP_special; else d = PWUP_good; if (i >= FT_death) { field_animation_add (x, y); srcimg = gfx.powerup[d].image; if (stone->frame >= gfx.powerup[d].frames) stone->frame = 0; src.y = stone->frame * gfx.block.y; } if (srcimg != NULL) SDL_BlitSurface (srcimg, &src, gfx.screen, &dest); if (i >= FT_death) { /* draw now the powerup itself */ srcimg = gfx.field[i].image; src.y = 0; SDL_BlitSurface (srcimg, &src, gfx.screen, &dest); } // draw explosions if there is any for (d = 0, i = 0; d < 4; d++) if (stone->ex[d].count > 0) { i = 1; // mark that there is already an explosion draw_fire (x, y, d, -1); } return; }; void draw_field () { int x, y; for (x = 0; x < bman.fieldsize.x; x++) for (y = 0; y < bman.fieldsize.y; y++) draw_stone (x, y); }; /* 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 field_load (FILE * map) { 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, map))) { length = strlen (currentline); if (currentline[0] == '%') continue; /* now each line correspond to the field */ else { for (i = 0; i < length; i++) { switch (currentline[i]) { case '#': bman.field[i][sizey].type = FT_block; break; case '@': bman.field[i][sizey].type = FT_stone; break; case ' ': bman.field[i][sizey].type = FT_nothing; default: break; } for (d = 0; d < 4; d++) bman.field[i][sizey].ex[d].frame = bman.field[i][sizey].ex[d].count = 0; bman.field[i][sizey].ex_nr = -1; bman.field[i][sizey].frame = 0; bman.field[i][sizey].frameto = 0; bman.field[i][sizey].special = FT_nothing; } sizey++; if (sizex < length) sizex = length; } } bman.fieldsize.x = sizex - 1; bman.fieldsize.y = sizey; /* darw the border so we know everything is right */ for (i = 0; i < bman.fieldsize.x; i++) bman.field[i][0].type = bman.field[i][bman.fieldsize.y - 1].type = FT_block; for (i = 0; i < bman.fieldsize.y; i++) bman.field[0][i].type = bman.field[bman.fieldsize.x - 1][i].type = FT_block; } /* 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 bman.players[i].pos.x #define PLY bman.players[i].pos.y void field_set_playerposition (int usermap) { int p, dist, i, j, mx, my, dx = 0, dy = 0; char txt[255]; p = 50; dist = 8; while (p == 50) { p = 0; dist--; for (i = 0; (p < 50 && i < MAX_PLAYERS);) { if (usermap) { int maxloop = 0; while (maxloop < 200 && (PLX == -1 || PLY == -1)) { maxloop++; PLX = s_random (bman.fieldsize.x - 2) + 1; PLY = s_random (bman.fieldsize.y - 2) + 1; for (dx = 10, dy = 10, j = 0; (j < i && j < MAX_PLAYERS && (dx > 1 || dy > 1)); j++) { /* is ther any other player */ dx = PLX - bman.players[j].pos.x; if (dx < 0) dx = -dx; dy = PLY - bman.players[j].pos.y; if (dy < 0) dy = -dy; } /* check if there is no block */ if ((dx > 1 || dy > 1) && ((bman.field[PLX][PLY].type != FT_block && maxloop > 100) || bman.field[PLX][PLY].type == FT_nothing)) { /* get (up or down) dx and (left or right) dy */ dx = s_random (2); if (dx == 0) dx = -1; dy = s_random (2); if (dy == 0) dy = -1; /* first check if there is and free place for us */ if (!((bman.field[PLX + dx][PLY].type != FT_block && maxloop > 100) || bman.field[PLX + dx][PLY].type == FT_nothing)) dx = -dx; if (!((bman.field[PLX + dx][PLY].type != FT_block && maxloop > 100) || bman.field[PLX + dx][PLY].type == FT_nothing)) PLX = -1; if (!((bman.field[PLX][PLY + dy].type != FT_block && maxloop > 100) || bman.field[PLX][PLY + dy].type == FT_nothing)) dy = -dy; if (!((bman.field[PLX][PLY + dy].type != FT_block && maxloop > 100) || bman.field[PLX][PLY + dy].type == FT_nothing)) PLY = -1; } else { PLX = -1; PLY = -1; } /* make some space */ if (PLX != -1 && PLY != -1) { bman.field[PLX][PLY].type = FT_nothing; bman.field[PLX + dx][PLY].type = FT_nothing; bman.field[PLX][PLY + dy].type = FT_nothing; } } } if (PLX == -1 || PLY == -1) { /* we could not set all fields or we don't run on a usermap */ if (usermap) { sprintf (txt, "Not all players could be set (Pl:%d)", i); menu_displaymessage ("MAP - ERROR", txt); } /* now there will be some fields deleted */ PLX = 2 * (s_random ((bman.fieldsize.x - 1) / 2)) + 1; PLY = 2 * (s_random ((bman.fieldsize.y - 1) / 2)) + 1; bman.field[PLX][PLY].type = FT_nothing; dx = s_random (4); // bit 1 = up/down bit 2 = left/right /* up and down */ if (((dx & 1) == 0 && PLX > 1) || PLX >= bman.fieldsize.x - 2) bman.field[PLX - 1][PLY].type = FT_nothing; else bman.field[PLX + 1][PLY].type = FT_nothing; /* left and right */ if (((dx & 2) == 0 && PLY > 1) || PLY >= bman.fieldsize.y - 2) bman.field[PLX][PLY - 1].type = FT_nothing; else bman.field[PLX][PLY + 1].type = FT_nothing; } mx = my = 100; for (j = 0; j <= i; j++) { /* search smalest distance */ dy = PLY - bman.players[j].pos.y; dx = PLX - bman.players[j].pos.x; if (dy < 0) dy = -dy; if (dx < 0) dx = -dx; if (mx > dx && i != j) mx = dx; if (my > dy && i != j) my = dy; } if (mx > dist || my > dist) i++; else p++; } } for (i = 0; i < MAX_PLAYERS; i++) { PLX = PLX << 8; PLY = PLY << 8; } }; #undef PLX #undef PLY // clear field and send this to all netplayers void field_clear (int x, int y) { bman.field[x][y].type = FT_nothing; if (bman.gametype != GT_single) net_game_send_field (x, y); } void field_update (int x, int y) { gfx_AddUpdateRect (x * gfx.block.x + gfx.offset.x, y * gfx.block.y + gfx.offset.y, gfx.block.x, gfx.block.y); } // put items into the field void field_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) (bman.fieldsize.x * bman.fieldsize.y)) / (25.0 * 17.0); /* put the row special in the field */ for (d = 0; d < num * fkt; d++) { x = y = 0; while (bman.field[x][y].type != FT_stone || bman.field[x][y].special != FT_nothing) { x = ((float) rand () / (float) RAND_MAX) * (bman.fieldsize.x - 1); y = ((float) rand () / (float) RAND_MAX) * (bman.fieldsize.y - 1); nb_try--; if (nb_try < 0) break; } bman.field[x][y].special = fieldtype; } } void field_new (char *filename) { int x, y, d; FILE *fmap; 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 */ if (fmap) field_load (fmap); } else { fmap = NULL; } /* this is the item factor we multiply it with this so we know how much items we want in the game */ // Clean and create the field // if (fmap == NULL) { /* if we can't load the map check first the fieldsize settings */ if (bman.fieldsize.x < MIN_FIELDSIZE_X) bman.fieldsize.x = MIN_FIELDSIZE_X; if (bman.fieldsize.x > MAX_FIELDSIZE_X) bman.fieldsize.x = MAX_FIELDSIZE_X; for (x = 0; x < bman.fieldsize.x; x++) for (y = 0; y < bman.fieldsize.y; y++) { if ((y == 0) || (y == bman.fieldsize.y - 1)) bman.field[x][y].type = FT_block; else if ((x == 0) || (x == bman.fieldsize.x - 1)) bman.field[x][y].type = FT_block; else if (((x & 1) == 0) && ((y & 1) == 0)) bman.field[x][y].type = FT_block; else { // create random field if ((s_random (256) & 3) == 0) bman.field[x][y].type = FT_nothing; else bman.field[x][y].type = FT_stone; } for (d = 0; d < 4; d++) bman.field[x][y].ex[d].frame = bman.field[x][y].ex[d].count = 0; bman.field[x][y].ex_nr = -1; bman.field[x][y].frame = 0; bman.field[x][y].frameto = 0; bman.field[x][y].special = FT_nothing; } } /* delete the bfield data */ for (x = 0; x < MAX_FIELDSIZE_X; x++) for (y = 0; y < MAX_FIELDSIZE_Y; y++) bman.bfield[x][y] = 0; /* Set the Playerinformation */ field_set_playerposition (fmap != NULL); /* put the fire powerups in the field */ field_fillitems (FT_fire, GAME_SPECIAL_ITEMFIRE); /* put the bomb powerups in the field */ field_fillitems (FT_bomb, GAME_SPECIAL_ITEMBOMB); /* put the shoe powerup in the field */ field_fillitems (FT_shoe, GAME_SPECIAL_ITEMSHOE); /* put the death ?powerups? in the field */ field_fillitems (FT_death, GAME_SPECIAL_ITEMDEATH); /* put the mixed powerrup in the field */ field_fillitems (FT_mixed, GAME_SPECIAL_ITEMMIXED); /* put the trigger special in the field */ field_fillitems (FT_sp_trigger, GAME_SPECIAL_ITEMSTRIGGER); /* put the row special in the field */ field_fillitems (FT_sp_row, GAME_SPECIAL_ITEMSROW); /* put the push special in the field */ field_fillitems (FT_sp_push, GAME_SPECIAL_ITEMSPUSH); /* put the kick special in the field */ field_fillitems (FT_sp_kick, GAME_SPECIAL_ITEMSKICK); } /* run this to every game cycle for the animations on the field */ void field_animation () { int i,j; _field *stone; for (i = 0; i < MAX_FILEDANIMATION; i++) if (fieldani[i].x >= 0 && fieldani[i].x < bman.fieldsize.x && fieldani[i].y >= 0 && fieldani[i].y < bman.fieldsize.y) { /* check if there is a need to animate this */ stone = &bman.field[fieldani[i].x][fieldani[i].y]; if ((stone->type == FT_stone && stone->frame > 0) || (stone->type >= FT_death)) { /* animate this stone */ if (stone->type == FT_stone) { if (stone->frameto == 0) if (stone->frame < gfx.field[FT_stone].frames) { stone->frame++; stone->frameto = ANI_STONETIMEOUT; } if (stone->frameto > 0) stone->frameto--; } else { /* animation is a powerup */ /* select right powerup animation */ if (stone->type == FT_death) j = PWUP_bad; else if (stone->type > FT_sp_trigger) j = PWUP_special; else j = PWUP_good; /* do the animation of the FT_mixed */ if (stone->frameto-- <= 0 || stone->frameto > ANI_STONETIMEOUT) { stone->frameto = ANI_STONETIMEOUT; stone->frame++; if (stone->type == FT_mixed) { stone->mixframe++; if (stone->mixframe < FT_death || stone->mixframe >= FT_mixed) stone->mixframe = FT_death; } } if (stone->frame >= gfx.powerup[j].frames) stone->frame = 0; } draw_stone (fieldani[i].x, fieldani[i].y); field_update (fieldani[i].x, fieldani[i].y); } else /* delete this entry */ fieldani[i].y = fieldani[i].x = -1; } else /* delete this entry */ fieldani[i].y = fieldani[i].x = -1; }; /* add a new field to the animation data */ void field_animation_add (int x, int y) { int i, j = -1, d = -1; for (i = 0; i < MAX_FILEDANIMATION; i++) { if (fieldani[i].x == x && fieldani[i].y == y) d = i; if (fieldani[i].x == -1 || fieldani[i].y == -1) j = i; } if (j == -1) { /* nothing anymore free */ d_printf ("field_animation_add: animation data line too full\n"); return; } if (d != -1) /* this stone is already in the list */ return; fieldani[j].x = x; fieldani[j].y = y; };