|
|
@ -0,0 +1,944 @@ |
|
|
|
|
|
|
|
#include "bomber.h" |
|
|
|
#include "game.h" |
|
|
|
#include "gfx.h" |
|
|
|
#include "network.h" |
|
|
|
#include "draw.h" |
|
|
|
#include "utils.h" |
|
|
|
#include "sound.h" |
|
|
|
#include "menu.h" |
|
|
|
#include "list.h" |
|
|
|
|
|
|
|
static int gameframe; |
|
|
|
|
|
|
|
static list activebombs; |
|
|
|
static list activedecays; |
|
|
|
static list activebonus; |
|
|
|
static list activegeneric; |
|
|
|
|
|
|
|
static bomb *detonated[MAXBOMBSDETONATED]; |
|
|
|
static int detonateput=0; |
|
|
|
static int detonatetake=0; |
|
|
|
|
|
|
|
static list activeflames; |
|
|
|
static list activeplayers; |
|
|
|
|
|
|
|
#define REGISTERLEN (1+4+4+4+16+1) |
|
|
|
|
|
|
|
figure walking[MAXSETS][NUMWALKFRAMES]; |
|
|
|
solid background,backgroundoriginal; |
|
|
|
|
|
|
|
/* The playfield array, contains FIELD_* equates */ |
|
|
|
unsigned char field[32][32]; |
|
|
|
void *info[32][32]; |
|
|
|
|
|
|
|
int gamemode = 0; |
|
|
|
char exitflag = 0; |
|
|
|
static int framecount = 0; |
|
|
|
|
|
|
|
char playername[16]; |
|
|
|
|
|
|
|
static int gountil, mycount; |
|
|
|
|
|
|
|
static int bonustotal; |
|
|
|
static const int bonuschances[]= { |
|
|
|
TILE_BOMB,20, |
|
|
|
TILE_FLAME,20, |
|
|
|
TILE_CONTROL,2, |
|
|
|
TILE_GOLDFLAME,2, |
|
|
|
TILE_SKATES,20, |
|
|
|
TILE_TURTLE,5, |
|
|
|
TILE_NONE,160 |
|
|
|
}; |
|
|
|
|
|
|
|
static unsigned char gameoptions[10]; |
|
|
|
|
|
|
|
static const unsigned char playerpositions[] = { /* color, x, y */ |
|
|
|
2,0,0, |
|
|
|
3,14,10, |
|
|
|
4,14,0, |
|
|
|
5,0,10, |
|
|
|
1,6,0, |
|
|
|
6,8,10, |
|
|
|
7,0,6, |
|
|
|
8,14,4, |
|
|
|
}; |
|
|
|
|
|
|
|
static void initplayer(int color,int x,int y,int controller) { |
|
|
|
player *pl; |
|
|
|
|
|
|
|
pl=allocentry(); |
|
|
|
if(!pl) |
|
|
|
nomem("Couldn't get player structure (allocentry())"); |
|
|
|
addtail(&activeplayers,pl); |
|
|
|
memset(pl,0,sizeof(player)); |
|
|
|
pl->xpos=arraytoscreenx(x); |
|
|
|
pl->ypos=arraytoscreeny(y); |
|
|
|
pl->color=color; |
|
|
|
pl->speed=SPEEDSTART; |
|
|
|
pl->flags=0; |
|
|
|
pl->fixx=-4; |
|
|
|
pl->fixy=-40; |
|
|
|
pl->flamelength=gameoptions[GO_FLAMES]+1; |
|
|
|
pl->bombsavailable=gameoptions[GO_BOMBS]+1; |
|
|
|
pl->controller=controller; |
|
|
|
field[y][x]=FIELD_EMPTY; |
|
|
|
if(x) field[y][x-1]=FIELD_EMPTY; |
|
|
|
if(y) field[y-1][x]=FIELD_EMPTY; |
|
|
|
if(x<arraynumx-1) field[y][x+1]=FIELD_EMPTY; |
|
|
|
if(y<arraynumy-1) field[y+1][x]=FIELD_EMPTY; |
|
|
|
} |
|
|
|
|
|
|
|
static void initplayers(void) { |
|
|
|
int i; |
|
|
|
const unsigned char *p; |
|
|
|
int c,x,y; |
|
|
|
|
|
|
|
if(!network) { |
|
|
|
initplayer(2,0,0,-1); |
|
|
|
return; |
|
|
|
} |
|
|
|
p=playerpositions; |
|
|
|
for(i=0;i<MAXNETNODES;++i) { |
|
|
|
if(!netnodes[i].used) continue; |
|
|
|
c=*p++; |
|
|
|
x=*p++; |
|
|
|
y=*p++; |
|
|
|
initplayer(c,x,y,i); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
static void firstzero(void) { |
|
|
|
gountil=mycount=mydatacount=0; |
|
|
|
memset(latestactions,0,sizeof(latestactions)); |
|
|
|
memset(latestcounts,0,sizeof(latestcounts)); |
|
|
|
actionput=actioncount=0; |
|
|
|
} |
|
|
|
|
|
|
|
static void initgame() { |
|
|
|
int i,j; |
|
|
|
int x,y; |
|
|
|
int bl; |
|
|
|
const int *p; |
|
|
|
int comp; |
|
|
|
|
|
|
|
if (network != NETWORK_SLAVE) |
|
|
|
set_game_options(configopts); |
|
|
|
gameframe=0; |
|
|
|
allocthings(); |
|
|
|
initheader(&activebombs); |
|
|
|
initheader(&activeflames); |
|
|
|
initheader(&activedecays); |
|
|
|
initheader(&activebonus); |
|
|
|
initheader(&activeplayers); |
|
|
|
initheader(&activegeneric); |
|
|
|
|
|
|
|
detonateput=detonatetake=0; |
|
|
|
|
|
|
|
p=bonuschances; |
|
|
|
bonustotal=0; |
|
|
|
for(;;) { |
|
|
|
i=*p++; |
|
|
|
if(i==TILE_NONE) break; |
|
|
|
bonustotal+=*p++; |
|
|
|
} |
|
|
|
bonustotal += 64*(3-gameoptions[GO_GENEROSITY]); |
|
|
|
memset(field,0,sizeof(field)); |
|
|
|
comp=gameoptions[GO_DENSITY]; |
|
|
|
for(j=0;j<arraynumy;++j) |
|
|
|
for(i=0;i<arraynumx;++i) { |
|
|
|
/* if((i&j)&1) { |
|
|
|
field[j][i]=FIELD_BORDER; |
|
|
|
} else*/ |
|
|
|
field[j][i]= |
|
|
|
(myrand()&3)>=comp ? FIELD_BRICK : FIELD_EMPTY; |
|
|
|
} |
|
|
|
|
|
|
|
solidcopyany(&backgroundoriginal,&background,0,0,IXSIZE,IYSIZE); |
|
|
|
|
|
|
|
initplayers(); |
|
|
|
|
|
|
|
for(j=0;j<arraynumy;++j) { |
|
|
|
y=arraystarty+j*arrayspacey; |
|
|
|
for(i=0;i<arraynumx;++i) { |
|
|
|
x=arraystartx+i*arrayspacex; |
|
|
|
bl=field[j][i]; |
|
|
|
if(bl==FIELD_BORDER) bl=2; |
|
|
|
else if(bl==FIELD_BRICK) bl=1; |
|
|
|
else continue; |
|
|
|
drawfigureany(x,y,blocks+bl,&background); |
|
|
|
} |
|
|
|
} |
|
|
|
solidcopy(&background,0,0,IXSIZE,IYSIZE); |
|
|
|
copyup(); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void run_single_player(void) { |
|
|
|
int code; |
|
|
|
network=0; |
|
|
|
|
|
|
|
firstzero(); |
|
|
|
do { |
|
|
|
initgame(); |
|
|
|
while(!(code=iterate())) ++framecount; |
|
|
|
} while (code != CODE_QUIT); |
|
|
|
|
|
|
|
gamemode=0; |
|
|
|
} |
|
|
|
|
|
|
|
void run_network_game(void) { |
|
|
|
int code; |
|
|
|
|
|
|
|
firstzero(); |
|
|
|
do { |
|
|
|
initgame(); |
|
|
|
while(!(code=iterate())) ++framecount; |
|
|
|
} while (code != CODE_QUIT); |
|
|
|
|
|
|
|
network = 0; |
|
|
|
gamemode = 0; |
|
|
|
} |
|
|
|
|
|
|
|
static void addflame(player *owner,int px,int py) { |
|
|
|
flame *fl,*fl2; |
|
|
|
|
|
|
|
fl=allocentry(); |
|
|
|
if(!fl) return; |
|
|
|
addtail(&activeflames,fl); |
|
|
|
field[py][px]=FIELD_FLAME; |
|
|
|
info[py][px]=fl; |
|
|
|
fl->px=px; |
|
|
|
fl->py=py; |
|
|
|
fl->xpos=arraytoscreenx(px); |
|
|
|
fl->ypos=arraytoscreeny(py); |
|
|
|
fl->owner=owner; |
|
|
|
if(px && field[py][px-1]==FIELD_FLAME) { |
|
|
|
fl2=info[py][px-1]; |
|
|
|
fl->lurd|=FL_LEFT; |
|
|
|
fl2->lurd|=FL_RIGHT; |
|
|
|
} |
|
|
|
if(py && field[py-1][px]==FIELD_FLAME) { |
|
|
|
fl2=info[py-1][px]; |
|
|
|
fl->lurd|=FL_UP; |
|
|
|
fl2->lurd|=FL_DOWN; |
|
|
|
} |
|
|
|
if(px<arraynumx-1 && field[py][px+1]==FIELD_FLAME) { |
|
|
|
fl2=info[py][px+1]; |
|
|
|
fl->lurd|=FL_RIGHT; |
|
|
|
fl2->lurd|=FL_LEFT; |
|
|
|
} |
|
|
|
if(py<arraynumy-1 && field[py+1][px]==FIELD_FLAME) { |
|
|
|
fl2=info[py+1][px]; |
|
|
|
fl->lurd|=FL_DOWN; |
|
|
|
fl2->lurd|=FL_UP; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
static void dropbomb(player *pl,int px,int py,int type){ |
|
|
|
bomb *bmb; |
|
|
|
|
|
|
|
if(field[py][px]!=FIELD_EMPTY) return; |
|
|
|
bmb=allocentry(); |
|
|
|
if(!bmb) return; |
|
|
|
playsound(3); |
|
|
|
addtail(&activebombs,bmb); |
|
|
|
|
|
|
|
--(pl->bombsavailable); |
|
|
|
field[py][px]=FIELD_BOMB; |
|
|
|
info[py][px]=bmb; |
|
|
|
bmb->type=type; |
|
|
|
bmb->px=px; |
|
|
|
bmb->py=py; |
|
|
|
bmb->xpos=arraytoscreenx(px); |
|
|
|
bmb->ypos=arraytoscreeny(py); |
|
|
|
bmb->power=pl->flamelength; |
|
|
|
bmb->owner=pl; |
|
|
|
} |
|
|
|
|
|
|
|
static void adddetonate(bomb *bmb) { |
|
|
|
if(bmb->type==BOMB_OFF) return; |
|
|
|
|
|
|
|
bmb->type=BOMB_OFF; |
|
|
|
field[bmb->py][bmb->px]=FIELD_EXPLODING; |
|
|
|
info[bmb->py][bmb->px]=0; |
|
|
|
detonated[detonateput++]=bmb; |
|
|
|
detonateput%=MAXBOMBSDETONATED; |
|
|
|
} |
|
|
|
|
|
|
|
static void processbombs() { |
|
|
|
bomb *bmb; |
|
|
|
|
|
|
|
bmb=activebombs.next; |
|
|
|
while(bmb) { |
|
|
|
switch(bmb->type) { |
|
|
|
case BOMB_NORMAL: |
|
|
|
++bmb->timer; |
|
|
|
if(bmb->timer==BOMBLIFE) |
|
|
|
adddetonate(bmb); |
|
|
|
++(bmb->figcount); |
|
|
|
break; |
|
|
|
case BOMB_CONTROLLED: |
|
|
|
++(bmb->figcount); |
|
|
|
break; |
|
|
|
} |
|
|
|
bmb=bmb->next; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
static void adddecay(int px,int py) { |
|
|
|
brickdecay *bd; |
|
|
|
int xpos,ypos; |
|
|
|
|
|
|
|
bd=allocentry(); |
|
|
|
if(!bd) return; |
|
|
|
field[py][px]=FIELD_EXPLODING; |
|
|
|
bd->xpos=arraytoscreenx(px); |
|
|
|
bd->ypos=arraytoscreeny(py); |
|
|
|
bd->px=px; |
|
|
|
bd->py=py; |
|
|
|
addtail(&activedecays,bd); |
|
|
|
xpos=tovideox(bd->xpos); |
|
|
|
ypos=tovideoy(bd->ypos); |
|
|
|
solidcopyany(&backgroundoriginal,&background,xpos,ypos, |
|
|
|
arrayspacex,arrayspacey); |
|
|
|
solidcopy(&background,xpos,ypos,arrayspacex,arrayspacey); |
|
|
|
} |
|
|
|
|
|
|
|
static void addbonus(int px,int py,int type) { |
|
|
|
bonustile *bonus; |
|
|
|
|
|
|
|
bonus=allocentry(); |
|
|
|
if(!bonus) return; |
|
|
|
addtail(&activebonus,bonus); |
|
|
|
bonus->px=px; |
|
|
|
bonus->py=py; |
|
|
|
bonus->xpos=arraytoscreenx(px); |
|
|
|
bonus->ypos=arraytoscreeny(py); |
|
|
|
bonus->type=type; |
|
|
|
field[py][px]=FIELD_BONUS; |
|
|
|
info[py][px]=bonus; |
|
|
|
} |
|
|
|
|
|
|
|
static void trybonus(int px,int py) { |
|
|
|
int i=0, r; |
|
|
|
const int *p; |
|
|
|
|
|
|
|
if(field[py][px]!=FIELD_EMPTY) return; |
|
|
|
p=bonuschances; |
|
|
|
r=myrand()%bonustotal; |
|
|
|
while(r>=0) { |
|
|
|
i=*p++; |
|
|
|
r-=*p++; |
|
|
|
} |
|
|
|
if(i==TILE_NONE) return; |
|
|
|
addbonus(px,py,i); |
|
|
|
} |
|
|
|
|
|
|
|
static void deletebonus(bonustile *bonus) { |
|
|
|
int px,py; |
|
|
|
|
|
|
|
px=bonus->px; |
|
|
|
py=bonus->py; |
|
|
|
field[py][px]=0; |
|
|
|
info[py][px]=0; |
|
|
|
delink(&activebonus,bonus); |
|
|
|
} |
|
|
|
|
|
|
|
static void flameshaft(player *owner,int px,int py,int dx,int dy,int power) { |
|
|
|
int there; |
|
|
|
bomb *bmb; |
|
|
|
|
|
|
|
while(power--) { |
|
|
|
px+=dx; |
|
|
|
py+=dy; |
|
|
|
if(px<0 || py<0 || px>=arraynumx || py>=arraynumy) break; |
|
|
|
there=field[py][px]; |
|
|
|
switch(there) { |
|
|
|
case FIELD_BOMB: |
|
|
|
bmb=info[py][px]; |
|
|
|
adddetonate(bmb); |
|
|
|
break; |
|
|
|
case FIELD_EMPTY: |
|
|
|
addflame(owner,px,py); |
|
|
|
break; |
|
|
|
case FIELD_BRICK: |
|
|
|
adddecay(px,py); |
|
|
|
power=0; |
|
|
|
break; |
|
|
|
case FIELD_BONUS: |
|
|
|
deletebonus(info[py][px]); |
|
|
|
power=0; |
|
|
|
break; |
|
|
|
case FIELD_BORDER: |
|
|
|
case FIELD_EXPLODING: |
|
|
|
default: |
|
|
|
power=0; |
|
|
|
case FIELD_FLAME: |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
static void detonatebomb(bomb *bmb) { |
|
|
|
int px,py; |
|
|
|
int power; |
|
|
|
player *owner; |
|
|
|
|
|
|
|
++(bmb->owner->bombsavailable); |
|
|
|
px=bmb->px; |
|
|
|
py=bmb->py; |
|
|
|
power=bmb->power; |
|
|
|
owner=bmb->owner; |
|
|
|
delink(&activebombs,bmb); |
|
|
|
addflame(owner,px,py); |
|
|
|
flameshaft(owner,px,py,-1,0,power); |
|
|
|
flameshaft(owner,px,py,0,-1,power); |
|
|
|
flameshaft(owner,px,py,1,0,power); |
|
|
|
flameshaft(owner,px,py,0,1,power); |
|
|
|
} |
|
|
|
|
|
|
|
static void dodetonations(void) { |
|
|
|
int i=0; |
|
|
|
|
|
|
|
while(detonatetake!=detonateput) { |
|
|
|
++i; |
|
|
|
detonatebomb(detonated[detonatetake]); |
|
|
|
detonatetake=(detonatetake+1) % MAXBOMBSDETONATED; |
|
|
|
} |
|
|
|
if(i) playsound((myrand()&1) ? 0 : 4); |
|
|
|
} |
|
|
|
|
|
|
|
static void processflames(void) { |
|
|
|
flame *fl,*fl2; |
|
|
|
|
|
|
|
fl=activeflames.next; |
|
|
|
while(fl) { |
|
|
|
++(fl->timer); |
|
|
|
fl=fl->next; |
|
|
|
} |
|
|
|
fl=activeflames.next; |
|
|
|
while(fl) { |
|
|
|
if(fl->timer==FLAMELIFE) |
|
|
|
{ |
|
|
|
field[fl->py][fl->px]=FIELD_EMPTY; |
|
|
|
info[fl->py][fl->px]=0; |
|
|
|
fl2=fl; |
|
|
|
fl=fl->next; |
|
|
|
delink(&activeflames,fl2); |
|
|
|
} else |
|
|
|
fl=fl->next; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
static void processdecays() { |
|
|
|
brickdecay *bd,*bd2; |
|
|
|
|
|
|
|
bd=activedecays.next; |
|
|
|
while(bd) { |
|
|
|
++(bd->timer); |
|
|
|
if(bd->timer==DECAYLIFE) { |
|
|
|
field[bd->py][bd->px]=FIELD_EMPTY; |
|
|
|
trybonus(bd->px,bd->py); |
|
|
|
bd2=bd; |
|
|
|
bd=bd->next; |
|
|
|
delink(&activedecays,bd2); |
|
|
|
} else |
|
|
|
bd=bd->next; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
static void drawbombs(void) { |
|
|
|
int j; |
|
|
|
bomb *bmb; |
|
|
|
struct figure *figtab; |
|
|
|
int color; |
|
|
|
int xpos,ypos; |
|
|
|
|
|
|
|
bmb=activebombs.next; |
|
|
|
while(bmb) { |
|
|
|
color=bmb->owner->color; |
|
|
|
figtab=(bmb->type==BOMB_NORMAL) ? bombs1[color] : bombs2[color]; |
|
|
|
j=bmb->figcount % (NUMBOMBFRAMES<<1); |
|
|
|
if(j>=NUMBOMBFRAMES) j=(NUMBOMBFRAMES<<1)-j-1; |
|
|
|
xpos=tovideox(bmb->xpos); |
|
|
|
ypos=tovideoy(bmb->ypos)-3; |
|
|
|
|
|
|
|
addsprite(xpos,ypos,figtab+j); |
|
|
|
bmb=bmb->next; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
static void drawflames(void) { |
|
|
|
flame *fl; |
|
|
|
int xpos,ypos; |
|
|
|
int color; |
|
|
|
int fig; |
|
|
|
|
|
|
|
fl=activeflames.next; |
|
|
|
while(fl) { |
|
|
|
color=fl->owner->color; |
|
|
|
xpos=tovideox(fl->xpos); |
|
|
|
ypos=tovideoy(fl->ypos); |
|
|
|
fig=(fl->timer*10)/FLAMELIFE; |
|
|
|
if(fig>=5) fig=9-fig; |
|
|
|
fig+=5*fl->lurd; |
|
|
|
addsprite(xpos,ypos,flamefigs[0/* color */]+fig); |
|
|
|
fl=fl->next; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
static void drawdecays() { |
|
|
|
brickdecay *bd; |
|
|
|
|
|
|
|
bd=activedecays.next; |
|
|
|
while(bd) { |
|
|
|
addsprite(tovideox(bd->xpos),tovideoy(bd->ypos), |
|
|
|
blocksx+(bd->timer*9)/DECAYLIFE); |
|
|
|
bd=bd->next; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
static void drawbonus() { |
|
|
|
bonustile *bonus; |
|
|
|
|
|
|
|
bonus=activebonus.next; |
|
|
|
while(bonus) { |
|
|
|
addsprite(tovideox(bonus->xpos),tovideoy(bonus->ypos), |
|
|
|
tiles+bonus->type); |
|
|
|
bonus=bonus->next; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
static void drawplayers() { |
|
|
|
player *pl; |
|
|
|
int xpos,ypos; |
|
|
|
|
|
|
|
pl=activeplayers.next; |
|
|
|
|
|
|
|
while(pl) { |
|
|
|
if(!(pl->flags & FLG_DEAD)) { |
|
|
|
if(!pl->figure) |
|
|
|
pl->figure=walking[pl->color]+30; |
|
|
|
xpos=tovideox(pl->xpos)+pl->fixx; |
|
|
|
ypos=tovideoy(pl->ypos)+pl->fixy; |
|
|
|
addsprite(xpos,ypos,pl->figure); |
|
|
|
} |
|
|
|
pl=pl->next; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
static void detonatecontrolled(player *pl) { |
|
|
|
bomb *bmb; |
|
|
|
|
|
|
|
bmb=activebombs.next; |
|
|
|
while(bmb) { |
|
|
|
if(bmb->owner==pl && bmb->type==BOMB_CONTROLLED) |
|
|
|
adddetonate(bmb); |
|
|
|
bmb=bmb->next; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
static void playonce(generic *gen) { |
|
|
|
if(gen->timer==gen->data1) |
|
|
|
delink(&activegeneric,gen); |
|
|
|
} |
|
|
|
|
|
|
|
static void drawgeneric(generic *gen) { |
|
|
|
addsprite(gen->xpos,gen->ypos,((figure *)(gen->ptr1))+gen->timer); |
|
|
|
} |
|
|
|
|
|
|
|
static void queuesequence(int xpos,int ypos,figure *fig,int count) { |
|
|
|
generic *gen; |
|
|
|
|
|
|
|
gen=allocentry(); |
|
|
|
if(!gen) return; |
|
|
|
gen->xpos=xpos; |
|
|
|
gen->ypos=ypos; |
|
|
|
gen->data1=count; |
|
|
|
gen->process=playonce; |
|
|
|
gen->draw=drawgeneric; |
|
|
|
gen->ptr1=fig; |
|
|
|
addtail(&activegeneric,gen); |
|
|
|
} |
|
|
|
|
|
|
|
static void adddeath(player *pl) { |
|
|
|
int xpos,ypos; |
|
|
|
|
|
|
|
xpos=tovideox(pl->xpos)+pl->fixx-10; |
|
|
|
ypos=tovideoy(pl->ypos)+pl->fixy; |
|
|
|
queuesequence(xpos,ypos,death,NUMDEATHFRAMES); |
|
|
|
} |
|
|
|
|
|
|
|
static void killplayer(player *pl) { |
|
|
|
pl->flags|=FLG_DEAD; |
|
|
|
playsound(2); |
|
|
|
adddeath(pl); |
|
|
|
detonatecontrolled(pl); |
|
|
|
} |
|
|
|
|
|
|
|
static void processgenerics(void) { |
|
|
|
generic *gen,*gen2; |
|
|
|
|
|
|
|
gen=activegeneric.next; |
|
|
|
while(gen) { |
|
|
|
gen2=gen; |
|
|
|
gen=gen->next; |
|
|
|
++(gen2->timer); |
|
|
|
gen2->process(gen2); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
static void drawgenerics(void) { |
|
|
|
generic *gen; |
|
|
|
|
|
|
|
gen=activegeneric.next; |
|
|
|
while(gen) { |
|
|
|
gen->draw(gen); |
|
|
|
gen=gen->next; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
static int centerxchange(player *pl) { |
|
|
|
int speed; |
|
|
|
int val; |
|
|
|
int line; |
|
|
|
int max; |
|
|
|
|
|
|
|
max=arrayspacex<<FRACTION; |
|
|
|
speed=pl->speed; |
|
|
|
val=pl->xpos+(max<<2); |
|
|
|
val%=max; |
|
|
|
line=max>>1; |
|
|
|
if(val<line) { |
|
|
|
if(val-speed<0) |
|
|
|
return -val; |
|
|
|
else |
|
|
|
return -speed; |
|
|
|
} else if(val>=line) { |
|
|
|
if(val+speed>max) |
|
|
|
return max-val; |
|
|
|
else |
|
|
|
return speed; |
|
|
|
} |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
static void centerx(player *pl) { |
|
|
|
pl->xpos+=centerxchange(pl); |
|
|
|
} |
|
|
|
|
|
|
|
static int centerychange(player *pl) { |
|
|
|
int speed; |
|
|
|
int val; |
|
|
|
int line; |
|
|
|
int max; |
|
|
|
|
|
|
|
max=arrayspacey<<FRACTION; |
|
|
|
speed=pl->speed; |
|
|
|
val=pl->ypos+(max<<2); |
|
|
|
val%=max; |
|
|
|
line=max>>1; |
|
|
|
if(val<line) |
|
|
|
{ |
|
|
|
if(val-speed<0) |
|
|
|
return -val; |
|
|
|
else |
|
|
|
return -speed; |
|
|
|
} else if(val>=line) |
|
|
|
{ |
|
|
|
if(val+speed>max) |
|
|
|
return max-val; |
|
|
|
else |
|
|
|
return speed; |
|
|
|
} |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
static void centery(player *pl) { |
|
|
|
pl->ypos+=centerychange(pl); |
|
|
|
} |
|
|
|
|
|
|
|
#define SGN(x) ((x)==0 ? 0 : ((x)<0 ? -1 : 1)) |
|
|
|
|
|
|
|
static void trymove(player *pl,int dx,int dy) { |
|
|
|
int wx,wy; |
|
|
|
int sx,sy; |
|
|
|
int there; |
|
|
|
int px,py; |
|
|
|
static int depth=0; |
|
|
|
int tx,ty; |
|
|
|
|
|
|
|
++depth; |
|
|
|
sx=(dx*(arrayspacex+1)) << (FRACTION-1); |
|
|
|
sy=(dy*(arrayspacey+1)) << (FRACTION-1); |
|
|
|
|
|
|
|
wx=screentoarrayx(pl->xpos+sx); |
|
|
|
wy=screentoarrayy(pl->ypos+sy); |
|
|
|
px=screentoarrayx(pl->xpos); |
|
|
|
py=screentoarrayy(pl->ypos); |
|
|
|
|
|
|
|
if(wx<0 || wx>=arraynumx || wy<0 || wy>=arraynumy) { |
|
|
|
--depth; |
|
|
|
return; |
|
|
|
} |
|
|
|
there=field[wy][wx]; |
|
|
|
if((px!=wx || py!=wy) && |
|
|
|
(there==FIELD_BRICK||there==FIELD_BOMB||there==FIELD_BORDER)) |
|
|
|
{ |
|
|
|
if(dx && !dy) { |
|
|
|
ty=centerychange(pl); |
|
|
|
if(ty && depth==1) |
|
|
|
trymove(pl,0,-SGN(ty)); |
|
|
|
|
|
|
|
} else if(dy && !dx) { |
|
|
|
tx=centerxchange(pl); |
|
|
|
if(tx && depth==1) |
|
|
|
trymove(pl,-SGN(tx),0); |
|
|
|
} |
|
|
|
|
|
|
|
} else { |
|
|
|
pl->xpos+=dx*pl->speed; |
|
|
|
pl->ypos+=dy*pl->speed; |
|
|
|
if(dx && !dy) centery(pl); |
|
|
|
if(dy && !dx) centerx(pl); |
|
|
|
} |
|
|
|
--depth; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void applybonus(player *pl,bonustile *bonus) { |
|
|
|
int type; |
|
|
|
int maxflame; |
|
|
|
|
|
|
|
maxflame=arraynumx>arraynumy ? arraynumx : arraynumy; |
|
|
|
type=bonus->type; |
|
|
|
deletebonus(bonus); |
|
|
|
switch(type) |
|
|
|
{ |
|
|
|
case TILE_BOMB: |
|
|
|
++(pl->bombsavailable); |
|
|
|
break; |
|
|
|
case TILE_FLAME: |
|
|
|
if(pl->flamelength<maxflame) |
|
|
|
++(pl->flamelength); |
|
|
|
break; |
|
|
|
case TILE_GOLDFLAME: |
|
|
|
pl->flamelength=maxflame; |
|
|
|
break; |
|
|
|
case TILE_CONTROL: |
|
|
|
pl->flags|=FLG_CONTROL; |
|
|
|
break; |
|
|
|
case TILE_SKATES: |
|
|
|
if (pl->speed < SPEEDSTART) { |
|
|
|
pl->speed = SPEEDSTART; |
|
|
|
} else { |
|
|
|
pl->speed+=SPEEDDELTA; |
|
|
|
} |
|
|
|
if(pl->speed>SPEEDMAX) pl->speed=SPEEDMAX; |
|
|
|
break; |
|
|
|
case TILE_TURTLE: |
|
|
|
pl->speed=SPEEDTURTLE; |
|
|
|
pl->speedturtle_timeout=SPEEDTURTLE_TIMEOUT; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|