diff --git a/Makefile b/Makefile index 61d1ee1..6bd384f 100644 --- a/Makefile +++ b/Makefile @@ -25,7 +25,7 @@ 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 +network.o: network.c announce.h bomber.h draw.h game.h menu.h network.h utils.h sound.o: sound.c sound.h diff --git a/bomber.h b/bomber.h index b3cb963..b526e67 100644 --- a/bomber.h +++ b/bomber.h @@ -166,13 +166,24 @@ typedef struct bonustile { int type; } bonustile; -#define TILE_NONE -1 -#define TILE_BOMB 5 -#define TILE_FLAME 2 -#define TILE_GOLDFLAME 7 -#define TILE_CONTROL 9 -#define TILE_SKATES 4 -#define TILE_TURTLE 14 +enum tile_types { + TILE_NONE = -1, + TILE_DISEASE = 0, + TILE_KICK = 1, + TILE_FLAME = 2, + TILE_PUNCH = 3, + TILE_SKATES = 4, + TILE_BOMB = 5, + TILE_SPOOGE = 6, + TILE_GOLDFLAME = 7, + TILE_BAD_DISEASE = 8, + TILE_TRIGGER = 9, + TILE_RANDOM = 10, + TILE_JELLY = 11, + TILE_GRAB = 12, + TILE_RANDOM2 = 13, + TILE_TURTLE = 14 +}; #define ACT_INVALID 0x88 @@ -204,7 +215,7 @@ typedef struct bonustile { #define MAXTHINGS 500 #define MAXSETS 8 -#define MAXSPRITES 128 +#define MAXSPRITES 256 #define MAXDAMAGES 512 #define MAXBOMBSDETONATED 32 diff --git a/draw.c b/draw.c index 5963e77..c6439e1 100644 --- a/draw.c +++ b/draw.c @@ -446,3 +446,27 @@ void loadgfx() { free(gs); bigscrprintf("Done loading graphics\n"); } + +void failure(char *str,...) { + char output[256]; + va_list ap; + int len; + long now; + + va_start(ap, str); + + len = vsnprintf(output, sizeof(output), str, ap); + if (len >= 256) len = 255; /* truncated string */ + clear(); + drawbigstring((IXSIZE - len*bigfontxsize) / 2, (IYSIZE-bigfontysize) / 2, output); + copyup(); + + now = longtime(); + while (!exitflag && longtime()-now < 3) { + scaninput(); + if (anydown()) { + takedown(); + return; + } + } +} diff --git a/draw.h b/draw.h index ecc8e93..89eb65e 100644 --- a/draw.h +++ b/draw.h @@ -21,6 +21,8 @@ int screentoarrayy(int y); int arraytoscreenx(int x); int arraytoscreeny(int y); +void failure(char *str,...); + extern int bigfontxsize,bigfontysize,bigfontyspace; /* On screen array variables */ diff --git a/game.c b/game.c index 18e4115..0a28b5a 100644 --- a/game.c +++ b/game.c @@ -23,8 +23,6 @@ static int detonatetake=0; static list activeflames; static list activeplayers; -#define REGISTERLEN (1+4+4+4+16+1) - figure walking[MAXSETS][NUMWALKFRAMES]; solid background,backgroundoriginal; @@ -32,19 +30,18 @@ solid background,backgroundoriginal; unsigned char field[32][32]; void *info[32][32]; -int gamemode = 0; char exitflag = 0; static int framecount = 0; char playername[16]; -static int gountil, mycount; +static int mycount; static int bonustotal; static const int bonuschances[]= { TILE_BOMB,20, TILE_FLAME,20, -TILE_CONTROL,2, +TILE_TRIGGER,2, TILE_GOLDFLAME,2, TILE_SKATES,20, TILE_TURTLE,5, @@ -53,7 +50,7 @@ TILE_NONE,160 static GameOptions gameoptions; -static const unsigned char playerpositions[] = { /* color, x, y */ +static const unsigned char playerpositions[MAXNETNODES*3] = { /* color, x, y */ 2,0,0, 3,14,10, 4,14,0, @@ -94,7 +91,7 @@ static void initplayers(void) { const unsigned char *p; int c,x,y; - if(!network) { + if(NETWORK_NONE == network) { initplayer(2,0,0,-1); return; } @@ -109,10 +106,11 @@ static void initplayers(void) { } static void firstzero(void) { - gountil=mycount=mydatacount=0; + mycount = mydatacount = 0; memset(latestactions,0,sizeof(latestactions)); memset(latestcounts,0,sizeof(latestcounts)); - actionput=actioncount=0; + memset(actionblock,0,sizeof(actionblock)); + actioncount = 0; } static void initgame() { @@ -173,33 +171,6 @@ static void initgame() { copyup(); } - -void run_single_player(void) { - int code; - network=0; - - firstzero(); - do { - initgame(); - while(!(code=iterate())) ++framecount; - } while (code != CODE_QUIT); - - gamemode=0; -} - -void run_network_game(void) { - int code; - - firstzero(); - do { - initgame(); - while(!(code=iterate())) ++framecount; - } while (code != CODE_QUIT); - - network = 0; - gamemode = 0; -} - static void addflame(player *owner,int px,int py) { flame *fl,*fl2; @@ -714,10 +685,10 @@ static void applybonus(player *pl,bonustile *bonus) { maxflame=arraynumx>arraynumy ? arraynumx : arraynumy; type=bonus->type; deletebonus(bonus); - switch(type) - { + switch(type) { case TILE_BOMB: - ++(pl->bombsavailable); + if (pl->bombsavailable < 9) + ++(pl->bombsavailable); break; case TILE_FLAME: if(pl->flamelengthflamelength=maxflame; break; - case TILE_CONTROL: + case TILE_TRIGGER: pl->flags|=FLG_CONTROL; break; case TILE_SKATES: @@ -863,9 +834,10 @@ static int getaction(void) { return what; } -int iterate(void) { +static int iterate(void) { int i; - static int deathcount=0; + int gountil; /* destination tick */ + static int deathcount = 0; mypause(); scaninput(); @@ -874,22 +846,22 @@ int iterate(void) { clearspritelist(); gfxunlock(); - myaction=getaction(); - if(!network && myaction==ACT_QUIT) return CODE_QUIT; - i=networktraffic(); - if(i<0) - gountil=mycount+1; - else - gountil=i; + myaction = getaction(); + if (NETWORK_NONE == network && myaction==ACT_QUIT) return CODE_QUIT; + if (NETWORK_NONE == network) { + gountil = mycount + 1; /* single step in singly player mode */ + } else { + gountil = networktraffic(); /* as master single step, as slave as many as we can do */ + } - while(mycount=ACTIONHIST) // too far behind - return CODE_QUIT; - memcpy(actions,actionblock+i*MAXNETNODES,MAXNETNODES); - if(actions[myslot]==ACT_QUIT) return CODE_QUIT; + if (NETWORK_NONE != network) { + i = gountil - mycount; + if(i >= ACTIONHIST) // too far behind + goto leave_game; + memcpy(actions, actionblock+i*MAXNETNODES, MAXNETNODES); + if (actions[myslot] == ACT_QUIT) return CODE_QUIT; } processbombs(); dodetonations(); @@ -919,16 +891,14 @@ int iterate(void) { if(!activegeneric.next) { player *pl; int deadplayers = 0; - pl=activeplayers.next; - i=0; - while(pl) { + i = 0; + for (pl = activeplayers.next; pl; pl = pl->next) { if(!(pl->flags & FLG_DEAD)) ++i; else deadplayers++; - pl=pl->next; } - if (deadplayers > 0 && (!i || (network && i==1))) { + if (deadplayers > 0 && (!i || (NETWORK_NONE != network && i==1))) { ++deathcount; if(deathcount==25) return CODE_ALLDEAD; @@ -936,8 +906,34 @@ int iterate(void) { deathcount=0; } return CODE_CONT; + +leave_game: /* client disconnect/timeout: send ACT_QUIT to master */ + myaction = ACT_QUIT; + networktraffic(); + return CODE_QUIT; } void set_game_options(GameOptions *options) { gameoptions = *options; } + +void run_single_player(void) { + int code; + network = NETWORK_NONE; + + firstzero(); + do { + initgame(); + while(!(code=iterate()) && !exitflag) ++framecount; + } while (code != CODE_QUIT && !exitflag); +} + +void run_network_game(void) { + int code; + + firstzero(); + do { + initgame(); + while (!(code=iterate()) && !exitflag) ++framecount; + } while (code != CODE_QUIT && !exitflag); +} diff --git a/game.h b/game.h index f66409d..084feb5 100644 --- a/game.h +++ b/game.h @@ -21,7 +21,6 @@ void run_network_game(void); void set_game_options(GameOptions *options); extern char playername[16]; -extern int gamemode; extern solid background,backgroundoriginal; diff --git a/menu.c b/menu.c index 2675245..4bb5bcc 100644 --- a/menu.c +++ b/menu.c @@ -118,7 +118,8 @@ static int domenu(menuname whichmenu, int (*pause)(void)) { } } } - return 0; + menudelta = 0; + return menuexit; } static void menustart() { @@ -172,84 +173,13 @@ static void addexit(char *item,...) { /* 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 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_STEP, /* 4 bytes unique #, 4 bytes frame #, history x MAXNETNODES bytes ACT_* */ PKT_INVALID = 0xff }; @@ -63,6 +63,13 @@ enum reject_reason { /* TODO: password? */ }; +#define _REJECT_LAST REJECT_VERSION + +const char *reject_reason_str[] = { + "Server full", + "Version mismatch" +}; + /* all bytes stored MSB first */ /* @@ -246,56 +253,35 @@ static int isvalidmsg_from_master() { /* Handling game actions */ static void addactions(void) { - memmove(hist[actionput],actions,MAXNETNODES); - ++actionput; - if(actionput==ACTIONHIST) - actionput=0; + memmove(actionblock+MAXNETNODES, actionblock, (ACTIONHIST-1)*MAXNETNODES); + memcpy(actionblock, actions, MAXNETNODES); ++actioncount; } -static void buildactions(void) { - unsigned char *p; - int i,j; - p=actionblock; - i=0; - while(i<20) { - if(actioncount-i>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[0] = PKT_STEP; - write_unique(msg+1); - writeuint32(msg+5, actioncount); - memcpy(msg+9,actionblock,MAXNETNODES*ACTIONHIST); - putmsg(&netnodes[which].netname,msg,MAXNETNODES*ACTIONHIST+9); + write_unique(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; - write_unique(msg+1); - writeuint32(msg+5, frame); - msg[9]=myaction; - putmsg(&mastername,msg,10); + write_unique(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; @@ -303,70 +289,68 @@ int networktraffic(void) { 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_from_slave(); - if(whosent<=0) continue; - count=readuint32(mesg+5); - if(count>latestcounts[whosent]) { - latestcounts[whosent]=count; - newactions[whosent]=mesg[9]; + memcpy(actions,latestactions,MAXNETNODES); + actions[0]=myaction; + if (myaction == ACT_QUIT) { + for (i = 1; i < MAXNETNODES; ++i) { + if (netnodes[i].used) + actions[i]=ACT_QUIT; + } + } else { + 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_from_slave(); + if (whosent <= 0) continue; + count = readuint32(mesg+5); + if (count > latestcounts[whosent]) { + latestcounts[whosent] = count; + actions[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= 0 && cur - now > 3) break; + if (exitflag || cur - now > 30) break; + + length = getmsg(count >= 0 ? 3 : 20); + + if (MAXNETNODES*ACTIONHIST+9 != length) continue; + if (!isvalidmsg_from_master()) continue; + + i = readuint32(mesg+5); + if (i < actioncount) continue; + count = actioncount = i; + memcpy(actionblock,mesg+9,MAXNETNODES*ACTIONHIST); } + return actioncount; } return -1; } @@ -671,6 +655,7 @@ int scaninvite(int msec) { } if (*mesg == PKT_BEGIN) { + network = NETWORK_SLAVE; return 3; } else { return 2; @@ -708,12 +693,17 @@ int send_join(struct sockaddr_in *netname, char playername[16]) { if (!read_inform(&buf,&size)) return 0; return 2; case PKT_REJECT: - /* TODO: print reject message */ + if (size < 10 || mesg[9] > _REJECT_LAST) { + failure("Couldn't connect"); + } else { + failure("Couldn't connect: %s", reject_reason_str[mesg[9]]); + } return 0; default: break; } } + failure("Could not connect - Timeout"); return 0; } diff --git a/network.h b/network.h index 3fa5628..7ac98dd 100644 --- a/network.h +++ b/network.h @@ -5,13 +5,15 @@ #include #include +#define MAXNETNODES 8 + struct netnode { struct sockaddr_in netname; char name[16]; char used; }; -extern struct netnode netnodes[64]; +extern struct netnode netnodes[MAXNETNODES]; void getsocket(void); void freesocket(void); @@ -27,11 +29,6 @@ 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;