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.
bomberclone/src/bomb.c

445 lines
12 KiB

/* everything what have to do with the bombs */
#include "bomberclone.h"
#include "network.h"
#include "gfx.h"
#include "sound.h"
void
draw_bomb (_bomb * bomb)
{
SDL_Rect src,
dest;
int x=bomb->pos.x >> 8,
y= bomb->pos.y >> 8;
if (x < 0 || y < 0 || x >= bman.fieldsize.x || y >= bman.fieldsize.y) {
d_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* gfx.block.x);
dest.y = gfx.offset.y + (y* gfx.block.y);
src.x = 0;
src.y = src.h * bomb->frame;
draw_stone (x, 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);
snd_play (SND_explode);
};
void
bomb_move (_bomb *bomb)
{
_point npos;
if (bomb->pos.x==bomb->moveto.x) {
if (bomb->pos.y==bomb->moveto.y) {
bomb->moves=0;return;}
if (bomb->pos.y>bomb->moveto.y) {
npos.y=bomb->pos.y-bomb->moves; //move bomb up
npos.x=bomb->pos.x;
} else {
npos.y=bomb->pos.y+bomb->moves; // move bomb down
npos.x=bomb->pos.x;
}
} else {
if (bomb->pos.x>bomb->moveto.x) {
npos.x=bomb->pos.x-bomb->moves; //move bomb left
npos.y=bomb->pos.y;
} else {
npos.x=bomb->pos.x+bomb->moves; // move bomb right
npos.y=bomb->pos.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 (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 >>8 == x && bomb->pos.y>>8 == 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;
_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 (--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 = 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 */
bman.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 >= 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, 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) {
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;
_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]++;
bman.field[bpos.x + dx][bpos.y + dy].ex[d].count++;
bman.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);
};