Merge branch 'upstream'
This commit is contained in:
commit
1b1d19bec5
2
Makefile
2
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
|
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
|
sound.o: sound.c sound.h
|
||||||
|
|
||||||
|
27
bomber.h
27
bomber.h
@ -166,13 +166,24 @@ typedef struct bonustile {
|
|||||||
int type;
|
int type;
|
||||||
} bonustile;
|
} bonustile;
|
||||||
|
|
||||||
#define TILE_NONE -1
|
enum tile_types {
|
||||||
#define TILE_BOMB 5
|
TILE_NONE = -1,
|
||||||
#define TILE_FLAME 2
|
TILE_DISEASE = 0,
|
||||||
#define TILE_GOLDFLAME 7
|
TILE_KICK = 1,
|
||||||
#define TILE_CONTROL 9
|
TILE_FLAME = 2,
|
||||||
#define TILE_SKATES 4
|
TILE_PUNCH = 3,
|
||||||
#define TILE_TURTLE 14
|
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
|
#define ACT_INVALID 0x88
|
||||||
@ -204,7 +215,7 @@ typedef struct bonustile {
|
|||||||
|
|
||||||
#define MAXTHINGS 500
|
#define MAXTHINGS 500
|
||||||
#define MAXSETS 8
|
#define MAXSETS 8
|
||||||
#define MAXSPRITES 128
|
#define MAXSPRITES 256
|
||||||
#define MAXDAMAGES 512
|
#define MAXDAMAGES 512
|
||||||
#define MAXBOMBSDETONATED 32
|
#define MAXBOMBSDETONATED 32
|
||||||
|
|
||||||
|
24
draw.c
24
draw.c
@ -446,3 +446,27 @@ void loadgfx() {
|
|||||||
free(gs);
|
free(gs);
|
||||||
bigscrprintf("Done loading graphics\n");
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
2
draw.h
2
draw.h
@ -21,6 +21,8 @@ int screentoarrayy(int y);
|
|||||||
int arraytoscreenx(int x);
|
int arraytoscreenx(int x);
|
||||||
int arraytoscreeny(int y);
|
int arraytoscreeny(int y);
|
||||||
|
|
||||||
|
void failure(char *str,...);
|
||||||
|
|
||||||
extern int bigfontxsize,bigfontysize,bigfontyspace;
|
extern int bigfontxsize,bigfontysize,bigfontyspace;
|
||||||
|
|
||||||
/* On screen array variables */
|
/* On screen array variables */
|
||||||
|
116
game.c
116
game.c
@ -23,8 +23,6 @@ static int detonatetake=0;
|
|||||||
static list activeflames;
|
static list activeflames;
|
||||||
static list activeplayers;
|
static list activeplayers;
|
||||||
|
|
||||||
#define REGISTERLEN (1+4+4+4+16+1)
|
|
||||||
|
|
||||||
figure walking[MAXSETS][NUMWALKFRAMES];
|
figure walking[MAXSETS][NUMWALKFRAMES];
|
||||||
solid background,backgroundoriginal;
|
solid background,backgroundoriginal;
|
||||||
|
|
||||||
@ -32,19 +30,18 @@ solid background,backgroundoriginal;
|
|||||||
unsigned char field[32][32];
|
unsigned char field[32][32];
|
||||||
void *info[32][32];
|
void *info[32][32];
|
||||||
|
|
||||||
int gamemode = 0;
|
|
||||||
char exitflag = 0;
|
char exitflag = 0;
|
||||||
static int framecount = 0;
|
static int framecount = 0;
|
||||||
|
|
||||||
char playername[16];
|
char playername[16];
|
||||||
|
|
||||||
static int gountil, mycount;
|
static int mycount;
|
||||||
|
|
||||||
static int bonustotal;
|
static int bonustotal;
|
||||||
static const int bonuschances[]= {
|
static const int bonuschances[]= {
|
||||||
TILE_BOMB,20,
|
TILE_BOMB,20,
|
||||||
TILE_FLAME,20,
|
TILE_FLAME,20,
|
||||||
TILE_CONTROL,2,
|
TILE_TRIGGER,2,
|
||||||
TILE_GOLDFLAME,2,
|
TILE_GOLDFLAME,2,
|
||||||
TILE_SKATES,20,
|
TILE_SKATES,20,
|
||||||
TILE_TURTLE,5,
|
TILE_TURTLE,5,
|
||||||
@ -53,7 +50,7 @@ TILE_NONE,160
|
|||||||
|
|
||||||
static GameOptions gameoptions;
|
static GameOptions gameoptions;
|
||||||
|
|
||||||
static const unsigned char playerpositions[] = { /* color, x, y */
|
static const unsigned char playerpositions[MAXNETNODES*3] = { /* color, x, y */
|
||||||
2,0,0,
|
2,0,0,
|
||||||
3,14,10,
|
3,14,10,
|
||||||
4,14,0,
|
4,14,0,
|
||||||
@ -94,7 +91,7 @@ static void initplayers(void) {
|
|||||||
const unsigned char *p;
|
const unsigned char *p;
|
||||||
int c,x,y;
|
int c,x,y;
|
||||||
|
|
||||||
if(!network) {
|
if(NETWORK_NONE == network) {
|
||||||
initplayer(2,0,0,-1);
|
initplayer(2,0,0,-1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -109,10 +106,11 @@ static void initplayers(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void firstzero(void) {
|
static void firstzero(void) {
|
||||||
gountil=mycount=mydatacount=0;
|
mycount = mydatacount = 0;
|
||||||
memset(latestactions,0,sizeof(latestactions));
|
memset(latestactions,0,sizeof(latestactions));
|
||||||
memset(latestcounts,0,sizeof(latestcounts));
|
memset(latestcounts,0,sizeof(latestcounts));
|
||||||
actionput=actioncount=0;
|
memset(actionblock,0,sizeof(actionblock));
|
||||||
|
actioncount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void initgame() {
|
static void initgame() {
|
||||||
@ -173,33 +171,6 @@ static void initgame() {
|
|||||||
copyup();
|
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) {
|
static void addflame(player *owner,int px,int py) {
|
||||||
flame *fl,*fl2;
|
flame *fl,*fl2;
|
||||||
|
|
||||||
@ -714,9 +685,9 @@ static void applybonus(player *pl,bonustile *bonus) {
|
|||||||
maxflame=arraynumx>arraynumy ? arraynumx : arraynumy;
|
maxflame=arraynumx>arraynumy ? arraynumx : arraynumy;
|
||||||
type=bonus->type;
|
type=bonus->type;
|
||||||
deletebonus(bonus);
|
deletebonus(bonus);
|
||||||
switch(type)
|
switch(type) {
|
||||||
{
|
|
||||||
case TILE_BOMB:
|
case TILE_BOMB:
|
||||||
|
if (pl->bombsavailable < 9)
|
||||||
++(pl->bombsavailable);
|
++(pl->bombsavailable);
|
||||||
break;
|
break;
|
||||||
case TILE_FLAME:
|
case TILE_FLAME:
|
||||||
@ -726,7 +697,7 @@ static void applybonus(player *pl,bonustile *bonus) {
|
|||||||
case TILE_GOLDFLAME:
|
case TILE_GOLDFLAME:
|
||||||
pl->flamelength=maxflame;
|
pl->flamelength=maxflame;
|
||||||
break;
|
break;
|
||||||
case TILE_CONTROL:
|
case TILE_TRIGGER:
|
||||||
pl->flags|=FLG_CONTROL;
|
pl->flags|=FLG_CONTROL;
|
||||||
break;
|
break;
|
||||||
case TILE_SKATES:
|
case TILE_SKATES:
|
||||||
@ -863,9 +834,10 @@ static int getaction(void) {
|
|||||||
return what;
|
return what;
|
||||||
}
|
}
|
||||||
|
|
||||||
int iterate(void) {
|
static int iterate(void) {
|
||||||
int i;
|
int i;
|
||||||
static int deathcount=0;
|
int gountil; /* destination tick */
|
||||||
|
static int deathcount = 0;
|
||||||
|
|
||||||
mypause();
|
mypause();
|
||||||
scaninput();
|
scaninput();
|
||||||
@ -874,22 +846,22 @@ int iterate(void) {
|
|||||||
clearspritelist();
|
clearspritelist();
|
||||||
gfxunlock();
|
gfxunlock();
|
||||||
|
|
||||||
myaction=getaction();
|
myaction = getaction();
|
||||||
if(!network && myaction==ACT_QUIT) return CODE_QUIT;
|
if (NETWORK_NONE == network && myaction==ACT_QUIT) return CODE_QUIT;
|
||||||
i=networktraffic();
|
if (NETWORK_NONE == network) {
|
||||||
if(i<0)
|
gountil = mycount + 1; /* single step in singly player mode */
|
||||||
gountil=mycount+1;
|
} else {
|
||||||
else
|
gountil = networktraffic(); /* as master single step, as slave as many as we can do */
|
||||||
gountil=i;
|
}
|
||||||
|
|
||||||
while(mycount<gountil) {
|
while (mycount < gountil) { /* simulate ticks up to gountil */
|
||||||
++mycount;
|
++mycount;
|
||||||
if(network) {
|
if (NETWORK_NONE != network) {
|
||||||
i=gountil-mycount;
|
i = gountil - mycount;
|
||||||
if(i>=ACTIONHIST) // too far behind
|
if(i >= ACTIONHIST) // too far behind
|
||||||
return CODE_QUIT;
|
goto leave_game;
|
||||||
memcpy(actions,actionblock+i*MAXNETNODES,MAXNETNODES);
|
memcpy(actions, actionblock+i*MAXNETNODES, MAXNETNODES);
|
||||||
if(actions[myslot]==ACT_QUIT) return CODE_QUIT;
|
if (actions[myslot] == ACT_QUIT) return CODE_QUIT;
|
||||||
}
|
}
|
||||||
processbombs();
|
processbombs();
|
||||||
dodetonations();
|
dodetonations();
|
||||||
@ -919,16 +891,14 @@ int iterate(void) {
|
|||||||
if(!activegeneric.next) {
|
if(!activegeneric.next) {
|
||||||
player *pl;
|
player *pl;
|
||||||
int deadplayers = 0;
|
int deadplayers = 0;
|
||||||
pl=activeplayers.next;
|
i = 0;
|
||||||
i=0;
|
for (pl = activeplayers.next; pl; pl = pl->next) {
|
||||||
while(pl) {
|
|
||||||
if(!(pl->flags & FLG_DEAD))
|
if(!(pl->flags & FLG_DEAD))
|
||||||
++i;
|
++i;
|
||||||
else
|
else
|
||||||
deadplayers++;
|
deadplayers++;
|
||||||
pl=pl->next;
|
|
||||||
}
|
}
|
||||||
if (deadplayers > 0 && (!i || (network && i==1))) {
|
if (deadplayers > 0 && (!i || (NETWORK_NONE != network && i==1))) {
|
||||||
++deathcount;
|
++deathcount;
|
||||||
if(deathcount==25)
|
if(deathcount==25)
|
||||||
return CODE_ALLDEAD;
|
return CODE_ALLDEAD;
|
||||||
@ -936,8 +906,34 @@ int iterate(void) {
|
|||||||
deathcount=0;
|
deathcount=0;
|
||||||
}
|
}
|
||||||
return CODE_CONT;
|
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) {
|
void set_game_options(GameOptions *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);
|
||||||
|
}
|
||||||
|
1
game.h
1
game.h
@ -21,7 +21,6 @@ void run_network_game(void);
|
|||||||
void set_game_options(GameOptions *options);
|
void set_game_options(GameOptions *options);
|
||||||
|
|
||||||
extern char playername[16];
|
extern char playername[16];
|
||||||
extern int gamemode;
|
|
||||||
|
|
||||||
extern solid background,backgroundoriginal;
|
extern solid background,backgroundoriginal;
|
||||||
|
|
||||||
|
205
menu.c
205
menu.c
@ -118,7 +118,8 @@ static int domenu(menuname whichmenu, int (*pause)(void)) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
menudelta = 0;
|
||||||
|
return menuexit;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void menustart() {
|
static void menustart() {
|
||||||
@ -172,84 +173,13 @@ static void addexit(char *item,...) {
|
|||||||
|
|
||||||
/* game menues */
|
/* 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<MAXNETNODES;++i)
|
|
||||||
{
|
|
||||||
if(!netnodes[i].used) continue;
|
|
||||||
memmove(name,netnodes[i].name,16);
|
|
||||||
name[16]=0;
|
|
||||||
sprintf(temp," %d %s",i+1,name);
|
|
||||||
drawbigstring(JX,JY+(i+1)*bigfontyspace,temp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int tryjoin(int which) {
|
|
||||||
int res;
|
|
||||||
|
|
||||||
if (0 == (res = send_join(&gamelistentries[which].netname, playername)))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
for ( ;; ) {
|
|
||||||
switch (res) {
|
|
||||||
case 1: return 0;
|
|
||||||
case 2:
|
|
||||||
drawjoinscreen();
|
|
||||||
copyup();
|
|
||||||
break;
|
|
||||||
case 3: return 1;
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
scaninput();
|
|
||||||
while(anydown()) {
|
|
||||||
switch(takedown()) {
|
|
||||||
case 0x1b:
|
|
||||||
send_quit();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
res=scaninvite(200);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void main_menu(void) {
|
|
||||||
int sel;
|
|
||||||
|
|
||||||
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(MENU_MAIN, NULL);
|
|
||||||
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;}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
char *densities[]={"PACKED","HIGH","MEDIUM","LOW"};
|
char *densities[]={"PACKED","HIGH","MEDIUM","LOW"};
|
||||||
char *generosities[]={"LOW","MEDIUM","HIGH","RIDICULOUS"};
|
char *generosities[]={"LOW","MEDIUM","HIGH","RIDICULOUS"};
|
||||||
|
|
||||||
static void config_menu(void) {
|
static void config_menu(void) {
|
||||||
int sel;
|
int sel;
|
||||||
|
|
||||||
for(;;) {
|
while (!exitflag) {
|
||||||
menustart();
|
menustart();
|
||||||
additem("GAME OPTIONS");
|
additem("GAME OPTIONS");
|
||||||
additem("RETURN TO MAIN MENU");
|
additem("RETURN TO MAIN MENU");
|
||||||
@ -258,30 +188,29 @@ static void config_menu(void) {
|
|||||||
additem("INITIAL FLAME LENGTH: %d",configopts.flames+1);
|
additem("INITIAL FLAME LENGTH: %d",configopts.flames+1);
|
||||||
additem("INITIAL NUMBER OF BOMBS: %d",configopts.bombs+1);
|
additem("INITIAL NUMBER OF BOMBS: %d",configopts.bombs+1);
|
||||||
sel=domenu(MENU_CONFIG, NULL);
|
sel=domenu(MENU_CONFIG, NULL);
|
||||||
if(!sel) {gamemode=0;break;}
|
switch (sel) {
|
||||||
if(sel==1) {
|
case 0:
|
||||||
|
return;
|
||||||
|
case 1:
|
||||||
configopts.density+=menudelta;
|
configopts.density+=menudelta;
|
||||||
configopts.density&=3;
|
configopts.density&=3;
|
||||||
}
|
break;
|
||||||
if(sel==2) {
|
case 2:
|
||||||
configopts.generosity+=menudelta;
|
configopts.generosity+=menudelta;
|
||||||
configopts.generosity&=3;
|
configopts.generosity&=3;
|
||||||
}
|
break;
|
||||||
if(sel==3) {
|
case 3:
|
||||||
configopts.flames+=menudelta;
|
configopts.flames+=menudelta;
|
||||||
configopts.flames&=7;
|
configopts.flames&=7;
|
||||||
}
|
break;
|
||||||
if(sel==4) {
|
case 4:
|
||||||
configopts.bombs+=menudelta;
|
configopts.bombs+=menudelta;
|
||||||
configopts.bombs&=7;
|
configopts.bombs&=7;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void failure(char *str,...) {
|
|
||||||
gamemode=0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void draw_host_game(void) {
|
static void draw_host_game(void) {
|
||||||
int i;
|
int i;
|
||||||
char *name;
|
char *name;
|
||||||
@ -319,13 +248,12 @@ static void host_game(void) {
|
|||||||
case 0x1b:
|
case 0x1b:
|
||||||
unregistergame();
|
unregistergame();
|
||||||
cancel_network_game();
|
cancel_network_game();
|
||||||
gamemode=0;
|
|
||||||
return;
|
return;
|
||||||
case ' ':
|
case ' ':
|
||||||
case 13:
|
case 13:
|
||||||
unregistergame();
|
unregistergame();
|
||||||
if (begin_network_game()) {
|
if (begin_network_game()) {
|
||||||
gamemode=5;
|
run_network_game();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
send_invites();
|
send_invites();
|
||||||
@ -338,8 +266,58 @@ static void host_game(void) {
|
|||||||
send_invites();
|
send_invites();
|
||||||
draw_host_game();
|
draw_host_game();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
gamemode=0;
|
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 < MAXNETNODES; ++i) {
|
||||||
|
if(!netnodes[i].used) continue;
|
||||||
|
memmove(name,netnodes[i].name,16);
|
||||||
|
name[16]=0;
|
||||||
|
sprintf(temp," %d %s",i+1,name);
|
||||||
|
drawbigstring(JX,JY+(i+1)*bigfontyspace,temp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tryjoin(int which) {
|
||||||
|
int res;
|
||||||
|
|
||||||
|
if (0 == (res = send_join(&gamelistentries[which].netname, playername))) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!exitflag) {
|
||||||
|
switch (res) {
|
||||||
|
case 1:
|
||||||
|
failure("Game closed");
|
||||||
|
return 0;
|
||||||
|
case 2:
|
||||||
|
drawjoinscreen();
|
||||||
|
copyup();
|
||||||
|
break;
|
||||||
|
case 3: return 1;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
scaninput();
|
||||||
|
while(anydown()) {
|
||||||
|
switch(takedown()) {
|
||||||
|
case 0x1b:
|
||||||
|
send_quit();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res=scaninvite(200);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int join_game_pause(void) {
|
static int join_game_pause(void) {
|
||||||
@ -353,7 +331,6 @@ static void join_game(void) {
|
|||||||
int sel = -1;
|
int sel = -1;
|
||||||
|
|
||||||
if (!searchgames()) {
|
if (!searchgames()) {
|
||||||
gamemode = 0;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -372,33 +349,49 @@ static void join_game(void) {
|
|||||||
addexit("EXIT");
|
addexit("EXIT");
|
||||||
}
|
}
|
||||||
sel = domenu(MENU_JOIN, join_game_pause);
|
sel = domenu(MENU_JOIN, join_game_pause);
|
||||||
|
if (menudelta < 0) sel = -1;
|
||||||
}
|
}
|
||||||
stop_search();
|
stop_search();
|
||||||
|
|
||||||
if(menuexit == sel || !gamelistsize) {
|
if(menuexit == sel || !gamelistsize) {
|
||||||
gamemode=0;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(!tryjoin(sel)) {
|
if(!tryjoin(sel)) {
|
||||||
gamemode=0;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
network = NETWORK_SLAVE;
|
run_network_game();
|
||||||
gamemode=5;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void (*modefunctions[])()= {
|
|
||||||
main_menu,
|
|
||||||
run_single_player,
|
|
||||||
config_menu,
|
|
||||||
host_game,
|
|
||||||
join_game,
|
|
||||||
run_network_game,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
void mainloop(void) {
|
void mainloop(void) {
|
||||||
exitflag=0;
|
int sel;
|
||||||
while(!exitflag)
|
|
||||||
modefunctions[gamemode]();
|
exitflag = 0;
|
||||||
|
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(MENU_MAIN, NULL);
|
||||||
|
if (menudelta < 0) sel = -1;
|
||||||
|
switch (sel) {
|
||||||
|
case 0:
|
||||||
|
return;
|
||||||
|
case 1:
|
||||||
|
run_single_player();
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
config_menu();
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
host_game();
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
join_game();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
2
menu.h
2
menu.h
@ -3,8 +3,6 @@
|
|||||||
|
|
||||||
void mainloop(void);
|
void mainloop(void);
|
||||||
|
|
||||||
int iterate(void); /* bomber.c */
|
|
||||||
|
|
||||||
extern struct GameOptions configopts;
|
extern struct GameOptions configopts;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
158
network.c
158
network.c
@ -5,13 +5,14 @@
|
|||||||
#include "menu.h"
|
#include "menu.h"
|
||||||
#include "network.h"
|
#include "network.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
#include "draw.h"
|
||||||
|
|
||||||
#define MAXMSG 4096
|
#define MAXMSG 4096
|
||||||
|
|
||||||
int udpsocket;
|
int udpsocket;
|
||||||
const unsigned char gameversion[4]={0xda,0x01,0x00,0x05};
|
const unsigned char gameversion[4]={0xda,0x01,0x00,0x06};
|
||||||
|
|
||||||
struct netnode netnodes[64];
|
struct netnode netnodes[MAXNETNODES];
|
||||||
|
|
||||||
static int informsize;
|
static int informsize;
|
||||||
static unsigned char regpacket[64];
|
static unsigned char regpacket[64];
|
||||||
@ -26,8 +27,7 @@ int mydatacount;
|
|||||||
int myslot;
|
int myslot;
|
||||||
network_type network = NETWORK_NONE;
|
network_type network = NETWORK_NONE;
|
||||||
|
|
||||||
static unsigned char hist[ACTIONHIST][MAXNETNODES];
|
int actioncount;
|
||||||
int actionput,actioncount;
|
|
||||||
unsigned char actionblock[ACTIONHIST*MAXNETNODES];
|
unsigned char actionblock[ACTIONHIST*MAXNETNODES];
|
||||||
|
|
||||||
int myaction;
|
int myaction;
|
||||||
@ -52,7 +52,7 @@ enum network_packet_types {
|
|||||||
/* slave -> master packets */
|
/* slave -> master packets */
|
||||||
PKT_MYDATA, /* 4 bytes unique #,4 bytes frame #, 1 byte data */
|
PKT_MYDATA, /* 4 bytes unique #,4 bytes frame #, 1 byte data */
|
||||||
/* master -> slave packets */
|
/* 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
|
PKT_INVALID = 0xff
|
||||||
};
|
};
|
||||||
@ -63,6 +63,13 @@ enum reject_reason {
|
|||||||
/* TODO: password? */
|
/* TODO: password? */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define _REJECT_LAST REJECT_VERSION
|
||||||
|
|
||||||
|
const char *reject_reason_str[] = {
|
||||||
|
"Server full",
|
||||||
|
"Version mismatch"
|
||||||
|
};
|
||||||
|
|
||||||
/* all bytes stored MSB first */
|
/* all bytes stored MSB first */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -246,56 +253,35 @@ static int isvalidmsg_from_master() {
|
|||||||
/* Handling game actions */
|
/* Handling game actions */
|
||||||
|
|
||||||
static void addactions(void) {
|
static void addactions(void) {
|
||||||
memmove(hist[actionput],actions,MAXNETNODES);
|
memmove(actionblock+MAXNETNODES, actionblock, (ACTIONHIST-1)*MAXNETNODES);
|
||||||
++actionput;
|
memcpy(actionblock, actions, MAXNETNODES);
|
||||||
if(actionput==ACTIONHIST)
|
|
||||||
actionput=0;
|
|
||||||
++actioncount;
|
++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) {
|
static void sendactions(int which) {
|
||||||
unsigned char msg[512];
|
unsigned char msg[512];
|
||||||
|
|
||||||
msg[0] = PKT_STEP;
|
msg[0] = PKT_STEP;
|
||||||
write_unique(msg+1);
|
write_unique(msg + 1);
|
||||||
writeuint32(msg+5, actioncount);
|
writeuint32(msg + 5, actioncount);
|
||||||
memcpy(msg+9,actionblock,MAXNETNODES*ACTIONHIST);
|
memcpy(msg + 9, actionblock, MAXNETNODES*ACTIONHIST);
|
||||||
putmsg(&netnodes[which].netname,msg,MAXNETNODES*ACTIONHIST+9);
|
putmsg(&netnodes[which].netname, msg, MAXNETNODES*ACTIONHIST + 9);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sendmine(int frame) {
|
static void sendmine(int frame) {
|
||||||
unsigned char msg[64];
|
unsigned char msg[64];
|
||||||
|
|
||||||
msg[0] = PKT_MYDATA;
|
msg[0] = PKT_MYDATA;
|
||||||
write_unique(msg+1);
|
write_unique(msg + 1);
|
||||||
writeuint32(msg+5, frame);
|
writeuint32(msg + 5, frame);
|
||||||
msg[9]=myaction;
|
msg[9] = myaction;
|
||||||
putmsg(&mastername,msg,10);
|
putmsg(&mastername, msg, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
int networktraffic(void) {
|
int networktraffic(void) {
|
||||||
int i;
|
int i;
|
||||||
int length;
|
int length;
|
||||||
int whosent;
|
int whosent;
|
||||||
unsigned char newactions[MAXNETNODES];
|
|
||||||
long now;
|
long now;
|
||||||
long count;
|
long count;
|
||||||
|
|
||||||
@ -303,70 +289,68 @@ int networktraffic(void) {
|
|||||||
case NETWORK_NONE:
|
case NETWORK_NONE:
|
||||||
return -1;
|
return -1;
|
||||||
case NETWORK_MASTER:
|
case NETWORK_MASTER:
|
||||||
memcpy(newactions,latestactions,MAXNETNODES);
|
memcpy(actions,latestactions,MAXNETNODES);
|
||||||
newactions[0]=myaction;
|
actions[0]=myaction;
|
||||||
|
if (myaction == ACT_QUIT) {
|
||||||
|
for (i = 1; i < MAXNETNODES; ++i) {
|
||||||
|
if (netnodes[i].used)
|
||||||
|
actions[i]=ACT_QUIT;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
now=gtime();
|
now=gtime();
|
||||||
for(;;) {
|
for(;;) {
|
||||||
if(gtime()-now>15) break;
|
if(gtime()-now>15) break;
|
||||||
length=getmsg(5);
|
length=getmsg(5);
|
||||||
if(length>0 && *mesg!=PKT_MYDATA) fprintf(stderr, "Strange packet %d\n", (int) *mesg);
|
if(length>0 && *mesg!=PKT_MYDATA) fprintf(stderr, "Strange packet %d\n", (int) *mesg);
|
||||||
// check for unexpected old packets...
|
/* check for unexpected old packets...
|
||||||
// for example JOIN on frame 0, respond with BEGIN if player already in game
|
* for example JOIN on frame 0, respond with BEGIN if player already in game
|
||||||
// respond with uninvite INVITE on JOIN from others
|
* respond with uninvite INVITE on JOIN from others
|
||||||
if(length<10) continue;
|
*/
|
||||||
|
if (length < 10) continue;
|
||||||
whosent = isvalidmsg_from_slave();
|
whosent = isvalidmsg_from_slave();
|
||||||
if(whosent<=0) continue;
|
if (whosent <= 0) continue;
|
||||||
count=readuint32(mesg+5);
|
count = readuint32(mesg+5);
|
||||||
if(count>latestcounts[whosent]) {
|
if (count > latestcounts[whosent]) {
|
||||||
latestcounts[whosent]=count;
|
latestcounts[whosent] = count;
|
||||||
newactions[whosent]=mesg[9];
|
actions[whosent] = mesg[9];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(myaction==ACT_QUIT) {
|
|
||||||
for(i=1;i<MAXNETNODES;++i)
|
|
||||||
if(netnodes[i].used)
|
|
||||||
newactions[i]=ACT_QUIT;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
memmove(actions,newactions,sizeof(actions));
|
addactions(); /* update action history block */
|
||||||
addactions();
|
|
||||||
buildactions();
|
for (i = 1; i < MAXNETNODES; ++i) {
|
||||||
for(i=1;i<MAXNETNODES;++i)
|
if(netnodes[i].used) {
|
||||||
if(netnodes[i].used)
|
sendactions(i); /* send actions to every active node */
|
||||||
sendactions(i);
|
if (actions[i]==ACT_QUIT)
|
||||||
for(i=1;i<MAXNETNODES;++i)
|
netnodes[i].used=0; /* remove disconnected clients */
|
||||||
if(netnodes[i].used && actions[i]==ACT_QUIT)
|
}
|
||||||
netnodes[i].used=0;
|
}
|
||||||
return actioncount;
|
return actioncount;
|
||||||
case NETWORK_SLAVE:
|
case NETWORK_SLAVE:
|
||||||
{
|
count = -1; /* set to actioncount if we got at least one packet */
|
||||||
long latest=-1;
|
now = gtime();
|
||||||
long lastsent;
|
|
||||||
|
|
||||||
lastsent=now=gtime();
|
|
||||||
++mydatacount;
|
++mydatacount;
|
||||||
sendmine(mydatacount);
|
sendmine(mydatacount);
|
||||||
|
|
||||||
for(;;) {
|
for(;;) {
|
||||||
/*
|
/* if we got already one packet we only wait 3msec, otherwise 30msec */
|
||||||
if(gtime()-lastsent>=1)
|
long cur = gtime();
|
||||||
{
|
if (count >= 0 && cur - now > 3) break;
|
||||||
lastsent=gtime();
|
if (exitflag || cur - now > 30) break;
|
||||||
sendmine(mydatacount);
|
|
||||||
}
|
length = getmsg(count >= 0 ? 3 : 20);
|
||||||
*/
|
|
||||||
if(latest>=0 && gtime()-now>3) break;
|
if (MAXNETNODES*ACTIONHIST+9 != length) continue;
|
||||||
length=getmsg(3);
|
if (!isvalidmsg_from_master()) continue;
|
||||||
if(length==MAXNETNODES*ACTIONHIST+9 &&
|
|
||||||
sender.sin_addr.s_addr==mastername.sin_addr.s_addr &&
|
i = readuint32(mesg+5);
|
||||||
sender.sin_port==mastername.sin_port) {
|
if (i < actioncount) continue;
|
||||||
i=readuint32(mesg+5);
|
count = actioncount = i;
|
||||||
if(i<latest) continue;
|
memcpy(actionblock,mesg+9,MAXNETNODES*ACTIONHIST);
|
||||||
latest=i;
|
|
||||||
memmove(actionblock,mesg+9,MAXNETNODES*ACTIONHIST);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return latest;
|
|
||||||
}
|
}
|
||||||
|
return actioncount;
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -671,6 +655,7 @@ int scaninvite(int msec) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (*mesg == PKT_BEGIN) {
|
if (*mesg == PKT_BEGIN) {
|
||||||
|
network = NETWORK_SLAVE;
|
||||||
return 3;
|
return 3;
|
||||||
} else {
|
} else {
|
||||||
return 2;
|
return 2;
|
||||||
@ -708,12 +693,17 @@ int send_join(struct sockaddr_in *netname, char playername[16]) {
|
|||||||
if (!read_inform(&buf,&size)) return 0;
|
if (!read_inform(&buf,&size)) return 0;
|
||||||
return 2;
|
return 2;
|
||||||
case PKT_REJECT:
|
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;
|
return 0;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
failure("Could not connect - Timeout");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,13 +5,15 @@
|
|||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
|
#define MAXNETNODES 8
|
||||||
|
|
||||||
struct netnode {
|
struct netnode {
|
||||||
struct sockaddr_in netname;
|
struct sockaddr_in netname;
|
||||||
char name[16];
|
char name[16];
|
||||||
char used;
|
char used;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct netnode netnodes[64];
|
extern struct netnode netnodes[MAXNETNODES];
|
||||||
|
|
||||||
void getsocket(void);
|
void getsocket(void);
|
||||||
void freesocket(void);
|
void freesocket(void);
|
||||||
@ -27,11 +29,6 @@ int begin_network_game();
|
|||||||
void send_invites();
|
void send_invites();
|
||||||
void cancel_network_game();
|
void cancel_network_game();
|
||||||
|
|
||||||
#define MAXNETNODES 10
|
|
||||||
|
|
||||||
extern struct netnode netnodes[64];
|
|
||||||
|
|
||||||
extern int udpsocket;
|
|
||||||
extern const unsigned char gameversion[4];
|
extern const unsigned char gameversion[4];
|
||||||
|
|
||||||
typedef enum { NETWORK_NONE = 0, NETWORK_MASTER, NETWORK_SLAVE } network_type;
|
typedef enum { NETWORK_NONE = 0, NETWORK_MASTER, NETWORK_SLAVE } network_type;
|
||||||
|
Loading…
Reference in New Issue
Block a user