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/player.c

737 lines
18 KiB

/* player.c - everything what have to do with the player */
#include <SDL.h>
#include "bomberclone.h"
#include "network.h"
#include "sound.h"
void
draw_player (_player * player)
{
SDL_Rect src,
dest;
int i;
dest.w = src.w = player->gfx->size.x;
dest.h = src.h = player->gfx->size.y;
dest.x =
gfx.offset.x + player->gfx->offset.x + (player->pos.x >> 8) * gfx.block.x +
gfx.postab[player->pos.x & 255];
dest.y =
gfx.offset.y + player->gfx->offset.y + (player->pos.y >> 8) * gfx.block.y +
gfx.postab[player->pos.y & 255];
src.x = player->d * player->gfx->size.x;
src.y = player->frame * player->gfx->size.y;
SDL_BlitSurface (player->gfx->ani.image, &src, gfx.screen, &dest);
/* if the player is ill, draw this image above him */
if (PS_IS_alife (player->state)) {
for (i = PI_max - 1; (i >= 0) && (player->ill[i].to == 0); i--);
if (i >= 0) {
dest.w = src.w = gfx.block.x * 2;
dest.h = src.h = gfx.block.y * 2;
src.x = 0;
src.y = (2 * gfx.block.y) * player->illframe;
dest.x =
(-(gfx.block.x >> 1)) + gfx.offset.x + (player->pos.x >> 8) * gfx.block.x +
gfx.postab[player->pos.x & 255];
dest.y =
gfx.offset.y + ((player->pos.y >> 8) - 1) * gfx.block.y +
gfx.postab[player->pos.y & 255];
SDL_BlitSurface (gfx.ill.image, &src, gfx.screen, &dest);
}
}
gfx_AddUpdateRect (dest.x, dest.y, dest.w, dest.h);
player->old = player->pos; // save this position
};
void
restore_players_screen ()
{
int i,
x,
xs,
xe,
y,
ys,
ye;
for (i = 0; i < MAX_PLAYERS; i++)
if ((PS_IS_used (bman.players[i].state)) && bman.players[i].old.x != -1) {
if ((bman.players[i].old.x & 0xFF) > 128) {
x = (bman.players[i].old.x >> 8);
xe = (bman.players[i].old.x >> 8) + 2;
}
else {
x = (bman.players[i].old.x >> 8) - 1;
xe = (bman.players[i].old.x >> 8) + 1;
}
if (x < 0)
x = 0;
if (xe >= bman.fieldsize.x)
xe = bman.fieldsize.x - 1;
ys = (bman.players[i].old.y >> 8) - 1;
ye = (bman.players[i].old.y >> 8) + 1;
if (ys < 0)
ys = 0;
if (ye >= bman.fieldsize.y)
ye = bman.fieldsize.y - 1;
xs = x;
for (; x <= xe; x++)
for (y = ys; y <= ye; y++)
draw_stone (x, y);
gfx_AddUpdateRect (xs * gfx.block.x + gfx.offset.x, ys * gfx.block.y + gfx.offset.y,
gfx.block.x * 3, gfx.block.y * 3);
}
};
void
player_check_powerup (int p_nr)
{
_player *p = &bman.players[p_nr];
int fx = p->pos.x >> 8;
int fy = p->pos.y >> 8;
int _x = p->pos.x & 255;
int _y = p->pos.y & 255;
int ft,
i;
if (PS_IS_netplayer (p->state))
return;
/* Get the right field position */
if (_x > 128)
fx = fx + 1;
if (_y > 128)
fy = fy + 1;
ft = bman.field[fx][fy].type;
/* we found a mixed powerup */
if (ft == FT_mixed) {
i = s_random (6);
switch (i) {
case 0:
ft = FT_bomb;
break;
case 1:
ft = FT_fire;
break;
case 2:
ft = FT_shoe;
break;
case 3:
case 4:
case 5:
ft = FT_death;
break;
}
}
switch (ft) {
/* we found a bomb powerup */
case FT_bomb:
if (p->bombs_n < MAX_BOMBS && p->ill[PI_nobomb].to <= 0) {
p->bombs_n++;
bman.updatestatusbar = 1;
}
field_clear (fx, fy);
break;
/* we found a fire powerup */
case FT_fire:
if (p->range < MAX_RANGE && p->ill[PI_range].to <= 0) {
p->range++;
bman.updatestatusbar = 1;
}
field_clear (fx, fy);
break;
/* we found a shoe powerup */
case FT_shoe:
if (p->speed < MAX_SPEED && p->ill[PI_slow].to <= 0) {
p->speed *= SPEEDMUL;
bman.updatestatusbar = 1;
}
field_clear (fx, fy);
break;
/* we found a death ?powerup? */
case FT_death:
player_set_ilness (p, -1);
bman.updatestatusbar = 1;
if (bman.gametype != GT_single)
net_game_send_ill (bman.p_nr);
field_clear (fx, fy);
break;
/* we found a special */
case FT_sp_trigger:
case FT_sp_row:
case FT_sp_push:
case FT_sp_kick:
special_pickup(p_nr,ft-FT_sp_trigger+1);
bman.updatestatusbar = 1;
field_clear (fx, fy);
break;
}
};
/*
check the givin field. if we are able to move on it
fx,fy = position on the field
*/
int
check_field (short int fx, short int fy, _player * p)
{
_point bombs[MAX_PLAYERS * MAX_BOMBS];
int res = 0;
if (bman.field[fx][fy].type != FT_stone && bman.field[fx][fy].type != FT_block)
res = 1;
get_bomb_on (fx, fy, bombs);
if (bombs[0].x != -1)
res = 0;
return res;
}
int
stepmove_player (int pl_nr)
{
_player *p = &bman.players[pl_nr];
int _x,
_y,
dx = 0,
dy = 0,
fx,
fy,
speed = 0;
if (p->m == 1) {
fx = p->pos.x >> 8;
fy = p->pos.y >> 8;
_x = p->pos.x & 255;
_y = p->pos.y & 255;
// do direction correction for going up/down
if (_x > 0 && _x <= 128 && (p->d == up || p->d == down))
p->d = left;
if (_x > 128 && _x < 256 && (p->d == up || p->d == down))
p->d = right;
// do direction correction for left/right
if (_y > 0 && _y <= 128 && (p->d == left || p->d == right))
p->d = up;
if (_y > 128 && _y < 256 && (p->d == left || p->d == right))
p->d = down;
/* get the pos to the next field */
if (p->d == left)
speed = _x;
else if (p->d == right)
speed = 256 - _x;
else if (p->d == up)
speed = _y;
else
speed = 256 - _y;
if (speed > p->speed || speed == 0)
speed = p->speed;
// go left
if (p->d == left && _y == 0 && ((_x == 0 && check_field (fx - 1, fy, p)) || (_x > 0)))
dx = -speed;
// go right
if (p->d == right && _y == 0 && ((_x == 0 && check_field (fx + 1, fy, p)) || (_x > 0)))
dx = speed;
// go up
if (p->d == up && _x == 0 && ((_y == 0 && check_field (fx, fy - 1, p)) || (_y > 0)))
dy = -speed;
// go down
if (p->d == down && _x == 0 && ((_y == 0 && check_field (fx, fy + 1, p)) || (_y > 0)))
dy = speed;
p->pos.x = p->pos.x + dx;
p->pos.y = p->pos.y + dy;
player_check_powerup (pl_nr);
}
if (dx == 0 && dy == 0)
return 0;
return (p->speed - speed);
};
void
move_player (int pl_nr)
{
int oldd,
stepsleft,
speed;
_player *p = &bman.players[pl_nr];
oldd = p->d;
if (p->m) {
player_animation (p);
if ((stepsleft = stepmove_player (pl_nr)) > 0) {
/* save the speed and go the rest of the step */
p->d = oldd;
speed = p->speed;
p->speed = stepsleft;
stepmove_player (pl_nr);
p->speed = speed;
}
/* network packet send control - send data if it's time to send or if we need to */
if (bman.gametype != GT_single)
net_game_send_playermove (pl_nr, (p->old_m == 0));
}
/* the player just stopt moving so send data */
if (bman.gametype != GT_single && p->m == 0 && p->old_m != 0)
net_game_send_playermove (pl_nr, 1);
p->old_m = p->m; // save the old state
p->m = 0;
};
void
player_drop_bomb (int pl_nr)
{
_player *player = &bman.players[pl_nr];
_bomb *bomb = NULL;
int i,
_x,
_y;
_point bombs[MAX_PLAYERS * MAX_BOMBS];
for (i = 0; ((i < player->bombs_n) && (player->bombs[i].state != BS_off)); i++);
if (i < player->bombs_n && PS_IS_alife(player->state)) { // free bomb found
// get the best position for the bomb.
bomb = &player->bombs[i];
bomb->pos.x = player->pos.x >> 8;
bomb->pos.y = player->pos.y >> 8;
_x = player->pos.x & 255;
_y = player->pos.y & 255;
if (_x > 0 && _x <= 128)
_x = 0;
else if (_x > 128) {
bomb->pos.x += 1;
_x = 0;
}
if (_y > 0 && _y <= 128)
_y = 0;
else if (_y > 12) {
bomb->pos.y += 1;
_y = 0;
}
get_bomb_on (bomb->pos.x, bomb->pos.y, bombs);
if (bombs[0].x != -1) // is there already a bomb
return;
d_printf ("Player %d Dropped Bomb %d\n", bman.p_nr, i);
bomb->r = player->range;
if (player->special.type == SP_trigger) {
bomb->state = BS_trigger;
bomb->to = SPECIAL_TRIGGER_TIMEOUT * TIME_FACTOR; // 5 Secs * 200
}
else {
bomb->state = BS_ticking;
bomb->to = BOMB_TIMEOUT * TIME_FACTOR; // 5 Secs * 200
}
bomb->ex_nr = -1;
bman.bfield[bomb->pos.x][bomb->pos.y] = 1;
bomb->pos.x=bomb->pos.x << 8;
bomb->pos.y=bomb->pos.y << 8;
if (bman.gametype != GT_single) {
net_game_send_bomb (pl_nr, i);
if (GT_MP_PTPS)
bomb->to = bomb->to + ((2 * RESENDCACHE_RETRY) / TIME_FACTOR);
}
snd_play (SND_bombdrop);
}
};
/*
check the field - 4 pixels from every side.. so it's not anymore that tricky to get
away from bombs.. */
void
get_player_on (short int x, short int y, int pl_nr[])
{
int i,
p;
for (i = 0, p = 0; p < MAX_PLAYERS; p++)
if (PS_IS_alife (bman.players[p].state)) {
if (bman.players[p].pos.x - EXPLOSION_SAVE_DISTANCE > x - 256
&& bman.players[p].pos.x + EXPLOSION_SAVE_DISTANCE < x + 256
&& bman.players[p].pos.y - EXPLOSION_SAVE_DISTANCE > y - 256
&& bman.players[p].pos.y + EXPLOSION_SAVE_DISTANCE < y + 256) {
pl_nr[i] = p;
i++;
}
}
pl_nr[i] = -1;
};
void
player_died (_player * player, signed char dead_by)
{
// player die !
d_printf ("player_died (%10s)\n", player->name);
bman.updatestatusbar = 1; // force an update
if (PS_IS_alife (player->state) && dead_by >= 0 && dead_by < MAX_PLAYERS)
if (bman.p_nr != dead_by)
bman.players[dead_by].points++;
player->state &= (0xFF - PSF_alife);
player->dead_by = dead_by;
if (GT_MP_PTP)
net_game_send_player (bman.p_nr);
snd_play (SND_dead);
};
void
draw_players ()
{
int p;
for (p = 0; p < MAX_PLAYERS; p++) {
if (PS_IS_playing (bman.players[p].state))
draw_player (&bman.players[p]);
}
};
void
player_animation (_player * player)
{
if (player->gfx == NULL)
return;
if (player->frame < player->gfx->ani.frames
&& (player->frameto <= 0 || player->frameto > ANI_PLAYERTIMEOUT)) {
player->frameto = ANI_PLAYERTIMEOUT;
player->frame++;
}
if (player->frame >= player->gfx->ani.frames && PS_IS_alife (player->state))
player->frame = 0;
if (player->frameto > 0)
player->frameto--;
};
int
dead_playerani ()
{
int i,
b = 0;
for (i = 0; i < MAX_PLAYERS; i++)
if (PS_IS_dead (bman.players[i].state)) {
player_animation (&bman.players[i]);
b++;
}
return b;
};
void
player_calcstep (_player * pl)
{
_point d;
int fx,
fy;
player_animation (pl);
fx = pl->pos.x >> 8;
fy = pl->pos.y >> 8;
if (bman.field[fx][fy].type != FT_block && bman.field[fx][fy].type != FT_stone) {
d.x = 0;
d.y = 0;
if (pl->d == left)
d.x = -16;
else if (pl->d == right)
d.x = 16;
else if (pl->d == up)
d.y = -16;
else if (pl->d == down)
d.y = 16;
pl->pos.x += d.x;
pl->pos.y += d.y;
}
};
/*
calc the position on the screen for moving network players
*/
void
player_calcpos ()
{
_player *pl;
int oldm,
oldd,
p;
for (p = 0; p < MAX_PLAYERS; p++) {
pl = &bman.players[p];
if (PS_IS_netplayer (pl->state) && PS_IS_alife (pl->state) && pl->m != 0) {
if (pl->speeddat == 0 || pl->speed == 1 || pl->speed == 3)
pl->speeddat = 1;
else
pl->speeddat = 0;
oldm = pl->m;
oldd = pl->d;
if (pl->speed > 1)
stepmove_player (p);
if (pl->speeddat) {
pl->m = oldm;
pl->d = oldd;
player_calcstep (pl);
}
}
}
};
void
player_ilness_loop (int pl_nr)
{
_player *p;
int type,
pnr,
i,
tmp,
send;
int pl[MAX_PLAYERS + 1];
/* do the illness for the network players */
if (GT_MP_PTP) {
for (pnr = 0; pnr < MAX_PLAYERS; pnr++)
if (pnr != pl_nr && PS_IS_alife (bman.players[pnr].state)) {
p = &bman.players[pnr];
for (type = 0; type < PI_max; type++)
if (p->ill[type].to > 0) {
p->ill[type].to--;
p->illframeto--;
if (p->illframeto <= 0 || p->illframeto > ANI_PLAYERILLTIMEOUT) {
p->illframeto = ANI_PLAYERILLTIMEOUT;
p->illframe++;
if (p->illframe < 0 || p->illframe >= gfx.ill.frames)
p->illframe = 0;
}
}
}
}
/* check if we have contact with an other ill player */
p = &bman.players[pl_nr];
get_player_on (p->pos.x, p->pos.y, pl);
for (i = 0; (pl[i] != -1 && i < MAX_PLAYERS); i++)
if (pl[i] != pl_nr) {
send = 0;
for (type = 0; type < PI_max; type++) {
if (bman.players[pl[i]].ill[type].to > p->ill[type].to) {
tmp = p->ill[type].to;
player_set_ilness (p, type);
p->ill[type].to = bman.players[pl[i]].ill[type].to;
if (tmp <= 0)
send = 1;
}
}
if (send != 0 && GT_MP_PTP)
net_game_send_ill (pl_nr);
}
/* do the illness for the givin player */
for (type = 0; type < PI_max; type++)
if (p->ill[type].to > 0) {
p->ill[type].to--;
if (p->ill[type].to == 0)
player_clear_ilness (p, type);
else {
p->illframeto--;
if (p->illframeto <= 0 || p->illframeto > ANI_PLAYERILLTIMEOUT) {
p->illframeto = ANI_PLAYERILLTIMEOUT;
p->illframe++;
if (p->illframe < 0 || p->illframe >= gfx.ill.frames)
p->illframe = 0;
}
if (type == PI_keys) {
/* switch direction for player key illness */
if (p->m > 0)
switch (p->d) {
case (left):
p->d = right;
break;
case (right):
p->d = left;
break;
case (up):
p->d = down;
break;
case (down):
p->d = up;
break;
}
}
else if (type == PI_bomb)
/* player is dropping bombs */
player_drop_bomb (pl_nr);
}
}
}
/* player picked up the death powerup, add timeout for
this illness to the maybe excisting timeout */
void
player_set_ilness (_player * p, int t)
{
int type;
if (t == -1)
type = s_random (PI_max);
else
type = t;
d_printf ("Ilness : %d\n", type);
switch (type) {
case PI_slow:
if (p->ill[type].to == 0) {
if (p->ill[PI_fast].to > 0) {
p->ill[type].data = p->ill[PI_fast].data;
p->ill[PI_fast].to = 0;
}
else
p->ill[type].data = p->speed;
}
p->speed = 6;
break;
case PI_fast:
if (p->ill[type].to == 0) {
if (p->ill[PI_slow].to > 0) {
p->ill[type].data = p->ill[PI_slow].data;
p->ill[PI_slow].to = 0;
}
else
p->ill[type].data = p->speed;
}
p->speed = 150;
break;
case PI_range:
if (p->ill[type].to == 0)
p->ill[type].data = p->range;
p->range = 1;
break;
case PI_nobomb:
if (p->ill[type].to == 0)
p->ill[type].data = p->bombs_n;
p->bombs_n = s_random (2);
break;
}
bman.updatestatusbar = 1;
p->ill[type].to += TIME_FACTOR * IL_TIMEOUT;
};
/* players ilness is over now */
void
player_clear_ilness (_player * p, int type)
{
if (type < 0 || type >= PI_max)
return;
switch (type) {
case PI_slow:
case PI_fast:
p->speed = p->ill[type].data;
break;
case PI_range:
p->range = p->ill[type].data;
break;
case PI_nobomb:
p->bombs_n = p->ill[type].data;
break;
}
p->ill[type].to = 0;
if (bman.gametype != GT_single)
net_game_send_ill (bman.p_nr);
bman.updatestatusbar = 1;
};
void
player_set_gfx (_player * p, signed char gfx_nr)
{
p->gfx_nr = gfx_nr;
if (p->gfx_nr < 0 || p->gfx_nr >= MAX_PLAYERS)
p->gfx_nr = -1;
if (p->gfx_nr == -1) {
p->gfx = NULL;
p->state &= (0xFF - (PSF_alife + PSF_playing));
}
else {
p->gfx = &gfx.players[gfx_nr];
p->state |= PSF_playing;
}
};