Split source in more files, changed network behavior to prepare for direct connect.

This commit is contained in:
Stefan Bühler 2009-08-08 21:45:49 +02:00
parent 69a7bcafc7
commit c5aa13ac27
21 changed files with 2755 additions and 2541 deletions

View File

@ -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

34
README
View File

@ -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.

34
TODO
View File

@ -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.

View File

@ -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;

View File

@ -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();

2433
bomber.c

File diff suppressed because it is too large Load Diff

View File

@ -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,8 +159,7 @@ typedef struct generic
int data1,data2;
} generic;
typedef struct bonustile
{
typedef struct bonustile {
struct bonustile *next;
int xpos,ypos;
int px,py;
@ -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

448
draw.c Normal file
View File

@ -0,0 +1,448 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <netdb.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <signal.h>
#include <fcntl.h>
#include <stdarg.h>
#include "bomber.h"
#include "draw.h"
#include "game.h"
#include "gfx.h"
#include "utils.h"
#ifndef DATADIR
#define DATADIR "data"
#endif
#define NUMCHARACTERS 50
static figure font[NUMCHARACTERS];
static figure bigfont[NUMCHARACTERS];
gfxset gfxsets[NUMGFX];
static char walkingname[256];
static char colorsetname[256];
static char backgroundname[256];
static char blocksname[256];
static char blocksxname[256];
static char bombs1name[256];
static char bombs2name[256];
static char flamesname[256];
static char tilesname[256];
static char deathname[256];
static char fontname[256];
static char bigfontname[256];
figure blocks[3];
figure blocksx[9];
figure bombs1[MAXSETS][NUMBOMBFRAMES];
figure bombs2[MAXSETS][NUMBOMBFRAMES];
figure flamefigs[MAXSETS][NUMFLAMEFRAMES];
figure tiles[15];
figure death[NUMDEATHFRAMES];
int fontxsize,fontysize;
int bigfontxsize,bigfontysize,bigfontyspace;
static int textx,texty;
static char *remapstring="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ.:!?\177/\\*-,>< =";
static char asciiremap[256];
/* On screen array variables */
int arraynumx=15;
int arraynumy=11;
int arraystartx=20;
int arraystarty=70;
int arrayspacex=40;
int arrayspacey=36;
static sprite sprites[MAXSPRITES];
static int spritesused=0;
#define IBUFFLEN 1024
int ileft=0,ihand=0,byteswide;
unsigned char ibuff[IBUFFLEN],*itake;
static void freegfxset(gfxset *gs) {
if(gs->gs_pic) free(gs->gs_pic);
gs->gs_pic=0;
}
static int myci() {
if (!ileft) {
ileft=read(ihand,ibuff,IBUFFLEN);
if(!ileft) return -1;
itake=ibuff;
}
ileft--;
return *itake++;
}
static int dopcxreal(char *name,gfxset *gs) {
int xs,ys;
int i,j,k;
int totalsize;
int width,height;
unsigned char *bm,*lp;
char tname[256];
memset(gs,0,sizeof(gfxset));
ileft=0;
sprintf(tname,DATADIR "/%s",name);
ihand=open(tname,O_RDONLY);
if(ihand<0) {
char tname2[256];
sprintf(tname2,"%s.pcx",tname);
ihand=open(tname2,O_RDONLY);
if(ihand<0)
return 1;
}
if(myci()!=10) {close(ihand);return 2;} // 10=zsoft .pcx
if(myci()!=5) {close(ihand);return 3;} // version 3.0
if(myci()!=1) {close(ihand);return 4;} //encoding method
if(myci()!=8) {close(ihand);return 5;} //bpp
xs=myci();
xs|=myci()<<8;
ys=myci();
ys|=myci()<<8;
width=myci();
width|=myci()<<8;
height=myci();
height|=myci()<<8;
width=width+1-xs;
height=height+1-ys;
for(i=0;i<48+4;++i) myci();
myci();
if(myci()!=1) {close(ihand);return 6;} // # of planes
byteswide=myci();
byteswide|=myci()<<8;
i=myci();
i|=myci()<<8;
// if(i!=1) {close(ihand);return 7;} // 1=color/bw,2=grey
for(i=0;i<58;++i) myci();
totalsize=height*byteswide;
bm=malloc(totalsize+1);
if(!bm) {close(ihand);return 8;} // no memory
gs->gs_pic=bm;
gs->gs_xsize=width;
gs->gs_ysize=height;
while(height--) {
lp=bm;
i=byteswide;
while(i>0) {
j=myci();
if(j<0xc0) {
*lp++=j;
--i;
} else {
j&=0x3f;
k=myci();
while(j-- && i) {
*lp++=k;
--i;
}
}
}
bm+=width;
}
lseek(ihand,-0x300,SEEK_END);
read(ihand,gs->gs_colormap,0x300);
close(ihand);
return 0;
}
static int dopcx(char *name,gfxset *gs) {
int err;
err=dopcxreal(name,gs);
if(err)
printf("Error loading \"%s\":code %d\n",name,err);
return err;
}
static void getgroup(char *name,gfxset *colorgs,figure *fig,int count) {
int err;
int i;
gfxset gs;
err=dopcx(name,&gs);
if(err) exit(1000+err);
createinout(&gs);
for(i=0;i<MAXSETS;++i,fig+=count,++colorgs) {
if(!colorgs->gs_pic) continue;
memmove(gs.gs_colormap,colorgs->gs_colormap,
sizeof(gs.gs_colormap));
createinout(&gs);
gfxfetch(&gs,fig,count);
}
freegfxset(&gs);
}
static void getsingle(char *name,figure *fig,int count) {
gfxset gs;
int err;
err=dopcx(name,&gs);
if(err) exit(1000+err);
createinout(&gs);
gfxfetch(&gs,fig,count);
freegfxset(&gs);
}
static void texthome(void) {
textx=texty=10;
}
// static void drawstring(int xpos,int ypos,char *str) {
// char ch;
//
// while((ch=*str++)) {
// drawfigure(xpos,ypos,font+asciiremap[toupper(ch)]);
// xpos+=fontxsize;
// }
// }
void drawbigstring(int xpos,int ypos,char *str) {
char ch;
while('\0' != (ch=*str++)) {
drawfigure(xpos,ypos,bigfont+asciiremap[toupper(ch)]);
xpos+=bigfontxsize;
}
}
void centerbig(int y,char *str) {
int w;
w=strlen(str)*bigfontxsize;
drawbigstring((IXSIZE-w)>>1,y,str);
}
// static void scrprintf(char *str,...) {
// char output[256],*p,*p2;
// va_list ap;
//
// va_start(ap, str);
//
// vsprintf(output,str,ap);
// p=output;
// for(;;) {
// p2=p;
// while(*p2 && *p2!='\n') ++p2;
// if(*p2) {
// *p2=0;
// drawstring(textx,texty,p);
// texty+=fontysize;
// textx=10;
// p=p2+1;
// } else {
// drawstring(textx,texty,p);
// textx+=fontxsize*(p2-p);
// break;
// }
// }
// copyup();
// }
static void bigscrprintf(char *str,...) {
char output[256],*p,*p2;
va_list ap;
va_start(ap, str);
vsprintf(output,str,ap);
p=output;
for(;;) {
p2=p;
while(*p2 && *p2!='\n') ++p2;
if(*p2) {
*p2=0;
drawbigstring(textx,texty,p);
texty+=bigfontysize;
textx=10;
p=p2+1;
} else {
drawbigstring(textx,texty,p);
textx+=bigfontxsize*(p2-p);
break;
}
}
copyup();
}
void addsprite(int x,int y,figure *fig) {
sprite *sp;
if(spritesused==MAXSPRITES) return;
sp=sprites+spritesused++;
sp->flags=0;
sp->xpos=x;
sp->ypos=y;
sp->fig=fig;
}
void plotsprites(void) {
int i;
sprite *sp;
sp=sprites;
for(i=0;i<spritesused;++i) {
drawfigure(sp->xpos,sp->ypos,sp->fig);
++sp;
}
}
void erasesprites(void) {
int i;
sprite *sp;
figure *fig;
sp=sprites;
for(i=0;i<spritesused;++i) {
fig=sp->fig;
solidcopy(&background,
sp->xpos+fig->xdelta,sp->ypos+fig->ydelta,
fig->xsize,fig->ysize);
++sp;
}
}
void clearsprites(void) {
int i;
sprite *sp;
figure *fig;
sp=sprites;
for(i=0;i<spritesused;++i) {
fig=sp->fig;
clearrect(sp->xpos+fig->xdelta,sp->ypos+fig->ydelta,
fig->xsize,fig->ysize);
++sp;
}
}
void clearspritelist(void) {
spritesused=0;
}
int tovideox(int x) {
return (x>>FRACTION)+arraystartx;
}
int tovideoy(int y) {
return (y>>FRACTION)+arraystarty;
}
int screentoarrayx(int x) {
x+=arrayspacex << (FRACTION+2);
return ((x>>FRACTION)+(arrayspacex>>1))/arrayspacex-4;
}
int screentoarrayy(int y) {
y+=arrayspacey << (FRACTION+2);
return ((y>>FRACTION)+(arrayspacey>>1))/arrayspacey-4;
}
int arraytoscreenx(int x) {
return arrayspacex*x<<FRACTION;
}
int arraytoscreeny(int y) {
return arrayspacey*y<<FRACTION;
}
static void loadfonts(void) {
int i,j;
char *p;
getsingle(fontname,font,NUMCHARACTERS);
getsingle(bigfontname,bigfont,NUMCHARACTERS);
fontxsize=8;
fontysize=12;
bigfontxsize=16;
bigfontysize=24;
bigfontyspace=32;
p=remapstring;
j=0;while(*p && *p!=' ') ++p,++j;
memset(asciiremap,j,sizeof(asciiremap));
p=remapstring;
i=0;
while(*p && i<40)
asciiremap[(int)*p++]=i++;
}
void loadgfx() {
gfxset *gs;
gfxset *colorgs;
int err;
int i;
char name[256];
strcpy(walkingname,"walk");
strcpy(colorsetname,"pal");
strcpy(backgroundname,"field0");
strcpy(blocksname,"blocks3");
strcpy(blocksxname,"blocks3x");
strcpy(bombs1name,"bomb1");
strcpy(bombs2name,"bomb2");
strcpy(flamesname,"flames");
strcpy(tilesname,"tiles");
strcpy(deathname,"death1");
strcpy(fontname,"font");
strcpy(bigfontname,"bigfont");
gs=malloc((MAXSETS+1)*sizeof(gfxset));
if(!gs)
nomem("loadgfx");
colorgs=gs+1;
for(i=0;i<MAXSETS;++i) {
sprintf(name,"%s%d",colorsetname,i);
err=dopcx(name,colorgs+i);
if(err) continue;
}
loadfonts();
texthome();
bigscrprintf("Loading graphics...\n");
err=dopcx(backgroundname,gs);
if(err) exit(1000+err);
createinout(gs);
solidfetch(gs,&background);
solidfetch(gs,&backgroundoriginal);
freegfxset(gs);
bigscrprintf("Loading blocks\n");
getsingle(blocksname,blocks,3);
bigscrprintf("Loading block explosions\n");
getsingle(blocksxname,blocksx,9);
bigscrprintf("Loading walking figures\n");
getgroup(walkingname,colorgs,walking[0],NUMWALKFRAMES);
bigscrprintf("Loading normal bombs\n");
getgroup(bombs1name,colorgs,bombs1[0],NUMBOMBFRAMES);
bigscrprintf("Loading controlled bombs\n");
getgroup(bombs2name,colorgs,bombs2[0],NUMBOMBFRAMES);
bigscrprintf("Loading flames\n");
// getgroup(flamesname,colorgs,flamefigs[0],NUMFLAMEFRAMES);
getsingle(flamesname,flamefigs[0],NUMFLAMEFRAMES);
bigscrprintf("Loading bonus tiles\n");
getsingle(tilesname,tiles,15);
bigscrprintf("Loading death sequence\n");
getsingle(deathname,death,NUMDEATHFRAMES);
for(i=0;i<MAXSETS;++i)
freegfxset(colorgs+i);
free(gs);
bigscrprintf("Done loading graphics\n");
}

38
draw.h Normal file
View File

@ -0,0 +1,38 @@
#ifndef DRAW_H
#define DRAW_H
void loadgfx(void);
void drawbigstring(int xpos,int ypos,char *str);
void centerbig(int y,char *str);
void addsprite(int x,int y,figure *fig);
void plotsprites(void);
void erasesprites(void);
void clearsprites(void);
void clearspritelist(void);
int tovideox(int x);
int tovideoy(int y);
int screentoarrayx(int x);
int screentoarrayy(int y);
int arraytoscreenx(int x);
int arraytoscreeny(int y);
extern int bigfontxsize,bigfontysize,bigfontyspace;
/* On screen array variables */
extern int arraynumx, arraynumy, arraystartx, arraystarty, arrayspacex, arrayspacey;
/* Animation specific #defines */
#define NUMBOMBFRAMES 10
#define NUMWALKFRAMES 60
#define NUMFLAMEFRAMES 80
#define NUMDEATHFRAMES 41
extern figure blocks[3], blocksx[9], bombs1[MAXSETS][NUMBOMBFRAMES], bombs2[MAXSETS][NUMBOMBFRAMES], flamefigs[MAXSETS][NUMFLAMEFRAMES], tiles[15], death[NUMDEATHFRAMES];
#endif

944
game.c Normal file
View File

@ -0,0 +1,944 @@
#include "bomber.h"
#include "game.h"
#include "gfx.h"
#include "network.h"
#include "draw.h"
#include "utils.h"
#include "sound.h"
#include "menu.h"
#include "list.h"
static int gameframe;
static list activebombs;
static list activedecays;
static list activebonus;
static list activegeneric;
static bomb *detonated[MAXBOMBSDETONATED];
static int detonateput=0;
static int detonatetake=0;
static list activeflames;
static list activeplayers;
#define REGISTERLEN (1+4+4+4+16+1)
figure walking[MAXSETS][NUMWALKFRAMES];
solid background,backgroundoriginal;
/* The playfield array, contains FIELD_* equates */
unsigned char field[32][32];
void *info[32][32];
int gamemode = 0;
char exitflag = 0;
static int framecount = 0;
char playername[16];
static int gountil, mycount;
static int bonustotal;
static const int bonuschances[]= {
TILE_BOMB,20,
TILE_FLAME,20,
TILE_CONTROL,2,
TILE_GOLDFLAME,2,
TILE_SKATES,20,
TILE_TURTLE,5,
TILE_NONE,160
};
static unsigned char gameoptions[10];
static const unsigned char playerpositions[] = { /* color, x, y */
2,0,0,
3,14,10,
4,14,0,
5,0,10,
1,6,0,
6,8,10,
7,0,6,
8,14,4,
};
static void initplayer(int color,int x,int y,int controller) {
player *pl;
pl=allocentry();
if(!pl)
nomem("Couldn't get player structure (allocentry())");
addtail(&activeplayers,pl);
memset(pl,0,sizeof(player));
pl->xpos=arraytoscreenx(x);
pl->ypos=arraytoscreeny(y);
pl->color=color;
pl->speed=SPEEDSTART;
pl->flags=0;
pl->fixx=-4;
pl->fixy=-40;
pl->flamelength=gameoptions[GO_FLAMES]+1;
pl->bombsavailable=gameoptions[GO_BOMBS]+1;
pl->controller=controller;
field[y][x]=FIELD_EMPTY;
if(x) field[y][x-1]=FIELD_EMPTY;
if(y) field[y-1][x]=FIELD_EMPTY;
if(x<arraynumx-1) field[y][x+1]=FIELD_EMPTY;
if(y<arraynumy-1) field[y+1][x]=FIELD_EMPTY;
}
static void initplayers(void) {
int i;
const unsigned char *p;
int c,x,y;
if(!network) {
initplayer(2,0,0,-1);
return;
}
p=playerpositions;
for(i=0;i<MAXNETNODES;++i) {
if(!netnodes[i].used) continue;
c=*p++;
x=*p++;
y=*p++;
initplayer(c,x,y,i);
}
}
static void firstzero(void) {
gountil=mycount=mydatacount=0;
memset(latestactions,0,sizeof(latestactions));
memset(latestcounts,0,sizeof(latestcounts));
actionput=actioncount=0;
}
static void initgame() {
int i,j;
int x,y;
int bl;
const int *p;
int comp;
if (network != NETWORK_SLAVE)
set_game_options(configopts);
gameframe=0;
allocthings();
initheader(&activebombs);
initheader(&activeflames);
initheader(&activedecays);
initheader(&activebonus);
initheader(&activeplayers);
initheader(&activegeneric);
detonateput=detonatetake=0;
p=bonuschances;
bonustotal=0;
for(;;) {
i=*p++;
if(i==TILE_NONE) break;
bonustotal+=*p++;
}
bonustotal += 64*(3-gameoptions[GO_GENEROSITY]);
memset(field,0,sizeof(field));
comp=gameoptions[GO_DENSITY];
for(j=0;j<arraynumy;++j)
for(i=0;i<arraynumx;++i) {
/* if((i&j)&1) {
field[j][i]=FIELD_BORDER;
} else*/
field[j][i]=
(myrand()&3)>=comp ? FIELD_BRICK : FIELD_EMPTY;
}
solidcopyany(&backgroundoriginal,&background,0,0,IXSIZE,IYSIZE);
initplayers();
for(j=0;j<arraynumy;++j) {
y=arraystarty+j*arrayspacey;
for(i=0;i<arraynumx;++i) {
x=arraystartx+i*arrayspacex;
bl=field[j][i];
if(bl==FIELD_BORDER) bl=2;
else if(bl==FIELD_BRICK) bl=1;
else continue;
drawfigureany(x,y,blocks+bl,&background);
}
}
solidcopy(&background,0,0,IXSIZE,IYSIZE);
copyup();
}
void run_single_player(void) {
int code;
network=0;
firstzero();
do {
initgame();
while(!(code=iterate())) ++framecount;
} while (code != CODE_QUIT);
gamemode=0;
}
void run_network_game(void) {
int code;
firstzero();
do {
initgame();
while(!(code=iterate())) ++framecount;
} while (code != CODE_QUIT);
network = 0;
gamemode = 0;
}
static void addflame(player *owner,int px,int py) {
flame *fl,*fl2;
fl=allocentry();
if(!fl) return;
addtail(&activeflames,fl);
field[py][px]=FIELD_FLAME;
info[py][px]=fl;
fl->px=px;
fl->py=py;
fl->xpos=arraytoscreenx(px);
fl->ypos=arraytoscreeny(py);
fl->owner=owner;
if(px && field[py][px-1]==FIELD_FLAME) {
fl2=info[py][px-1];
fl->lurd|=FL_LEFT;
fl2->lurd|=FL_RIGHT;
}
if(py && field[py-1][px]==FIELD_FLAME) {
fl2=info[py-1][px];
fl->lurd|=FL_UP;
fl2->lurd|=FL_DOWN;
}
if(px<arraynumx-1 && field[py][px+1]==FIELD_FLAME) {
fl2=info[py][px+1];
fl->lurd|=FL_RIGHT;
fl2->lurd|=FL_LEFT;
}
if(py<arraynumy-1 && field[py+1][px]==FIELD_FLAME) {
fl2=info[py+1][px];
fl->lurd|=FL_DOWN;
fl2->lurd|=FL_UP;
}
}
static void dropbomb(player *pl,int px,int py,int type){
bomb *bmb;
if(field[py][px]!=FIELD_EMPTY) return;
bmb=allocentry();
if(!bmb) return;
playsound(3);
addtail(&activebombs,bmb);
--(pl->bombsavailable);
field[py][px]=FIELD_BOMB;
info[py][px]=bmb;
bmb->type=type;
bmb->px=px;
bmb->py=py;
bmb->xpos=arraytoscreenx(px);
bmb->ypos=arraytoscreeny(py);
bmb->power=pl->flamelength;
bmb->owner=pl;
}
static void adddetonate(bomb *bmb) {
if(bmb->type==BOMB_OFF) return;
bmb->type=BOMB_OFF;
field[bmb->py][bmb->px]=FIELD_EXPLODING;
info[bmb->py][bmb->px]=0;
detonated[detonateput++]=bmb;
detonateput%=MAXBOMBSDETONATED;
}
static void processbombs() {
bomb *bmb;
bmb=activebombs.next;
while(bmb) {
switch(bmb->type) {
case BOMB_NORMAL:
++bmb->timer;
if(bmb->timer==BOMBLIFE)
adddetonate(bmb);
++(bmb->figcount);
break;
case BOMB_CONTROLLED:
++(bmb->figcount);
break;
}
bmb=bmb->next;
}
}
static void adddecay(int px,int py) {
brickdecay *bd;
int xpos,ypos;
bd=allocentry();
if(!bd) return;
field[py][px]=FIELD_EXPLODING;
bd->xpos=arraytoscreenx(px);
bd->ypos=arraytoscreeny(py);
bd->px=px;
bd->py=py;
addtail(&activedecays,bd);
xpos=tovideox(bd->xpos);
ypos=tovideoy(bd->ypos);
solidcopyany(&backgroundoriginal,&background,xpos,ypos,
arrayspacex,arrayspacey);
solidcopy(&background,xpos,ypos,arrayspacex,arrayspacey);
}
static void addbonus(int px,int py,int type) {
bonustile *bonus;
bonus=allocentry();
if(!bonus) return;
addtail(&activebonus,bonus);
bonus->px=px;
bonus->py=py;
bonus->xpos=arraytoscreenx(px);
bonus->ypos=arraytoscreeny(py);
bonus->type=type;
field[py][px]=FIELD_BONUS;
info[py][px]=bonus;
}
static void trybonus(int px,int py) {
int i=0, r;
const int *p;
if(field[py][px]!=FIELD_EMPTY) return;
p=bonuschances;
r=myrand()%bonustotal;
while(r>=0) {
i=*p++;
r-=*p++;
}
if(i==TILE_NONE) return;
addbonus(px,py,i);
}
static void deletebonus(bonustile *bonus) {
int px,py;
px=bonus->px;
py=bonus->py;
field[py][px]=0;
info[py][px]=0;
delink(&activebonus,bonus);
}
static void flameshaft(player *owner,int px,int py,int dx,int dy,int power) {
int there;
bomb *bmb;
while(power--) {
px+=dx;
py+=dy;
if(px<0 || py<0 || px>=arraynumx || py>=arraynumy) break;
there=field[py][px];
switch(there) {
case FIELD_BOMB:
bmb=info[py][px];
adddetonate(bmb);
break;
case FIELD_EMPTY:
addflame(owner,px,py);
break;
case FIELD_BRICK:
adddecay(px,py);
power=0;
break;
case FIELD_BONUS:
deletebonus(info[py][px]);
power=0;
break;
case FIELD_BORDER:
case FIELD_EXPLODING:
default:
power=0;
case FIELD_FLAME:
break;
}
}
}
static void detonatebomb(bomb *bmb) {
int px,py;
int power;
player *owner;
++(bmb->owner->bombsavailable);
px=bmb->px;
py=bmb->py;
power=bmb->power;
owner=bmb->owner;
delink(&activebombs,bmb);
addflame(owner,px,py);
flameshaft(owner,px,py,-1,0,power);
flameshaft(owner,px,py,0,-1,power);
flameshaft(owner,px,py,1,0,power);
flameshaft(owner,px,py,0,1,power);
}
static void dodetonations(void) {
int i=0;
while(detonatetake!=detonateput) {
++i;
detonatebomb(detonated[detonatetake]);
detonatetake=(detonatetake+1) % MAXBOMBSDETONATED;
}
if(i) playsound((myrand()&1) ? 0 : 4);
}
static void processflames(void) {
flame *fl,*fl2;
fl=activeflames.next;
while(fl) {
++(fl->timer);
fl=fl->next;
}
fl=activeflames.next;
while(fl) {
if(fl->timer==FLAMELIFE)
{
field[fl->py][fl->px]=FIELD_EMPTY;
info[fl->py][fl->px]=0;
fl2=fl;
fl=fl->next;
delink(&activeflames,fl2);
} else
fl=fl->next;
}
}
static void processdecays() {
brickdecay *bd,*bd2;
bd=activedecays.next;
while(bd) {
++(bd->timer);
if(bd->timer==DECAYLIFE) {
field[bd->py][bd->px]=FIELD_EMPTY;
trybonus(bd->px,bd->py);
bd2=bd;
bd=bd->next;
delink(&activedecays,bd2);
} else
bd=bd->next;
}
}
static void drawbombs(void) {
int j;
bomb *bmb;
struct figure *figtab;
int color;
int xpos,ypos;
bmb=activebombs.next;
while(bmb) {
color=bmb->owner->color;
figtab=(bmb->type==BOMB_NORMAL) ? bombs1[color] : bombs2[color];
j=bmb->figcount % (NUMBOMBFRAMES<<1);
if(j>=NUMBOMBFRAMES) j=(NUMBOMBFRAMES<<1)-j-1;
xpos=tovideox(bmb->xpos);
ypos=tovideoy(bmb->ypos)-3;
addsprite(xpos,ypos,figtab+j);
bmb=bmb->next;
}
}
static void drawflames(void) {
flame *fl;
int xpos,ypos;
int color;
int fig;
fl=activeflames.next;
while(fl) {
color=fl->owner->color;
xpos=tovideox(fl->xpos);
ypos=tovideoy(fl->ypos);
fig=(fl->timer*10)/FLAMELIFE;
if(fig>=5) fig=9-fig;
fig+=5*fl->lurd;
addsprite(xpos,ypos,flamefigs[0/* color */]+fig);
fl=fl->next;
}
}
static void drawdecays() {
brickdecay *bd;
bd=activedecays.next;
while(bd) {
addsprite(tovideox(bd->xpos),tovideoy(bd->ypos),
blocksx+(bd->timer*9)/DECAYLIFE);
bd=bd->next;
}
}
static void drawbonus() {
bonustile *bonus;
bonus=activebonus.next;
while(bonus) {
addsprite(tovideox(bonus->xpos),tovideoy(bonus->ypos),
tiles+bonus->type);
bonus=bonus->next;
}
}
static void drawplayers() {
player *pl;
int xpos,ypos;
pl=activeplayers.next;
while(pl) {
if(!(pl->flags & FLG_DEAD)) {
if(!pl->figure)
pl->figure=walking[pl->color]+30;
xpos=tovideox(pl->xpos)+pl->fixx;
ypos=tovideoy(pl->ypos)+pl->fixy;
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<<FRACTION;
speed=pl->speed;
val=pl->xpos+(max<<2);
val%=max;
line=max>>1;
if(val<line) {
if(val-speed<0)
return -val;
else
return -speed;
} else 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<<FRACTION;
speed=pl->speed;
val=pl->ypos+(max<<2);
val%=max;
line=max>>1;
if(val<line)
{
if(val-speed<0)
return -val;
else
return -speed;
} else 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->flamelength<maxflame)
++(pl->flamelength);
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<MAXNETNODES;++i)
{
if(netnodes[i].used && actions[i]==ACT_QUIT)
netnodes[i].used=0;
}
}
static int getaction(void) {
int what;
what=ACT_NONE;
if(checkpressed(MYLEFT)) what=ACT_LEFT;
else if(checkpressed(MYRIGHT)) what=ACT_RIGHT;
else if(checkpressed(MYDOWN)) what=ACT_DOWN;
else if(checkpressed(MYUP)) what=ACT_UP;
else if(checkdown(13)) what=ACT_ENTER;
else if(checkdown(0x1b)) what=ACT_QUIT;
if(checkdown(' '))
what|=ACT_PRIMARY;
if(checkdown('b'))
what|=ACT_SECONDARY;
return what;
}
int iterate(void) {
int i;
static int deathcount=0;
mypause();
scaninput();
erasesprites();
clearspritelist();
gfxunlock();
myaction=getaction();
if(!network && myaction==ACT_QUIT) return CODE_QUIT;
i=networktraffic();
if(i<0)
gountil=mycount+1;
else
gountil=i;
while(mycount<gountil) {
++mycount;
if(network) {
i=gountil-mycount;
if(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));
}

23
game.h Normal file
View File

@ -0,0 +1,23 @@
#ifndef GAME_H
#define GAME_H
#define FRACTION 9
#define SPEEDDELTA (1<<(FRACTION-1))
#define SPEEDMAX (10<<FRACTION)
#define SPEEDSTART (6<<FRACTION)
#define SPEEDTURTLE (3<<FRACTION)
#define SPEEDTURTLE_TIMEOUT 250
#define TEMPNODES 2
void run_single_player(void);
void run_network_game(void);
void set_game_options(unsigned char options[10]);
extern char playername[16];
extern int gamemode;
extern solid background,backgroundoriginal;
#endif

62
list.c Normal file
View File

@ -0,0 +1,62 @@
#include "bomber.h"
#include "list.h"
#include "utils.h"
static listitem *things=0, *free_things;
void allocthings(void) {
int i;
const int num = MAXTHINGS;
if (!things) {
things = calloc(sizeof(listitem), num);
} else {
memset(things, 0, sizeof(listitem)*num);
}
if(!things) nomem("Trying to allocate thing memory");
for(i=0;i<num-1;++i) {
things[i].next = &things[i+1];
}
things[i].next = 0;
free_things = things;
}
void *allocentry(void) {
listitem *entry = free_things;
if (free_things) {
free_things = free_things->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));
}

12
list.h Normal file
View File

@ -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

360
menu.c Normal file
View File

@ -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<menunum;++i)
{
j=strlen(menuitems[i])*bigfontxsize;
tx=(IXSIZE-j) >> 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<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(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;}
}
}
char *densities[]={"PACKED","HIGH","MEDIUM","LOW"};
char *generosities[]={"LOW","MEDIUM","HIGH","RIDICULOUS"};
static void config_menu(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 draw_host_game(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<MAXNETNODES;++i) {
if(!netnodes[i].used) continue;
name=netnodes[i].name;
sprintf(temp," %d %s",i+1,name);
drawbigstring(M3X,M3Y+(i+2)*bigfontyspace,temp);
}
copyup();
}
static void host_game(void) {
create_unique();
if (!start_network_game()) {
failure("COULD NOT REGISTER GAME");
return;
}
draw_host_game();
for(;;) {
scaninput();
while(anydown()) {
switch(takedown()) {
case 0x1b:
unregistergame();
cancel_network_game();
gamemode=0;
return;
case ' ':
case 13:
unregistergame();
if (begin_network_game()) {
gamemode=5;
return;
}
send_invites();
draw_host_game();
}
}
if (!handle_joins()) continue;
send_invites();
draw_host_game();
}
gamemode=0;
}
static void join_game(void) {
int i;
int sel;
if (!searchgames(gameversion)) {
gamemode = 0;
return;
}
if (gamelistsize == 0) {
menustart();
additem("NO GAMES AVAILABLE");
domenu(-1);
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)) {
gamemode=0;
return;
}
network = NETWORK_SLAVE;
gamemode=5;
}
void (*modefunctions[])()= {
main_menu,
run_single_player,
config_menu,
host_game,
join_game,
run_network_game,
};
void mainloop(void) {
exitflag=0;
while(!exitflag)
modefunctions[gamemode]();
}

