#include #include #include #include #include #include #include #include #include #include #include #include "bomber.h" #include "gfx.h" #include #include #include "announce.h" static void domode(void); static int iterate(void); static int scaninvite(int size); #define FRACTION 9 #define MAXMSG 4096 #define PORT 5521 #define SPEEDDELTA (1<<(FRACTION-1)) #define SPEEDMAX (10<>8; } p=myrandblock+14; msk=0xff; msb=0x80; do { *p&=msk; *p|=msb; p+=11; msk>>=1; msb>>=1; } while(msk); i=500; while(i--) myrand(); } #if defined (TEST_LATENCY) #define NUMQ 512 struct message { int time; struct sockaddr_in *to; int tosize; unsigned char msg[512]; int len; } message[NUMQ]={0}; outmsgs() { int i; for(i=0;i>FRACTION)+arraystartx; } static int tovideoy(int y) { return (y>>FRACTION)+arraystarty; } #define SGN(x) ((x)==0 ? 0 : ((x)<0 ? -1 : 1)) static int screentoarrayx(int x) { x+=arrayspacex << (FRACTION+2); return ((x>>FRACTION)+(arrayspacex>>1))/arrayspacex-4; } static int screentoarrayy(int y) { y+=arrayspacey << (FRACTION+2); return ((y>>FRACTION)+(arrayspacey>>1))/arrayspacey-4; } static int arraytoscreenx(int x) { return arrayspacex*x<0) { j=actionput-i-1; if(j<0) j+=ACTIONHIST; memmove(p,hist[j],MAXNETNODES); } else { memset(p,0,MAXNETNODES); } p+=MAXNETNODES; ++i; } } static void sendactions(int which) { unsigned char msg[512]; *msg = PKT_STEP; memmove(msg+1,regpacket+1,4); msg[5]=actioncount>>24L; msg[6]=actioncount>>16L; msg[7]=actioncount>>8L; msg[8]=actioncount; memcpy(msg+9,actionblock,MAXNETNODES*ACTIONHIST); putmsg(&netnodes[which].netname,msg,MAXNETNODES*ACTIONHIST+9); } static void sendmine(int frame) { unsigned char msg[64]; *msg = PKT_MYDATA; memmove(msg+1,regpacket+1,4); msg[5]=frame>>24L; msg[6]=frame>>16L; msg[7]=frame>>8L; msg[8]=frame; msg[9]=myaction; putmsg(&mastername,msg,10); } static int informsize; static void buildinform(unsigned char type) { unsigned char *put; int i; put=mesg; *put++=type; memmove(put,regpacket+1,4); put+=4; ++put; // slot specific for each slave for (i = 0; i < MAXNETNODES; ++i) { if(!netnodes[i].used) continue; *put++=i; memmove(put,netnodes[i].name,16); put+=16; } *put++=0xff; memcpy(put, configopts, sizeof(configopts)); put += sizeof(configopts); informsize=put-mesg; } static void inform1(int which) { mesg[5]=which; putmsg(&netnodes[which].netname,mesg,informsize); } static void inform(unsigned char type) { int i; buildinform(type); for(i=1;i15) break; if(!netframe && gtime()-now>=2000) { for(i=1;i0 && *mesg!=PKT_MYDATA) printf("Strange packet %d\n",*mesg); // check for unexpected old packets... // for example JOIN on frame 0, respond with BEGIN if player already in game // respond with uninvite INVITE on JOIN from others if(length<10) continue; whosent=isvalidmsg(); if(whosent<=0) continue; count=longind(mesg+5); if(count>latestcounts[whosent]) { latestcounts[whosent]=count; newactions[whosent]=mesg[9]; } } if(myaction==ACT_QUIT) { for(i=1;i=1) { lastsent=gtime(); sendmine(mydatacount); } */ if(latest>=0 && gtime()-now>3) break; length=getmsg(3); if(length==MAXNETNODES*ACTIONHIST+9 && sender.sin_addr.s_addr==mastername.sin_addr.s_addr && sender.sin_port==mastername.sin_port) { i=longind(mesg+5); if(igs_pic) free(gs->gs_pic); gs->gs_pic=0; } static void nomem(char *str) { printf("No memory!!![%s]\n",str); exit(1); } 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;igs_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 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++; } static 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>1,y,str); } static 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 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((ch=*str++)) { drawfigure(xpos,ypos,bigfont+asciiremap[toupper(ch)]); xpos+=bigfontxsize; } } #define IBUFFLEN 1024 int ileft=0,ihand=0,byteswide; unsigned char ibuff[IBUFFLEN],*itake; 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,"data/%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; } 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 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(pxlurd|=FL_RIGHT; fl2->lurd|=FL_LEFT; } if(pylurd|=FL_DOWN; fl2->lurd|=FL_UP; } } 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 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; } } 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; } 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; } } } 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 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 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 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; } } 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 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 drawdecays() { brickdecay *bd; bd=activedecays.next; while(bd) { addsprite(tovideox(bd->xpos),tovideoy(bd->ypos), blocksx+(bd->timer*9)/DECAYLIFE); bd=bd->next; } } int bonustotal; int bonuschances[]= { TILE_BOMB,20, TILE_FLAME,20, TILE_CONTROL,2, TILE_GOLDFLAME,2, TILE_SKATES,20, TILE_TURTLE,5, TILE_NONE,160 }; void trybonus(int px,int py) { int i=0, *p,r; 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); } void deletebonus(bonustile *bonus) { int px,py; px=bonus->px; py=bonus->py; field[py][px]=0; info[py][px]=0; delink(&activebonus,bonus); } 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 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; } } void killplayer(player *pl) { pl->flags|=FLG_DEAD; playsound(2); adddeath(pl); detonatecontrolled(pl); } 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); } 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); } void playonce(generic *gen) { if(gen->timer==gen->data1) delink(&activegeneric,gen); } void drawgeneric(generic *gen) { addsprite(gen->xpos,gen->ypos,((figure *)(gen->ptr1))+gen->timer); } void processgenerics(void) { generic *gen,*gen2; gen=activegeneric.next; while(gen) { gen2=gen; gen=gen->next; ++(gen2->timer); gen2->process(gen2); } } void drawgenerics(void) { generic *gen; gen=activegeneric.next; while(gen) { gen->draw(gen); gen=gen->next; } } static void plotsprites(void) { int i; sprite *sp; figure *fig; sp=sprites; for(i=0;ifig; drawfigure(sp->xpos,sp->ypos,fig); ++sp; } } static void erasesprites(void) { int i; sprite *sp; figure *fig; sp=sprites; for(i=0;ifig; solidcopy(&background, sp->xpos+fig->xdelta,sp->ypos+fig->ydelta, fig->xsize,fig->ysize); ++sp; } } static void clearsprites(void) { int i; sprite *sp; figure *fig; sp=sprites; for(i=0;ifig; clearrect(sp->xpos+fig->xdelta,sp->ypos+fig->ydelta, fig->xsize,fig->ysize); ++sp; } } static void clearspritelist(void) { spritesused=0; } static int centerxchange(player *pl) { int speed; int val; int line; int max; max=arrayspacex<speed; val=pl->xpos+(max<<2); val%=max; line=max>>1; if(val=line) { if(val+speed>max) return max-val; else return speed; } return 0; } void centerx(player *pl) { pl->xpos+=centerxchange(pl); } static int centerychange(player *pl) { int speed; int val; int line; int max; max=arrayspacey<speed; val=pl->ypos+(max<<2); val%=max; line=max>>1; if(val=line) { if(val+speed>max) return max-val; else return speed; } return 0; } void centery(player *pl) { pl->ypos+=centerychange(pl); } 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->flamelengthflamelength); 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; } } static void doplayer(player *pl) { int last; int color; int speed; int px,py; int there; int flags; int what; if(pl->controller==-1) what=myaction; else what=actions[pl->controller]; flags=pl->flags; if(flags&FLG_DEAD) return; color=pl->color; last=pl->doing; pl->doing=what; speed=pl->speed; px=screentoarrayx(pl->xpos); py=screentoarrayy(pl->ypos); there=field[py][px]; if(what==ACT_QUIT) { killplayer(pl); return; } if(there==FIELD_BONUS) { playsound((myrand()&1) ? 1 : 5); applybonus(pl,info[py][px]); } else if(there==FIELD_FLAME) { killplayer(pl); return; } // if(what&ACT_TURBO) speed<<=2; if(what&ACT_PRIMARY) { if(there==FIELD_EMPTY && pl->bombsavailable) dropbomb(pl,px,py, (flags&FLG_CONTROL) ? BOMB_CONTROLLED :BOMB_NORMAL); } if(what&ACT_SECONDARY && (flags&FLG_CONTROL)) detonatecontrolled(pl); switch(what&ACT_MASK) { case ACT_UP: trymove(pl,0,-1); pl->figcount=(pl->figcount+1)%15; pl->figure=walking[color]+pl->figcount+15; break; case ACT_DOWN: trymove(pl,0,1); pl->figcount=(pl->figcount+1)%15; pl->figure=walking[color]+pl->figcount+30; break; case ACT_LEFT: trymove(pl,-1,0); pl->figcount=(pl->figcount+1)%15; pl->figure=walking[color]+pl->figcount+45; break; case ACT_RIGHT: trymove(pl,1,0); pl->figcount=(pl->figcount+1)%15; pl->figure=walking[color]+pl->figcount; break; case ACT_NONE: break; } if (pl->speedturtle_timeout > 0) { pl->speedturtle_timeout--; if (0 == pl->speedturtle_timeout) { if (pl->speed < SPEEDSTART) pl->speed = SPEEDSTART; } } } 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(xnext=(void *)p; first=p; } ((list *)first)->next=0; } void *allocentry() { list *entry; if(!(entry=((list *)things)->next)) return 0; ((list *)things)->next=entry->next; memset(entry,0,thingsize); return entry; } void freeentry(void *entry) { ((list *)entry)->next=((list *)things)->next; ((list *)things)->next=entry; } void addtail(void *header,void *entry) { while(((list *)header)->next) header=((list *)header)->next; ((list *)header)->next=entry; ((list *)entry)->next=0; } void delink(void *header,void *entry) { while(((list *)header)->next != entry) header=((list *)header)->next; ((list *)header)->next=((list *)entry)->next; ((list *)entry)->next=0; freeentry(entry); } static void allocthings() { if(!things) { thingsize=sizeof(bomb); if((int)sizeof(flame)>thingsize) thingsize=sizeof(flame); if((int)sizeof(brickdecay)>thingsize) thingsize=sizeof(brickdecay); if((int)sizeof(player)>thingsize) thingsize=sizeof(player); thingnum=MAXTHINGS; things=malloc(thingsize*thingnum); if(!things) nomem("Trying to allocate thing memory"); } initlist(things,thingsize,thingnum); } static void initheader(void *p) { memset(p,0,sizeof(list)); } static void firstzero(void) { gountil=mycount=mydatacount=0; memset(latestactions,0,sizeof(latestactions)); memset(latestcounts,0,sizeof(latestcounts)); actionput=actioncount=0; netframe=0; } static void zerocounts(void) { } static void initgame() { int i,j; int x,y; int bl; int *p; int comp; // gountil=mycount=mydatacount=netframe=0; zerocounts(); if (network != SLAVE) memmove(gameoptions,configopts,sizeof(gameoptions)); 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+=*p=64*(3-gameoptions[GO_GENEROSITY]); memset(field,0,sizeof(field)); comp=gameoptions[GO_DENSITY]; for(j=0;j=comp ? FIELD_BRICK : FIELD_EMPTY; } solidcopyany(&backgroundoriginal,&background,0,0,IXSIZE,IYSIZE); initplayers(); for(j=0;j> 1,20,menutitle); ty=((IYSIZE-(bigfontysize*menunum))>>1)-(IYSIZE>>3); for(i=0;i> 1; if(i==selected) { greyrect(0,ty-1,tx-5,bigfontysize); greyrect(tx+j+3,ty-1,IXSIZE-(tx+j+3),bigfontysize); } drawbigstring(tx,ty,menuitems[i]); ty+=bigfontyspace; } } static void drawjoinscreen(void) { int i; char name[17]; char temp[64]; #define JX (IXSIZE/3) #define JY (IYSIZE/4) clear(); centerbig(20,"JOIN NETWORK GAME"); drawbigstring(JX,JY,"SLOT NAME"); for(i=0;i=17) { if((i=*take)=0) selected=menuhistory[whichmenu]; else selected=0; redraw=1; clearspritelist(); pulseon(); while(!exitflag) { if(redraw) { drawmenu(selected); redraw=0; } mypause(); scaninput(); ++mcount; clearsprites(); clearspritelist(); addsprite(IXSIZE/2-50-20,IYSIZE-80,walking[2]+(30+mcount%15)); addsprite(IXSIZE/2+50-20,IYSIZE-80,walking[3]+(30+(mcount+7)%15)); plotsprites(); update(); if(anydown()) playsound(3); while(anydown()) switch(takedown()) { case MYLEFT: menudelta=-1; return selected; case MYRIGHT: case ' ': case 13: menudelta=1; return selected; case 'k': case MYUP: if(selected) --selected; else selected=menunum-1; if(whichmenu>=0) menuhistory[whichmenu]=selected; redraw=1; break; case 'j': case MYDOWN: ++selected; if(selected==menunum) selected=0; if(whichmenu>=0) menuhistory[whichmenu]=selected; redraw=1; break; case 0x1b: if(!whichmenu && selected) { selected=0; redraw=1; break; } menudelta=1; return 0; } } return 0; } static void domode0(void) { int sel; pulseon(); while(!exitflag) { menustart(); additem("BOMBER MAIN MENU"); additem("EXIT GAME"); additem("START SINGLE PLAYER GAME"); additem("OPTIONS"); // additem("REMAP MOVEMENT KEYS"); additem("START NETWORK GAME"); additem("JOIN NETWORK GAME"); sel=domenu(0); if(!sel) {exitflag=1;break;} if(sel==1) {gamemode=1;break;} if(sel==2) {gamemode=2;break;} if(sel==3) {gamemode=3;break;} if(sel==4) {gamemode=4;break;} } } static void domode1(void) { int code; network=0; initgame(); pulseon(); while(!(code=iterate())) ++framecount; if(code==CODE_QUIT) gamemode=0; } unsigned char gameoptions[10]; char *densities[]={"PACKED","HIGH","MEDIUM","LOW"}; char *generosities[]={"LOW","MEDIUM","HIGH","RIDICULOUS"}; static void domode2(void) { int sel; for(;;) { menustart(); additem("GAME OPTIONS"); additem("RETURN TO MAIN MENU"); additem("DENSITY: %s",densities[configopts[GO_DENSITY]]); additem("GENEROSITY: %s",generosities[configopts[GO_GENEROSITY]]); additem("INITIAL FLAME LENGTH: %d",configopts[GO_FLAMES]+1); additem("INITIAL NUMBER OF BOMBS: %d",configopts[GO_BOMBS]+1); sel=domenu(2); if(!sel) {gamemode=0;break;} if(sel==1) { configopts[GO_DENSITY]+=menudelta; configopts[GO_DENSITY]&=3; } if(sel==2) { configopts[GO_GENEROSITY]+=menudelta; configopts[GO_GENEROSITY]&=3; } if(sel==3) { configopts[GO_FLAMES]+=menudelta; configopts[GO_FLAMES]&=7; } if(sel==4) { configopts[GO_BOMBS]+=menudelta; configopts[GO_BOMBS]&=7; } } } static void failure(char *str,...) { gamemode=0; } static void drawmode3(void) { int i; char *name; char temp[64]; #define M3X (IXSIZE/3) #define M3Y (IYSIZE/4) clear(); centerbig(20,"HOST NETWORK GAME"); drawbigstring(M3X,M3Y,"SLOT NAME"); for(i=0;i=21 && *mesg==PKT_JOIN) || (size>=5 && *mesg==PKT_QUIT))) continue; if(memcmp(mesg+1,regpacket+1,4)) continue; j=-1; for (i=1; i < MAXNETNODES; ++i) { if(!netnodes[i].used) { if(j==-1) j=i; continue; } if(memcmp(&netnodes[i].netname.sin_addr.s_addr, &sender.sin_addr.s_addr,4)) continue; if(memcmp(&netnodes[i].netname.sin_port, &sender.sin_port,2)) continue; break; } if(*mesg==PKT_QUIT) { if(inext; doplayer(pl2); } } static void processquits(void) { int i; if(network!=SLAVE) return; for(i=0;i=ACTIONHIST) // too far behind return CODE_QUIT; memcpy(actions,actionblock+i*MAXNETNODES,MAXNETNODES); if(actions[myslot]==ACT_QUIT) return CODE_QUIT; } processbombs(); dodetonations(); processdecays(); processflames(); processgenerics(); processquits(); processplayers(); } /* if(!(rand()&127)) { i=gtime(); while(gtime()-i<100); } */ drawbombs(); drawbonus(); drawgenerics(); drawdecays(); drawflames(); drawplayers(); plotsprites(); update(); if(!activegeneric.next) { player *pl; int deadplayers = 0; pl=activeplayers.next; i=0; while(pl) { if(!(pl->flags & FLG_DEAD)) ++i; else deadplayers++; pl=pl->next; } if (deadplayers > 0 && (!i || (network && i==1))) { ++deathcount; if(deathcount==25) return CODE_ALLDEAD; } else deathcount=0; } return CODE_CONT; }