/* everything what have to do with the bombs */ #include "bomberclone.h" #include "network.h" #include "gfx.h" void draw_bomb (_bomb * bomb) { SDL_Rect src, dest; if (bomb->state != BS_trigger) { /* check the framenumber */ if (bomb->frameto-- == 0) { bomb->frameto = ANI_BOMBTIMEOUT; bomb->frame++; }; if (bomb->frame < 0 || bomb->frame >= gfx.bomb.frames || bomb->frameto > ANI_BOMBTIMEOUT) { bomb->frame = 0; bomb->frameto = ANI_BOMBTIMEOUT; } } dest.w = src.w = gfx.bomb.image->w; dest.h = src.h = gfx.block.y; dest.x = gfx.offset.x + (bomb->pos.x * gfx.block.x); dest.y = gfx.offset.y + (bomb->pos.y * gfx.block.y); src.x = 0; src.y = src.h * bomb->frame; draw_stone (bomb->pos.x, bomb->pos.y); SDL_BlitSurface (gfx.bomb.image, &src, gfx.screen, &dest); gfx_AddUpdateRect (dest.x, dest.y, dest.w, dest.h); }; void bomb_explode (int p, int b, int net) { int d; _bomb *bomb = &bman.players[p].bombs[b]; d_printf ("Bomb Explode p:%d, b:%d [%d,%d]\n", p, b, bomb->pos.x, bomb->pos.y); if (bomb->ex_nr == -1) bomb->ex_nr = bman.last_ex_nr++; // set bomb explosion id bomb->to = EXPLOSIONTIMEOUT; /* set the timeout for the fireexplosion */ bomb->state = BS_exploding; for (d = 0; d < 4; d++) { bomb->firer[d] = 0; bomb->firerst[d] = -1; } if (GT_MP_PTPM && net) /* from now on only the server let the bomb explode */ net_game_send_bomb (p, b); }; int bomb_loop () { int p, i, b = 0; _player *player; _bomb *bomb; for (p = 0; p < MAX_PLAYERS; p++) { player = &bman.players[p]; if ((bman.players[p].state & PSFM_used) != 0) { for (i = 0; i < MAX_BOMBS; i++) { bomb = &player->bombs[i]; switch (bomb->state){ case BS_ticking: if (GT_MP_PTPM || bman.gametype == GT_single) { if (--bomb->to == 0) // bomb will have to explode in the next loop bomb_explode (p, i, 1); else draw_bomb (bomb); } else { if (--bomb->to == 0) { // bomb did not explode -> resend bombdata bomb->to = BOMB_TIMEOUT * TIME_FACTOR; net_game_send_bomb (bman.p_nr, i); bomb->to = bomb->to + ((2 * RESENDCACHE_RETRY) / TIME_FACTOR); } draw_bomb (bomb); } b++; // Count ticking Bombs for Return value break; case BS_trigger: draw_bomb (bomb); b++; // Count ticking Bombs for Return value break; case BS_exploding: if (bomb->to > 0) { do_explosion (p, i); } if (bomb->to == 0) { // explosion done restore_explosion (bomb); bomb->to = 0; bomb->state = BS_off; } bomb->to--; b++; break; } } } } return b; }; void get_bomb_on (int x, int y, _point bombs[]) { int p, b, i; _bomb *bomb; for (i = 0, p = 0; p < MAX_PLAYERS; p++) if ((bman.players[p].state & PSFM_used) != 0) { for (b = 0; b < MAX_BOMBS; b++) { bomb = &bman.players[p].bombs[b]; if (bomb->state == BS_ticking || bomb->state==BS_trigger) { if (bomb->pos.x == x && bomb->pos.y == y) { bombs[i].x = p; bombs[i].y = b; i++; } } } } bombs[i].x = bombs[i].y = -1; }; /* if frame == -1 we will draw the framenumber in the field.ex data */ void draw_fire (int x, int y, int d, int frame) { SDL_Rect src, dest; if (frame == -1) // no giving frame frame = bman.field[x][y].ex[d].frame; src.w = src.w = gfx.block.x; dest.h = src.h = gfx.block.y; dest.x = gfx.offset.x + x * gfx.block.x; dest.y = gfx.offset.y + y * gfx.block.y; src.y = frame * src.w; src.x = d * src.w; SDL_BlitSurface (gfx.fire.image, &src, gfx.screen, &dest); gfx_AddUpdateRect (dest.x, dest.y, dest.w, dest.h); }; void restore_explosion (_bomb * bomb) { int i, d; int dx = 0, dy = 0; int _x, _y; for (d = 0; d < 4; d++) { switch (d) { case (left): dx = -1; dy = 0; break; case (right): dx = 1; dy = 0; break; case (up): dx = 0; dy = -1; break; case (down): dx = 0; dy = 1; break; } _x = bomb->pos.x; _y = bomb->pos.y; for (i = 0; i < bomb->firer[d]; i++) { if (--bman.field[_x][_y].ex[d].count == 0) // there was only one explosion so bman.field[_x][_y].ex[d].frame = 0; // reset the framenumber if (i == 0 && d == 3) draw_stone (_x, _y); if (i > 0) draw_stone (_x, _y); _x = _x + dx; _y = _y + dy; } // delete the stone completly if there was any in the way if (bomb->firer[d] <= bomb->r && bman.field[_x][_y].type != FT_block && bomb->ex_nr != bman.field[_x][_y].ex_nr) { bman.field[_x][_y].ex_nr = bomb->ex_nr; bman.field[_x][_y].frame = 0; bman.field[_x][_y].frameto = 0; if (bman.field[_x][_y].special != FT_nothing) { bman.field[_x][_y].type = bman.field[_x][_y].special; bman.field[_x][_y].special = FT_nothing; d_printf ("field_explode (%d,%d) ex_nr = %d\n", _x, _y, bman.field[_x][_y].ex_nr); } else bman.field[_x][_y].type = FT_nothing; draw_stone (_x, _y); if (GT_MP_PTPM) /* send only if we are the master */ net_game_send_field (_x, _y); } } _x = bomb->pos.x; _y = bomb->pos.y; gfx_AddUpdateRect (gfx.offset.x + (_x - bomb->firer[left]) * gfx.block.x, gfx.offset.y + (_y - bomb->firer[up]) * gfx.block.y, gfx.block.x * (bomb->firer[left] + bomb->firer[right] + 1), gfx.block.x * (bomb->firer[up] + bomb->firer[down] + 1)); /* delete field from the bfield map */ bman.bfield[bomb->pos.x][bomb->pos.y] = 0; }; /* check the field on which the explosion is */ int explosion_check_field (int x, int y, int p, int b) { _bomb *bomb = &bman.players[p].bombs[b]; int pl[MAX_PLAYERS]; int i; _point bo[MAX_PLAYERS * MAX_BOMBS]; _bomb *tmpbomb; _player *tmpplayer; if (x < 0 || x >= bman.fieldsize.x || y < 0 || y >= bman.fieldsize.y) return FT_block; get_player_on (x << 8, y << 8, pl); get_bomb_on (x, y, bo); // check if any bomb have to explode.. for (i = 0; bo[i].x != -1; i++) { tmpbomb = &bman.players[bo[i].x].bombs[bo[i].y]; if (tmpbomb != bomb && tmpbomb->state != BS_exploding) { tmpbomb->ex_nr = bomb->ex_nr; // set the ex_nr to identify explosions bomb_explode (bo[i].x, bo[i].y, 1); } } // check if any player is in the explosion for (i = 0; pl[i] != -1; i++) { tmpplayer = &bman.players[pl[i]]; if (((tmpplayer->state & PSF_alife) != 0) && (bman.gametype == GT_single || (GT_MP_PTP && (&bman.players[bman.p_nr] == tmpplayer)))) player_died (tmpplayer, p); } // let the stones right beside explode if (bman.field[x][y].type != FT_nothing && bman.field[x][y].type != FT_block && bomb->ex_nr != bman.field[x][y].ex_nr) { if (bman.field[x][y].frame == 0) { bman.field[x][y].frameto = ANI_STONETIMEOUT; bman.field[x][y].frame = 1; } draw_stone (x, y); field_update(x,y); } return bman.field[x][y].type; }; /* draw the explosion as far as she got */ void draw_explosion (_bomb * bomb) { int d, r, dx, dy; _point p; bomb->frameto--; if (bomb->frameto < 0 || bomb->frameto > ANI_FIRETIMEOUT) bomb->frameto = ANI_FIRETIMEOUT; for (d = 0; d < 4; d++) { switch (d) { case (left): dx = -1; dy = 0; break; case (right): dx = 1; dy = 0; break; case (up): dx = 0; dy = -1; break; default: dx = 0; dy = 1; break; } p.x = bomb->pos.x; p.y = bomb->pos.y; for (r = 0; r < bomb->firer[d]; r++) { if (bomb->frameto == 0) { bman.field[p.x][p.y].ex[d].frame++; if (bman.field[p.x][p.y].ex[d].frame >= gfx.fire.frames) bman.field[p.x][p.y].ex[d].frame = 0; } draw_fire (p.x, p.y, d, -1); p.x += dx; p.y += dy; } } } /* check the fields and all this */ void do_explosion (int p, int b) { _bomb *bomb = &bman.players[p].bombs[b]; int dx = 0, dy = 0, d; for (d = 0; d < 4; d++) { switch (d) { case (left): dx = -1; dy = 0; break; case (right): dx = 1; dy = 0; break; case (up): dx = 0; dy = -1; break; case (down): dx = 0; dy = 1; break; } if (bomb->firer[d] <= bomb->r) { dx = bomb->firer[d] * dx; dy = bomb->firer[d] * dy; if (explosion_check_field (bomb->pos.x + dx, bomb->pos.y + dy, p, b) == BS_off && bomb->firerst[d] == -1) { bomb->firer[d]++; bman.field[bomb->pos.x + dx][bomb->pos.y + dy].ex[d].count++; bman.field[bomb->pos.x + dx][bomb->pos.y + dy].ex[d].frame = bomb->firer[d]; /* if we have a slow pc we can enable this and disable the drawing animation */ // draw_fire (bomb->pos.x + dx, bomb->pos.y + dy, d, gfx.fire.frames>>1); } else { bomb->firerst[d] = bomb->firer[d]; draw_stone (bomb->pos.x + dx, bomb->pos.y + dy); } } } /* with a slow pc disable this --- maybe option over a config menu */ if (bomb->state == BS_exploding) draw_explosion (bomb); };