/* $Id: bomb.c,v 1.34 2003/07/16 14:42:00 stpohle Exp $ */ /* everything what have to do with the bombs */ #include "bomberclone.h" #include void draw_bomb (_bomb * bomb) { SDL_Rect src, dest; int x = bomb->pos.x, y = bomb->pos.y; if (x < 0 || y < 0 || x>>8 >= map.size.x || y>>8 >= map.size.y) { d_printf ("FATAL: Draw Bomb out of range [%d,%d]\n", x, y); return; } if (bomb->state != BS_trigger || ((bomb->state == BS_trigger) && (bomb->to < BOMB_TIMEOUT * TIME_FACTOR))) { /* 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 + (x >> 8) * gfx.block.x + gfx.postab[bomb->pos.x & 0x0FF]; dest.y = gfx.offset.y + (y >> 8) * gfx.block.y + gfx.postab[bomb->pos.y & 0x0FF]; src.x = 0; src.y = src.h * bomb->frame; draw_stone (x>>8, y>>8); if (bomb->moves) { draw_stone ((x>>8)+1, y>>8); draw_stone (x>>8, (y>>8)+1); draw_stone ((x>>8)+1, (y>>8)+1); gfx_AddUpdateRect (gfx.offset.x + (x >> 8) * gfx.block.x, gfx.offset.y + (y >> 8) * gfx.block.y, dest.w*2, dest.h*2); } else { gfx_AddUpdateRect (dest.x, dest.y, dest.w, dest.h); } SDL_BlitSurface (gfx.bomb.image, &src, gfx.screen, &dest); }; 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 bman.players[p].bomb_lastex = b; 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); snd_play (SND_explode); }; void bomb_move (_bomb * bomb) { _point npos; int dx = 0, dy = 0; float vec; if (bomb->moveto.x < 0) { switch (bomb->moveto.x) { case -1: case -2: dx = -bomb->moves; //move bomb left case -3: case -4: dx = bomb->moves; //move bomb right } } else { dx = bomb->moveto.x - bomb->pos.x; //move bomb to field } if (bomb->moveto.y < 0) { switch (bomb->moveto.y) { case -1: case -2: dy = -bomb->moves; //move bomb up case -3: case -4: dy = bomb->moves; //move bomb down } } else { dy = bomb->moveto.y - bomb->pos.y; //move bomb to field } if (!dx && !dy) { // bomb has reached its final position bomb->moves = 0; return; } // calculate movement if (abs(dx)>bomb->moves || abs(dy)>bomb->moves) { vec=sqrt(dx*dx+dy*dy); dx=dx*bomb->moves/vec; dy=dy*bomb->moves/vec; } npos.x=bomb->pos.x+dx; npos.y=bomb->pos.y+dy; // check if field is used /* if (!(dx && dy)) { fpos.x=npos.x>>8; fpos.y=npos.y>>8; if (((npos.x & 0xff ) >0) && (dx>0)) fpos.x++; if (((npos.y & 0xff ) >0) && (dy>0)) fpos.y++; if (bman.bfield[fpos.x][fpos.y] || bman.field[fpos.x][fpos.y].type != FT_nothing) { npos.x &= 0xff00; npos.y &= 0xff00; if (dx<0) npos.x+=0x100; if (dy<0) npos.y+=0x100; } } */ bomb->pos.x=npos.x; bomb->pos.y=npos.y; } 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: case BS_trigger: 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 if (bomb->state == BS_ticking) bomb->to = BOMB_TIMEOUT * TIME_FACTOR; else bomb->to = SPECIAL_TRIGGER_TIMEOUT * TIME_FACTOR; net_game_send_bomb (bman.p_nr, i); bomb->to = bomb->to + ((2 * RESENDCACHE_RETRY) / TIME_FACTOR); } draw_bomb (bomb); } if (bomb->moves > 0) bomb_move(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 (short int x, short 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-0x100 < x && bomb->pos.x+0x100 > x && bomb->pos.y-0x100 < y && bomb->pos.y+0x100 > 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 = map.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; _point bpos; bpos.x = bomb->pos.x >> 8; bpos.y = bomb->pos.y >> 8; 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 = bpos.x; _y = bpos.y; for (i = 0; i < bomb->firer[d]; i++) { if (--map.field[_x][_y].ex[d].count == 0) // there was only one explosion so map.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 && map.field[_x][_y].type != FT_block && bomb->ex_nr != map.field[_x][_y].ex_nr) { map.field[_x][_y].ex_nr = bomb->ex_nr; map.field[_x][_y].frame = 0; map.field[_x][_y].frameto = 0; if (map.field[_x][_y].special != FT_nothing) { map.field[_x][_y].type = map.field[_x][_y].special; map.field[_x][_y].special = FT_nothing; d_printf ("field_explode (%d,%d) ex_nr = %d\n", _x, _y, map.field[_x][_y].ex_nr); } else map.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 = bpos.x; _y = bpos.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 */ map.bfield[bpos.x][bpos.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 >= map.size.x || y < 0 || y >= map.size.y) return FT_block; get_player_on (x << 8, y << 8, pl); get_bomb_on (x << 8, y << 8, 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 (map.field[x][y].type != FT_nothing && map.field[x][y].type != FT_block && bomb->ex_nr != map.field[x][y].ex_nr) if (map.field[x][y].frame == 0) { map.field[x][y].frameto = ANI_STONETIMEOUT; map.field[x][y].frame = 1; draw_stone (x, y); field_update (x, y); } return map.field[x][y].type; }; /* draw the explosion as far as she got */ void draw_explosion (_bomb * bomb) { int d, r, dx, dy; _point p, bpos; bpos.x = bomb->pos.x >> 8; bpos.y = bomb->pos.y >> 8; 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 = bpos.x; p.y = bpos.y; for (r = 0; r < bomb->firer[d]; r++) { if (bomb->frameto == 0) { map.field[p.x][p.y].ex[d].frame++; if (map.field[p.x][p.y].ex[d].frame >= gfx.fire.frames) map.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; _point bpos; bpos.x = bomb->pos.x >> 8; bpos.y = bomb->pos.y >> 8; 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 (bpos.x + dx, bpos.y + dy, p, b) == BS_off && bomb->firerst[d] == -1) { bomb->firer[d]++; map.field[bpos.x + dx][bpos.y + dy].ex[d].count++; map.field[bpos.x + dx][bpos.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 (bpos.x + dx, bpos.y + dy); } } } /* with a slow pc disable this --- maybe option over a config menu */ if (bomb->state == BS_exploding) draw_explosion (bomb); };