|
|
/* $Id: single.c,v 1.41 2003/07/27 19:49:57 stpohle Exp $ */
|
|
|
/* single player */
|
|
|
|
|
|
#include "basic.h"
|
|
|
#include "bomberclone.h"
|
|
|
|
|
|
void
|
|
|
single_game_new ()
|
|
|
{
|
|
|
int p,
|
|
|
i;
|
|
|
|
|
|
bman.players_nr_s = 1;
|
|
|
bman.players_nr = 1;
|
|
|
|
|
|
// set players variables
|
|
|
for (p = 0; p < MAX_PLAYERS; p++) {
|
|
|
bman.players[p].pos.x = -1;
|
|
|
bman.players[p].pos.y = -1;
|
|
|
if (PS_IS_used (bman.players[p].state)) {
|
|
|
bman.players_nr_s++;
|
|
|
bman.players_nr++;
|
|
|
bman.players[p].state = PSF_used + PSF_alife + PSF_playing;
|
|
|
}
|
|
|
else
|
|
|
bman.players[p].state = 0;
|
|
|
|
|
|
// reset bombs
|
|
|
bman.players[p].bombs_n = START_BOMBS;
|
|
|
bman.players[p].range = START_RANGE;
|
|
|
bman.players[p].speed = START_SPEED;
|
|
|
bman.players[p].special.type = SP_nothing;
|
|
|
bman.updatestatusbar = 1;
|
|
|
for (i = 0; i < MAX_BOMBS; i++) {
|
|
|
bman.players[p].bombs[i].state = BS_off;
|
|
|
bman.players[p].bombs[i].ex_nr = -1;
|
|
|
bman.players[p].bombs[i].moves = 0;
|
|
|
bman.players[p].bombs[i].moveto.x = 0;
|
|
|
bman.players[p].bombs[i].moveto.y = 0;
|
|
|
}
|
|
|
|
|
|
for (i = 0; i < PI_max; i++)
|
|
|
bman.players[p].ill[i].to = 0;
|
|
|
bman.players[p].frame = 0;
|
|
|
bman.players[p].frameto = 0;
|
|
|
bman.players[p].d = 0;
|
|
|
}
|
|
|
|
|
|
bman.players[bman.p_nr].state = PSFM_alife;
|
|
|
player_set_gfx (&bman.players[bman.p_nr], bman.players[bman.p_nr].gfx_nr);
|
|
|
bman.last_ex_nr = 1;
|
|
|
|
|
|
init_map_tileset ();
|
|
|
|
|
|
bman.gametype = GT_single;
|
|
|
bman.state = GS_running;
|
|
|
};
|
|
|
|
|
|
|
|
|
inline int
|
|
|
ai_checkfield (int x, int y)
|
|
|
{
|
|
|
return ((map.field[x][y].type == FT_nothing || map.field[x][y].type == FT_fire
|
|
|
|| map.field[x][y].type == FT_shoe || map.field[x][y].type == FT_bomb
|
|
|
|| map.field[x][y].type == FT_mixed)
|
|
|
&& map.bfield[x][y] == 0);
|
|
|
}
|
|
|
|
|
|
|
|
|
/* give the run away direction */
|
|
|
int
|
|
|
ai_easyrunaway (_point p)
|
|
|
{
|
|
|
int i,
|
|
|
done = 0,
|
|
|
dir = 0;
|
|
|
_point pos[4],
|
|
|
m[4];
|
|
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
|
pos[i] = p;
|
|
|
switch (i) {
|
|
|
case (left):
|
|
|
m[i].x = -1;
|
|
|
m[i].y = 0;
|
|
|
break;
|
|
|
case (right):
|
|
|
m[i].x = 1;
|
|
|
m[i].y = 0;
|
|
|
break;
|
|
|
case (up):
|
|
|
m[i].x = 0;
|
|
|
m[i].y = -1;
|
|
|
break;
|
|
|
default:
|
|
|
m[i].x = 0;
|
|
|
m[i].y = 1;
|
|
|
break;
|
|
|
}
|
|
|
pos[i].x += m[i].x;
|
|
|
pos[i].y += m[i].y;
|
|
|
}
|
|
|
|
|
|
/* test the possible ways */
|
|
|
while (!done) {
|
|
|
done = 1;
|
|
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
|
/* check if we are still in the game field */
|
|
|
if (pos[i].x <= 0 || pos[i].y <= 0 || pos[i].x >= map.size.x - 1
|
|
|
|| pos[i].y >= map.size.y - 1)
|
|
|
pos[i].x = pos[i].y = -1;
|
|
|
|
|
|
if (pos[i].x != -1 && pos[i].y != -1) {
|
|
|
/* check if this place is free to go to */
|
|
|
if (ai_checkfield (pos[i].x, pos[i].y)) {
|
|
|
done = 0;
|
|
|
/* check the field left and right beside */
|
|
|
if (i == left || i == right) {
|
|
|
if (ai_findnearbombs (pos[i]) == 0
|
|
|
&& (ai_checkfield (pos[i].x, pos[i].y - 1)
|
|
|
|| ai_checkfield (pos[i].x, pos[i].y + 1)))
|
|
|
dir |= (1 << i);
|
|
|
}
|
|
|
else {
|
|
|
if (ai_findnearbombs (pos[i]) == 0
|
|
|
&& (ai_checkfield (pos[i].x - 1, pos[i].y)
|
|
|
|| ai_checkfield (pos[i].x + 1, pos[i].y)))
|
|
|
dir |= (1 << i);
|
|
|
}
|
|
|
pos[i].x += m[i].x;
|
|
|
pos[i].y += m[i].y;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return dir;
|
|
|
};
|
|
|
|
|
|
|
|
|
/* give the run away direction
|
|
|
the return value: */
|
|
|
_airunaway
|
|
|
ai_runawayfrom (_point p, int nearbomb, signed char norecursive)
|
|
|
{
|
|
|
int i,
|
|
|
done = 0,
|
|
|
nbomb,
|
|
|
tdir,
|
|
|
_i,
|
|
|
bdirpoints = 10,
|
|
|
j,
|
|
|
c;
|
|
|
_airunaway res;
|
|
|
_point pos[4],
|
|
|
m[4],
|
|
|
tpos;
|
|
|
|
|
|
res.dir = 0;
|
|
|
res.bestdir = -1;
|
|
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
|
pos[i] = p;
|
|
|
switch (i) {
|
|
|
case (left):
|
|
|
m[i].x = -1;
|
|
|
m[i].y = 0;
|
|
|
break;
|
|
|
case (right):
|
|
|
m[i].x = 1;
|
|
|
m[i].y = 0;
|
|
|
break;
|
|
|
case (up):
|
|
|
m[i].x = 0;
|
|
|
m[i].y = -1;
|
|
|
break;
|
|
|
default:
|
|
|
m[i].x = 0;
|
|
|
m[i].y = 1;
|
|
|
break;
|
|
|
}
|
|
|
pos[i].x += m[i].x;
|
|
|
pos[i].y += m[i].y;
|
|
|
}
|
|
|
|
|
|
/* test if we just have to move to the side */
|
|
|
if (!norecursive)
|
|
|
for (i = 0; i < 4; i++)
|
|
|
if (ai_checkfield (pos[i].x, pos[i].y) && ai_findnearbombs (pos[i]) == 0) {
|
|
|
bdirpoints = 0;
|
|
|
res.bestdir = i;
|
|
|
res.dir |= (1 << i);
|
|
|
}
|
|
|
|
|
|
/* test the possible ways */
|
|
|
while (!done) {
|
|
|
done = 1;
|
|
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
|
/* check if we are still in the game field */
|
|
|
if (pos[i].x <= 0 || pos[i].y <= 0 || pos[i].x >= map.size.x - 1
|
|
|
|| pos[i].y >= map.size.y - 1)
|
|
|
pos[i].x = pos[i].y = -1;
|
|
|
|
|
|
if (pos[i].x != -1 && pos[i].y != -1) {
|
|
|
/* check if this place is free to go to */
|
|
|
if (ai_checkfield (pos[i].x, pos[i].y)) {
|
|
|
done = 0;
|
|
|
/* check the field left and right beside */
|
|
|
for (j = 0; j < 4; j++)
|
|
|
if (((i == left || i == right) && (j == up || j == down)) ||
|
|
|
((j == left || j == right) && (i == up || i == down))) {
|
|
|
c = 10;
|
|
|
tpos.x = pos[i].x + m[j].x;
|
|
|
tpos.y = pos[i].y + m[j].y;
|
|
|
if (ai_checkfield (tpos.x, tpos.y)) {
|
|
|
nbomb = ai_findnearbombs (tpos);
|
|
|
c = s_countbits (nbomb, 5);
|
|
|
if (!norecursive) {
|
|
|
tdir = ai_runawayfrom (tpos, nbomb, 1).dir;
|
|
|
_i = ai_invertdir (i);
|
|
|
if (tdir != (1 << _i)) { // usefull direction
|
|
|
res.dir |= (1 << i); // add this one
|
|
|
}
|
|
|
else {
|
|
|
c = -1;
|
|
|
}
|
|
|
}
|
|
|
else
|
|
|
res.dir |= (1 << i);
|
|
|
|
|
|
/* check for the best direction */
|
|
|
if (c != -1 && !norecursive) {
|
|
|
if (c < bdirpoints) {
|
|
|
bdirpoints = c;
|
|
|
res.bestdir = i;
|
|
|
}
|
|
|
else if (bdirpoints != 0 && c == bdirpoints && c < 5
|
|
|
&& s_random (2) == 0)
|
|
|
res.bestdir = i; // random if the points are equal
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
pos[i].x += m[i].x;
|
|
|
pos[i].y += m[i].y;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
return res;
|
|
|
};
|
|
|
|
|
|
|
|
|
/* count the points for dropping a bomb here
|
|
|
this will even count if there is any powerup*/
|
|
|
int
|
|
|
ai_bombpoints (_point pos, int range)
|
|
|
{
|
|
|
int points = 0,
|
|
|
d,
|
|
|
r;
|
|
|
_point p,
|
|
|
m;
|
|
|
|
|
|
if (map.field[pos.x][pos.y].type != FT_block && map.field[pos.x][pos.y].type != FT_stone
|
|
|
&& ai_checkfield (pos.x, pos.y)) {
|
|
|
for (d = 0; d < 4; d++) {
|
|
|
switch (d) {
|
|
|
case (left):
|
|
|
m.x = -1;
|
|
|
m.y = 0;
|
|
|
break;
|
|
|
case (right):
|
|
|
m.x = 1;
|
|
|
m.y = 0;
|
|
|
break;
|
|
|
case (up):
|
|
|
m.x = 0;
|
|
|
m.y = -1;
|
|
|
break;
|
|
|
default:
|
|
|
m.x = 0;
|
|
|
m.y = 1;
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
p = pos;
|
|
|
|
|
|
for (r = 0; (r < range && map.field[p.x][p.y].type == FT_nothing); r++) {
|
|
|
p.x += m.x;
|
|
|
p.y += m.y;
|
|
|
}
|
|
|
|
|
|
if (map.field[p.x][p.y].type != FT_nothing
|
|
|
&& (map.field[p.x][p.y].type != FT_block || map.field[p.x][p.y].type == FT_shoe
|
|
|
|| map.field[p.x][p.y].type == FT_bomb || map.field[p.x][p.y].type == FT_fire))
|
|
|
points++;
|
|
|
if (map.field[p.x][p.y].type == FT_shoe || map.field[p.x][p.y].type == FT_bomb ||
|
|
|
map.field[p.x][p.y].type == FT_fire)
|
|
|
points += 2;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (ai_easyrunaway (pos) == 0 || ai_findnearbombs (pos) != 0)
|
|
|
points = 0;
|
|
|
|
|
|
return points;
|
|
|
};
|
|
|
|
|
|
|
|
|
/* find the best position to go for dropping a bomb */
|
|
|
int
|
|
|
ai_findbestbombdir (_point pos, int dir, int range)
|
|
|
{
|
|
|
int points[5] = { 0, 0, 0, 0, 0 };
|
|
|
int d,
|
|
|
done = 0,
|
|
|
j,
|
|
|
maxpoints = 0,
|
|
|
bestd;
|
|
|
_point m[4],
|
|
|
p[4];
|
|
|
|
|
|
points[4] = ai_bombpoints (pos, range);
|
|
|
|
|
|
/* fill in the positions */
|
|
|
for (d = 0; d < 4; d++) {
|
|
|
p[d] = pos;
|
|
|
|
|
|
switch (d) {
|
|
|
case (left):
|
|
|
m[d].x = -1;
|
|
|
m[d].y = 0;
|
|
|
break;
|
|
|
case (right):
|
|
|
m[d].x = 1;
|
|
|
m[d].y = 0;
|
|
|
break;
|
|
|
case (up):
|
|
|
m[d].x = 0;
|
|
|
m[d].y = -1;
|
|
|
break;
|
|
|
default:
|
|
|
m[d].x = 0;
|
|
|
m[d].y = 1;
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
while (!done) {
|
|
|
done = 1;
|
|
|
|
|
|
for (d = 0; d < 5; d++) {
|
|
|
|
|
|
if (d < 4) {
|
|
|
p[d].x += m[d].x;
|
|
|
p[d].y += m[d].y;
|
|
|
if (p[d].x > 0 && p[d].y > 0 && p[d].x < map.size.x - 1 && p[d].y < map.size.y - 1) {
|
|
|
if (ai_checkfield (p[d].x, p[d].y)) {
|
|
|
/* we are opn a empty field go on with the test */
|
|
|
done = 0;
|
|
|
j = ai_bombpoints (p[d], range);
|
|
|
if (points[d] < j)
|
|
|
points[d] = j;
|
|
|
}
|
|
|
else /* no empty field */
|
|
|
p[d].x = p[d].y = -1;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (maxpoints < points[d])
|
|
|
maxpoints = points[d];
|
|
|
}
|
|
|
}
|
|
|
|
|
|
bestd = 0;
|
|
|
if (maxpoints > 2)
|
|
|
maxpoints--;
|
|
|
|
|
|
for (d = 0; d < 5; d++)
|
|
|
if (points[d] >= maxpoints)
|
|
|
bestd |= (1 << d);
|
|
|
|
|
|
/* prevent from turning around */
|
|
|
if (dir != -1 && (bestd & (0xFF - (1 << ai_invertdir (dir)))))
|
|
|
bestd &= (0xFF - (1 << ai_invertdir (dir)));
|
|
|
|
|
|
return bestd;
|
|
|
}
|
|
|
|
|
|
|
|
|
/* check if is there is a bom in the near
|
|
|
returns the directions (bits 0(left)-3(down) bit4 bomb under us) where a bomb is */
|
|
|
int
|
|
|
ai_findnearbombs (_point pos)
|
|
|
{
|
|
|
int d,
|
|
|
res = 0, // result if there is a bomb
|
|
|
|
|
|
done = 0;
|
|
|
_point m[4]; // direction addition
|
|
|
_point dist[4]; // to check every direction (on three ways)
|
|
|
|
|
|
for (d = 0; d < 4; d++)
|
|
|
switch (d) {
|
|
|
case (left):
|
|
|
m[d].x = -1;
|
|
|
m[d].y = 0;
|
|
|
dist[d].x = pos.x - 1;
|
|
|
dist[d].y = pos.y;
|
|
|
break;
|
|
|
case (right):
|
|
|
m[d].x = 1;
|
|
|
m[d].y = 0;
|
|
|
dist[d].x = pos.x + 1;
|
|
|
dist[d].y = pos.y;
|
|
|
break;
|
|
|
case (up):
|
|
|
m[d].x = 0;
|
|
|
m[d].y = -1;
|
|
|
dist[d].x = pos.x;
|
|
|
dist[d].y = pos.y - 1;
|
|
|
break;
|
|
|
case (down):
|
|
|
m[d].x = 0;
|
|
|
m[d].y = 1;
|
|
|
dist[d].x = pos.x;
|
|
|
dist[d].y = pos.y + 1;
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
while (!done) {
|
|
|
done = 1;
|
|
|
/* check every direction again */
|
|
|
for (d = 0; d < 4; d++)
|
|
|
if (dist[d].x >= 0 && dist[d].x < map.size.x &&
|
|
|
dist[d].y >= 0 && dist[d].y < map.size.y) {
|
|
|
if (map.bfield[dist[d].x][dist[d].y] != 0) {
|
|
|
res |= (1 << d); // set the bit for the direction;
|
|
|
dist[d].x = dist[d].y = -1; // don't check no more.
|
|
|
}
|
|
|
if (map.field[dist[d].x][dist[d].y].type != FT_nothing)
|
|
|
dist[d].x = dist[d].y = -1; // don't check no more.
|
|
|
else if (dist[d].x != -1 && dist[d].y != -1) {
|
|
|
dist[d].x += m[d].x;
|
|
|
dist[d].y += m[d].y;
|
|
|
done = 0;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (map.bfield[pos.x][pos.y] != 0)
|
|
|
res |= 16; // set the 4th. bit
|
|
|
|
|
|
return res;
|
|
|
}
|
|
|
|
|
|
|
|
|
/* check if we are still running and fill out the position
|
|
|
return == 0 we're still walking ... else we have reached a point */
|
|
|
inline int
|
|
|
ai_checkpos (_player * pl, _point * pos)
|
|
|
{
|
|
|
_point _p;
|
|
|
|
|
|
_p.x = pl->pos.x & 255;
|
|
|
_p.y = pl->pos.y & 255;
|
|
|
|
|
|
pos->x = pl->pos.x >> 8;
|
|
|
pos->y = pl->pos.y >> 8;
|
|
|
|
|
|
if (_p.x > 128)
|
|
|
(pos->x)++;
|
|
|
if (_p.y > 128)
|
|
|
(pos->y)++;
|
|
|
|
|
|
return ((_p.x < 42 || _p.x > 213) && (_p.y < 42 || _p.y > 213));
|
|
|
};
|
|
|
|
|
|
|
|
|
/* random choose direction */
|
|
|
int
|
|
|
ai_choosedir (int dir, int nearbomb, int oldpos)
|
|
|
{
|
|
|
int rdir[4];
|
|
|
int bdir[4 * 3];
|
|
|
int i,
|
|
|
rnr,
|
|
|
bnr;
|
|
|
|
|
|
for (rnr = bnr = i = 0; i < 4; i++) {
|
|
|
if ((dir & (1 << i)) != 0) {
|
|
|
rdir[rnr] = i;
|
|
|
rnr++;
|
|
|
}
|
|
|
if (((nearbomb & (DIRM_up + DIRM_down)) != 0) && ((dir & (1 << i)) != 0)
|
|
|
&& (i == left || i == right) && i != ai_invertdir (oldpos)) {
|
|
|
bdir[bnr] = i;
|
|
|
bnr++;
|
|
|
}
|
|
|
if (((nearbomb & (DIRM_left + DIRM_right)) != 0) && ((dir & (1 << i)) != 0)
|
|
|
&& (i == down || i == up) && i != ai_invertdir (oldpos)) {
|
|
|
bdir[bnr] = i;
|
|
|
bnr++;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (rnr == 0)
|
|
|
return (s_random (4));
|
|
|
|
|
|
if (bnr != 0)
|
|
|
i = bdir[s_random (bnr)];
|
|
|
else
|
|
|
i = rdir[s_random (rnr)];
|
|
|
|
|
|
return i;
|
|
|
};
|
|
|
|
|
|
|
|
|
inline int
|
|
|
ai_invertdir (int dir)
|
|
|
{
|
|
|
int idir;
|
|
|
switch (dir) {
|
|
|
case (left):
|
|
|
idir = right;
|
|
|
break;
|
|
|
case (right):
|
|
|
idir = left;
|
|
|
break;
|
|
|
case (down):
|
|
|
idir = up;
|
|
|
break;
|
|
|
default:
|
|
|
idir = down;
|
|
|
break;
|
|
|
}
|
|
|
return idir;
|
|
|
};
|
|
|
|
|
|
|
|
|
inline int
|
|
|
ai_checknewpos (_point pos, int d)
|
|
|
{
|
|
|
_point m;
|
|
|
switch (d) {
|
|
|
case (left):
|
|
|
m.x = pos.x - 1;
|
|
|
m.y = pos.y;
|
|
|
break;
|
|
|
case (right):
|
|
|
m.x = pos.x + 1;
|
|
|
m.y = pos.y;
|
|
|
break;
|
|
|
case (up):
|
|
|
m.x = pos.x;
|
|
|
m.y = pos.y - 1;
|
|
|
break;
|
|
|
default:
|
|
|
m.x = pos.x;
|
|
|
m.y = pos.y + 1;
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
return (ai_findnearbombs (m) == 0);
|
|
|
};
|
|
|
|
|
|
|
|
|
/* create a giving number of ai players */
|
|
|
void
|
|
|
single_create_ai (int players)
|
|
|
{
|
|
|
int p,
|
|
|
count,
|
|
|
gfx_sel,
|
|
|
i = 0;
|
|
|
_player *pl;
|
|
|
|
|
|
for (count = 0; count < players; count++) {
|
|
|
/* find free players */
|
|
|
for (pl = NULL, p = 0; (pl == NULL && p < MAX_PLAYERS); p++)
|
|
|
if (!(PS_IS_used (bman.players[p].state))) {
|
|
|
pl = &bman.players[p];
|
|
|
sprintf (pl->name, "AI %d", count + 1);
|
|
|
pl->state |= PSF_used + PSF_alife + PSF_playing;
|
|
|
do {
|
|
|
gfx_sel = s_random (MAX_PLAYERS);
|
|
|
MW_IS_GFX_SELECT (gfx_sel, i);
|
|
|
} while (i != -1);
|
|
|
player_set_gfx (pl, gfx_sel);
|
|
|
}
|
|
|
|
|
|
if (pl == NULL)
|
|
|
return;
|
|
|
}
|
|
|
};
|
|
|
|
|
|
|
|
|
/* single player game win/point screen */
|
|
|
void
|
|
|
single_playergame ()
|
|
|
{
|
|
|
int p,
|
|
|
done = 0;
|
|
|
|
|
|
/* delete player from the game */
|
|
|
for (p = 0; p < MAX_PLAYERS; p++) {
|
|
|
bman.players[p].points = 0;
|
|
|
bman.players[p].wins = 0;
|
|
|
bman.players[p].state = 0;
|
|
|
bman.players[p].gfx_nr = -1;
|
|
|
bman.players[p].gfx = NULL;
|
|
|
}
|
|
|
|
|
|
for (bman.p_nr = -1, p = 0; (bman.p_nr == -1 && p < MAX_PLAYERS); p++)
|
|
|
if (!(PS_IS_used (bman.players[p].state)))
|
|
|
bman.p_nr = p;
|
|
|
|
|
|
if (bman.p_nr >= MAX_PLAYERS) {
|
|
|
printf ("ERROR in function (single_game_new): couldn't find any free player\n");
|
|
|
exit (1);
|
|
|
}
|
|
|
|
|
|
if ((bman.players[bman.p_nr].gfx_nr = single_select_player ()) == -1)
|
|
|
return;
|
|
|
|
|
|
bman.players[bman.p_nr].state = PSF_used + PSF_alife + PSF_playing;
|
|
|
strncpy (bman.players[bman.p_nr].name, bman.playername, LEN_PLAYERNAME);
|
|
|
single_create_ai (bman.ai_players);
|
|
|
bman.state = GS_ready;
|
|
|
|
|
|
while (!done && bman.state != GS_quit && bman.state != GS_startup) {
|
|
|
single_game_new ();
|
|
|
game_start ();
|
|
|
game_loop ();
|
|
|
game_end ();
|
|
|
}
|
|
|
};
|
|
|
|
|
|
|
|
|
/* single player loop for calculating the ai players */
|
|
|
void
|
|
|
single_loop ()
|
|
|
{
|
|
|
int p;
|
|
|
_player *pl;
|
|
|
_point plpos;
|
|
|
int nearbomb = 0,
|
|
|
bestbdir,
|
|
|
i;
|
|
|
_airunaway rawdir;
|
|
|
|
|
|
for (p = 0; p < MAX_PLAYERS; p++)
|
|
|
if (p != bman.p_nr && PS_IS_alife (bman.players[p].state)) {
|
|
|
pl = &bman.players[p];
|
|
|
|
|
|
i = ai_checkpos (pl, &plpos);
|
|
|
|
|
|
if (!i)
|
|
|
/* we're still moving */
|
|
|
pl->m = 1;
|
|
|
else {
|
|
|
nearbomb = ai_findnearbombs (plpos);
|
|
|
if (nearbomb == 0) { // no bombs found
|
|
|
bestbdir = ai_findbestbombdir (plpos, pl->d, pl->range);
|
|
|
if (bestbdir & DIRM_under) {
|
|
|
if (ai_easyrunaway (plpos) != 0)
|
|
|
player_drop_bomb (p);
|
|
|
}
|
|
|
else if (bestbdir == 0) {
|
|
|
pl->d = s_random (4);
|
|
|
pl->m = 1;
|
|
|
}
|
|
|
else {
|
|
|
pl->d = ai_choosedir (bestbdir, 0, pl->d);
|
|
|
pl->m = 1;
|
|
|
}
|
|
|
if (!ai_checknewpos (plpos, pl->d))
|
|
|
pl->m = 0;
|
|
|
}
|
|
|
else {
|
|
|
// bombs in the near found
|
|
|
rawdir = ai_runawayfrom (plpos, nearbomb, 0);
|
|
|
if (rawdir.dir != 0 && rawdir.bestdir == -1) {
|
|
|
pl->d = ai_choosedir (rawdir.dir, nearbomb, pl->d); // we have to make a choice.. do it
|
|
|
pl->m = 1;
|
|
|
}
|
|
|
else if (rawdir.bestdir != -1) {
|
|
|
pl->d = rawdir.bestdir;
|
|
|
pl->m = 1;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
player_ilness_loop (p);
|
|
|
move_player (p);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
|
|
|
/* singleplayer men<65> with some options you can make */
|
|
|
void
|
|
|
single_menu ()
|
|
|
{
|
|
|
int menuselect = 0;
|
|
|
_menu menu[] = {
|
|
|
{1, "Start Game"},
|
|
|
{2, "Number Of Players"},
|
|
|
{3, "Map Option"},
|
|
|
{4, "Return To Main Menu"},
|
|
|
{-1, ""}
|
|
|
};
|
|
|
|
|
|
while (menuselect != -1 && bman.state != GS_quit) {
|
|
|
sprintf (menu[1].text, "%d AI Player", bman.ai_players);
|
|
|
menuselect = menu_loop ("Single Player", menu, menuselect);
|
|
|
switch (menuselect) {
|
|
|
case (0): // Start Game
|
|
|
single_playergame ();
|
|
|
break;
|
|
|
case (1): // Change number of Player
|
|
|
bman.ai_players++;
|
|
|
if (bman.ai_players >= MAX_PLAYERS) {
|
|
|
if (debug)
|
|
|
bman.ai_players = 0; // null players with debugging on
|
|
|
else
|
|
|
bman.ai_players = 1;
|
|
|
}
|
|
|
break;
|
|
|
case (2): // Map Options
|
|
|
mapmenu ();
|
|
|
break;
|
|
|
case (3):
|
|
|
menuselect = -1;
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
};
|
|
|
|
|
|
|
|
|
/* single player selection
|
|
|
return value the gfx of the player or -1 for escape */
|
|
|
int
|
|
|
single_select_player ()
|
|
|
{
|
|
|
int selgfx = 0,
|
|
|
done = 0,
|
|
|
x,
|
|
|
y,
|
|
|
keypressed = 0,
|
|
|
frame = 0,
|
|
|
d = 0,
|
|
|
dto = 2,
|
|
|
newplayer = -1,
|
|
|
pos = 0,
|
|
|
i;
|
|
|
SDL_Rect dest,
|
|
|
src;
|
|
|
char text[255];
|
|
|
SDL_Event event;
|
|
|
Uint8 *keys;
|
|
|
Uint32 timeloop1;
|
|
|
|
|
|
menu_displaytext ("Loading..", "Please Wait", 32, 128, 32);
|
|
|
|
|
|
dest.x = dest.y = 0;
|
|
|
dest.w = gfx.res.x;
|
|
|
dest.h = gfx.res.y;
|
|
|
|
|
|
gfx_load_players (64, 64);
|
|
|
gfx_blitupdaterectclear ();
|
|
|
|
|
|
draw_logo ();
|
|
|
|
|
|
strcpy (text, "Select your Player");
|
|
|
x = (gfx.res.x - (font[2].size.x * strlen (text)) - 64) / 2;
|
|
|
y = (gfx.res.y - font[2].size.y - 64 - 128) / 2;
|
|
|
font_setcolor (128, 128, 0, 2);
|
|
|
font_draw (x - 2, y, text, 2);
|
|
|
font_draw (x + 2, y, text, 2);
|
|
|
font_draw (x, y - 2, text, 2);
|
|
|
font_draw (x, y + 2, text, 2);
|
|
|
font_setcolor (255, 255, 128, 2);
|
|
|
font_draw (x, y, text, 2);
|
|
|
|
|
|
gfx_blitupdaterectadd (&dest);
|
|
|
|
|
|
while (!done) {
|
|
|
|
|
|
/* draw selected player */
|
|
|
frame++;
|
|
|
if (frame >= gfx.players[selgfx].ani.frames) {
|
|
|
frame = 0;
|
|
|
if (dto-- <= 0 && newplayer == -1) {
|
|
|
dto = 5;
|
|
|
if (d == up)
|
|
|
d = left;
|
|
|
else if (d == left)
|
|
|
d = down;
|
|
|
else if (d == down)
|
|
|
d = right;
|
|
|
else
|
|
|
d = up;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (newplayer != -1) {
|
|
|
SDL_Rect dest1,
|
|
|
src1;
|
|
|
|
|
|
pos += 8;
|
|
|
|
|
|
if (d == left) {
|
|
|
/* image 1 */
|
|
|
src.h = dest.h = gfx.players[selgfx].ani.h;
|
|
|
src.w = dest.w = gfx.players[selgfx].ani.w;
|
|
|
src.x = gfx.players[selgfx].ani.w * d;
|
|
|
src.y = gfx.players[selgfx].ani.h * frame;
|
|
|
dest.x = ((gfx.res.x - gfx.players[selgfx].ani.w) / 2) - pos;
|
|
|
dest.y = y + font[0].size.y + 64;
|
|
|
|
|
|
/* image 2 */
|
|
|
src1.h = dest1.h = gfx.players[newplayer].ani.h;
|
|
|
src1.w = dest1.w = gfx.players[newplayer].ani.w;
|
|
|
src1.x = gfx.players[newplayer].ani.w * d;
|
|
|
src1.y = gfx.players[newplayer].ani.h * frame;
|
|
|
dest1.x = ((gfx.res.x - gfx.players[newplayer].ani.w) / 2) + ((gfx.res.x / 2)+ 128) - pos;
|
|
|
dest1.y = y + font[0].size.y + 64;
|
|
|
}
|
|
|
else {
|
|
|
/* image 1 */
|
|
|
src.h = dest.h = gfx.players[selgfx].ani.h;
|
|
|
src.w = dest.w = gfx.players[selgfx].ani.w;
|
|
|
src.x = gfx.players[selgfx].ani.w * d;
|
|
|
src.y = gfx.players[selgfx].ani.h * frame;
|
|
|
dest.x = ((gfx.res.x - gfx.players[selgfx].ani.w) / 2) + pos;
|
|
|
dest.y = y + font[0].size.y + 64;
|
|
|
|
|
|
/* image 2 */
|
|
|
src1.h = dest1.h = gfx.players[newplayer].ani.h;
|
|
|
src1.w = dest1.w = gfx.players[newplayer].ani.w;
|
|
|
src1.x = gfx.players[newplayer].ani.w * d;
|
|
|
src1.y = gfx.players[newplayer].ani.h * frame;
|
|
|
dest1.x = ((gfx.res.x - gfx.players[newplayer].ani.w) / 2) - ((gfx.res.x / 2)+ 128) + pos;
|
|
|
dest1.y = y + font[0].size.y + 64;
|
|
|
}
|
|
|
|
|
|
redraw_logo (0, y + font[0].size.y + 64, gfx.res.x, 128);
|
|
|
|
|
|
if (dest.x + dest.w > 0)
|
|
|
gfx_blit (gfx.players[selgfx].ani.image, &src, gfx.screen, &dest, 0);
|
|
|
if (dest1.x + dest1.w > 0)
|
|
|
gfx_blit (gfx.players[newplayer].ani.image, &src1, gfx.screen, &dest1, 0);
|
|
|
|
|
|
if (pos > (gfx.res.x / 2)+ 128) {
|
|
|
selgfx = newplayer;
|
|
|
newplayer = -1;
|
|
|
pos = 0;
|
|
|
frame = 0;
|
|
|
d = down;
|
|
|
}
|
|
|
frame++;
|
|
|
}
|
|
|
else {
|
|
|
src.h = dest.h = gfx.players[selgfx].ani.h;
|
|
|
src.w = dest.w = gfx.players[selgfx].ani.w;
|
|
|
src.x = gfx.players[selgfx].ani.w * d;
|
|
|
src.y = gfx.players[selgfx].ani.h * frame;
|
|
|
dest.x = (gfx.res.x - gfx.players[selgfx].ani.w) / 2;
|
|
|
dest.y = y + font[0].size.y + 64;
|
|
|
redraw_logo (dest.x, dest.y, dest.w, dest.h);
|
|
|
gfx_blit (gfx.players[selgfx].ani.image, &src, gfx.screen, &dest, 0);
|
|
|
}
|
|
|
|
|
|
gfx_blitdraw ();
|
|
|
|
|
|
/* do the keyboard handling */
|
|
|
if (SDL_PollEvent (&event) != 0)
|
|
|
switch (event.type) {
|
|
|
case (SDL_QUIT):
|
|
|
bman.state = GS_quit;
|
|
|
bman.p_nr = -1;
|
|
|
done = 1;
|
|
|
selgfx = -1;
|
|
|
}
|
|
|
|
|
|
keys = SDL_GetKeyState (NULL);
|
|
|
|
|
|
if (keys[SDLK_ESCAPE] && event.type == SDL_KEYDOWN) {
|
|
|
/* we want to quit */
|
|
|
done = 1;
|
|
|
bman.p_nr = -1;
|
|
|
keypressed = 1;
|
|
|
bman.state = GS_startup;
|
|
|
selgfx = -1;
|
|
|
}
|
|
|
|
|
|
if (keys[SDLK_LEFT] && (!keypressed) && newplayer == -1) {
|
|
|
newplayer = selgfx - 1;
|
|
|
if (newplayer < 0)
|
|
|
newplayer = MAX_PLAYERS - 1;
|
|
|
d = left;
|
|
|
}
|
|
|
|
|
|
if (keys[SDLK_RIGHT] && (!keypressed) && newplayer == -1) {
|
|
|
newplayer = selgfx + 1;
|
|
|
if (newplayer >= MAX_PLAYERS)
|
|
|
newplayer = 0;
|
|
|
d = right;
|
|
|
}
|
|
|
|
|
|
if ((keys[SDLK_RETURN] ||keys[SDLK_RCTRL] || keys[SDLK_LCTRL]) && (!keypressed) && (event.type = SDL_KEYDOWN) && newplayer == -1) {
|
|
|
done = 1;
|
|
|
keypressed = 1;
|
|
|
// d_printf("return pressed - done=1\n");
|
|
|
}
|
|
|
if (event.type == SDL_KEYUP)
|
|
|
keypressed = 0;
|
|
|
else if (event.type == SDL_KEYDOWN)
|
|
|
keypressed = 1;
|
|
|
|
|
|
// calculate time sync.
|
|
|
timeloop1 = SDL_GetTicks ();
|
|
|
|
|
|
if (newplayer != -1)
|
|
|
i = 17;
|
|
|
else
|
|
|
i = 25;
|
|
|
|
|
|
while (timeloop1 - timestamp >= 0 && timeloop1 - timestamp < i) {
|
|
|
s_delay (i - (timeloop1 - timestamp) - 1);
|
|
|
timeloop1 = SDL_GetTicks ();
|
|
|
}
|
|
|
|
|
|
timestamp = timeloop1;
|
|
|
}
|
|
|
|
|
|
gfx_free_players ();
|
|
|
|
|
|
return selgfx;
|
|
|
};
|