From 69a7bcafc71271f79bc65d33411591473d21456f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20B=C3=BChler?= Date: Fri, 7 Aug 2009 15:39:51 +0200 Subject: [PATCH 1/3] Fix makefiles --- Makefile | 4 ++-- Makefile.osx | 17 +++++++++-------- Makefile.sdldemoswin32 | 4 ++-- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/Makefile b/Makefile index 3759586..cba6ad7 100644 --- a/Makefile +++ b/Makefile @@ -11,11 +11,11 @@ sdlbomber: bomber.o gfx.o sound.o announce.o matcher: matcher.c -bomber.o: bomber.c bomber.h gfx.h announce.h +bomber.o: bomber.c bomber.h gfx.h announce.h sound.h gfx.o: gfx.c gfx.h bomber.h -sound.o: sound.c +sound.o: sound.c sound.h announce.o: announce.c announce.h diff --git a/Makefile.osx b/Makefile.osx index 8bd267f..e29725c 100644 --- a/Makefile.osx +++ b/Makefile.osx @@ -3,23 +3,24 @@ CC = gcc CFLAGS = -O2 -Wall -I/Library/Frameworks/SDL.framework/Headers $(DBG) -LDFLAGS += -framework SDL -framework Cocoa -o $@ +LDFLAGS += -framework SDL -framework Cocoa -o $@ -lavahi-client -all: bomber -bomber: gfx.o bomber.o sound.o SDLMain.o +all: sdlbomber +sdlbomber: gfx.o bomber.o sound.o SDLMain.o announce.o SDLMain.o: SDLmain.m -bomber.o: bomber.c bomber.h gfx.h +bomber.o: bomber.c bomber.h gfx.h sound.h announce.h gfx.o: gfx.c bomber.h gfx.h -sound.o: sound.c bomber.h +sound.o: sound.c bomber.h sound.h +announce.o: announce.c announce.h clean: - rm -f *.o bomber + rm -f *.o sdlbomber matcher -test: all - ./bomber +test: all + ./sdlbomber diff --git a/Makefile.sdldemoswin32 b/Makefile.sdldemoswin32 index 1f74b2c..b158abf 100644 --- a/Makefile.sdldemoswin32 +++ b/Makefile.sdldemoswin32 @@ -1,9 +1,9 @@ # Makefile for bomber # -TARGET = bomber +TARGET = sdlbomber USEINET = true include ../GNUmake -$(TARGET): bomber.o gfx.o sound.o +$(TARGET): bomber.o gfx.o sound.o announce.o From c5aa13ac27da6069c168d7706ed6660ea3147e0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20B=C3=BChler?= Date: Sat, 8 Aug 2009 21:45:49 +0200 Subject: [PATCH 2/3] Split source in more files, changed network behavior to prepare for direct connect. --- Makefile | 22 +- README | 34 - TODO | 34 + announce.c | 24 +- announce.h | 5 +- bomber.c | 2433 +--------------------------------------------------- bomber.h | 78 +- draw.c | 448 ++++++++++ draw.h | 38 + game.c | 944 ++++++++++++++++++++ game.h | 23 + list.c | 62 ++ list.h | 12 + menu.c | 360 ++++++++ menu.h | 10 + network.c | 550 ++++++++++++ network.h | 58 ++ sound.c | 4 + sound.h | 4 - utils.c | 127 +++ utils.h | 26 + 21 files changed, 2755 insertions(+), 2541 deletions(-) create mode 100644 draw.c create mode 100644 draw.h create mode 100644 game.c create mode 100644 game.h create mode 100644 list.c create mode 100644 list.h create mode 100644 menu.c create mode 100644 menu.h create mode 100644 network.c create mode 100644 network.h create mode 100644 utils.c create mode 100644 utils.h diff --git a/Makefile b/Makefile index cba6ad7..6474715 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -#DBG = -g +DBG = -g CC = gcc WARNFLAGS = -Wall -Wmissing-declarations -Wdeclaration-after-statement -Wcast-align -Winline -Wsign-compare -Wnested-externs -Wpointer-arith -Wformat-security override CFLAGS += -D_REENTRANT -O2 $(shell sdl-config --cflags) $(DBG) $(WARNFLAGS) @@ -6,18 +6,30 @@ override CFLAGS += -D_REENTRANT -O2 $(shell sdl-config --cflags) $(DBG) $(WARNFL .PHONY: all clean install all: sdlbomber -sdlbomber: bomber.o gfx.o sound.o announce.o - gcc -o sdlbomber bomber.o gfx.o sound.o announce.o $(shell sdl-config --libs) -lavahi-common -lavahi-client $(DBG) +sdlbomber: announce.o bomber.o draw.o game.o gfx.o sound.o list.o network.o menu.o utils.o + gcc -o $@ $^ $(shell sdl-config --libs) -lavahi-common -lavahi-client $(DBG) matcher: matcher.c -bomber.o: bomber.c bomber.h gfx.h announce.h sound.h +announce.o: announce.c announce.h + +bomber.o: bomber.c announce.h bomber.h draw.h game.h gfx.h list.h menu.h network.h sound.h utils.h + +draw.o: draw.c draw.h bomber.h gfx.h + +game.o: game.c announce.h bomber.h draw.h game.h gfx.h list.h menu.h network.h sound.h utils.h gfx.o: gfx.c gfx.h bomber.h +list.o: list.c bomber.h list.h utils.h + +menu.o: menu.c announce.h bomber.h draw.h game.h gfx.h list.h menu.h network.h sound.h utils.h + +network.o: network.c announce.h bomber.h game.h menu.h network.h utils.h + sound.o: sound.c sound.h -announce.o: announce.c announce.h +utils.o: utils.c bomber.h utils.h gfx.h clean: rm -f *.o matcher sdlbomber diff --git a/README b/README index 4f6ddfe..a23f398 100644 --- a/README +++ b/README @@ -55,40 +55,6 @@ There isn't much point in playing the game alone (single player). In that case the only thing to avoid is accidentally killing yourself. Big deal... It's really a multiplayer game. ------------------ 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. - ---------------- Direct comments, complaints and questions to dash@xdr.com This code is GPL. diff --git a/TODO b/TODO index e69de29..f1096a4 100644 --- a/TODO +++ b/TODO @@ -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. + diff --git a/announce.c b/announce.c index 66a7bba..5fecf6f 100644 --- a/announce.c +++ b/announce.c @@ -26,7 +26,7 @@ static AvahiEntryGroup *group = NULL; static char* name = NULL; static uint16_t port = 0; -static uint32_t unique = 0, version = 0; +static uint32_t version = 0; static volatile int all_for_now; @@ -82,10 +82,9 @@ static void create_services(AvahiClient *c) { again: if (avahi_entry_group_is_empty(group)) { - char buf_unique[128], buf_version[128]; - snprintf(buf_unique, sizeof(buf_unique), "unique=%X", (unsigned int) unique); + char buf_version[128]; snprintf(buf_version, sizeof(buf_version), "version=%X", (unsigned int) version); - if ((ret = avahi_entry_group_add_service(group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, name, SERVICE_TYPE, NULL, NULL, port, buf_unique, buf_version, NULL)) < 0) { + if ((ret = avahi_entry_group_add_service(group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, name, SERVICE_TYPE, NULL, NULL, port, buf_version, NULL)) < 0) { if (ret == AVAHI_ERR_COLLISION) goto collision; @@ -136,12 +135,11 @@ static void client_callback(AvahiClient *c, AvahiClientState state, void * userd } } -int registergame(char *playername, uint16_t p, uint32_t uniq, unsigned char v[4]) { +int registergame(const char *playername, uint16_t p, const unsigned char v[4]) { if (name) avahi_free(name); name = avahi_strdup(playername); port = p; - unique = htonl(uniq); memcpy(&version, v, 4); version = htonl(version); @@ -180,20 +178,17 @@ static void resolve_callback(AvahiServiceResolver *r, AvahiIfIndex interface, Av case AVAHI_RESOLVER_FOUND: { gamelistentry *ge; - unsigned int uniq, version; - int have_unique = 0, have_version = 0; + unsigned int version; + int have_version = 0; AvahiStringList *psl; for (psl = txt ; psl ; psl = psl->next) { - if (0 == strncmp("unique=", (const char*) psl->text, 7)) { - sscanf((const char*) psl->text, "unique=%X", &uniq); - have_unique = 1; - } else if (0 == strncmp("version=", (const char*) psl->text, 8)) { + if (0 == strncmp("version=", (const char*) psl->text, 8)) { sscanf((const char*) psl->text, "version=%X", &version); if (version != want_version) goto done; /* version mismatch */ have_version = 1; } } - if (!have_unique || !have_version) goto done; + if (!have_version) goto done; i = gamelistsize++; ge = &gamelistentries[i]; memset(ge, 0, sizeof(*ge)); @@ -201,7 +196,6 @@ static void resolve_callback(AvahiServiceResolver *r, AvahiIfIndex interface, Av ge->netname.sin_family = AF_INET; ge->netname.sin_port = port; ge->name = avahi_strdup(name); - ge->unique = ntohl(uniq); } } @@ -257,7 +251,7 @@ static void freefoundgames() { gamelistsize = 0; } -int searchgames(unsigned char version[4]) { +int searchgames(const unsigned char version[4]) { int i; AvahiServiceBrowser *sb = NULL; uint32_t gameversion; diff --git a/announce.h b/announce.h index b625ae4..aaa5a77 100644 --- a/announce.h +++ b/announce.h @@ -7,12 +7,11 @@ typedef struct gamelistentry gamelistentry; struct gamelistentry { struct sockaddr_in netname; char *name; - uint32_t unique; }; -int registergame(char *playername, uint16_t port, uint32_t unique, unsigned char version[4]); +int registergame(const char *playername, uint16_t port, const unsigned char version[4]); void unregistergame(); -int searchgames(unsigned char version[4]); +int searchgames(const unsigned char version[4]); int initannouncer(); void freeannouncer(); diff --git a/bomber.c b/bomber.c index 88d45de..0a8af9c 100644 --- a/bomber.c +++ b/bomber.c @@ -3,1828 +3,22 @@ #include #include #include -#include -#include #include #include #include #include +#include +#include + #include "bomber.h" #include "gfx.h" #include "announce.h" #include "sound.h" -#include -#include - -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,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; - -} - -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; -} diff --git a/bomber.h b/bomber.h index f3e806b..08708cc 100644 --- a/bomber.h +++ b/bomber.h @@ -84,27 +84,22 @@ typedef struct player #define FLG_DEAD 2 - -typedef struct sprite -{ +typedef struct sprite { int flags; int xpos,ypos; figure *fig; } sprite; -typedef struct damage -{ +typedef struct damage { int xpos,ypos; int xsize,ysize; } damage; -typedef struct list -{ +typedef struct list { void *next; } list; -typedef struct bomb -{ +typedef struct bomb { struct bomb *next; int type; int xpos,ypos; @@ -123,8 +118,7 @@ typedef struct bomb #define FLAMELIFE 15 #define DECAYLIFE 15 -typedef struct flame -{ +typedef struct flame { struct flame *next; int xpos,ypos; int px,py; @@ -138,16 +132,23 @@ typedef struct flame #define FL_LEFT 1 #define FL_RIGHT 4 -typedef struct brickdecay -{ +typedef struct brickdecay { struct brickdecay *next; int xpos,ypos; int px,py; int timer; } brickdecay; -typedef struct generic -{ +typedef union listitem listitem; +union listitem { + listitem *next; + bomb b; + flame f; + brickdecay bc; + player p; +}; + +typedef struct generic { struct generic *next; int xpos,ypos; int px,py; @@ -158,13 +159,12 @@ typedef struct generic int data1,data2; } generic; -typedef struct bonustile -{ +typedef struct bonustile { struct bonustile *next; int xpos,ypos; int px,py; int type; -}bonustile; +} bonustile; #define TILE_NONE -1 #define TILE_BOMB 5 @@ -210,48 +210,8 @@ typedef struct bonustile extern char exitflag; -extern player players[]; -extern sprite sprites[]; -extern gfxset gfxsets[NUMGFX]; extern uchar needwhole; extern figure walking[MAXSETS][60]; -extern damage damages[]; -extern bomb bombs[]; - -extern void centerx(player *pl); -extern void centery(player *pl); -extern void dropbomb(player *pl,int px,int py,int type); -extern void adddetonate(bomb *bmb); -extern void flameshaft(player *owner,int px,int py,int dx,int dy,int power); -extern void detonatebomb(bomb *bmb); -extern void initlist(void *first,int size,int num); -extern void freeentry(void *entry); -extern void addtail(void *header,void *entry); -extern void delink(void *header,void *entry); -extern void *allocentry(); -extern void adddecay(int px,int py); -extern void trybonus(int px,int py); -extern void addbonus(int px,int py,int type); -extern void deletebonus(bonustile *bonus); -extern void queuesequence(int xpos,int ypos,figure *fig,int count); -extern void playonce(generic *gen); -extern void processgenerics(void); -extern void drawgenerics(void); -extern void drawgeneric(generic *gen); -extern void killplayer(player *pl); -extern void adddeath(player *pl); -extern void drawbigstring(int xpos,int ypos,char *str); -extern void bigscrprintf(char *str, ...); -extern void drawstring(int xpos,int ypos,char *str); -extern void scrprintf(char *str, ...); -extern int textx,texty,fontxsize,fontysize; -extern void texthome(void); - -extern unsigned char field[32][32]; -extern void *info[32][32]; -extern unsigned char singleoptions[10]; -extern unsigned char gameoptions[10]; -extern int getmsg(int); #define GO_DENSITY 0 #define GO_FLAMES 1 @@ -261,7 +221,7 @@ extern int getmsg(int); // network packet types // slave -> master packets #define PKT_MYDATA 0 // 4 bytes unique #,4 bytes frame #, 1 byte data -#define PKT_JOIN 1 // 4 bytes unique #,16 bytes name +#define PKT_JOIN 1 // 4 bytes version #,16 bytes name // master -> slave packets #define PKT_INVITE 9 // 4 bytes unique #, any # of 1:slot,16:name sets (-1 end) #define PKT_BEGIN 10 // clone of INVITE diff --git a/draw.c b/draw.c new file mode 100644 index 0000000..5963e77 --- /dev/null +++ b/draw.c @@ -0,0 +1,448 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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;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 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;ixpos,sp->ypos,sp->fig); + ++sp; + } +} + +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; + } +} + +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; + } +} + +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<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=comp ? FIELD_BRICK : FIELD_EMPTY; + } + + solidcopyany(&backgroundoriginal,&background,0,0,IXSIZE,IYSIZE); + + initplayers(); + + for(j=0;jpx=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; + } +} + +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<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; +} + +static 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; +} + +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->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 processplayers(void) { + player *pl,*pl2; + + pl=activeplayers.next; + while(pl) { + pl2=pl; + pl=pl->next; + doplayer(pl2); + } +} + +static void processquits(void) { + int i; + + if(network!=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(); + copyup(); + 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; +} + +void set_game_options(unsigned char options[10]) { + memmove(gameoptions, options, sizeof(gameoptions)); +} diff --git a/game.h b/game.h new file mode 100644 index 0000000..f3af7f1 --- /dev/null +++ b/game.h @@ -0,0 +1,23 @@ +#ifndef GAME_H +#define GAME_H + +#define FRACTION 9 +#define SPEEDDELTA (1<<(FRACTION-1)) +#define SPEEDMAX (10<next; + memset(entry, 0, sizeof(*entry)); + } + return entry; +} + +void freeentry(void *_entry) { + listitem *entry = _entry; + + entry->next = free_things; + free_things = entry; +} + +void addtail(void *_header,void *_entry) { + listitem *header = _header, *entry = _entry; + + while (header->next) header = header->next; + header->next = entry; + entry->next = 0; +} + +void delink(void *_header,void *_entry) { + listitem *header = _header, *entry = _entry; + + while (header->next != entry) header = header->next; + header->next = entry->next; + entry->next = 0; + freeentry(entry); +} + +void initheader(void *p) { + memset(p,0,sizeof(list)); +} + diff --git a/list.h b/list.h new file mode 100644 index 0000000..b2a628f --- /dev/null +++ b/list.h @@ -0,0 +1,12 @@ +#ifndef LIST_H +#define LIST_H + +void allocthings(void); +void *allocentry(void); +void freeentry(void *entry); +void addtail(void *header,void *entry); +void delink(void *header,void *entry); + +void initheader(void *p); + +#endif diff --git a/menu.c b/menu.c new file mode 100644 index 0000000..242f37f --- /dev/null +++ b/menu.c @@ -0,0 +1,360 @@ + +#include "bomber.h" +#include "menu.h" +#include "draw.h" +#include "gfx.h" +#include "utils.h" +#include "sound.h" +#include "network.h" +#include "announce.h" +#include "game.h" + +unsigned char configopts[10]={2,1,0,2,0,0,0,0,0}; + +/* Generic menu */ + +int menuhistory[32]={0}; +char menustring[1024]; +char *menuput,*menuitems[40],*menutitle; +int menunum; +int menudelta; + +static void drawmenu(int selected) { + int i,j; + int tx,ty; + + clear(); + j=strlen(menutitle)*bigfontxsize; + drawbigstring((IXSIZE-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 int domenu(int whichmenu) { + char redraw; + int selected; + int mcount=0; + + if(whichmenu>=0) + selected=menuhistory[whichmenu]; + else + selected=0; + + redraw=1; + clearspritelist(); + 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(); + copyup(); + + 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 menustart() { + menunum=-1; + menuput=menustring; + *menuput=0; +} + +static void additem(char *item,...) { + char output[256]; + va_list ap; + + va_start(ap, item); + + vsprintf(output,item,ap); + if(menunum<0) + menutitle=menuput; + else + menuitems[menunum]=menuput; + ++menunum; + strcpy(menuput,output); + menuput+=strlen(output)+1; +} + +/* end generic menu */ + +/* game menues */ + +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>24L; + p[1]=i>>16L; + p[2]=i>>8L; + p[3]=i; + return p+4; +} + +static Uint32 readuint32(unsigned char *p) { + return (p[0]<<24L) | (p[1]<<16L) | (p[2]<<8) | p[3]; +} + +static unsigned char* writeunique(unsigned char *p) { + memcpy(p, &network_unique, 4); + return p + 4; +} + +static unsigned char* writeversion(unsigned char *p) { + memcpy(p, &gameversion, 4); + return p + 4; +} + +static int isvalidmsg() { + int i; + void *host; + void *port; + + if (!isvalidunique(mesg+1)) return -1; + host=&sender.sin_addr.s_addr; + port=&sender.sin_port; + for(i=1;i0) { + 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[0] = PKT_STEP; + writeunique(msg+1); + writeuint32(msg+5, 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[0] = PKT_MYDATA; + writeunique(msg+1); + writeuint32(msg+5, frame); + msg[9]=myaction; + putmsg(&mastername,msg,10); +} + +int networktraffic(void) { + int i; + int length; + int whosent; + unsigned char newactions[MAXNETNODES]; + long now; + long count; + + switch (network) { + case NETWORK_NONE: + return -1; + case NETWORK_MASTER: + memcpy(newactions,latestactions,MAXNETNODES); + newactions[0]=myaction; + now=gtime(); + for(;;) { + if(gtime()-now>15) break; + length=getmsg(5); + if(length>0 && *mesg!=PKT_MYDATA) fprintf(stderr, "Strange packet %d\n", (int) *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=readuint32(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=readuint32(mesg+5); + if(i=17) { + if((i=*take) +#include +#include + +struct netnode { + struct sockaddr_in netname; + char name[16]; + char used; +}; + +extern struct netnode netnodes[64]; + +void getsocket(void); +void freesocket(void); + +int send_join(struct sockaddr_in *netname, char playername[16]); +void send_quit(); +int scaninvite(int msec); + +int start_network_game(); +int handle_joins(); +// void inform(unsigned char type); +int begin_network_game(); +void send_invites(); +void cancel_network_game(); + +#define MAXNETNODES 10 + +extern struct netnode netnodes[64]; + +extern int udpsocket; +extern const unsigned char gameversion[4]; + +typedef enum { NETWORK_NONE = 0, NETWORK_MASTER, NETWORK_SLAVE } network_type; +extern network_type network; + +/* actions */ +int networktraffic(void); + +#define ACTIONHIST 20 + +extern int mydatacount; +extern int myslot; +extern int actionput,actioncount; +extern unsigned char actionblock[ACTIONHIST*MAXNETNODES]; + +extern int myaction; +extern unsigned char actions[MAXNETNODES]; + +extern unsigned char latestactions[MAXNETNODES]; +extern long latestcounts[MAXNETNODES]; + +// extern int netframe; + +#endif diff --git a/sound.c b/sound.c index 50ce9db..4ca5598 100644 --- a/sound.c +++ b/sound.c @@ -7,6 +7,10 @@ #include "sound.h" +#ifndef DATADIR +#define DATADIR "data" +#endif + static char dirlist[]=DATADIR; static int readsound(int num); diff --git a/sound.h b/sound.h index d3ae16c..ae173c0 100644 --- a/sound.h +++ b/sound.h @@ -1,10 +1,6 @@ #ifndef SOUND_H #define SOUND_H -#ifndef DATADIR -#define DATADIR "data" -#endif - int soundopen(void); void soundclose(void); void playsound(int n); diff --git a/utils.c b/utils.c new file mode 100644 index 0000000..768fdfb --- /dev/null +++ b/utils.c @@ -0,0 +1,127 @@ + +#include "bomber.h" +#include "utils.h" +#include "gfx.h" + +#include + +int volatile hc=0; +char volatile interrupted=0; +static Uint32 cur_unique; +Uint32 network_unique; + +Uint32 gtime(void) { + return SDL_GetTicks(); +} + +Uint32 longtime(void) { + return gtime()/1000; +} + +/* random generator */ + +#define TAP1 250 +#define TAP2 103 +/* +#define TAP1 55 +#define TAP2 31 +*/ + +static unsigned char myrandblock[TAP1]; +static int myrandtake; + +static int myrand1(void) { + int i; + int val; + + i=myrandtake-TAP2; + if(i<0) i+=TAP1; + val=myrandblock[myrandtake++]^=myrandblock[i]; + if(myrandtake==TAP1) myrandtake=0; + return val; +} + +int myrand(void) { + int v; + v=myrand1(); + return (v<<8) | myrand1(); +} + +static void initmyrand(Uint32 unique) { + int i,j; + unsigned char *p; + int msb,msk; + + myrandtake=0; + p=myrandblock; + j=12345 ^ unique; + i=TAP1; + while(i--) { + j=(j*1277)&0xffff; + *p++=j>>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(); +} + +void create_unique(void) { + set_unique(gtime()); +} + +void set_unique(Uint32 unique) { + cur_unique = unique; + network_unique = htonl(cur_unique); + initmyrand(cur_unique); +} + +Uint32 get_unique(void) { + return cur_unique; +} + +void nomem(char *str) { + printf("No memory!!![%s]\n",str); + exit(1); +} + +void mypause(void) { + while(!interrupted) { + pollinput(); + SDL_Delay(1); + } + interrupted=0; +} + +static Uint32 sdlhandler(Uint32 time) { +#if defined (SDL_LATENCY) + outmsgs(); +#endif + interrupted=1; + hc++; + return time; +} + +void pulseon(void) { + SDL_SetTimer(40,sdlhandler); +} + +void hexdump(unsigned char *p, int len) { + int i; + for (i = 0; i < len; i++) { + if (15 == len % 16) + fprintf(stderr, "0x%X\n", p[i]); + else + fprintf(stderr, "0x%X ", p[i]); + } + if (i % 16) + fprintf(stderr, "\n"); +} diff --git a/utils.h b/utils.h new file mode 100644 index 0000000..4d1650b --- /dev/null +++ b/utils.h @@ -0,0 +1,26 @@ +#ifndef UTILS_H +#define UTILS_H + +Uint32 gtime(void); +Uint32 longtime(void); + +void create_unique(void); +void set_unique(Uint32 unique); +Uint32 get_unique(void); + +extern Uint32 network_unique; + +int myrand(void); + +void nomem(char *str); + +void mypause(void); +void pulseon(void); + +void hexdump(unsigned char *p, int len); + +extern volatile int hc; +extern volatile char interrupted; + + +#endif \ No newline at end of file From 94df5eb6dde893e56bd56dfab244e0830a914a05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20B=C3=BChler?= Date: Sun, 9 Aug 2009 19:10:35 +0200 Subject: [PATCH 3/3] use surf for random, async game search --- Makefile | 2 +- TODO | 1 - announce.c | 112 ++++++++------ announce.h | 13 +- bomber.c | 2 +- bomber.h | 77 +--------- game.c | 23 ++- game.h | 7 +- menu.c | 170 ++++++++++++++-------- menu.h | 2 +- network.c | 417 ++++++++++++++++++++++++++++++++++++++--------------- network.h | 4 +- utils.c | 115 ++++++++++++++- utils.h | 9 +- 14 files changed, 629 insertions(+), 325 deletions(-) diff --git a/Makefile b/Makefile index 6474715..61d1ee1 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ sdlbomber: announce.o bomber.o draw.o game.o gfx.o sound.o list.o network.o menu matcher: matcher.c -announce.o: announce.c announce.h +announce.o: announce.c announce.h network.h bomber.o: bomber.c announce.h bomber.h draw.h game.h gfx.h list.h menu.h network.h sound.h utils.h diff --git a/TODO b/TODO index f1096a4..9acf9a5 100644 --- a/TODO +++ b/TODO @@ -31,4 +31,3 @@ 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. - diff --git a/announce.c b/announce.c index 5fecf6f..12c353d 100644 --- a/announce.c +++ b/announce.c @@ -1,5 +1,6 @@ #include "announce.h" +#include "network.h" #include #include @@ -22,13 +23,16 @@ static AvahiClient *client = NULL; static AvahiThreadedPoll *threaded_poll = NULL; static AvahiEntryGroup *group = NULL; +static AvahiServiceBrowser *browser = NULL; static char* name = NULL; static uint16_t port = 0; static uint32_t version = 0; -static volatile int all_for_now; +static gamelistentry buffer_glentries[10]; +static int buffer_glsize = 0; +static char buffer_glchanged[10]; gamelistentry gamelistentries[10]; int gamelistsize = 0; @@ -150,7 +154,7 @@ int registergame(const char *playername, uint16_t p, const unsigned char v[4]) { return 1; } -void unregistergame() { +void unregistergame(void) { port = 0; avahi_threaded_poll_lock(threaded_poll); @@ -159,15 +163,33 @@ void unregistergame() { avahi_threaded_poll_unlock(threaded_poll); } +static void remove_game_with_name(const char *name) { + int i; + + for (i = 0; i < buffer_glsize; i++) { + if (0 == strcmp(buffer_glentries[i].name, name)) { + /* Remove it */ + buffer_glsize--; + if (i != buffer_glsize) { + buffer_glentries[i] = buffer_glentries[buffer_glsize]; + buffer_glchanged[i] = 1; + } + } + } +} + static void resolve_callback(AvahiServiceResolver *r, AvahiIfIndex interface, AvahiProtocol protocol, AvahiResolverEvent event, const char *name, const char *type, const char *domain, const char *host_name, const AvahiAddress *address, uint16_t port, AvahiStringList *txt, AvahiLookupResultFlags flags, void* userdata) { int i; - uint32_t want_version = *(uint32_t*) userdata; + uint32_t want_version; assert(r); if (protocol != AVAHI_PROTO_INET) goto done; /* ignore non IPv4 for now */ - if (gamelistsize >= GAMELIST_MAXSIZE) goto done; + if (buffer_glsize >= GAMELIST_MAXSIZE) goto done; + + memcpy(&want_version, gameversion, 4); + want_version = htonl(want_version); /* Called whenever a service has been resolved successfully or timed out */ @@ -189,13 +211,15 @@ static void resolve_callback(AvahiServiceResolver *r, AvahiIfIndex interface, Av } } if (!have_version) goto done; - i = gamelistsize++; - ge = &gamelistentries[i]; + remove_game_with_name(name); + i = buffer_glsize++; + ge = &buffer_glentries[i]; + buffer_glchanged[i] = 1; memset(ge, 0, sizeof(*ge)); ge->netname.sin_addr.s_addr = address->data.ipv4.address; ge->netname.sin_family = AF_INET; ge->netname.sin_port = port; - ge->name = avahi_strdup(name); + strncpy(ge->name, name, 15); } } @@ -231,40 +255,31 @@ static void browse_callback(AvahiServiceBrowser *b, AvahiIfIndex interface, Avah break; case AVAHI_BROWSER_REMOVE: + remove_game_with_name(name); break; case AVAHI_BROWSER_ALL_FOR_NOW: - all_for_now = 1; break; case AVAHI_BROWSER_CACHE_EXHAUSTED: - all_for_now = 1; break; } } -static void freefoundgames() { - int i; +static void freefoundgames(void) { + memset(gamelistentries, 0, sizeof(gamelistentries)); + memset(buffer_glentries, 0, sizeof(buffer_glentries)); + memset(buffer_glchanged, 0, sizeof(buffer_glchanged)); - for (i = 0; i < gamelistsize; i++) { - avahi_free(gamelistentries[i].name); - } gamelistsize = 0; + buffer_glsize = 0; } -int searchgames(const unsigned char version[4]) { - int i; - AvahiServiceBrowser *sb = NULL; - uint32_t gameversion; - memcpy(&gameversion, version, 4); - gameversion = htonl(gameversion); - +int searchgames(void) { freefoundgames(); avahi_threaded_poll_lock(threaded_poll); - all_for_now = 0; - - if (NULL == (sb = avahi_service_browser_new(client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, SERVICE_TYPE, NULL, 0, browse_callback, &gameversion))) { + if (NULL == (browser = avahi_service_browser_new(client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, SERVICE_TYPE, NULL, 0, browse_callback, &gameversion))) { fprintf(stderr, "Failed to create service browser: %s\n", avahi_strerror(avahi_client_errno(client))); avahi_threaded_poll_unlock(threaded_poll); return 0; @@ -272,29 +287,40 @@ int searchgames(const unsigned char version[4]) { avahi_threaded_poll_unlock(threaded_poll); - for (i = 0; i < 10; i++) { - usleep(200000); - - avahi_threaded_poll_lock(threaded_poll); - - if (all_for_now) { - avahi_service_browser_free(sb); - avahi_threaded_poll_unlock(threaded_poll); - return 1; - } - - avahi_threaded_poll_unlock(threaded_poll); - } - - avahi_threaded_poll_lock(threaded_poll); - avahi_service_browser_free(sb); - avahi_threaded_poll_unlock(threaded_poll); + usleep(200000); + find_more_games(); return 1; } +int find_more_games(void) { + int i, res = 0; -int initannouncer() { + avahi_threaded_poll_lock(threaded_poll); + + for (i = 0; i < buffer_glsize; i++) { + if (!buffer_glchanged[i]) continue; + buffer_glchanged[i] = 0; + gamelistentries[i] = buffer_glentries[i]; + res = 1; + } + if (gamelistsize != buffer_glsize) { + res = 1; + gamelistsize = buffer_glsize; + } + + avahi_threaded_poll_unlock(threaded_poll); + + return res; +} + +void stop_search(void) { + avahi_threaded_poll_lock(threaded_poll); + avahi_service_browser_free(browser); + avahi_threaded_poll_unlock(threaded_poll); +} + +int initannouncer(void) { if (!(threaded_poll = avahi_threaded_poll_new())) { fprintf(stderr, "avahi_threaded_poll_new failed\n"); return 0; @@ -319,7 +345,7 @@ int initannouncer() { return 1; } -void freeannouncer() { +void freeannouncer(void) { freefoundgames(); avahi_threaded_poll_stop(threaded_poll); diff --git a/announce.h b/announce.h index aaa5a77..e264242 100644 --- a/announce.h +++ b/announce.h @@ -6,15 +6,18 @@ typedef struct gamelistentry gamelistentry; struct gamelistentry { struct sockaddr_in netname; - char *name; + char name[16]; }; int registergame(const char *playername, uint16_t port, const unsigned char version[4]); -void unregistergame(); -int searchgames(const unsigned char version[4]); +void unregistergame(void); -int initannouncer(); -void freeannouncer(); +int searchgames(void); +int find_more_games(void); +void stop_search(void); + +int initannouncer(void); +void freeannouncer(void); #define GAMELIST_MAXSIZE 10 diff --git a/bomber.c b/bomber.c index 0a8af9c..9315d19 100644 --- a/bomber.c +++ b/bomber.c @@ -27,7 +27,7 @@ int main(int argc,char **argv) { p=getenv("USER"); if(p) strncpy(playername,p,sizeof(playername)); - create_unique(); + create_seed_unique(); opengfx(argc, argv); getsocket(); diff --git a/bomber.h b/bomber.h index 08708cc..b3cb963 100644 --- a/bomber.h +++ b/bomber.h @@ -213,79 +213,4 @@ extern char exitflag; extern uchar needwhole; extern figure walking[MAXSETS][60]; -#define GO_DENSITY 0 -#define GO_FLAMES 1 -#define GO_BOMBS 2 -#define GO_GENEROSITY 3 - -// network packet types -// slave -> master packets -#define PKT_MYDATA 0 // 4 bytes unique #,4 bytes frame #, 1 byte data -#define PKT_JOIN 1 // 4 bytes version #,16 bytes name -// master -> slave packets -#define PKT_INVITE 9 // 4 bytes unique #, any # of 1:slot,16:name sets (-1 end) -#define PKT_BEGIN 10 // clone of INVITE -#define PKT_STEP 11 // 4 bytes unique #, 4 bytes frame #, 8 bytes ACT_* -#define PKT_QUIT 12 // 4 bytes unique # -// master -> matcher packets -#define PKT_REGISTER 16 // 4:unique #,4:pword hash,4:version #,16:name, 1:status -// matcher -> master packets -#define PKT_ACK 24 // perfect copy of packet received -// slave -> matcher packets -#define PKT_QUERY 32 // 4 bytes password hash -// matcher -> slave packets -#define PKT_INFO 40 // 4: pword hash, 2: count,#(4:unique,4:IP,2:port,16:name) - -// all bytes stored MSB first - -/* -game startup: - -Master: send REGISTER to matcher with optional password, wait for ack. If - timout, resend. -matcher: Wait for REGISTER packet, when received maintain database. respond - to sender with ACK. REGISTER packet can close a game also. The REGISTER - packet sent by the master has a unique word to be used to avoid confusion. - REGISTER packet also contains a game version # - -After master registers game and receives ACK, just waits for slaves to contact. - - -slave: send QUERY to matcher with optional password, wait for INFO, if timeout, - resend. -matcher: respond to QUERY with INFO packet. matcher need not maintain any - database for slave requests. INFO packet contains IP addr and port for each - master machine that matches the QUERY spec (ALL or password). Only a - certain MAX # of entries are sent if there are too many to choose from. - - -slave: send JOIN to master, wait for INVITE. If timeout, resend. JOIN packet - contains the unique word the master created. JOIN also contains username. -master: Respond to JOIN with INVITE. INVITE contains unique word from JOIN - packet. INVITE either contains NO meaning game no longer exists or is closed - or player is not invited. IF yes, INVITE contains info on other players - already in the game (username and slot # for each). Master allocates the - slots and avoids confusion based on IP addr and port #. INVITE also contains - game options structure. Whenever a new player JOINS and is admitted, master - sends updated INVITE packets to everyone already in the JOIN list. Whenever - master changes game options, master sends out another set of INVITES - -Duplicate JOINS are answered with updated INVITE but nothing changes as far -as allocation. - -Master player launches game after he's satisfied everyone has joined. - -Master sends BEGIN packet to everyone. BEGIN is identical to INVITE except -that the data is final. Slave must respond with its first MYDATA packet with -frame # of 0. If master times out waiting, master sends duplicate BEGIN to -wayward slaves. Once master has received MYDATA from everyone, game starts. - -Within game slave sends MYDATA to master and waits for STEP packet. If -timeout, slave sends duplicate MYDATA. - -If master times out waiting for a slave's MYDATA, slave gets dropped. MYDATAs -received will be answered with PKT_QUIT. - -*/ - -#endif // BOMBER_H +#endif /* BOMBER_H */ diff --git a/game.c b/game.c index 25e3b93..18e4115 100644 --- a/game.c +++ b/game.c @@ -51,7 +51,7 @@ TILE_TURTLE,5, TILE_NONE,160 }; -static unsigned char gameoptions[10]; +static GameOptions gameoptions; static const unsigned char playerpositions[] = { /* color, x, y */ 2,0,0, @@ -79,8 +79,8 @@ static void initplayer(int color,int x,int y,int controller) { pl->flags=0; pl->fixx=-4; pl->fixy=-40; - pl->flamelength=gameoptions[GO_FLAMES]+1; - pl->bombsavailable=gameoptions[GO_BOMBS]+1; + pl->flamelength=gameoptions.flames+1; + pl->bombsavailable=gameoptions.bombs+1; pl->controller=controller; field[y][x]=FIELD_EMPTY; if(x) field[y][x-1]=FIELD_EMPTY; @@ -123,7 +123,7 @@ static void initgame() { int comp; if (network != NETWORK_SLAVE) - set_game_options(configopts); + set_game_options(&configopts); gameframe=0; allocthings(); initheader(&activebombs); @@ -142,9 +142,9 @@ static void initgame() { if(i==TILE_NONE) break; bonustotal+=*p++; } - bonustotal += 64*(3-gameoptions[GO_GENEROSITY]); + bonustotal += 64*(3-gameoptions.generosity); memset(field,0,sizeof(field)); - comp=gameoptions[GO_DENSITY]; + comp=gameoptions.density; for(j=0;j=0) selected=menuhistory[whichmenu]; else - selected=0; + selected=-whichmenu-1; + + if (!pause) pause=mypause; redraw=1; clearspritelist(); @@ -58,7 +69,7 @@ static int domenu(int whichmenu) { drawmenu(selected); redraw=0; } - mypause(); + if (!pause()) return -1; scaninput(); ++mcount; @@ -70,7 +81,7 @@ static int domenu(int whichmenu) { copyup(); if(anydown()) playsound(3); - while(anydown()) + while(anydown()) { switch(takedown()) { case MYLEFT: menudelta=-1; @@ -82,29 +93,29 @@ static int domenu(int whichmenu) { return selected; case 'k': case MYUP: - if(selected) --selected; + if (selected) --selected; else selected=menunum-1; - if(whichmenu>=0) + if (whichmenu>=0) menuhistory[whichmenu]=selected; redraw=1; break; case 'j': case MYDOWN: ++selected; - if(selected==menunum) selected=0; - if(whichmenu>=0) + if (selected==menunum) selected=0; + if (whichmenu>=0) menuhistory[whichmenu]=selected; redraw=1; break; case 0x1b: - if(!whichmenu && selected) - { - selected=0; - redraw=1; + if (MENU_MAIN == whichmenu && menuexit != selected) { + selected = menuexit; + redraw = 1; break; } - menudelta=1; - return 0; + menudelta = 1; + return menuexit; + } } } return 0; @@ -114,24 +125,49 @@ static void menustart() { menunum=-1; menuput=menustring; *menuput=0; + menuexit = 0; } -static void additem(char *item,...) { - char output[256]; - va_list ap; +static void additem_s(char *item, int len) { + if (len < 0 || (menustring+sizeof(menustring)-menuput <= len)) return; - va_start(ap, item); - - vsprintf(output,item,ap); if(menunum<0) menutitle=menuput; else menuitems[menunum]=menuput; ++menunum; - strcpy(menuput,output); - menuput+=strlen(output)+1; + memcpy(menuput,item,len+1); + menuput += len+1; } +static void additem(char *item,...) { + char output[256]; + va_list ap; + int len; + + va_start(ap, item); + + len = vsnprintf(output,sizeof(output),item,ap); + if (len >= 256) len = 255; /* truncated string */ + + additem_s(output, len); +} + +static void addexit(char *item,...) { + char output[256]; + va_list ap; + int len; + + va_start(ap, item); + + len = vsnprintf(output,sizeof(output),item,ap); + if (len >= 256) len = 255; /* truncated string */ + + menuexit = menunum; + additem_s(output, len); +} + + /* end generic menu */ /* game menues */ @@ -198,7 +234,7 @@ static void main_menu(void) { // additem("REMAP MOVEMENT KEYS"); additem("START NETWORK GAME"); additem("JOIN NETWORK GAME"); - sel=domenu(0); + sel=domenu(MENU_MAIN, NULL); if(!sel) {exitflag=1;break;} if(sel==1) {gamemode=1;break;} if(sel==2) {gamemode=2;break;} @@ -217,27 +253,27 @@ static void config_menu(void) { 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); + additem("DENSITY: %s",densities[configopts.density]); + additem("GENEROSITY: %s",generosities[configopts.generosity]); + additem("INITIAL FLAME LENGTH: %d",configopts.flames+1); + additem("INITIAL NUMBER OF BOMBS: %d",configopts.bombs+1); + sel=domenu(MENU_CONFIG, NULL); if(!sel) {gamemode=0;break;} if(sel==1) { - configopts[GO_DENSITY]+=menudelta; - configopts[GO_DENSITY]&=3; + configopts.density+=menudelta; + configopts.density&=3; } if(sel==2) { - configopts[GO_GENEROSITY]+=menudelta; - configopts[GO_GENEROSITY]&=3; + configopts.generosity+=menudelta; + configopts.generosity&=3; } if(sel==3) { - configopts[GO_FLAMES]+=menudelta; - configopts[GO_FLAMES]&=7; + configopts.flames+=menudelta; + configopts.flames&=7; } if(sel==4) { - configopts[GO_BOMBS]+=menudelta; - configopts[GO_BOMBS]&=7; + configopts.bombs+=menudelta; + configopts.bombs&=7; } } } @@ -269,7 +305,7 @@ static void draw_host_game(void) { static void host_game(void) { - create_unique(); + create_seed_unique(); if (!start_network_game()) { failure("COULD NOT REGISTER GAME"); return; @@ -306,36 +342,44 @@ static void host_game(void) { gamemode=0; } +static int join_game_pause(void) { + if (find_more_games()) return 0; + mypause(); + return 1; +} + static void join_game(void) { int i; - int sel; + int sel = -1; - if (!searchgames(gameversion)) { + if (!searchgames()) { gamemode = 0; return; } - if (gamelistsize == 0) { + + menuhistory[MENU_JOIN] = 0; + + while (-1 == sel) { menustart(); - additem("NO GAMES AVAILABLE"); - domenu(-1); + if (gamelistsize == 0) { + additem("JOIN NETWORK GAME - NO GAMES AVAILABLE"); + addexit("EXIT"); + } else { + additem("JOIN NETWORK GAME"); + for (i = 0; i < gamelistsize; i++) { + additem(gamelistentries[i].name); + } + addexit("EXIT"); + } + sel = domenu(MENU_JOIN, join_game_pause); + } + stop_search(); + + if(menuexit == sel || !gamelistsize) { gamemode=0; return; } - - menustart(); - additem("JOIN NETWORK GAME"); - additem("EXIT"); - - for (i = 0; i < gamelistsize; i++) { - additem(gamelistentries[i].name); - } - - sel=domenu(-1); - if(!sel) { - gamemode=0; - return; - } - if(!tryjoin(sel-1)) { + if(!tryjoin(sel)) { gamemode=0; return; } diff --git a/menu.h b/menu.h index 25b0230..9137a4e 100644 --- a/menu.h +++ b/menu.h @@ -5,6 +5,6 @@ void mainloop(void); int iterate(void); /* bomber.c */ -extern unsigned char configopts[10]; +extern struct GameOptions configopts; #endif diff --git a/network.c b/network.c index 2cfbad4..eb0ad7d 100644 --- a/network.c +++ b/network.c @@ -9,7 +9,7 @@ #define MAXMSG 4096 int udpsocket; -const unsigned char gameversion[4]={0xda,0x01,0x00,0x04}; +const unsigned char gameversion[4]={0xda,0x01,0x00,0x05}; struct netnode netnodes[64]; @@ -36,6 +36,84 @@ unsigned char actions[MAXNETNODES]; unsigned char latestactions[MAXNETNODES]; long latestcounts[MAXNETNODES]; +enum network_packet_types { + PKT_ACK, /* perfect copy of packet received */ +/* join / host game */ + /* slave -> master packets */ + PKT_JOIN, /* 4 bytes version #, 4 bytes joinunique #, 16 bytes name */ + PKT_QUIT, /* 4 bytes unique # */ + /* master -> slave packets */ + PKT_INVITE, /* 4 bytes unique #, 1 byte your slot (0xff for kick, no data following it) #, any # of 1:slot,16:name sets (-1 end) */ + PKT_BEGIN, /* clone of INVITE */ + PKT_CONFIG, /* 4 bytes unique #, config */ + PKT_ACCEPT, /* 4 bytes join unique #, 132 bytes seed + unique #, config, slot info (see invite) */ + PKT_REJECT, /* 4 bytes join unique #, 4 bytes version #, 1: reason */ +/* ingame actions */ + /* slave -> master packets */ + PKT_MYDATA, /* 4 bytes unique #,4 bytes frame #, 1 byte data */ + /* master -> slave packets */ + PKT_STEP, /* 4 bytes unique #, 4 bytes frame #, 8 bytes ACT_* */ + + PKT_INVALID = 0xff +}; + +enum reject_reason { + REJECT_FULL, + REJECT_VERSION + /* TODO: password? */ +}; + +/* all bytes stored MSB first */ + +/* +game startup: + +Master: send REGISTER to matcher with optional password, wait for ack. If + timout, resend. +matcher: Wait for REGISTER packet, when received maintain database. respond + to sender with ACK. REGISTER packet can close a game also. The REGISTER + packet sent by the master has a unique word to be used to avoid confusion. + REGISTER packet also contains a game version # + +After master registers game and receives ACK, just waits for slaves to contact. + + +slave: send QUERY to matcher with optional password, wait for INFO, if timeout, + resend. +matcher: respond to QUERY with INFO packet. matcher need not maintain any + database for slave requests. INFO packet contains IP addr and port for each + master machine that matches the QUERY spec (ALL or password). Only a + certain MAX # of entries are sent if there are too many to choose from. + + +slave: send JOIN to master, wait for INVITE. If timeout, resend. JOIN packet + contains the unique word the master created. JOIN also contains username. +master: Respond to JOIN with INVITE. INVITE contains unique word from JOIN + packet. INVITE either contains NO meaning game no longer exists or is closed + or player is not invited. IF yes, INVITE contains info on other players + already in the game (username and slot # for each). Master allocates the + slots and avoids confusion based on IP addr and port #. INVITE also contains + game options structure. Whenever a new player JOINS and is admitted, master + sends updated INVITE packets to everyone already in the JOIN list. Whenever + master changes game options, master sends out another set of INVITES + +Duplicate JOINS are answered with updated INVITE but nothing changes as far +as allocation. + +Master player launches game after he's satisfied everyone has joined. + +Master sends BEGIN packet to everyone. BEGIN is identical to INVITE except +that the data is final. Slave must respond with its first MYDATA packet with +frame # of 0. If master times out waiting, master sends duplicate BEGIN to +wayward slaves. Once master has received MYDATA from everyone, game starts. + +Within game slave sends MYDATA to master and waits for STEP packet. If +timeout, slave sends duplicate MYDATA. + +If master times out waiting for a slave's MYDATA, slave gets dropped. MYDATAs +received will be answered with PKT_QUIT. + +*/ /* Network I/O, building/checking packets */ @@ -132,17 +210,17 @@ static Uint32 readuint32(unsigned char *p) { return (p[0]<<24L) | (p[1]<<16L) | (p[2]<<8) | p[3]; } -static unsigned char* writeunique(unsigned char *p) { +static unsigned char* write_unique(unsigned char *p) { memcpy(p, &network_unique, 4); return p + 4; } -static unsigned char* writeversion(unsigned char *p) { +static unsigned char* write_version(unsigned char *p) { memcpy(p, &gameversion, 4); return p + 4; } -static int isvalidmsg() { +static int isvalidmsg_from_slave() { int i; void *host; void *port; @@ -158,6 +236,13 @@ static int isvalidmsg() { return -1; } +static int isvalidmsg_from_master() { + if (sender.sin_family != mastername.sin_family + || sender.sin_addr.s_addr != mastername.sin_addr.s_addr + || sender.sin_port != mastername.sin_port) return 0; + return 1; +} + /* Handling game actions */ static void addactions(void) { @@ -190,7 +275,7 @@ static void sendactions(int which) { unsigned char msg[512]; msg[0] = PKT_STEP; - writeunique(msg+1); + write_unique(msg+1); writeuint32(msg+5, actioncount); memcpy(msg+9,actionblock,MAXNETNODES*ACTIONHIST); putmsg(&netnodes[which].netname,msg,MAXNETNODES*ACTIONHIST+9); @@ -200,7 +285,7 @@ static void sendmine(int frame) { unsigned char msg[64]; msg[0] = PKT_MYDATA; - writeunique(msg+1); + write_unique(msg+1); writeuint32(msg+5, frame); msg[9]=myaction; putmsg(&mastername,msg,10); @@ -229,7 +314,7 @@ int networktraffic(void) { // 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(); + whosent = isvalidmsg_from_slave(); if(whosent<=0) continue; count=readuint32(mesg+5); if(count>latestcounts[whosent]) { @@ -333,120 +418,86 @@ void freesocket(void) { /* Join / Host Games */ -static void buildinform(unsigned char type) { - unsigned char *put; +/* Master side */ + +static unsigned char* write_inform(unsigned char* put) { int i; - put=mesg; - *put++=type; - put = writeunique(put); - ++put; // slot specific for each slave + *put++ = 0xff; /* 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++ = i; + memmove(put, netnodes[i].name, 16); + put += 16; } - *put++=0xff; - memcpy(put, configopts, sizeof(configopts)); - put += sizeof(configopts); + *put++ = 0xff; + return put; +} + +static void send_inform_all(unsigned char type) { + int i; + unsigned char *put = mesg; + + *put++ = type; + put = write_unique(put); + put = write_inform(put); + informsize = put-mesg; + + for(i=1;i=17) { - if((i=*take)= MAXNETNODES) return 0; + netnodes[i].used = 1; + memcpy(netnodes[i].name, buf, 16); + buf += 16; + size -= 16; + } + + *psize = size; + *pbuf = buf; + return 1; +} + +static void read_config(unsigned char* buf) { + GameOptions opts; + memset(&opts, 0, sizeof(opts)); + opts.density = *buf++; + opts.flames = *buf++; + opts.bombs = *buf++; + opts.generosity = *buf++; + set_game_options(&opts); +} + +/* returns 0=ignore packet,1=we're rejected,2=INVITE/CONFIG,3=BEGIN */ +int scaninvite(int msec) { + int size; + unsigned char *take; + + size = getmsg(msec); + + if (size < 6) return 0; + if (*mesg!=PKT_INVITE && *mesg!=PKT_BEGIN && *mesg!=PKT_CONFIG) return 0; + if (!isvalidmsg_from_master()) return 0; + if (!isvalidunique(mesg+1)) return 0; + + take = mesg+5; + size -= 5; + + switch (*mesg) { + case PKT_INVITE: + case PKT_BEGIN: + if (!read_inform(&take, &size)) return 0; + if (0xff == myslot) return 1; /* master closed game */ + break; + case PKT_CONFIG: + if (size < 4) return 0; + read_config(take); + break; + } + + if (*mesg == PKT_BEGIN) { + return 3; + } else { + return 2; + } +} + +int send_join(struct sockaddr_in *netname, char playername[16]) { + int size; + long now; + Uint32 join_unique = gtime(); + unsigned char *buf; + + mastername = *netname; + *regpacket=PKT_JOIN; + write_version(regpacket + 1); + writeuint32(regpacket+5, join_unique); + memcpy(regpacket+9, playername, 16); + now=longtime(); + putmsg(&mastername,regpacket,1+4+4+16); + while(longtime()-now < 3) { + if (0 == (size = getmsg(1000))) { + /* got no message, send join again */ + putmsg(&mastername,regpacket,1+4+4+16); + continue; + } + if (size < 5) continue; + if (readuint32(mesg+1) != join_unique) continue; + switch (*mesg) { + case PKT_ACCEPT: + if (size < 1+4+132+4+2) continue; + read_seed_unique(mesg + 5); + read_config(mesg+137); + buf = mesg+141; + size -= 141; + if (!read_inform(&buf,&size)) return 0; + return 2; + case PKT_REJECT: + /* TODO: print reject message */ + return 0; + default: + break; + } + } + return 0; +} + +void send_quit() { + long now; + int size; + + *regpacket = PKT_QUIT; + write_unique(regpacket+1); + now=longtime(); + while(longtime()-now<10) { + putmsg(&mastername,regpacket,5); + size=getmsg(1000); + if(size<6) continue; + if(mesg[0] != PKT_ACK || mesg[1] != PKT_QUIT) continue; + if (isvalidunique(mesg+2)) + break; + } +} diff --git a/network.h b/network.h index a5f4096..3fa5628 100644 --- a/network.h +++ b/network.h @@ -17,12 +17,12 @@ void getsocket(void); void freesocket(void); int send_join(struct sockaddr_in *netname, char playername[16]); +void send_config(); void send_quit(); int scaninvite(int msec); int start_network_game(); int handle_joins(); -// void inform(unsigned char type); int begin_network_game(); void send_invites(); void cancel_network_game(); @@ -53,6 +53,4 @@ extern unsigned char actions[MAXNETNODES]; extern unsigned char latestactions[MAXNETNODES]; extern long latestcounts[MAXNETNODES]; -// extern int netframe; - #endif diff --git a/utils.c b/utils.c index 768fdfb..a9e391a 100644 --- a/utils.c +++ b/utils.c @@ -5,6 +5,11 @@ #include +#include +#include +#include +#include + int volatile hc=0; char volatile interrupted=0; static Uint32 cur_unique; @@ -18,6 +23,112 @@ Uint32 longtime(void) { return gtime()/1000; } +/* surf random generator: x (Daniel J. Bernstein) */ +#define ROT(x, b) (((x) << (b)) | ((x) >> (32-(b)))) +#define MUSH(i, b) x = t[i] += (((x ^ seed[i]) + sum) ^ ROT(x,b)) +static void surf(Uint32 out[8], const Uint32 in[12], const Uint32 seed[32]) { + Uint32 t[12], x, sum = 0; + int r, i, loop; + for (i = 0; i < 12; ++i) t[i] = in[i] ^ seed[12 + i]; + for (i = 0; i < 8; ++i) out[i] = seed[24 + i]; + x = t[11]; + for (loop = 0; loop < 2; ++loop) { + for (r = 0; r < 16; ++r) { + sum += 0x9e3779b9; + MUSH(0, 5); MUSH(1, 7); MUSH(2, 9); MUSH(3, 13); + MUSH(4, 5); MUSH(5, 7); MUSH(6, 9); MUSH(7, 13); + MUSH(8, 5); MUSH(9, 7); MUSH(10, 9); MUSH(11, 13); + } + for (i = 0; i < 8; ++i) out[i] ^= t[i+4]; + } +} +#undef ROT +#undef MUSH + +static Uint32 surf_seed[32]; +static Uint32 surf_in[12], surf_out[8]; +static int surf_left; + +static Uint32 surf_init(void) { + Uint32 unique = 0; + int fd; + + memset(surf_in, 0, sizeof(surf_in)); + memset(surf_out, 0, sizeof(surf_out)); + memset(surf_seed, 0, sizeof(surf_seed)); + surf_left = 0; + + fd = open("/dev/urandom", O_RDONLY); + if (-1 == fd) { + Uint32 genseed[4][8]; + surf_seed[0] = surf_seed[1] = gtime(); + surf_in[0]++; surf(genseed[0], surf_in, surf_seed); + surf_in[0]++; surf(genseed[1], surf_in, surf_seed); + surf_in[0]++; surf(genseed[2], surf_in, surf_seed); + surf_in[0]++; surf(genseed[3], surf_in, surf_seed); + memcpy(surf_seed, genseed[0], 32); + memcpy(surf_seed, genseed[1], 32); + memcpy(surf_seed, genseed[2], 32); + memcpy(surf_seed, genseed[3], 32); + surf_in[0] = gtime(); + surf(genseed[0], surf_in, surf_seed); + surf_in[0] = 0; + unique = genseed[0][0]; + } else { + read(fd, &unique, sizeof(unique)); + read(fd, &surf_seed, sizeof(surf_seed)); + close(fd); + } + + return unique; +} + +static Uint32 surf_random(void) { + if (surf_left == 0) { + int i; + for (i = 0; (i < 12) && !(++surf_in[i]); i++) ; + surf_left = 8; + surf(surf_out, surf_in, surf_seed); + } + return surf_out[--surf_left]; +} + +void read_seed_unique(unsigned char *buf) { + int i; + + memset(surf_in, 0, sizeof(surf_in)); + memset(surf_out, 0, sizeof(surf_out)); + surf_left = 0; + + memcpy(&surf_seed, buf, sizeof(surf_seed)); + memcpy(&network_unique, buf+sizeof(surf_seed), sizeof(network_unique)); + cur_unique = ntohl(network_unique); + for (i = 0; i < 32; i++) surf_seed[i] = ntohl(surf_seed[i]); +} + +unsigned char* write_seed_unique(unsigned char *buf) { + int i; + + for (i = 0; i < 32; i++) { + Uint32 l = htonl(surf_seed[i]); + memcpy(buf, &l, sizeof(l)); + buf += sizeof(l); + } + memcpy(buf, &network_unique, sizeof(network_unique)); + buf += sizeof(network_unique); + return buf; +} + +void create_seed_unique(void) { + cur_unique = surf_init(); + network_unique = htonl(cur_unique); +} + +int myrand(void) { + return surf_random() & 0xffffu; +} + +#if 0 /* random generator */ #define TAP1 250 @@ -87,18 +198,20 @@ void set_unique(Uint32 unique) { Uint32 get_unique(void) { return cur_unique; } +#endif void nomem(char *str) { printf("No memory!!![%s]\n",str); exit(1); } -void mypause(void) { +int mypause(void) { while(!interrupted) { pollinput(); SDL_Delay(1); } interrupted=0; + return 1; } static Uint32 sdlhandler(Uint32 time) { diff --git a/utils.h b/utils.h index 4d1650b..45b69b8 100644 --- a/utils.h +++ b/utils.h @@ -4,9 +4,16 @@ Uint32 gtime(void); Uint32 longtime(void); +#if 0 void create_unique(void); void set_unique(Uint32 unique); Uint32 get_unique(void); +#endif + +#define SEED_UNIQUE_SIZE (32*4+4) +void read_seed_unique(unsigned char *buf); +unsigned char* write_seed_unique(unsigned char *buf); +void create_seed_unique(void); extern Uint32 network_unique; @@ -14,7 +21,7 @@ int myrand(void); void nomem(char *str); -void mypause(void); +int mypause(void); void pulseon(void); void hexdump(unsigned char *p, int len);