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.
491 lines
13 KiB
491 lines
13 KiB
/* $Id: bomb.c,v 1.38 2003/07/27 14:34:39 stpohle Exp $ */
|
|
/* everything what have to do with the bombs */
|
|
|
|
#include "bomberclone.h"
|
|
#include <math.h>
|
|
|
|
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;
|
|
stonelist_add (x>>8, y>>8);
|
|
if (bomb->moves) {
|
|
stonelist_add ((x>>8)+1, y>>8);
|
|
stonelist_add (x>>8, (y>>8)+1);
|
|
stonelist_add ((x>>8)+1, (y>>8)+1);
|
|
}
|
|
|
|
gfx_blit (gfx.bomb.image, &src, gfx.screen, &dest, y + 2);
|
|
};
|
|
|
|
|
|
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;
|
|
};
|
|
|
|
|
|
/* check if on the givin place is a bomb
|
|
bombs[].x = player, bombs[].y = bombnumber */
|
|
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;
|
|
|
|
dest.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;
|
|
|
|
gfx_blit (gfx.fire.image, &src, gfx.screen, &dest, (y << 8));
|
|
};
|
|
|
|
|
|
void
|
|
restore_explosion (_bomb * bomb)
|
|
{
|
|
int i, j,
|
|
d, dx = 0,
|
|
dy = 0, _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
|
|
|
|
for (j = 0; j >= 0 && j < 4; j++)
|
|
if (map.field[_x][_y].ex[j].count > 0 && j != d)
|
|
j = -4;
|
|
if (j > 0)
|
|
stonelist_add (_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;
|
|
|
|
stonelist_add (_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;
|
|
|
|
/* 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;
|
|
|
|
stonelist_add (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;
|
|
}
|
|
stonelist_add (p.x, p.y);
|
|
draw_fire (p.x, p.y, d, -1);
|
|
p.x += dx;
|
|
p.y += dy;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* do the bombexplosion itself */
|
|
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];
|
|
stonelist_add (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);
|
|
};
|