
21 changed files with 2755 additions and 2541 deletions
@ -0,0 +1,34 @@
|
||||
----------------- Left to do: ------------------- |
||||
Come up with a better scheme for internet play, as it is any latency will |
||||
kill the game playability. Works fine on LAN though. |
||||
|
||||
Figure out why matching doesn't work through a firewall... |
||||
[Specific case is 2 machines on my LAN cannot be matched by a machine that |
||||
is outside the firewall, and the firewall machine is doing IP masquerading. |
||||
Net result is matcher gets remapped IP addresses and these mean nothing |
||||
inside the LAN, only make sense when used from the outside world] |
||||
|
||||
Score. |
||||
|
||||
Remap movement keys not implemented. |
||||
|
||||
Allow game hoster to set network game options and have them visible to players |
||||
who have joined the game. |
||||
|
||||
Alternate gfx sets. |
||||
|
||||
Better handling of 8 bit mode with limited palette. |
||||
|
||||
Computer controlled things that can kill you. |
||||
|
||||
Other bonus types that can be harmful, such as skull. |
||||
|
||||
Internet play where everything is asynchronous, thus playable with a fixed |
||||
latency. As it is now slaves send to master, then master sends back to |
||||
slaves, and this data xfer must complete before the game can advance a step. |
||||
For internet this would be intolerable. I've never tried though... |
||||
|
||||
Better docs, online explanations, attract mode... |
||||
|
||||
Single player with computer controlled figures that must be killed/avoided. |
||||
|
@ -0,0 +1,448 @@
|
||||
|
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
#include <unistd.h> |
||||
#include <string.h> |
||||
#include <sys/types.h> |
||||
#include <netdb.h> |
||||
#include <sys/socket.h> |
||||
#include <sys/time.h> |
||||
#include <signal.h> |
||||
#include <fcntl.h> |
||||
#include <stdarg.h> |
||||
|
||||
#include "bomber.h" |
||||
#include "draw.h" |
||||
#include "game.h" |
||||
#include "gfx.h" |
||||
#include "utils.h" |
||||
|
||||
#ifndef DATADIR |
||||
#define DATADIR "data" |
||||
#endif |
||||
|
||||
#define NUMCHARACTERS 50 |
||||
|
||||
static figure font[NUMCHARACTERS]; |
||||
static figure bigfont[NUMCHARACTERS]; |
||||
|
||||
gfxset gfxsets[NUMGFX]; |
||||
static char walkingname[256]; |
||||
static char colorsetname[256]; |
||||
static char backgroundname[256]; |
||||
static char blocksname[256]; |
||||
static char blocksxname[256]; |
||||
static char bombs1name[256]; |
||||
static char bombs2name[256]; |
||||
static char flamesname[256]; |
||||
static char tilesname[256]; |
||||
static char deathname[256]; |
||||
static char fontname[256]; |
||||
static char bigfontname[256]; |
||||
|
||||
figure blocks[3]; |
||||
figure blocksx[9]; |
||||
figure bombs1[MAXSETS][NUMBOMBFRAMES]; |
||||
figure bombs2[MAXSETS][NUMBOMBFRAMES]; |
||||
figure flamefigs[MAXSETS][NUMFLAMEFRAMES]; |
||||
figure tiles[15]; |
||||
figure death[NUMDEATHFRAMES]; |
||||
|
||||
int fontxsize,fontysize; |
||||
int bigfontxsize,bigfontysize,bigfontyspace; |
||||
|
||||
static int textx,texty; |
||||
|
||||
static char *remapstring="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ.:!?\177/\\*-,>< ="; |
||||
static char asciiremap[256]; |
||||
|
||||
/* On screen array variables */ |
||||
int arraynumx=15; |
||||
int arraynumy=11; |
||||
int arraystartx=20; |
||||
int arraystarty=70; |
||||
int arrayspacex=40; |
||||
int arrayspacey=36; |
||||
|
||||
static sprite sprites[MAXSPRITES]; |
||||
static int spritesused=0; |
||||
|
||||
#define IBUFFLEN 1024 |
||||
int ileft=0,ihand=0,byteswide; |
||||
unsigned char ibuff[IBUFFLEN],*itake; |
||||
|
||||
static void freegfxset(gfxset *gs) { |
||||
if(gs->gs_pic) free(gs->gs_pic); |
||||
gs->gs_pic=0; |
||||
} |
||||
|
||||
static int myci() { |
||||
if (!ileft) { |
||||
ileft=read(ihand,ibuff,IBUFFLEN); |
||||
|
||||
if(!ileft) return -1; |
||||
itake=ibuff; |
||||
} |
||||
ileft--; |
||||
return *itake++; |
||||
} |
||||
|
||||
static int dopcxreal(char *name,gfxset *gs) { |
||||
int xs,ys; |
||||
int i,j,k; |
||||
int totalsize; |
||||
int width,height; |
||||
unsigned char *bm,*lp; |
||||
char tname[256]; |
||||
|
||||
memset(gs,0,sizeof(gfxset)); |
||||
ileft=0; |
||||
sprintf(tname,DATADIR "/%s",name); |
||||
ihand=open(tname,O_RDONLY); |
||||
if(ihand<0) { |
||||
char tname2[256]; |
||||
sprintf(tname2,"%s.pcx",tname); |
||||
ihand=open(tname2,O_RDONLY); |
||||
if(ihand<0) |
||||
return 1; |
||||
} |
||||
if(myci()!=10) {close(ihand);return 2;} // 10=zsoft .pcx
|
||||
if(myci()!=5) {close(ihand);return 3;} // version 3.0
|
||||
if(myci()!=1) {close(ihand);return 4;} //encoding method
|
||||
if(myci()!=8) {close(ihand);return 5;} //bpp
|
||||
xs=myci(); |
||||
xs|=myci()<<8; |
||||
ys=myci(); |
||||
ys|=myci()<<8; |
||||
width=myci(); |
||||
width|=myci()<<8; |
||||
height=myci(); |
||||
height|=myci()<<8; |
||||
width=width+1-xs; |
||||
height=height+1-ys; |
||||
for(i=0;i<48+4;++i) myci(); |
||||
myci(); |
||||
if(myci()!=1) {close(ihand);return 6;} // # of planes
|
||||
byteswide=myci(); |
||||
byteswide|=myci()<<8; |
||||
i=myci(); |
||||
i|=myci()<<8; |
||||
// if(i!=1) {close(ihand);return 7;} // 1=color/bw,2=grey
|
||||
for(i=0;i<58;++i) myci(); |
||||
totalsize=height*byteswide; |
||||
bm=malloc(totalsize+1); |
||||
if(!bm) {close(ihand);return 8;} // no memory
|
||||
gs->gs_pic=bm; |
||||
gs->gs_xsize=width; |
||||
gs->gs_ysize=height; |
||||
while(height--) { |
||||
lp=bm; |
||||
i=byteswide; |
||||
while(i>0) { |
||||
j=myci(); |
||||
if(j<0xc0) { |
||||
*lp++=j; |
||||
--i; |
||||
} else { |
||||
j&=0x3f; |
||||
k=myci(); |
||||
while(j-- && i) { |
||||
*lp++=k; |
||||
--i; |
||||
} |
||||
} |
||||
} |
||||
bm+=width; |
||||
} |
||||
lseek(ihand,-0x300,SEEK_END); |
||||
read(ihand,gs->gs_colormap,0x300); |
||||
close(ihand); |
||||
return 0; |
||||
} |
||||
|
||||
static int dopcx(char *name,gfxset *gs) { |
||||
int err; |
||||
|
||||
err=dopcxreal(name,gs); |
||||
if(err) |
||||
printf("Error loading \"%s\":code %d\n",name,err); |
||||
return err; |
||||
} |
||||
|
||||
static void getgroup(char *name,gfxset *colorgs,figure *fig,int count) { |
||||
int err; |
||||
int i; |
||||
gfxset gs; |
||||
|
||||
err=dopcx(name,&gs); |
||||
if(err) exit(1000+err); |
||||
createinout(&gs); |
||||
for(i=0;i<MAXSETS;++i,fig+=count,++colorgs) { |
||||
if(!colorgs->gs_pic) continue; |
||||
memmove(gs.gs_colormap,colorgs->gs_colormap, |
||||
sizeof(gs.gs_colormap)); |
||||
createinout(&gs); |
||||
gfxfetch(&gs,fig,count); |
||||
} |
||||
freegfxset(&gs); |
||||
} |
||||
|
||||
static void getsingle(char *name,figure *fig,int count) { |
||||
gfxset gs; |
||||
int err; |
||||
|
||||
err=dopcx(name,&gs); |
||||
if(err) exit(1000+err); |
||||
createinout(&gs); |
||||
gfxfetch(&gs,fig,count); |
||||
freegfxset(&gs); |
||||
} |
||||
|
||||
static void texthome(void) { |
||||
textx=texty=10; |
||||
} |
||||
|
||||
// static void drawstring(int xpos,int ypos,char *str) {
|
||||
// char ch;
|
||||
//
|
||||
// while((ch=*str++)) {
|
||||
// drawfigure(xpos,ypos,font+asciiremap[toupper(ch)]);
|
||||
// xpos+=fontxsize;
|
||||
// }
|
||||
// }
|
||||
|
||||
void drawbigstring(int xpos,int ypos,char *str) { |
||||
char ch; |
||||
|
||||
while('\0' != (ch=*str++)) { |
||||
drawfigure(xpos,ypos,bigfont+asciiremap[toupper(ch)]); |
||||
xpos+=bigfontxsize; |
||||
} |
||||
} |
||||
|
||||
void centerbig(int y,char *str) { |
||||
int w; |
||||
|
||||
w=strlen(str)*bigfontxsize; |
||||
drawbigstring((IXSIZE-w)>>1,y,str); |
||||
} |
||||
|
||||
// static void scrprintf(char *str,...) {
|
||||
// char output[256],*p,*p2;
|
||||
// va_list ap;
|
||||
//
|
||||
// va_start(ap, str);
|
||||
//
|
||||
// vsprintf(output,str,ap);
|
||||
// p=output;
|
||||
// for(;;) {
|
||||
// p2=p;
|
||||
// while(*p2 && *p2!='\n') ++p2;
|
||||
// if(*p2) {
|
||||
// *p2=0;
|
||||
// drawstring(textx,texty,p);
|
||||
// texty+=fontysize;
|
||||
// textx=10;
|
||||
// p=p2+1;
|
||||
// } else {
|
||||
// drawstring(textx,texty,p);
|
||||
// textx+=fontxsize*(p2-p);
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// copyup();
|
||||
// }
|
||||
|
||||
static void bigscrprintf(char *str,...) { |
||||
char output[256],*p,*p2; |
||||
va_list ap; |
||||
|
||||
va_start(ap, str); |
||||
vsprintf(output,str,ap); |
||||
p=output; |
||||
for(;;) { |
||||
p2=p; |
||||
while(*p2 && *p2!='\n') ++p2; |
||||
if(*p2) { |
||||
*p2=0; |
||||
drawbigstring(textx,texty,p); |
||||
texty+=bigfontysize; |
||||
textx=10; |
||||
p=p2+1; |
||||
} else { |
||||
drawbigstring(textx,texty,p); |
||||
textx+=bigfontxsize*(p2-p); |
||||
break; |
||||
} |
||||
} |
||||
copyup(); |
||||
} |
||||
|
||||
void addsprite(int x,int y,figure *fig) { |
||||
sprite *sp; |
||||
|
||||
if(spritesused==MAXSPRITES) return; |
||||
sp=sprites+spritesused++; |
||||
sp->flags=0; |
||||
sp->xpos=x; |
||||
sp->ypos=y; |
||||
sp->fig=fig; |
||||
} |
||||
|
||||
void plotsprites(void) { |
||||
int i; |
||||
sprite *sp; |
||||
|
||||
sp=sprites; |
||||
for(i=0;i<spritesused;++i) { |
||||
drawfigure(sp->xpos,sp->ypos,sp->fig); |
||||
++sp; |
||||
} |
||||
} |
||||
|
||||
void erasesprites(void) { |
||||
int i; |
||||
sprite *sp; |
||||
figure *fig; |
||||
|
||||
sp=sprites; |
||||
for(i=0;i<spritesused;++i) { |
||||
fig=sp->fig; |
||||
|
||||
solidcopy(&background, |
||||
sp->xpos+fig->xdelta,sp->ypos+fig->ydelta, |
||||
fig->xsize,fig->ysize); |
||||
++sp; |
||||
} |
||||
} |
||||
|
||||
void clearsprites(void) { |
||||
int i; |
||||
sprite *sp; |
||||
figure *fig; |
||||
|
||||
sp=sprites; |
||||
for(i=0;i<spritesused;++i) { |
||||
fig=sp->fig; |
||||
|
||||
clearrect(sp->xpos+fig->xdelta,sp->ypos+fig->ydelta, |
||||
fig->xsize,fig->ysize); |
||||
++sp; |
||||
} |
||||
} |
||||
|
||||
void clearspritelist(void) { |
||||
spritesused=0; |
||||
} |
||||
|
||||
int tovideox(int x) { |
||||
return (x>>FRACTION)+arraystartx; |
||||
} |
||||
|
||||
int tovideoy(int y) { |
||||
return (y>>FRACTION)+arraystarty; |
||||
} |
||||
|
||||
int screentoarrayx(int x) { |
||||
x+=arrayspacex << (FRACTION+2); |
||||
return ((x>>FRACTION)+(arrayspacex>>1))/arrayspacex-4; |
||||
} |
||||
|
||||
int screentoarrayy(int y) { |
||||
y+=arrayspacey << (FRACTION+2); |
||||
return ((y>>FRACTION)+(arrayspacey>>1))/arrayspacey-4; |
||||
} |
||||
|
||||
int arraytoscreenx(int x) { |
||||
return arrayspacex*x<<FRACTION; |
||||
} |
||||
|
||||
int arraytoscreeny(int y) { |
||||
return arrayspacey*y<<FRACTION; |
||||
} |
||||
|
||||
static void loadfonts(void) { |
||||
int i,j; |
||||
char *p; |
||||
|
||||
getsingle(fontname,font,NUMCHARACTERS); |
||||
getsingle(bigfontname,bigfont,NUMCHARACTERS); |
||||
fontxsize=8; |
||||
fontysize=12; |
||||
bigfontxsize=16; |
||||
bigfontysize=24; |
||||
bigfontyspace=32; |
||||
p=remapstring; |
||||
j=0;while(*p && *p!=' ') ++p,++j; |
||||
memset(asciiremap,j,sizeof(asciiremap)); |
||||
p=remapstring; |
||||
i=0; |
||||
while(*p && i<40) |
||||
asciiremap[(int)*p++]=i++; |
||||
} |
||||
|
||||
void loadgfx() { |
||||
gfxset *gs; |
||||
gfxset *colorgs; |
||||
int err; |
||||
int i; |
||||
char name[256]; |
||||
|
||||
strcpy(walkingname,"walk"); |
||||
strcpy(colorsetname,"pal"); |
||||
strcpy(backgroundname,"field0"); |
||||
strcpy(blocksname,"blocks3"); |
||||
strcpy(blocksxname,"blocks3x"); |
||||
strcpy(bombs1name,"bomb1"); |
||||
strcpy(bombs2name,"bomb2"); |
||||
strcpy(flamesname,"flames"); |
||||
strcpy(tilesname,"tiles"); |
||||
strcpy(deathname,"death1"); |
||||
strcpy(fontname,"font"); |
||||
strcpy(bigfontname,"bigfont"); |
||||
|
||||
gs=malloc((MAXSETS+1)*sizeof(gfxset)); |
||||
if(!gs) |
||||
nomem("loadgfx"); |
||||
colorgs=gs+1; |
||||
|
||||
for(i=0;i<MAXSETS;++i) { |
||||
sprintf(name,"%s%d",colorsetname,i); |
||||
err=dopcx(name,colorgs+i); |
||||
if(err) continue; |
||||
} |
||||
|
||||
loadfonts(); |
||||
texthome(); |
||||
bigscrprintf("Loading graphics...\n"); |
||||
|
||||
err=dopcx(backgroundname,gs); |
||||
if(err) exit(1000+err); |
||||
createinout(gs); |
||||
solidfetch(gs,&background); |
||||
solidfetch(gs,&backgroundoriginal); |
||||
freegfxset(gs); |
||||
|
||||
bigscrprintf("Loading blocks\n"); |
||||
getsingle(blocksname,blocks,3); |
||||
bigscrprintf("Loading block explosions\n"); |
||||
getsingle(blocksxname,blocksx,9); |
||||
bigscrprintf("Loading walking figures\n"); |
||||
getgroup(walkingname,colorgs,walking[0],NUMWALKFRAMES); |
||||
bigscrprintf("Loading normal bombs\n"); |
||||
getgroup(bombs1name,colorgs,bombs1[0],NUMBOMBFRAMES); |
||||
bigscrprintf("Loading controlled bombs\n"); |
||||
getgroup(bombs2name,colorgs,bombs2[0],NUMBOMBFRAMES); |
||||
bigscrprintf("Loading flames\n"); |
||||
// getgroup(flamesname,colorgs,flamefigs[0],NUMFLAMEFRAMES);
|
||||
getsingle(flamesname,flamefigs[0],NUMFLAMEFRAMES); |
||||
bigscrprintf("Loading bonus tiles\n"); |
||||
getsingle(tilesname,tiles,15); |
||||
bigscrprintf("Loading death sequence\n"); |
||||
getsingle(deathname,death,NUMDEATHFRAMES); |
||||
|
||||
for(i=0;i<MAXSETS;++i) |
||||
freegfxset(colorgs+i); |
||||
free(gs); |
||||
bigscrprintf("Done loading graphics\n"); |
||||
} |
@ -0,0 +1,38 @@
|
||||
#ifndef DRAW_H |
||||
#define DRAW_H |
||||
|
||||
void loadgfx(void); |
||||
|
||||
void drawbigstring(int xpos,int ypos,char *str); |
||||
|
||||
void centerbig(int y,char *str); |
||||
|
||||
void addsprite(int x,int y,figure *fig); |
||||
void plotsprites(void); |
||||
void erasesprites(void); |
||||
void clearsprites(void); |
||||
void clearspritelist(void); |
||||
|
||||
int tovideox(int x); |
||||
int tovideoy(int y); |
||||
|
||||
int screentoarrayx(int x); |
||||
int screentoarrayy(int y); |
||||
int arraytoscreenx(int x); |
||||
int arraytoscreeny(int y); |
||||
|
||||
extern int bigfontxsize,bigfontysize,bigfontyspace; |
||||
|
||||
/* On screen array variables */ |
||||
extern int arraynumx, arraynumy, arraystartx, arraystarty, arrayspacex, arrayspacey; |
||||
|
||||
/* Animation specific #defines */ |
||||
#define NUMBOMBFRAMES 10 |
||||
#define NUMWALKFRAMES 60 |
||||
#define NUMFLAMEFRAMES 80 |
||||
#define NUMDEATHFRAMES 41 |
||||
|
||||
|
||||
extern figure blocks[3], blocksx[9], bombs1[MAXSETS][NUMBOMBFRAMES], bombs2[MAXSETS][NUMBOMBFRAMES], flamefigs[MAXSETS][NUMFLAMEFRAMES], tiles[15], death[NUMDEATHFRAMES]; |
||||
|
||||
#endif |
@ -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; |