diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7dca63a --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.o +bomber +matcher diff --git a/AUTHORS b/AUTHORS index 08f91a0..1c7d11d 100644 --- a/AUTHORS +++ b/AUTHORS @@ -2,3 +2,6 @@ David Ashley dashxdr@gmail.com http://www.xdr.com/dash http://www.linuxmotors.com + +Stefan Bühler +http://stbuehler.de/ diff --git a/INSTALL b/INSTALL deleted file mode 100644 index e69de29..0000000 diff --git a/Makefile b/Makefile index efb16d6..606c584 100644 --- a/Makefile +++ b/Makefile @@ -1,37 +1,23 @@ #DBG = -g CC = gcc -CFLAGS = -O2 -Wall $(shell sdl-config --cflags) $(DBG) +WARNFLAGS = -Wall -Wmissing-declarations -Wdeclaration-after-statement -Wcast-align -Winline -Wsign-compare -Wnested-externs -Wpointer-arith -Wformat-security +CFLAGS = -g -D_REENTRANT -O2 -Wall $(shell sdl-config --cflags) $(DBG) $(WARNFLAGS) -all: bomber matcher +.PHONY: all clean +all: bomber -bomber: bomber.o gfx.o sound.o matcher - gcc -o bomber bomber.o gfx.o sound.o $(shell sdl-config --libs) $(DBG) +bomber: bomber.o gfx.o sound.o announce.o matcher + gcc -o bomber bomber.o gfx.o sound.o announce.o $(shell sdl-config --libs) -lavahi-common -lavahi-client $(DBG) matcher: matcher.c -bomber.o: bomber.c bomber.h gfx.h +bomber.o: bomber.c bomber.h gfx.h announce.h -gfx.o: gfx.c gfx.h bomber.h +gfx.o: gfx.c gfx.h bomber.h -sound.o: sound.c +sound.o: sound.c + +announce.o: announce.c announce.h clean: rm -f *.o matcher bomber - -test: all - ./bomber - - - - -WORK = /ram -VER = 1.0.3 -DDIR = SDL_bomber-$(VER) - -package: clean - rm -rf $(WORK)/$(DDIR) - mkdir $(WORK)/$(DDIR) - cp *.c *.h Makefile* README INSTALL COPYING AUTHORS TODO $(WORK)/$(DDIR) - cp -a data $(WORK)/$(DDIR) - cp ChangeLog $(WORK)/$(DDIR) - cd $(WORK) && tar czf $(DDIR).tgz $(DDIR) diff --git a/announce.c b/announce.c new file mode 100644 index 0000000..66a7bba --- /dev/null +++ b/announce.c @@ -0,0 +1,408 @@ + +#include "announce.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#define SERVICE_TYPE "_sdlbomber._udp" + +static AvahiClient *client = NULL; +static AvahiThreadedPoll *threaded_poll = NULL; +static AvahiEntryGroup *group = NULL; + +static char* name = NULL; + +static uint16_t port = 0; +static uint32_t unique = 0, version = 0; + +static volatile int all_for_now; + +gamelistentry gamelistentries[10]; +int gamelistsize = 0; + +static void myerror(AvahiClient *c, const char *s) { + fprintf(stderr, "Error in: %s\n (%s)", s, avahi_strerror(avahi_client_errno(client))); +} + +static void create_services(AvahiClient *c); + +static void entry_group_callback(AvahiEntryGroup *g, AvahiEntryGroupState state, AVAHI_GCC_UNUSED void *userdata) { + group = g; + + switch (state) { + case AVAHI_ENTRY_GROUP_ESTABLISHED : + break; + + case AVAHI_ENTRY_GROUP_COLLISION : + { + char *n = avahi_alternative_service_name(name); + avahi_free(name); + name = n; + } + + /* And recreate the services */ + avahi_entry_group_reset(group); + create_services(avahi_entry_group_get_client(g)); + break; + + case AVAHI_ENTRY_GROUP_FAILURE : + fprintf(stderr, "Entry group failure: %s\n", avahi_strerror(avahi_client_errno(avahi_entry_group_get_client(g)))); + + avahi_threaded_poll_quit(threaded_poll); + break; + + case AVAHI_ENTRY_GROUP_UNCOMMITED: + case AVAHI_ENTRY_GROUP_REGISTERING: + break; + } +} + +static void create_services(AvahiClient *c) { + int ret; + + if (!group) { + if (!(group = avahi_entry_group_new(c, entry_group_callback, NULL))) { + myerror(c, "avahi_entry_group_new"); + goto fail; + } + } + +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); + 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_ERR_COLLISION) + goto collision; + + fprintf(stderr, "Failed to add "SERVICE_TYPE": %s\n", avahi_strerror(ret)); + goto fail; + } + + if ((ret = avahi_entry_group_commit(group)) < 0) { + fprintf(stderr, "Failed to commit entry group: %s\n", avahi_strerror(ret)); + goto fail; + } + } + + return; + +collision: + { + char *n = avahi_alternative_service_name(name); + avahi_free(name); + name = n; + } + avahi_entry_group_reset(group); + goto again; + +fail: + avahi_threaded_poll_quit(threaded_poll); +} + +static void client_callback(AvahiClient *c, AvahiClientState state, void * userdata) { + client = c; + switch (state) { + case AVAHI_CLIENT_S_RUNNING: + if (port != 0) create_services(c); + break; + case AVAHI_CLIENT_FAILURE: + myerror(c, "client failure"); + avahi_threaded_poll_quit(threaded_poll); + break; + case AVAHI_CLIENT_S_COLLISION: + case AVAHI_CLIENT_S_REGISTERING: + if (group) { + avahi_entry_group_reset(group); + } + break; + case AVAHI_CLIENT_CONNECTING: + break; + } +} + +int registergame(char *playername, uint16_t p, uint32_t uniq, 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); + + avahi_threaded_poll_lock(threaded_poll); + create_services(client); + avahi_threaded_poll_unlock(threaded_poll); + + return 1; +} + +void unregistergame() { + port = 0; + + avahi_threaded_poll_lock(threaded_poll); + if (group) avahi_entry_group_reset(group); + group = NULL; + avahi_threaded_poll_unlock(threaded_poll); +} + +static void resolve_callback(AvahiServiceResolver *r, AvahiIfIndex interface, AvahiProtocol protocol, AvahiResolverEvent event, + const char *name, const char *type, const char *domain, const char *host_name, const AvahiAddress *address, + uint16_t port, AvahiStringList *txt, AvahiLookupResultFlags flags, void* userdata) { + int i; + uint32_t want_version = *(uint32_t*) userdata; + assert(r); + + if (protocol != AVAHI_PROTO_INET) goto done; /* ignore non IPv4 for now */ + if (gamelistsize >= GAMELIST_MAXSIZE) goto done; + + /* Called whenever a service has been resolved successfully or timed out */ + + switch (event) { + case AVAHI_RESOLVER_FAILURE: + fprintf(stderr, "(Resolver) Failed to resolve service '%s' of type '%s' in domain '%s': %s\n", name, type, domain, avahi_strerror(avahi_client_errno(avahi_service_resolver_get_client(r)))); + break; + + case AVAHI_RESOLVER_FOUND: { + gamelistentry *ge; + unsigned int uniq, version; + int have_unique = 0, 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)) { + 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; + i = gamelistsize++; + ge = &gamelistentries[i]; + memset(ge, 0, sizeof(*ge)); + ge->netname.sin_addr.s_addr = address->data.ipv4.address; + ge->netname.sin_family = AF_INET; + ge->netname.sin_port = port; + ge->name = avahi_strdup(name); + ge->unique = ntohl(uniq); + } + } + +done: + avahi_service_resolver_free(r); +} + +static void browse_callback(AvahiServiceBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, + const char *name, const char *type, const char *domain, AvahiLookupResultFlags flags, void* userdata) { + + assert(b); + + /* Called whenever a new services becomes available on the LAN or is removed from the LAN */ + + switch (event) { + case AVAHI_BROWSER_FAILURE: + + fprintf(stderr, "(Browser) %s\n", avahi_strerror(avahi_client_errno(client))); + avahi_threaded_poll_quit(threaded_poll); + return; + + case AVAHI_BROWSER_NEW: + /* fprintf(stderr, "(Browser) NEW: service '%s' of type '%s' in domain '%s'\n", name, type, domain); */ + + /* We ignore the returned resolver object. In the callback + function we free it. If the server is terminated before + the callback function is called the server will free + the resolver for us. */ + + if (!(avahi_service_resolver_new(client, interface, protocol, name, type, domain, AVAHI_PROTO_UNSPEC, 0, resolve_callback, userdata))) + fprintf(stderr, "Failed to resolve service '%s': %s\n", name, avahi_strerror(avahi_client_errno(client))); + + break; + + case AVAHI_BROWSER_REMOVE: + break; + + case AVAHI_BROWSER_ALL_FOR_NOW: + all_for_now = 1; + break; + case AVAHI_BROWSER_CACHE_EXHAUSTED: + all_for_now = 1; + break; + } +} + +static void freefoundgames() { + int i; + + for (i = 0; i < gamelistsize; i++) { + avahi_free(gamelistentries[i].name); + } + gamelistsize = 0; +} + +int searchgames(unsigned char version[4]) { + int i; + AvahiServiceBrowser *sb = NULL; + uint32_t gameversion; + memcpy(&gameversion, version, 4); + gameversion = htonl(gameversion); + + freefoundgames(); + + avahi_threaded_poll_lock(threaded_poll); + + all_for_now = 0; + + if (NULL == (sb = avahi_service_browser_new(client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, SERVICE_TYPE, NULL, 0, browse_callback, &gameversion))) { + fprintf(stderr, "Failed to create service browser: %s\n", avahi_strerror(avahi_client_errno(client))); + avahi_threaded_poll_unlock(threaded_poll); + return 0; + } + + avahi_threaded_poll_unlock(threaded_poll); + + for (i = 0; i < 10; i++) { + usleep(200000); + + avahi_threaded_poll_lock(threaded_poll); + + if (all_for_now) { + avahi_service_browser_free(sb); + avahi_threaded_poll_unlock(threaded_poll); + return 1; + } + + avahi_threaded_poll_unlock(threaded_poll); + } + + avahi_threaded_poll_lock(threaded_poll); + avahi_service_browser_free(sb); + avahi_threaded_poll_unlock(threaded_poll); + + return 1; +} + + +int initannouncer() { + if (!(threaded_poll = avahi_threaded_poll_new())) { + fprintf(stderr, "avahi_threaded_poll_new failed\n"); + return 0; + } + + if (!(client = avahi_client_new(avahi_threaded_poll_get(threaded_poll), 0, client_callback, NULL, NULL))) { + fprintf(stderr, "avahi_client_new failed\n"); + avahi_threaded_poll_free(threaded_poll); + threaded_poll = NULL; + return 0; + } + + if (avahi_threaded_poll_start(threaded_poll) < 0) { + fprintf(stderr, "avahi_threaded_poll_start failed\n"); + avahi_client_free(client); + avahi_threaded_poll_free(threaded_poll); + client = NULL; + threaded_poll = NULL; + return 0; + } + + return 1; +} + +void freeannouncer() { + freefoundgames(); + + avahi_threaded_poll_stop(threaded_poll); + if (client) avahi_client_free(client); + if (threaded_poll) avahi_threaded_poll_free(threaded_poll); + client = NULL; + threaded_poll = NULL; + + avahi_free(name); + name = NULL; +} + +#if 0 +int openmatcher() +{ +struct hostent *hostptr; + if(matcheropened) return 1; + hostptr=gethostbyname(mname); + if(!hostptr) + { + hostptr=gethostbyaddr(mname,strlen(mname),AF_INET); + if(!hostptr) + return 0; + } + memset(&matchername,0,sizeof(matchername)); + matchername.sin_family=AF_INET; + matchername.sin_port=htons(PORT); + memcpy(&matchername.sin_addr,hostptr->h_addr,hostptr->h_length); + matcheropened=1; + return 1; +} + +int registergame() +{ +long now; +int size; +long lastreg; + + if(!openmatcher()) return 0; + pulseoff(); + now=longtime(); + lastreg=now-1; + while(longtime()-now<10) + { + if(longtime()-lastreg>=1) + { + lastreg=longtime(); + putmsg(&matchername,regpacket,REGISTERLEN); + } + size=getmsg(1000); + if(size + +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]); +void unregistergame(); +int searchgames(unsigned char version[4]); + +int initannouncer(); +void freeannouncer(); + +#define GAMELIST_MAXSIZE 10 + +extern gamelistentry gamelistentries[GAMELIST_MAXSIZE]; +extern int gamelistsize; + +#endif diff --git a/bomber.c b/bomber.c index 6c66afe..dca3214 100644 --- a/bomber.c +++ b/bomber.c @@ -13,18 +13,21 @@ #include "gfx.h" #include #include +#include "announce.h" + +static void domode(void); +static int iterate(void); +static int scaninvite(int size); -void domode(void); -int iterate(void); -int scaninvite(int size); - - -#define FRACTION 8 +#define FRACTION 9 #define MAXMSG 4096 #define PORT 5521 #define SPEEDDELTA (1<<(FRACTION-1)) #define SPEEDMAX (10<>8; } p=myrandblock+14; msk=0xff; msb=0x80; - do - { + do { *p&=msk; *p|=msb; p+=11; @@ -226,8 +220,7 @@ int msb,msk; #if defined (TEST_LATENCY) #define NUMQ 512 -struct message -{ +struct message { int time; struct sockaddr_in *to; int tosize; @@ -236,13 +229,11 @@ struct message } message[NUMQ]={0}; -outmsgs() -{ -int i; - for(i=0;i>FRACTION)+arraystartx; } -int tovideoy(int y) -{ + +static int tovideoy(int y) { return (y>>FRACTION)+arraystarty; } #define SGN(x) ((x)==0 ? 0 : ((x)<0 ? -1 : 1)) -int screentoarrayx(int x) -{ +static int screentoarrayx(int x) { x+=arrayspacex << (FRACTION+2); return ((x>>FRACTION)+(arrayspacex>>1))/arrayspacex-4; } -int screentoarrayy(int y) -{ + +static int screentoarrayy(int y) { y+=arrayspacey << (FRACTION+2); return ((y>>FRACTION)+(arrayspacey>>1))/arrayspacey-4; } -int arraytoscreenx(int x) -{ + +static int arraytoscreenx(int x) { return arrayspacex*x<0) - { + while(i<20) { + if(actioncount-i>0) { j=actionput-i-1; if(j<0) j+=ACTIONHIST; memmove(p,hist[j],MAXNETNODES); - } else - { + } else { memset(p,0,MAXNETNODES); } p+=MAXNETNODES; @@ -395,11 +370,10 @@ int i,j; } } -void sendactions(int which) -{ -unsigned char msg[512]; +static void sendactions(int which) { + unsigned char msg[512]; - *msg=PKT_STEP; + *msg = PKT_STEP; memmove(msg+1,regpacket+1,4); msg[5]=actioncount>>24L; msg[6]=actioncount>>16L; @@ -408,10 +382,11 @@ unsigned char msg[512]; memcpy(msg+9,actionblock,MAXNETNODES*ACTIONHIST); putmsg(&netnodes[which].netname,msg,MAXNETNODES*ACTIONHIST+9); } -void sendmine(int frame) -{ -unsigned char msg[64]; - *msg=PKT_MYDATA; + +static void sendmine(int frame) { + unsigned char msg[64]; + + *msg = PKT_MYDATA; memmove(msg+1,regpacket+1,4); msg[5]=frame>>24L; msg[6]=frame>>16L; @@ -420,36 +395,37 @@ unsigned char msg[64]; msg[9]=myaction; putmsg(&mastername,msg,10); } -int informsize; -void buildinform(unsigned char type) -{ -unsigned char *put; -int i; + +static int informsize; + +static void buildinform(unsigned char type) { + unsigned char *put; + int i; put=mesg; *put++=type; memmove(put,regpacket+1,4); put+=4; ++put; // slot specific for each slave - for(i=0;i15) break; - if(!netframe && gtime()-now>=2000) - { - for(i=1;i=2000) { + for(i=1;i0 && *mesg!=PKT_MYDATA) printf("Strange packet %d\n",*mesg); + if(length>0 && *mesg!=PKT_MYDATA) printf("Strange packet %d\n",*mesg); // check for unexpected old packets... // for example JOIN on frame 0, respond with BEGIN if player already in game // respond with uninvite INVITE on JOIN from others @@ -495,14 +466,12 @@ if(length>0 && *mesg!=PKT_MYDATA) printf("Strange packet %d\n",*mesg); whosent=isvalidmsg(); if(whosent<=0) continue; count=longind(mesg+5); - if(count>latestcounts[whosent]) - { + if(count>latestcounts[whosent]) { latestcounts[whosent]=count; newactions[whosent]=mesg[9]; } } - if(myaction==ACT_QUIT) - { + if(myaction==ACT_QUIT) { for(i=1;i0 && *mesg!=PKT_MYDATA) printf("Strange packet %d\n",*mesg); netnodes[i].used=0; ++netframe; return actioncount; - } else /* slave */ - { + } else { /* slave */ long latest=-1; long lastsent; lastsent=now=gtime(); ++mydatacount; sendmine(mydatacount); - for(;;) - { + for(;;) { /* if(gtime()-lastsent>=1) { @@ -539,9 +506,8 @@ if(length>0 && *mesg!=PKT_MYDATA) printf("Strange packet %d\n",*mesg); 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) - { + sender.sin_addr.s_addr==mastername.sin_addr.s_addr && + sender.sin_port==mastername.sin_port) { i=longind(mesg+5); if(i0 && *mesg!=PKT_MYDATA) printf("Strange packet %d\n",*mesg); int winsock=0; -void getsocket(void) -{ -int status; +static void getsocket(void) { + int status; + socklen_t slen = sizeof(myname); #if defined(__WIN32__) || defined(WIN32) char dummydata[128]; - if(WSAStartup(0x0101,(void *)dummydata)) - { + if(WSAStartup(0x0101,(void *)dummydata)) { printf("Windows dumped\n"); exit(1); } @@ -570,8 +535,7 @@ char dummydata[128]; #endif udpsocket=socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP); - if(udpsocket==-1) - { + if(udpsocket==-1) { perror("socket()"); exit(1); } @@ -580,56 +544,38 @@ char dummydata[128]; myname.sin_addr.s_addr=htonl(INADDR_ANY); myname.sin_port=htons(0); status=bind(udpsocket,(struct sockaddr *) &myname,sizeof(myname)); - if(status==-1) - { + if(-1 == status) { perror("bind()"); exit(1); } + status = getsockname(udpsocket, (struct sockaddr *) &myname, &slen); + if(-1 == status) { + perror("getsockname()"); + exit(1); + } } -void freesocket(void) -{ +static void freesocket(void) { #if defined(__WIN32__) || defined(WIN32) if(!winsock) return; WSACleanup(); #endif } - -int openmatcher() -{ -struct hostent *hostptr; - if(matcheropened) return 1; - hostptr=gethostbyname(mname); - if(!hostptr) - { - hostptr=gethostbyaddr(mname,strlen(mname),AF_INET); - if(!hostptr) - return 0; - } - memset(&matchername,0,sizeof(matchername)); - matchername.sin_family=AF_INET; - matchername.sin_port=htons(PORT); - memcpy(&matchername.sin_addr,hostptr->h_addr,hostptr->h_length); - matcheropened=1; - return 1; -} - - -void freegfxset(gfxset *gs) +static void freegfxset(gfxset *gs) { if(gs->gs_pic) free(gs->gs_pic); gs->gs_pic=0; } -void nomem(char *str) +static void nomem(char *str) { printf("No memory!!![%s]\n",str); exit(1); } -void getgroup(char *name,gfxset *colorgs,figure *fig,int count) +static void getgroup(char *name,gfxset *colorgs,figure *fig,int count) { int err; int i; @@ -648,7 +594,7 @@ gfxset gs; } freegfxset(&gs); } -void getsingle(char *name,figure *fig,int count) +static void getsingle(char *name,figure *fig,int count) { gfxset gs; int err; @@ -658,7 +604,7 @@ int err; gfxfetch(&gs,fig,count); freegfxset(&gs); } -void loadfonts(void) +static void loadfonts(void) { int i,j; char *p; @@ -679,7 +625,7 @@ char *p; asciiremap[(int)*p++]=i++; } -void loadgfx() +static void loadgfx() { gfxset *gs; gfxset *colorgs; @@ -752,7 +698,7 @@ void texthome(void) textx=texty=10; } -void update(void) +static void update(void) { copyup(); } @@ -815,7 +761,7 @@ va_list ap; } update(); } -void centerbig(int y,char *str) +static void centerbig(int y,char *str) { int w; @@ -823,7 +769,7 @@ int w; drawbigstring((IXSIZE-w)>>1,y,str); } -void addsprite(int x,int y,figure *fig) +static void addsprite(int x,int y,figure *fig) { sprite *sp; if(spritesused==MAXSPRITES) return; @@ -860,7 +806,7 @@ char ch; int ileft=0,ihand=0,byteswide; unsigned char ibuff[IBUFFLEN],*itake; -int myci() +static int myci() { if(!ileft) { @@ -874,7 +820,7 @@ int myci() } -int dopcxreal(char *name,gfxset *gs) +static int dopcxreal(char *name,gfxset *gs) { int xs,ys; int i,j,k; @@ -967,7 +913,7 @@ int err; -void addflame(player *owner,int px,int py) +static void addflame(player *owner,int px,int py) { flame *fl,*fl2; @@ -1029,7 +975,7 @@ bomb *bmb; bmb->owner=pl; } -void processbombs() +static void processbombs() { bomb *bmb; bmb=activebombs.next; @@ -1114,7 +1060,7 @@ player *owner; flameshaft(owner,px,py,1,0,power); flameshaft(owner,px,py,0,1,power); } -void dodetonations(void) +static void dodetonations(void) { int i=0; while(detonatetake!=detonateput) @@ -1126,7 +1072,7 @@ int i=0; if(i) playsound((myrand()&1) ? 0 : 4); } -void drawbombs(void) +static void drawbombs(void) { int j; bomb *bmb; @@ -1148,7 +1094,7 @@ int xpos,ypos; bmb=bmb->next; } } -void processflames(void) +static void processflames(void) { flame *fl,*fl2; fl=activeflames.next; @@ -1171,7 +1117,7 @@ flame *fl,*fl2; fl=fl->next; } } -void drawflames(void) +static void drawflames(void) { flame *fl; int xpos,ypos; @@ -1210,7 +1156,7 @@ int xpos,ypos; solidcopy(&background,xpos,ypos,arrayspacex,arrayspacey); } -void processdecays() +static void processdecays() { brickdecay *bd,*bd2; @@ -1230,7 +1176,7 @@ brickdecay *bd,*bd2; } } -void drawdecays() +static void drawdecays() { brickdecay *bd; @@ -1291,7 +1237,7 @@ bonustile *bonus; field[py][px]=FIELD_BONUS; info[py][px]=bonus; } -void drawbonus() +static void drawbonus() { bonustile *bonus; bonus=activebonus.next; @@ -1303,7 +1249,7 @@ bonustile *bonus; } } -void drawplayers() +static void drawplayers() { player *pl; int xpos,ypos; @@ -1322,7 +1268,7 @@ int xpos,ypos; pl=pl->next; } } -void detonatecontrolled(player *pl) +static void detonatecontrolled(player *pl) { bomb *bmb; bmb=activebombs.next; @@ -1394,7 +1340,7 @@ generic *gen; } -void plotsprites(void) +static void plotsprites(void) { int i; sprite *sp; @@ -1408,7 +1354,7 @@ figure *fig; ++sp; } } -void erasesprites(void) +static void erasesprites(void) { int i; sprite *sp; @@ -1425,15 +1371,14 @@ figure *fig; ++sp; } } -void clearsprites(void) -{ -int i; -sprite *sp; -figure *fig; + +static void clearsprites(void) { + int i; + sprite *sp; + figure *fig; sp=sprites; - for(i=0;ifig; clearrect(sp->xpos+fig->xdelta,sp->ypos+fig->ydelta, @@ -1442,32 +1387,28 @@ figure *fig; } } -void clearspritelist(void) -{ +static void clearspritelist(void) { spritesused=0; } -int centerxchange(player *pl) -{ -int speed; -int val; -int line; -int max; +static int centerxchange(player *pl) { + int speed; + int val; + int line; + int max; max=arrayspacex<speed; val=pl->xpos+(max<<2); val%=max; line=max>>1; - if(val=line) - { + } else if(val>=line) { if(val+speed>max) return max-val; else @@ -1475,16 +1416,16 @@ int max; } return 0; } -void centerx(player *pl) -{ + +void centerx(player *pl) { pl->xpos+=centerxchange(pl); } -int centerychange(player *pl) -{ -int speed; -int val; -int line; -int max; + +static int centerychange(player *pl) { + int speed; + int val; + int line; + int max; max=arrayspacey<speed; @@ -1506,19 +1447,18 @@ int max; } return 0; } -void centery(player *pl) -{ + +void centery(player *pl) { pl->ypos+=centerychange(pl); } -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; +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); @@ -1529,8 +1469,7 @@ int tx,ty; px=screentoarrayx(pl->xpos); py=screentoarrayy(pl->ypos); - if(wx<0 || wx>=arraynumx || wy<0 || wy>=arraynumy) - { + if(wx<0 || wx>=arraynumx || wy<0 || wy>=arraynumy) { --depth; return; } @@ -1538,21 +1477,18 @@ int tx,ty; if((px!=wx || py!=wy) && (there==FIELD_BRICK||there==FIELD_BOMB||there==FIELD_BORDER)) { - if(dx && !dy) - { + if(dx && !dy) { ty=centerychange(pl); if(ty && depth==1) trymove(pl,0,-SGN(ty)); - } else if(dy && !dx) - { + } else if(dy && !dx) { tx=centerxchange(pl); if(tx && depth==1) trymove(pl,-SGN(tx),0); } - } else - { + } else { pl->xpos+=dx*pl->speed; pl->ypos+=dy*pl->speed; if(dx && !dy) centery(pl); @@ -1562,10 +1498,9 @@ int tx,ty; } -void applybonus(player *pl,bonustile *bonus) -{ -int type; -int maxflame; +static void applybonus(player *pl,bonustile *bonus) { + int type; + int maxflame; maxflame=arraynumx>arraynumy ? arraynumx : arraynumy; type=bonus->type; @@ -1586,25 +1521,28 @@ int maxflame; pl->flags|=FLG_CONTROL; break; case TILE_SKATES: - pl->speed+=SPEEDDELTA; + if (pl->speed < SPEEDSTART) { + pl->speed = SPEEDSTART; + } else { + pl->speed+=SPEEDDELTA; + } if(pl->speed>SPEEDMAX) pl->speed=SPEEDMAX; break; case TILE_TURTLE: - pl->speed=3<speed=SPEEDTURTLE; + pl->speedturtle_timeout=SPEEDTURTLE_TIMEOUT; break; } } -void doplayer(player *pl) -{ -int last; -int color; -int speed; -int px,py; -int there; -int flags; -int what; - +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; @@ -1621,26 +1559,21 @@ int what; py=screentoarrayy(pl->ypos); there=field[py][px]; - if(what==ACT_QUIT) - { + if(what==ACT_QUIT) { killplayer(pl); return; } - if(there==FIELD_BONUS) - { + if(there==FIELD_BONUS) { playsound((myrand()&1) ? 1 : 5); applybonus(pl,info[py][px]); - } - else if(there==FIELD_FLAME) - { + } else if(there==FIELD_FLAME) { killplayer(pl); return; } // if(what&ACT_TURBO) speed<<=2; - if(what&ACT_PRIMARY) - { + if(what&ACT_PRIMARY) { if(there==FIELD_EMPTY && pl->bombsavailable) dropbomb(pl,px,py, (flags&FLG_CONTROL) ? BOMB_CONTROLLED :BOMB_NORMAL); @@ -1648,8 +1581,7 @@ int what; if(what&ACT_SECONDARY && (flags&FLG_CONTROL)) detonatecontrolled(pl); - switch(what&ACT_MASK) - { + switch(what&ACT_MASK) { case ACT_UP: trymove(pl,0,-1); pl->figcount=(pl->figcount+1)%15; @@ -1673,13 +1605,18 @@ int what; case ACT_NONE: break; } + + if (pl->speedturtle_timeout > 0) { + pl->speedturtle_timeout--; + if (0 == pl->speedturtle_timeout) { + if (pl->speed < SPEEDSTART) pl->speed = SPEEDSTART; + } + } } +static void initplayer(int color,int x,int y,int controller) { + player *pl; - -void initplayer(int color,int x,int y,int controller) -{ -player *pl; pl=allocentry(); if(!pl) nomem("Couldn't get player structure (allocentry())"); @@ -1688,7 +1625,7 @@ player *pl; pl->xpos=arraytoscreenx(x); pl->ypos=arraytoscreeny(y); pl->color=color; - pl->speed=6<speed=SPEEDSTART; pl->flags=0; pl->fixx=-4; pl->fixy=-40; @@ -1702,8 +1639,7 @@ player *pl; if(ynext=0; } -void *allocentry() -{ + +void *allocentry() { list *entry; if(!(entry=((list *)things)->next)) return 0; ((list *)things)->next=entry->next; memset(entry,0,thingsize); return entry; } -void freeentry(void *entry) -{ + +void freeentry(void *entry) { ((list *)entry)->next=((list *)things)->next; ((list *)things)->next=entry; } -void addtail(void *header,void *entry) -{ + +void addtail(void *header,void *entry) { while(((list *)header)->next) header=((list *)header)->next; ((list *)header)->next=entry; ((list *)entry)->next=0; } -void delink(void *header,void *entry) -{ + +void delink(void *header,void *entry) { while(((list *)header)->next != entry) header=((list *)header)->next; ((list *)header)->next=((list *)entry)->next; ((list *)entry)->next=0; freeentry(entry); } -void allocthings() -{ + +static void allocthings() { if(!things) { thingsize=sizeof(bomb); - if(sizeof(flame)>thingsize) thingsize=sizeof(flame); - if(sizeof(brickdecay)>thingsize) thingsize=sizeof(brickdecay); - if(sizeof(player)>thingsize) thingsize=sizeof(player); + if((int)sizeof(flame)>thingsize) thingsize=sizeof(flame); + if((int)sizeof(brickdecay)>thingsize) thingsize=sizeof(brickdecay); + if((int)sizeof(player)>thingsize) thingsize=sizeof(player); thingnum=MAXTHINGS; things=malloc(thingsize*thingnum); if(!things) nomem("Trying to allocate thing memory"); } initlist(things,thingsize,thingnum); } -void initheader(void *p) -{ + +static void initheader(void *p) { memset(p,0,sizeof(list)); } -unsigned char opts[]={2,1,0,1,0,0,0,0,0}; - -void firstzero(void) -{ +static void firstzero(void) { gountil=mycount=mydatacount=0; memset(latestactions,0,sizeof(latestactions)); memset(latestcounts,0,sizeof(latestcounts)); @@ -1806,24 +1738,20 @@ void firstzero(void) netframe=0; } -void zerocounts(void) -{ +static void zerocounts(void) { } -void initgame() -{ -int i,j; -int x,y; -int bl; -int *p; -int comp; +static void initgame() { + int i,j; + int x,y; + int bl; + int *p; + int comp; // gountil=mycount=mydatacount=netframe=0; zerocounts(); - if(numnetnodes) - memmove(gameoptions,opts,sizeof(gameoptions)); - else - memmove(gameoptions,singleoptions,sizeof(gameoptions)); + if (network != SLAVE) + memmove(gameoptions,configopts,sizeof(gameoptions)); gameframe=0; allocthings(); initheader(&activebombs); @@ -1837,8 +1765,7 @@ int comp; p=bonuschances; bonustotal=0; - for(;;) - { + for(;;) { i=*p++; if(i==TILE_NONE) break; bonustotal+=*p++; @@ -1847,42 +1774,34 @@ int comp; memset(field,0,sizeof(field)); comp=gameoptions[GO_DENSITY]; for(j=0;j=comp ? FIELD_BRICK : FIELD_EMPTY; } - - solidcopyany(&backgroundoriginal,&background,0,0, - IXSIZE,IYSIZE); + solidcopyany(&backgroundoriginal,&background,0,0,IXSIZE,IYSIZE); initplayers(); - - for(j=0;j=argc) - { - helptext(argv[0]); - exit(0); - } - mname=malloc(strlen(argv[i])); - if(mname) - strcpy(mname,argv[i]); - } else - { - helptext(argv[0]); - exit(0); - } - - } - if(!mname) mname="matcher.xdr.com"; +int main(int argc,char **argv) { + char *p; strcpy(playername,"ANONYMOUS"); p=getenv("USER"); @@ -1949,6 +1837,7 @@ char *p; opengfx(argc, argv); network=0; getsocket(); + if (!initannouncer()) exit(1); soundopen(); loadgfx(); @@ -1960,6 +1849,7 @@ char *p; domode(); soundclose(); + freeannouncer(); freesocket(); closegfx(); return 0; @@ -1971,16 +1861,15 @@ char *menuput,*menuitems[40],*menutitle; int menunum; int menudelta; -void menustart() -{ +static void menustart() { menunum=-1; menuput=menustring; *menuput=0; } -void additem(char *item,...) -{ -char output[256]; -va_list ap; + +static void additem(char *item,...) { + char output[256]; + va_list ap; va_start(ap, item); @@ -1993,10 +1882,10 @@ va_list ap; strcpy(menuput,output); menuput+=strlen(output)+1; } -void drawmenu(int selected) -{ -int i,j; -int tx,ty; + +static void drawmenu(int selected) { + int i,j; + int tx,ty; clear(); j=strlen(menutitle)*bigfontxsize; @@ -2016,34 +1905,7 @@ int tx,ty; } } -long longhash(char *str) -{ -long val=0; -char ch; - while((ch=*str++)) - { - val=(val<<4) | ((val>>28)&0x0f); - val^=ch; - } - return val; -} -void makereg(void) -{ -long val; - val=gtime(); - regpacket[0]=PKT_REGISTER; - memmove(regpacket+1,&val,4); - memset(regpacket+5,0,4); - memmove(regpacket+9,gameversion,4); - memmove(regpacket+13,playername,16); - regpacket[29]=1; -} -void clearreg(void) -{ - regpacket[29]=0; -} -void drawjoinscreen(void) -{ +static void drawjoinscreen(void) { int i; char name[17]; char temp[64]; @@ -2063,23 +1925,23 @@ char temp[64]; drawbigstring(JX,JY+(i+1)*bigfontyspace,temp); } } -int tryjoin(int which) -{ -long now; -int size; -char amin; -int res; + +static int tryjoin(int which) { + long now; + int size; + char amin; + int res; pulseoff(); - memmove(&mastername,&netnodes[which].netname,sizeof(mastername)); + memmove(&mastername, &gamelistentries[which].netname,sizeof(mastername)); *regpacket=PKT_JOIN; - memmove(regpacket+1,netnodes[which].unique,4); + memmove(regpacket+1, &gamelistentries[which].unique,4); + unique = gamelistentries[which].unique; memmove(regpacket+5,playername,16); now=longtime(); amin=0; size=0; - while(longtime()-now<10 && !amin) - { + while(longtime()-now<10 && !amin) { putmsg(&mastername,regpacket,1+4+16); size=getmsg(1000); res=scaninvite(size); @@ -2092,12 +1954,10 @@ int res; drawjoinscreen(); copyup(); if(*mesg==PKT_BEGIN) amin=2; - while(amin<2) - { + while(amin<2) { scaninput(); while(anydown()) - switch(takedown()) - { + switch(takedown()) { case 0x1b: *regpacket=PKT_QUIT; now=longtime(); @@ -2113,8 +1973,7 @@ int res; return 0; } size=getmsg(200); - if((res=scaninvite(size))) - { + if((res=scaninvite(size))) { drawjoinscreen(); copyup(); if(res==3) return 1; @@ -2124,10 +1983,9 @@ int res; return 0; } //returns 0=ignore packet,1=we're rejected,2=INVITE,3=BEGIN -int scaninvite(int size) -{ -int i; -unsigned char *take; +static int scaninvite(int size) { + int i; + unsigned char *take; if(size<7) return 0; if(*mesg!=PKT_INVITE && *mesg!=PKT_BEGIN) return 0; @@ -2137,24 +1995,29 @@ unsigned char *take; memset(netnodes,0,sizeof(netnodes)); size-=6; take=mesg+6; - while(*take!=0xff && size>=17) - { - if((i=*take)=17) { + if((i=*take)=0) selected=menuhistory[whichmenu]; @@ -2176,10 +2038,8 @@ int mcount=0; redraw=1; clearspritelist(); pulseon(); - while(!exitflag) - { - if(redraw) - { + while(!exitflag) { + if(redraw) { drawmenu(selected); redraw=0; } @@ -2196,8 +2056,7 @@ int mcount=0; if(anydown()) playsound(3); while(anydown()) - switch(takedown()) - { + switch(takedown()) { case MYLEFT: menudelta=-1; return selected; @@ -2237,141 +2096,83 @@ int mcount=0; } -void domode0(void) -{ -int sel; +static void domode0(void) { + int sel; pulseon(); - while(!exitflag) - { + while(!exitflag) { menustart(); additem("BOMBER MAIN MENU"); additem("EXIT GAME"); additem("START SINGLE PLAYER GAME"); - additem("SINGLE PLAYER OPTIONS"); - additem("REMAP MOVEMENT KEYS"); + 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==4) {gamemode=3;break;} - if(sel==5) {gamemode=4;break;} + if(sel==3) {gamemode=3;break;} + if(sel==4) {gamemode=4;break;} } } -void domode1(void) -{ -int code; +static void domode1(void) { + int code; network=0; + initgame(); pulseon(); while(!(code=iterate())) ++framecount; if(code==CODE_QUIT) gamemode=0; } -unsigned char singleoptions[10]={0}; + unsigned char gameoptions[10]; char *densities[]={"PACKED","HIGH","MEDIUM","LOW"}; char *generosities[]={"LOW","MEDIUM","HIGH","RIDICULOUS"}; -void domode2(void) -{ -int sel; - for(;;) - { +static void domode2(void) { + int sel; + + for(;;) { menustart(); - additem("SINGLE PLAYER GAME OPTIONS"); + additem("GAME OPTIONS"); additem("RETURN TO MAIN MENU"); - additem("DENSITY: %s",densities[singleoptions[GO_DENSITY]]); - additem("GENEROSITY: %s",generosities[singleoptions[GO_GENEROSITY]]); - additem("INITIAL FLAME LENGTH: %d",singleoptions[GO_FLAMES]+1); - additem("INITIAL NUMBER OF BOMBS: %d",singleoptions[GO_BOMBS]+1); + 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) - { - singleoptions[GO_DENSITY]+=menudelta; - singleoptions[GO_DENSITY]&=3; + if(sel==1) { + configopts[GO_DENSITY]+=menudelta; + configopts[GO_DENSITY]&=3; } - if(sel==2) - { - singleoptions[GO_GENEROSITY]+=menudelta; - singleoptions[GO_GENEROSITY]&=3; + if(sel==2) { + configopts[GO_GENEROSITY]+=menudelta; + configopts[GO_GENEROSITY]&=3; } - if(sel==3) - { - singleoptions[GO_FLAMES]+=menudelta; - singleoptions[GO_FLAMES]&=7; + if(sel==3) { + configopts[GO_FLAMES]+=menudelta; + configopts[GO_FLAMES]&=7; } - if(sel==4) - { - singleoptions[GO_BOMBS]+=menudelta; - singleoptions[GO_BOMBS]&=7; + if(sel==4) { + configopts[GO_BOMBS]+=menudelta; + configopts[GO_BOMBS]&=7; } } } -int registergame() -{ -long now; -int size; -long lastreg; - - if(!openmatcher()) return 0; - pulseoff(); - now=longtime(); - lastreg=now-1; - while(longtime()-now<10) - { - if(longtime()-lastreg>=1) - { - lastreg=longtime(); - putmsg(&matchername,regpacket,REGISTERLEN); - } - size=getmsg(1000); - if(size=21 && *mesg==PKT_JOIN) || (size>=5 && *mesg==PKT_QUIT))) continue; if(memcmp(mesg+1,regpacket+1,4)) continue; j=-1; - for(i=1;inetname,0,sizeof(struct sockaddr_in)); - nn->netname.sin_family=AF_INET; - memmove(&nn->netname.sin_addr,take+4,4); - memmove(&nn->netname.sin_port,take+8,2); - memmove(nn->unique,take,4); - memmove(nn->name,take+10,16); - memmove(temp,take+10,16); - temp[16]=0; - additem(temp); - } - take+=26; - --count; - } - break; - } - if(!numnetnodes) - { - failure("NO GAMES AVAILABLE"); + if (!searchgames(gameversion)) { + gamemode = 0; return; } - sel=domenu(-1); - if(!sel) - { + if (gamelistsize == 0) { + menustart(); + additem("NO GAMES AVAILABLE"); + domenu(-1); gamemode=0; return; } - if(!tryjoin(sel-1)) - { + + 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; } @@ -2554,9 +2313,10 @@ int sel; firstzero(); gamemode=5; } -void domode5(void) /* network game */ -{ -int code; + +static void domode5(void) { /* network game */ + int code; + initgame(); pulseon(); while(!(code=iterate())) ++framecount; @@ -2564,26 +2324,24 @@ int code; } -void (*modefunctions[])()= -{ -domode0, -domode1, -domode2, -domode3, -domode4, -domode5, +void (*modefunctions[])()= { + domode0, + domode1, + domode2, + domode3, + domode4, + domode5, }; -void domode(void) -{ +static void domode(void) { modefunctions[gamemode](); } -int getaction(void) -{ -int what; +static int getaction(void) { + int what; + what=ACT_NONE; if(checkpressed(MYLEFT)) what=ACT_LEFT; else if(checkpressed(MYRIGHT)) what=ACT_RIGHT; @@ -2600,21 +2358,20 @@ int what; return what; } -void processplayers(void) -{ -player *pl,*pl2; +static void processplayers(void) { + player *pl,*pl2; + pl=activeplayers.next; - while(pl) - { + while(pl) { pl2=pl; pl=pl->next; doplayer(pl2); } } -void processquits(void) -{ -int i; +static void processquits(void) { + int i; + if(network!=SLAVE) return; for(i=0;i=ACTIONHIST) // too far behind return CODE_QUIT; @@ -2679,19 +2433,19 @@ static int deathcount=0; drawplayers(); plotsprites(); update(); - if(!activegeneric.next) - { + if(!activegeneric.next) { player *pl; + int deadplayers = 0; pl=activeplayers.next; i=0; - while(pl) - { + while(pl) { if(!(pl->flags & FLG_DEAD)) ++i; + else + deadplayers++; pl=pl->next; } - if(!i || (network && i==1)) - { + if (deadplayers > 0 && (!i || (network && i==1))) { ++deathcount; if(deathcount==25) return CODE_ALLDEAD; diff --git a/bomber.h b/bomber.h index 13e84d6..72cabff 100644 --- a/bomber.h +++ b/bomber.h @@ -66,6 +66,7 @@ typedef struct player int flags; int abilities; int speed; + int speedturtle_timeout; int bombsused; int bombsavailable; int flamelength; @@ -164,6 +165,7 @@ typedef struct bonustile int px,py; int type; }bonustile; + #define TILE_NONE -1 #define TILE_BOMB 5 #define TILE_FLAME 2 diff --git a/gfx.c b/gfx.c index e0025e1..42d8d6c 100644 --- a/gfx.c +++ b/gfx.c @@ -29,7 +29,7 @@ void dumpgfx() { usedcolors = 0; } -int bestmatch(int red,int green,int blue) +static int bestmatch(int red,int green,int blue) { int i; int bestcolor,bestdelta=0; @@ -61,7 +61,7 @@ int delta; return bestcolor; } -void updatemap(void) +static void updatemap(void) { SDL_SetColors(thescreen, themap, 0, 256); } @@ -117,7 +117,7 @@ int cnt; updatemap(); } -uchar *compressfig(uchar *put,gfxset *gs, +static uchar *compressfig(uchar *put,gfxset *gs, int sourcex,int sourcey,int sizex,int sizey) { int j,gswidth; @@ -154,7 +154,7 @@ int dx,dy; *put++=0; return put; } -void gfxfetchsingle(figure *fig,gfxset *gs,int sourcex,int sourcey,int sizex,int sizey) +static void gfxfetchsingle(figure *fig,gfxset *gs,int sourcex,int sourcey,int sizex,int sizey) { uchar *p,*p2; int dx,dy; @@ -401,16 +401,14 @@ void copyupxysize(int x,int y,int xsize,int ysize) } -void set_color(int color, int red, int green, int blue) -{ - themap[color].r=red; - themap[color].g=green; - themap[color].b=blue; +// static void set_color(int color, int red, int green, int blue) { +// themap[color].r=red; +// themap[color].g=green; +// themap[color].b=blue; +// } -} -void opengfx(int argc, char **argv) -{ -unsigned long videoflags; +void opengfx(int argc, char **argv) { + unsigned long videoflags; themap[0].r=0; themap[0].g=0; @@ -657,17 +655,16 @@ SDLK_LALT,MYALTL, SDLK_RALT,MYALTR, ENDMARK }; -int looklist(int code,int *list) +static int looklist(int code,int *list) { - while(*list!=ENDMARK) - { + while((unsigned int)*list!=ENDMARK) { if(*list==code) return list[1]; list+=2; } return -1; } -int mapkey(int code,int qual) +static int mapkey(int code,int qual) { if(qual & KMOD_SHIFT) @@ -681,7 +678,7 @@ int mapkey(int code,int qual) return code; } -void markkey(int code,int status) +static void markkey(int code,int status) { int i; int *ip; @@ -818,7 +815,7 @@ int i,*ip,code; } */ -void drawrect(int x,int y,int xs,int ys,int c) +static void drawrect(int x,int y,int xs,int ys,int c) { uchar *p;