10
menu.h Normal file
View File

@ -0,0 +1,10 @@
#ifndef MENU_H
#define MENU_H
void mainloop(void);
int iterate(void); /* bomber.c */
extern unsigned char configopts[10];
#endif

550
network.c Normal file
View File

@ -0,0 +1,550 @@
#include "bomber.h"
#include "announce.h"
#include "game.h"
#include "menu.h"
#include "network.h"
#include "utils.h"
#define MAXMSG 4096
int udpsocket;
const unsigned char gameversion[4]={0xda,0x01,0x00,0x04};
struct netnode netnodes[64];
static int informsize;
static unsigned char regpacket[64];
static struct sockaddr_in myname={0},mastername={0};
static socklen_t senderlength;
static struct sockaddr_in sender={0};
static unsigned char mesg[MAXMSG]="";
uchar needwhole=0;
int mydatacount;
int myslot;
network_type network = NETWORK_NONE;
static unsigned char hist[ACTIONHIST][MAXNETNODES];
int actionput,actioncount;
unsigned char actionblock[ACTIONHIST*MAXNETNODES];
int myaction;
unsigned char actions[MAXNETNODES];
unsigned char latestactions[MAXNETNODES];
long latestcounts[MAXNETNODES];
/* Network I/O, building/checking packets */
#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<NUMQ;++i) {
if(message[i].time) {
--message[i].time;
if(message[i].time) continue;
sendto(udpsocket,message[i].msg,message[i].len,0,
message[i].to,sizeof(struct sockaddr_in));
}
}
}
#endif
static int putmsg(struct sockaddr_in *toname,unsigned char *msg,int len) {
int status;
#if defined (TEST_LATENCY)
int i;
for(i=0;i<NUMQ;++i) {
if(!message[i].time) {
message[i].time=10;
message[i].to=toname;
memcpy(message[i].msg,msg,len);
message[i].len=len;
break;
}
}
return 0;
#else
status=sendto(udpsocket,msg,len,0,
(struct sockaddr *)toname,sizeof(struct sockaddr_in));
return status;
#endif
}
static int getmsg(int msec) {
int size;
memset(&sender,0,sizeof(sender));
senderlength=sizeof(sender);
if(msec) {
struct timeval timeout;
fd_set readfds;
int res;
memset(&timeout,0,sizeof(timeout));
timeout.tv_sec=msec/1000;
timeout.tv_usec=(msec%1000)*1000;
FD_ZERO(&readfds);
FD_SET(udpsocket,&readfds);
res=select(udpsocket+1,&readfds,0,0,&timeout);
if(res<=0) return -1;
}
size=recvfrom(udpsocket,mesg,MAXMSG,0,
(struct sockaddr *)&sender,&senderlength);
return size;
}
static int isvalidunique(unsigned char *p) {
return 0 == memcmp(p, &network_unique, 4);
}
static int isvalidversion(unsigned char *p) {
return 0 == memcmp(p, gameversion, 4);
}
static unsigned char* writeuint32(unsigned char *p, Uint32 i) {
p[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;i<MAXNETNODES;++i)
if(netnodes[i].used &&
!memcmp(&netnodes[i].netname.sin_addr.s_addr,host,4) &&
!memcmp(&netnodes[i].netname.sin_port,port,2))
return i;
return -1;
}
/* Handling game actions */
static void addactions(void) {
memmove(hist[actionput],actions,MAXNETNODES);
++actionput;
if(actionput==ACTIONHIST)
actionput=0;
++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;
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<MAXNETNODES;++i)
if(netnodes[i].used)
newactions[i]=ACT_QUIT;
}
memmove(actions,newactions,sizeof(actions));
addactions();
buildactions();
for(i=1;i<MAXNETNODES;++i)
if(netnodes[i].used)
sendactions(i);
for(i=1;i<MAXNETNODES;++i)
if(netnodes[i].used && actions[i]==ACT_QUIT)
netnodes[i].used=0;
return actioncount;
case NETWORK_SLAVE:
{
long latest=-1;
long lastsent;
lastsent=now=gtime();
++mydatacount;
sendmine(mydatacount);
for(;;) {
/*
if(gtime()-lastsent>=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<latest) continue;
latest=i;
memmove(actionblock,mesg+9,MAXNETNODES*ACTIONHIST);
}
}
return latest;
}
}
return -1;
}
/* Handling socket init */
int winsock=0;
void getsocket(void) {
int status;
socklen_t slen = sizeof(myname);
#if defined(__WIN32__) || defined(WIN32)
char dummydata[128];
if(WSAStartup(0x0101,(void *)dummydata)) {
printf("Windows dumped\n");
exit(1);
}
winsock=1;
#endif
udpsocket=socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP);
if(udpsocket==-1) {
perror("socket()");
exit(1);
}
memset(&myname,0,sizeof(myname));
myname.sin_family=AF_INET;
myname.sin_addr.s_addr=htonl(INADDR_ANY);
myname.sin_port=htons(0);
status=bind(udpsocket,(struct sockaddr *) &myname,sizeof(myname));
if(-1 == status) {
perror("bind()");
exit(1);
}
status = getsockname(udpsocket, (struct sockaddr *) &myname, &slen);
if(-1 == status) {
perror("getsockname()");
exit(1);
}
}
void freesocket(void) {
#if defined(__WIN32__) || defined(WIN32)
if(!winsock) return;
WSACleanup();
#endif
}
/* Join / Host Games */
static void buildinform(unsigned char type) {
unsigned char *put;
int i;
put=mesg;
*put++=type;
put = writeunique(put);
++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;i<MAXNETNODES;++i)
if(netnodes[i].used)
inform1(i);
}
//returns 0=ignore packet,1=we're rejected,2=INVITE,3=BEGIN
int scaninvite(int msec) {
int i, size;
unsigned char *take;
Uint32 unique = 0;
size = getmsg(msec);
if (size < 6) return 0;
if (*mesg!=PKT_INVITE && *mesg!=PKT_BEGIN) return 0;
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;
myslot=mesg[5];
if (6 == size || 0xff == mesg[5] || 0xff == mesg[6]) return 1;
/* update unique */
memcpy(&unique, mesg+1, 4);
if (unique != network_unique)
set_unique(ntohl(unique));
memset(netnodes,0,sizeof(netnodes));
size-=6;
take=mesg+6;
while(*take!=0xff && size>=17) {
if((i=*take)<MAXNETNODES) {
netnodes[i].used=1;
memmove(netnodes[i].name,take+1,16);
}
take+=17;
size-=17;
}
take++; size--; /* read 0xff */
if(*mesg==PKT_INVITE) {
return 2;
} else { /* BEGIN */
if (size != sizeof(configopts)) {
fprintf(stderr, "PKT_BEGIN has wrong size: %i != %i\n", size, (int) sizeof(configopts));
return 1; /* broken packet */
}
set_game_options(take);
return 3;
}
}
int send_join(struct sockaddr_in *netname, char playername[16]) {
int res = 0;
long now;
set_unique(-1); /* reset unique and random */
mastername = *netname;
*regpacket=PKT_JOIN;
writeversion(regpacket + 1);
memmove(regpacket+5, playername, 16);
now=longtime();
while(longtime()-now<10) {
putmsg(&mastername,regpacket,1+4+16);
if (0 == (res=scaninvite(1000))) continue;
return res;
}
return 0;
}
void send_quit() {
long now;
int size;
*regpacket = PKT_QUIT;
writeunique(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;
}
}
int start_network_game() {
if(!registergame(playername, myname.sin_port, gameversion)) return 0;
memset(netnodes,0,sizeof(netnodes));
netnodes[0].used=1;
memmove(netnodes[0].name,playername,16);
myslot=0;
return 1;
}
int begin_network_game() {
inform(PKT_BEGIN);
network = NETWORK_MASTER;
/* TODO: wait for ack */
return 1;
}
void send_invites() {
inform(PKT_INVITE);
}
void cancel_network_game() {
int i;
mesg[0] = PKT_INVITE;
writeunique(mesg+1);
mesg[5] = 0xff;
for(i=1;i<MAXNETNODES;++i) {
if(netnodes[i].used) {
putmsg(&netnodes[i].netname,mesg,6);
}
}
}
int handle_joins() {
int size;
int i, j;
unsigned char temp[64];
size=getmsg(40);
switch (*mesg) {
case PKT_JOIN:
if (size < 21 || !isvalidversion(mesg+1)) return 0;
break;
case PKT_QUIT:
if (size < 5 || !isvalidunique(mesg+1)) return 0;
break;
default:
return 0;
}
/* Find host in list:
* i == MAXETNODES: host not found, otherwise the found host
* only if host not found:
* j == -1: no free slot, otherwise first free slot
*/
j = -1;
for (i = 1; i < MAXNETNODES; ++i) {
if (!netnodes[i].used) {
if (-1 == j) j = i;
continue; /* don't compare with unused host */
}
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;
/* found host */
break;
}
if(*mesg==PKT_QUIT) {
if(i < MAXNETNODES) /* if host found, reset entry */
memset(netnodes+i,0,sizeof(struct netnode));
/* send always ACK for QUITs */
*temp=PKT_ACK;
memmove(temp+1,mesg,5);
putmsg(&sender,temp,6);
} else {
if (i==MAXNETNODES && j==-1) { /* reject */
*mesg=PKT_INVITE;
writeunique(mesg+1);
mesg[5]=0xff;
putmsg(&sender,mesg,6);
return 0;
}
/* no explicit ack, send invites to all later */
if(i==MAXNETNODES) i=j;
memmove(&netnodes[i].netname.sin_addr.s_addr,
&sender.sin_addr.s_addr,4);
memmove(&netnodes[i].netname.sin_port,
&sender.sin_port,2);
netnodes[i].netname.sin_family=AF_INET;
netnodes[i].used=1;
memmove(netnodes[i].name,mesg+5,16);
netnodes[i].name[15] = '\0';
}
return 1;
}

58
network.h Normal file
View File

@ -0,0 +1,58 @@
#ifndef NETWORK_H
#define NETWORK_H
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
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

View File

@ -7,6 +7,10 @@
#include "sound.h"
#ifndef DATADIR
#define DATADIR "data"
#endif
static char dirlist[]=DATADIR;
static int readsound(int num);

View File

@ -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);

127
utils.c Normal file
View File

@ -0,0 +1,127 @@
#include "bomber.h"
#include "utils.h"
#include "gfx.h"
#include <arpa/inet.h>
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");
}

26
utils.h Normal file
View File

@ -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