/* player.c - everything what have to do with the player */ #include #include "bomberclone.h" #include "network.h" #include "sound.h" void draw_player (_player * player) { SDL_Rect src, dest; int i; if ((player->pos.x >> 8) < 0 || (player->pos.x >> 8) >= bman.fieldsize.x || (player->pos.y >> 8) < 0 || (player->pos.y >> 8) >= bman.fieldsize.y) { d_printf ("FATAL: Draw Player out of range : [%d,%d]\n", (player->pos.x >> 8), (player->pos.y >> 8)); return; } if (PS_IS_alife (player->state)) { /* player is alife */ 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); } } } else { /* player is dead */ dest.w = src.w = gfx.dead.image->w; 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 = 0; src.y = (2 * gfx.block.y) * player->frame; SDL_BlitSurface (gfx.dead.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 >> 8) < 0 || (bman.players[i].old.x >> 8) >= bman.fieldsize.x || (bman.players[i].old.y >> 8) < 0 || (bman.players[i].old.y >> 8) >= bman.fieldsize.y) d_printf ("FATAL: Restore Player out of range : playernr %d [%d,%d]\n", i, (bman.players[i].old.x >> 8), (bman.players[i].old.y >> 8)); else { 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 x, short int y) { int res = 0; if (bman.field[x][y].type != FT_stone && bman.field[x][y].type != FT_block) res = 1; return res; } /* make only a smal step until i can go around the corner return the rest speed for this move */ int stepmove_player (int pl_nr) { _point bomb1[MAX_PLAYERS * MAX_BOMBS], bomb2[MAX_PLAYERS * MAX_BOMBS]; _player *p = &bman.players[pl_nr]; int speed = 0, i, j, f; _point fpos, // field position _pos, // position inside the field d; if (p->m == 1) { fpos.x = p->pos.x >> 8; fpos.y = p->pos.y >> 8; _pos.x = p->pos.x & 255; _pos.y = p->pos.y & 255; // do direction correction for going up/down if (_pos.x > 0 && _pos.x <= 128 && (p->d == up || p->d == down)) p->d = left; if (_pos.x > 128 && _pos.x < 256 && (p->d == up || p->d == down)) p->d = right; // do direction correction for left/right if (_pos.y > 0 && _pos.y <= 128 && (p->d == left || p->d == right)) p->d = up; if (_pos.y > 128 && _pos.y < 256 && (p->d == left || p->d == right)) p->d = down; /* get the distance/speed until we reach the next position */ if (p->d == left) speed = _pos.x; else if (p->d == right) speed = 256 - _pos.x; else if (p->d == up) speed = _pos.y; else speed = 256 - _pos.y; if (speed > p->speed || speed == 0) speed = p->speed; // check the new field position d.x = d.y = 0; if (p->d == left && _pos.y == 0 && ((_pos.x == 0 && check_field (fpos.x - 1, fpos.y)) || (_pos.x > 0))) d.x = -speed; if (p->d == right && _pos.y == 0 && ((_pos.x == 0 && check_field (fpos.x + 1, fpos.y)) || (_pos.x > 0))) d.x = speed; if (p->d == up && _pos.x == 0 && ((_pos.y == 0 && check_field (fpos.x, fpos.y - 1)) || (_pos.y > 0))) d.y = -speed; if (p->d == down && _pos.x == 0 && ((_pos.y == 0 && check_field (fpos.x, fpos.y + 1)) || (_pos.y > 0))) d.y = speed; // check if we can move and if there is any bomb if (d.y != 0 || d.x != 0) { get_bomb_on (p->pos.x, p->pos.y, bomb1); get_bomb_on (p->pos.x + d.x, p->pos.y + d.y, bomb2); if (bomb1[0].x == -1 && bomb2[0].x != -1) /* old pos no bomb, new pos no bomb */ d.x = d.y = 0; else if (bomb2[0].x != -1) { /* new pos bomb, old pos bomb... check if it's the same use f to save if we found the bomb or not f == 0 no bomb found, f == 1 bomb found */ for (i = 0, f = 1; (bomb2[i].x != -1 && f == 1); i++) for (f = 0, j = 0; (bomb1[j].x != -1 && f == 0); j++) if (bomb1[j].x == bomb2[i].x && bomb1[j].y == bomb2[i].y) /* identical bomb found ... f = 1 */ f = 1; if (f == 0) d.x = d.y = 0; } } p->pos.x += d.x; p->pos.y += d.y; player_check_powerup (pl_nr); } if (d.x == 0 && d.y == 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]; i = player_findfreebomb (player); if (i >= 0 && i < MAX_BOMBS && 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; } bomb->pos.x = bomb->pos.x << 8; bomb->pos.y = bomb->pos.y << 8; 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", pl_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 >> 8][bomb->pos.y >> 8] = 1; 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->frame = 0; 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 (PS_IS_alife (player->state)) { 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) player->frame = 0; } if (PS_IS_dead (player->state)) { if (player->frame < gfx.dead.frames && (player->frameto <= 0 || player->frameto > ANI_PLAYERTIMEOUT * 2)) { player->frameto = ANI_PLAYERTIMEOUT * 2; player->frame++; } } 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; } }; /* find a free bomb */ int player_findfreebomb (_player *player) { int i, bombused = 0, res = -1, nr; /* check every free bomb from next entry of the last exploded bomb to the last exploded bomb */ if (player->bomb_lastex < 0 || player->bomb_lastex >= MAX_BOMBS) player->bomb_lastex = 0; for (i = 0; i < MAX_BOMBS; i++) { nr = player->bomb_lastex + 1 + i; if (nr < 0 || nr >= MAX_BOMBS) // i out of range .. restart at bomb 0 nr -= MAX_BOMBS; if (player->bombs[i].state == BS_off) { /* check if this bomb is free */ if (res == -1) res = i; } else bombused++; // count number of used bombs } if (res == -1 && i == player->bomb_lastex && player->bombs[i].state == BS_off) res = i; if (bombused >= player->bombs_n) res = -1; /* all max number of bombs lay */ return res; };