Compare commits

...

4 Commits

Author SHA1 Message Date
Stefan Bühler 56458af5fc add clang-format config and format everything 2021-09-15 19:20:26 +02:00
Stefan Bühler 187ec1a68e use c17 std, fix warnings / errors 2021-09-15 18:52:43 +02:00
Stefan Bühler 7e9fbaf5d2 move code files to src/, move to meson build system 2021-09-15 16:58:28 +02:00
Stefan Bühler eb78414668 update author links 2021-09-15 16:39:51 +02:00
36 changed files with 3942 additions and 3927 deletions

29
.clang-format Normal file
View File

@ -0,0 +1,29 @@
---
BasedOnStyle: LLVM
IndentWidth: 4
TabWidth: 4
---
Language: Cpp
AccessModifierOffset: -4
AlignAfterOpenBracket: AlwaysBreak
AlignOperands: false
AlignTrailingComments: false
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortBlocksOnASingleLine: true
AllowShortFunctionsOnASingleLine: Empty
AllowShortIfStatementsOnASingleLine: true
AllowShortLoopsOnASingleLine: true
AlwaysBreakTemplateDeclarations: true
BinPackArguments: false
BinPackParameters: false
BreakConstructorInitializersBeforeComma: true
ColumnLimit: 160
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 0
MaxEmptyLinesToKeep: 2
NamespaceIndentation: All
PointerAlignment: Left
SpaceAfterCStyleCast: true
Standard: Cpp11
UseTab: Always
...

View File

@ -1,7 +1,6 @@
David Ashley
dashxdr@gmail.com
http://www.xdr.com/dash
http://www.linuxmotors.com
https://www.linuxmotors.com/linux/SDL_bomber/
Stefan Bühler
http://stbuehler.de/
https://stbuehler.de/

View File

@ -1,41 +0,0 @@
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 $(shell sdl-config --cflags) $(DBG) $(WARNFLAGS)
.PHONY: all clean install
all: sdlbomber
sdlbomber: announce.o bomber.o draw.o game.o gfx.o sound.o list.o network.o menu.o utils.o
gcc $(LDFLAGS) -o $@ $^ $(shell sdl-config --libs) -lavahi-common -lavahi-client $(DBG)
matcher: matcher.c
announce.o: announce.c announce.h network.h
bomber.o: bomber.c announce.h bomber.h draw.h game.h gfx.h list.h menu.h network.h sound.h utils.h
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 draw.h game.h menu.h network.h utils.h
sound.o: sound.c sound.h
utils.o: utils.c bomber.h utils.h gfx.h
clean:
rm -f *.o matcher sdlbomber
install: sdlbomber
echo "Installing into $(DESTDIR)"
mkdir -p "$(DESTDIR)/usr/bin/" "$(DESTDIR)/usr/share/sdlbomber/"
install -m 0755 sdlbomber "$(DESTDIR)/usr/bin/"
install -m 0644 data/*.pcx data/*.raw "$(DESTDIR)/usr/share/sdlbomber/"

View File

@ -1,26 +0,0 @@
#DBG += -g
#DBG += -pg
CC = gcc
CFLAGS = -O2 -Wall -I/Library/Frameworks/SDL.framework/Headers $(DBG)
LDFLAGS += -framework SDL -framework Cocoa -o $@ -lavahi-client
all: sdlbomber
sdlbomber: gfx.o bomber.o sound.o SDLMain.o announce.o
SDLMain.o: SDLmain.m
bomber.o: bomber.c bomber.h gfx.h sound.h announce.h
gfx.o: gfx.c bomber.h gfx.h
sound.o: sound.c bomber.h sound.h
announce.o: announce.c announce.h
clean:
rm -f *.o sdlbomber matcher
test: all
./sdlbomber

View File

@ -1,9 +0,0 @@
# Makefile for bomber
#
TARGET = sdlbomber
USEINET = true
include ../GNUmake
$(TARGET): bomber.o gfx.o sound.o announce.o

472
draw.c
View File

@ -1,472 +0,0 @@
#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 const unsigned char *remapstring = (const unsigned char*) "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;
snprintf(tname,sizeof(tname),DATADIR "/%s",name);
ihand=open(tname,O_RDONLY);
if(ihand<0) {
char tname2[260];
snprintf(tname2,sizeof(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;
}
void drawstring(int xpos, int ypos, const char *str) {
char ch;
while((ch=*str++)) {
drawfigure(xpos,ypos,font+asciiremap[toupper(ch)]);
xpos+=fontxsize;
}
}
void drawbigstring(int xpos, int ypos, const char *str) {
char ch;
while('\0' != (ch=*str++)) {
drawfigure(xpos,ypos,bigfont+asciiremap[toupper(ch)]);
xpos+=bigfontxsize;
}
}
void centerbig(int y, const 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);
vsnprintf(output,sizeof(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;
const unsigned 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<NUMCHARACTERS)
asciiremap[(int)*p++]=i++;
}
void loadgfx() {
gfxset *gs;
gfxset *colorgs;
int err;
int i;
char name[267];
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) {
snprintf(name,sizeof(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");
}
void failure(char *str,...) {
char output[256];
va_list ap;
int len;
long now;
va_start(ap, str);
len = vsnprintf(output, sizeof(output), str, ap);
if (len >= 256) len = 255; /* truncated string */
clear();
drawbigstring((IXSIZE - len*bigfontxsize) / 2, (IYSIZE-bigfontysize) / 2, output);
copyup();
now = longtime();
while (!exitflag && longtime()-now < 3) {
scaninput();
if (anydown()) {
takedown();
return;
}
}
}

980
game.c
View File

@ -1,980 +0,0 @@
#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 listhead activebombs;
static listhead activedecays;
static listhead activebonus;
static listhead activegeneric;
static listhead detonatebombs;
static listhead activeflames;
static listhead activeplayers;
static listhead allplayers;
figure walking[MAXSETS][NUMWALKFRAMES];
solid background, backgroundoriginal;
/* The playfield array, contains FIELD_* equates */
unsigned char field[32][32];
void *info[32][32];
volatile char exitflag = 0;
static int framecount = 0;
char playername[16];
static int mycount;
static int bonustotal;
static const int bonuschances[]= {
TILE_BOMB,20,
TILE_FLAME,20,
TILE_TRIGGER,2,
TILE_GOLDFLAME,2,
TILE_SKATES,20,
TILE_TURTLE,5,
TILE_NONE,160
};
static GameOptions gameoptions;
static const unsigned char playerpositions[MAXNETNODES*3] = { /* 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 resetplayer(player *pl, int color, int x, int y) {
pl->speed=SPEEDSTART;
pl->flags=0;
pl->flamelength=gameoptions.flames+1;
pl->bombsavailable=gameoptions.bombs+1;
pl->color=color;
pl->xpos=arraytoscreenx(x);
pl->ypos=arraytoscreeny(y);
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;
addtail(&activeplayers, pl);
}
static void initplayer(int color,int x,int y,int controller) {
player *pl;
pl = allocentry(player);
if(!pl)
nomem("Couldn't get player structure (allocentry())");
list_add_tail(&allplayers, &pl->list_all_players);
pl->controller=controller;
pl->fixx=-4;
pl->fixy=-40;
pl->kills = pl->deaths = 0;
resetplayer(pl, color, x, y);
}
static void initplayers(void) {
int i;
const unsigned char *p;
int c,x,y;
if(NETWORK_NONE == 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 resetplayers(void) {
const unsigned char *p;
int c,x,y;
player *pl;
p=playerpositions;
list_for_each_entry(pl, &allplayers, list_all_players) {
c=*p++;
x=*p++;
y=*p++;
resetplayer(pl, c, x, y);
}
}
static void firstzero(void) {
alloc_things();
list_init_head(&activebombs);
list_init_head(&detonatebombs);
list_init_head(&activeflames);
list_init_head(&activedecays);
list_init_head(&activebonus);
list_init_head(&activeplayers);
list_init_head(&activegeneric);
list_init_head(&allplayers);
mycount = mydatacount = 0;
memset(latestactions,0,sizeof(latestactions));
memset(latestcounts,0,sizeof(latestcounts));
memset(actionblock,0,sizeof(actionblock));
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;
things_list_clear(&activebombs);
things_list_clear(&detonatebombs);
things_list_clear(&activeflames);
things_list_clear(&activedecays);
things_list_clear(&activebonus);
list_init_head(&activeplayers);
things_list_clear(&activegeneric);
p=bonuschances;
bonustotal=0;
for(;;) {
i=*p++;
if(i==TILE_NONE) break;
bonustotal+=*p++;
}
bonustotal += 64*(3-gameoptions.generosity);
memset(field,0,sizeof(field));
comp=gameoptions.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);
resetplayers();
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();
}
static void addflame(player *owner,int px,int py) {
flame *fl,*fl2;
fl = allocentry(flame);
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(bomb);
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 adddecay(int px,int py) {
brickdecay *bd;
int xpos,ypos;
bd = allocentry(brickdecay);
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(bonustile);
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;
list_del(&bonus->list);
freeentry(bonus);
}
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;
removeitem(bmb);
addtail(&detonatebombs, bmb);
}
static void processbombs() {
bomb *bmb, *next;
list_for_each_entry_safe(bmb, next, &activebombs, list) {
++(bmb->figcount);
++bmb->timer;
switch(bmb->type) {
case BOMB_NORMAL:
if (bmb->timer == BOMBLIFE)
adddetonate(bmb);
break;
case BOMB_CONTROLLED:
if (bmb->timer == BOMB_CONTROLLED_LIFE) {
bmb->timer = 0;
bmb->type = BOMB_NORMAL;
}
break;
}
}
}
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;
list_del(&bmb->list);
freeentry(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;
bomb *bmb;
while (!list_empty(&detonatebombs)) {
bmb = (bomb*) detonatebombs.next;
++i;
detonatebomb(bmb);
}
if(i) playsound((myrand()&1) ? 0 : 4);
}
static void processflames(void) {
flame *fl, *next;
list_for_each_entry_safe(fl, next, &activeflames, list) {
++(fl->timer);
if(fl->timer==FLAMELIFE) {
field[fl->py][fl->px]=FIELD_EMPTY;
info[fl->py][fl->px]=0;
list_del(&fl->list);
freeentry(fl);
}
}
}
static void processdecays() {
brickdecay *bd, *next;
list_for_each_entry_safe(bd, next, &activedecays, list) {
++(bd->timer);
if(bd->timer == DECAYLIFE) {
field[bd->py][bd->px] = FIELD_EMPTY;
trybonus(bd->px, bd->py);
list_del(&bd->list);
freeentry(bd);
}
}
}
static void drawbombs(void) {
int j;
bomb *bmb;
struct figure *figtab;
int color;
int xpos,ypos;
list_for_each_entry(bmb, &activebombs, list) {
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);
}
}
static void drawflames(void) {
flame *fl;
int xpos,ypos;
/* no player specific flame sprites yet */
/* int color; */
int fig;
list_for_each_entry(fl, &activeflames, list) {
/* 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);
}
}
static void drawdecays() {
brickdecay *bd;
list_for_each_entry(bd, &activedecays, list) {
addsprite(tovideox(bd->xpos),tovideoy(bd->ypos),
blocksx+(bd->timer*9)/DECAYLIFE);
}
}
static void drawbonus() {
bonustile *bonus;
list_for_each_entry(bonus, &activebonus, list) {
addsprite(tovideox(bonus->xpos),tovideoy(bonus->ypos),
tiles+bonus->type);
}
}
static void drawplayers() {
player *pl;
int xpos,ypos;
list_for_each_entry(pl, &activeplayers, list) {
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);
}
}
}
static void detonatecontrolled(player *pl) {
bomb *bmb, *next;
list_for_each_entry_safe(bmb, next, &activebombs, list) {
if(bmb->owner==pl && bmb->type==BOMB_CONTROLLED)
adddetonate(bmb);
}
}
static void playonce(generic *gen) {
if (gen->timer == gen->data1) {
list_del(&gen->list);
freeentry(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(generic);
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->deaths++;
pl->flags|=FLG_DEAD;
playsound(2);
adddeath(pl);
detonatecontrolled(pl);
}
static void processgenerics(void) {
generic *gen, *next;
list_for_each_entry_safe(gen, next, &activegeneric, list) {
++(gen->timer);
gen->process(gen);
}
}
static void drawgenerics(void) {
generic *gen;
list_for_each_entry(gen, &activegeneric, list) {
gen->draw(gen);
}
}
static void drawstats(void) {
player *pl;
int p = 0;
const char *n;
char buf[16];
solidcopy(&background, 0, 0, IXSIZE, arraystarty);
list_for_each_entry(pl, &allplayers, list_all_players) {
if (pl->controller >= 0) {
n = netnodes[pl->controller].name;
} else {
n = playername;
}
snprintf(buf, sizeof(buf), "%-8.8s %2i/%2i", n, pl->kills % 100, pl->deaths % 100);
drawstring(11 + (p/2) * (15 * fontxsize + 7), 11 + (p%2) * (fontysize+2), buf);
p++;
}
}
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:
if (pl->bombsavailable < 9)
++(pl->bombsavailable);
break;
case TILE_FLAME:
if(pl->flamelength<maxflame)
++(pl->flamelength);
break;
case TILE_GOLDFLAME:
pl->flamelength=maxflame;
break;
case TILE_TRIGGER:
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);
list_del(&pl->list_all_players);
return;
}
if(there==FIELD_BONUS) {
playsound((myrand()&1) ? 1 : 5);
applybonus(pl,info[py][px]);
} else if(there==FIELD_FLAME) {
flame *fl = info[py][px];
if (fl->owner == pl) {
pl->kills--;
} else {
fl->owner->kills++;
}
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, *next;
list_for_each_entry_safe(pl, next, &activeplayers, list) {
doplayer(pl);
}
}
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;
}
static int iterate(void) {
int i;
int gountil; /* destination tick */
static int deathcount = 0;
mypause();
scaninput();
erasesprites();
clearspritelist();
gfxunlock();
myaction = getaction();
if (NETWORK_NONE == network && myaction==ACT_QUIT) return CODE_QUIT;
if (NETWORK_NONE == network) {
gountil = mycount + 1; /* single step in singly player mode */
} else {
gountil = networktraffic(); /* as master single step, as slave as many as we can do */
}
while (mycount < gountil) { /* simulate ticks up to gountil */
++mycount;
if (NETWORK_NONE != network) {
i = gountil - mycount;
if(i >= ACTIONHIST) // too far behind
goto leave_game;
memcpy(actions, actionblock+i*MAXNETNODES, MAXNETNODES);
if (actions[myslot] == ACT_QUIT) return CODE_QUIT;
}
processbombs();
dodetonations();
processdecays();
processflames();
processgenerics();
processquits();
processplayers();
}
/*
if(!(rand()&127))
{
i=gtime();
while(gtime()-i<100);
}
*/
drawbombs();
drawbonus();
drawgenerics();
drawdecays();
drawflames();
drawplayers();
drawstats();
plotsprites();
copyup();
if (list_empty(&activegeneric)) {
player *pl;
int deadplayers = 0;
i = 0;
list_for_each_entry(pl, &activeplayers, list) {
if(!(pl->flags & FLG_DEAD))
++i;
else
deadplayers++;
}
if (deadplayers > 0 && (!i || (NETWORK_NONE != network && i==1))) {
++deathcount;
if(deathcount==25)
return CODE_ALLDEAD;
} else
deathcount=0;
}
return CODE_CONT;
leave_game: /* client disconnect/timeout: send ACT_QUIT to master */
myaction = ACT_QUIT;
networktraffic();
return CODE_QUIT;
}
void set_game_options(GameOptions *options) {
gameoptions = *options;
}
void run_single_player(void) {
int code;
network = NETWORK_NONE;
firstzero();
initplayers();
do {
initgame();
while(!(code=iterate()) && !exitflag) ++framecount;
} while (code != CODE_QUIT && !exitflag);
}
void run_network_game(void) {
int code;
firstzero();
initplayers();
do {
initgame();
while (!(code=iterate()) && !exitflag) ++framecount;
} while (code != CODE_QUIT && !exitflag);
}

872
gfx.c
View File

@ -1,872 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "bomber.h"
#include "gfx.h"
#define MAXCOLORS 256
int usedcolors=0;
SDL_Surface *thescreen;
SDL_Color themap[256];
uchar *videomem;
int stride;
int mousex,mousey,mouseb;
uchar mustlock=0,locked=0;
uchar *block64;
int buttonstate=0,buttondown=0;
int mxpos,mypos;
int pressedcodes[KEYMAX],downcodes[KEYMAX],numpressed,numdown;
void dumpgfx()
{
usedcolors = 0;
}
static int bestmatch(int red,int green,int blue)
{
int i;
int bestcolor,bestdelta=0;
int rdelta,gdelta,bdelta;
int delta;
i=0;
bestcolor=-1;
while(i<usedcolors)
{
rdelta=themap[i].r;
rdelta-=red;
rdelta*=rdelta;
gdelta=themap[i].g;
gdelta-=green;
gdelta*=gdelta;
bdelta=themap[i].b;
bdelta-=blue;
bdelta*=bdelta;
delta=rdelta+gdelta+bdelta;
if(bestcolor<0 || delta<bestdelta)
{
bestdelta=delta;
bestcolor=i;
}
i++;
}
return bestcolor;
}
static void updatemap(void)
{
SDL_SetColors(thescreen, themap, 0, 256);
}
void createinout(gfxset *gs)
{
uchar *p;
int i,j,counts[256];
uchar red,green,blue;
int cnt;
p=gs->gs_pic;
for(i=0;i<256;i++) counts[i]=0;
i=gs->gs_xsize*gs->gs_ysize;
while(i--)
counts[*p++]++;
cnt=0;
gs->gs_inout[0]=0;
for(i=1;i<256;i++)
{
if(counts[i])
{
cnt++;
p=gs->gs_colormap+i+i+i;
red=*p++;
green=*p++;
blue=*p++;
for(j=0;j<usedcolors;j++)
{
if(red==themap[j].r &&
green==themap[j].g && blue==themap[j].b)
{
gs->gs_inout[i]=j;
break;
}
}
if(j==usedcolors)
{
if(usedcolors<MAXCOLORS)
{
themap[j].r=red;
themap[j].g=green;
themap[j].b=blue;
gs->gs_inout[i]=usedcolors;
++usedcolors;
} else
gs->gs_inout[i]=bestmatch(red,green,blue);
}
}
}
updatemap();
}
static uchar *compressfig(uchar *put,gfxset *gs,
int sourcex,int sourcey,int sizex,int sizey)
{
int j,gswidth;
uchar *p, *p2,pixel,*map1;
int dx,dy;
gswidth=gs->gs_xsize;
map1=gs->gs_inout;
p=gs->gs_pic+sourcex+gswidth*sourcey;
for(dy=0;dy<sizey;dy++)
{
p2=p;
j=0;
for(dx=0;dx<=sizex;dx++)
{
if(dx<sizex) pixel=*p2;
else pixel=0;
++p2;
if(pixel)
++j;
else if(j)
{
*put++=j;
*put++=dx-j;
*put++=dy;
p2-=j+1;
while(j)
*put++=map1[*p2++],--j;
++p2;
}
}
p+=gswidth;
}
*put++=0;
return put;
}
static void gfxfetchsingle(figure *fig,gfxset *gs,int sourcex,int sourcey,int sizex,int sizey)
{
uchar *p,*p2;
int dx,dy;
/* uchar *map1; */
int gswidth;
int minx,miny,maxx,maxy;
int tx,ty;
/* map1=gs->gs_inout; */
gswidth=gs->gs_xsize;
p=gs->gs_pic+sourcex+gswidth*sourcey;
minx=miny=maxx=maxy=-1;
for(dy=0;dy<sizey;dy++)
{
p2=p;
ty=sourcey+dy;
for(dx=0;dx<sizex;dx++)
{
if(!*p2++) continue;
if(miny==-1 || ty<miny) miny=ty;
if(maxy==-1 || ty>maxy) maxy=ty;
tx=sourcex+dx;
if(minx==-1 || tx<minx) minx=tx;
if(maxx==-1 || tx>maxx) maxx=tx;
}
p+=gswidth;
}
if(minx==-1)
{
minx=maxx=sourcex;
miny=maxy=sourcey;
}
fig->xdelta=minx-sourcex;
fig->ydelta=miny-sourcey;
sourcex=minx;
sourcey=miny;
fig->xsize=sizex=maxx-minx+1;
fig->ysize=sizey=maxy-miny+1;
p=compressfig(block64,gs,sourcex,sourcey,sizex,sizey);
fig->graphics=malloc(p-block64);
if(fig->graphics)
memcpy(fig->graphics,block64,p-block64);
}
//(gfxset *gs,figure *fig,int sourcex,int sourcey,int sizex,int sizey)
void gfxfetch(gfxset *gs,figure *fig,int num)
{
int x,y;
int xsize,ysize;
int fxsize,fysize;
unsigned char *p,*p2;
xsize=gs->gs_xsize;
ysize=gs->gs_ysize;
p2=p=gs->gs_pic+xsize+1;
fxsize=2;
while(*p++==0) ++fxsize;
fysize=2;
while(*p2==0) ++fysize,p2+=xsize;
x=fxsize;
y=0;
while(num--)
{
gfxfetchsingle(fig,gs,x,y,fxsize,fysize);
x+=fxsize;
if(x>xsize-fxsize)
{
x=0;
y+=fysize;
if(y>ysize-fysize)
y=0;
}
fig++;
}
}
void solidfetch(gfxset *gs,solid *dest)
{
int xsize,ysize;
int i;
unsigned char *p,*map;
uchar *gfx;
memset(dest,0,sizeof(solid));
xsize=gs->gs_xsize;
ysize=gs->gs_ysize;
i=xsize*ysize;
gfx=dest->graphics=malloc(i);
if(!gfx) return;
dest->xsize=xsize;
dest->ysize=ysize;
map=gs->gs_inout;
memcpy(gfx,gs->gs_pic,i);
p=gfx;
while(i--)
{
if(*p) *p=map[*p];
++p;
}
}
void solidcopyany(solid *src,solid *dest,int destx,int desty,int sizex,int sizey)
{
int xmax,ymax;
int j;
uchar *p1,*p2;
int w;
xmax=src->xsize;
ymax=src->ysize;
if(destx>=xmax || desty>=ymax || destx+sizex<=0 || desty+sizey<=0)
return;
if(destx<0)
{
sizex+=destx;
destx=0;
}
if(desty<0)
{
sizey+=desty;
desty=0;
}
if(destx+sizex>xmax)
sizex=xmax-destx;
if(desty+sizey>ymax)
sizey=ymax-desty;
if(dest)
{
w=dest->xsize;
p1=dest->graphics+desty*w+destx;
} else
{
gfxlock();
w=stride;
p1=videomem+desty*stride+destx;
}
p2=src->graphics+desty*xmax+destx;
for(j=0;j<sizey;++j)
{
memcpy(p1,p2,sizex);
p1+=w;
p2+=xmax;
}
}
void solidcopy(solid *solid,int destx,int desty,int sizex,int sizey)
{
solidcopyany(solid,0,destx,desty,sizex,sizey);
}
void drawfigureany(int x,int y,figure *fig,solid *dest)
{
int run;
int dx,dy;
int xsize,ysize;
int clipx,clipy,w;
unsigned char *pc,*p,*p2,*take;
take=fig->graphics;
if(dest)
{
w=clipx=dest->xsize;
clipy=dest->ysize;
pc=dest->graphics;
} else
{
gfxlock();
w=stride;
clipx=IXSIZE;
clipy=IYSIZE;
pc=videomem;
}
dx=fig->xdelta;
dy=fig->ydelta;
xsize=fig->xsize;
ysize=fig->ysize;
x+=dx;
y+=dy;
if(x>=0 && y>=0 && x<=clipx-xsize && y<=clipy-ysize)
{
while((run=*take++))
{
dx=*((signed char *)take); ++take;
dy=*((signed char *)take); ++take;
p=pc+w*(y+dy)+x+dx;
while(run--)
*p++=*take++;
}
} else
{
while((run=*take++))
{
dx=*((signed char *)take); ++take;
dy=*((signed char *)take); ++take;
dx+=x;
dy+=y;
p2=take;
take+=run;
if(dy<0 || dy>=clipy) continue;
if(dx>=clipx) continue;
if(dx<0)
{
p2-=dx;
run+=dx;
dx=0;
} else if(dx+run>clipx)
run=clipx-dx;
p=pc+w*dy+dx;
if(run)
memcpy(p,p2,run);
}
}
}
void drawfigure(int destx,int desty,figure *fig)
{
drawfigureany(destx,desty,fig,0);
}
void copyup()
{
gfxunlock();
SDL_UpdateRect(thescreen, 0, 0, 0, 0);
needwhole=0;
}
void copyupxy(int x,int y)
{
gfxunlock();
SDL_UpdateRect(thescreen,x,y,24,24);
}
void copyupxysize(int x,int y,int xsize,int ysize)
{
gfxunlock();
SDL_UpdateRect(thescreen,x,y,xsize,ysize);
}
// 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;
themap[0].r=0;
themap[0].g=0;
themap[0].b=0;
usedcolors=1;
block64=malloc(65536);
if(!block64)
{
printf("Couldn't allocate block64\n");
exit(50);
}
if ( SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER|SDL_INIT_AUDIO) < 0 )
{
fprintf(stderr, "Couldn't initialize SDL: %s\n",SDL_GetError());
exit(1);
}
videoflags = SDL_SWSURFACE|SDL_HWPALETTE; //|SDL_FULLSCREEN;
thescreen = SDL_SetVideoMode(IXSIZE, IYSIZE, 8, videoflags);
if ( thescreen == NULL )
{
fprintf(stderr, "Couldn't set display mode: %s\n",
SDL_GetError());
SDL_Quit();
exit(5);
}
stride=thescreen->pitch;
videomem=thescreen->pixels;
mustlock=SDL_MUSTLOCK(thescreen);
locked=0;
SDL_ShowCursor(0);
}
void closegfx(void)
{
SDL_Quit();
}
int checkpressed(int code)
{
int *p,i;
i=numpressed;
p=pressedcodes;
while(i--)
if(*p++==code) return 1;
return 0;
}
int checkdown(int code)
{
int *p,i;
i=numdown;
p=downcodes;
while(i--)
if(*p++==code) return 1;
return 0;
}
int checkbutton(int button)
{
return buttonstate & (1<<button);
}
int checkbuttondown(int button)
{
return buttondown & (1<<button);
}
int anydown(void)
{
return numdown;
}
int takedown(void)
{
int res=0;
if(numdown)
{
res=*downcodes;
--numdown;
if(numdown)
memmove(downcodes,downcodes+1,numdown*sizeof(int));
}
return res;
}
int firstdown(void)
{
return *downcodes;
}
#define ENDMARK 0xaabacada
int sdlinoutnormal[]={
SDLK_0,'0',
SDLK_1,'1',
SDLK_2,'2',
SDLK_3,'3',
SDLK_4,'4',
SDLK_5,'5',
SDLK_6,'6',
SDLK_7,'7',
SDLK_8,'8',
SDLK_9,'9',
SDLK_a,'a',
SDLK_b,'b',
SDLK_c,'c',
SDLK_d,'d',
SDLK_e,'e',
SDLK_f,'f',
SDLK_g,'g',
SDLK_h,'h',
SDLK_i,'i',
SDLK_j,'j',
SDLK_k,'k',
SDLK_l,'l',
SDLK_m,'m',
SDLK_n,'n',
SDLK_o,'o',
SDLK_p,'p',
SDLK_q,'q',
SDLK_r,'r',
SDLK_s,'s',
SDLK_t,'t',
SDLK_u,'u',
SDLK_v,'v',
SDLK_w,'w',
SDLK_x,'x',
SDLK_y,'y',
SDLK_z,'z',
SDLK_MINUS,'-',
SDLK_EQUALS,'=',
SDLK_LEFTBRACKET,'[',
SDLK_RIGHTBRACKET,']',
SDLK_SEMICOLON,';',
SDLK_QUOTE,'\'',
SDLK_SLASH,'/',
SDLK_PERIOD,'.',
SDLK_COMMA,',',
SDLK_BACKQUOTE,'`',
SDLK_BACKSPACE,8,
SDLK_TAB,9,
SDLK_DELETE,MYDELETE,
SDLK_RETURN,13,
SDLK_F1,MYF1,
SDLK_F2,MYF2,
SDLK_F3,MYF3,
SDLK_F4,MYF4,
SDLK_F5,MYF5,
SDLK_F6,MYF6,
SDLK_F7,MYF7,
SDLK_F8,MYF8,
SDLK_F9,MYF9,
SDLK_F10,MYF10,
SDLK_ESCAPE,0x1b,
SDLK_LEFT,MYLEFT,
SDLK_RIGHT,MYRIGHT,
SDLK_UP,MYUP,
SDLK_DOWN,MYDOWN,
SDLK_PAGEUP,MYPAGEUP,
SDLK_PAGEDOWN,MYPAGEDOWN,
SDLK_SPACE,' ',
SDLK_HOME,MYHOME,
SDLK_END,MYEND,
SDLK_LALT,MYALTL,
SDLK_RALT,MYALTR,
ENDMARK
};
int sdlinoutshifted[]={
SDLK_0,')',
SDLK_1,'!',
SDLK_2,'@',
SDLK_3,'#',
SDLK_4,'$',
SDLK_5,'%',
SDLK_6,'^',
SDLK_7,'&',
SDLK_8,'*',
SDLK_9,'(',
SDLK_a,'A',
SDLK_b,'B',
SDLK_c,'C',
SDLK_d,'D',
SDLK_e,'E',
SDLK_f,'F',
SDLK_g,'G',
SDLK_h,'H',
SDLK_i,'I',
SDLK_j,'J',
SDLK_k,'K',
SDLK_l,'L',
SDLK_m,'M',
SDLK_n,'N',
SDLK_o,'O',
SDLK_p,'P',
SDLK_q,'Q',
SDLK_r,'R',
SDLK_s,'S',
SDLK_t,'T',
SDLK_u,'U',
SDLK_v,'V',
SDLK_w,'W',
SDLK_x,'X',
SDLK_y,'Y',
SDLK_z,'Z',
SDLK_MINUS,'_',
SDLK_EQUALS,'+',
SDLK_LEFTBRACKET,'{',
SDLK_RIGHTBRACKET,'}',
SDLK_SEMICOLON,':',
SDLK_QUOTE,'"',
SDLK_SLASH,'?',
SDLK_PERIOD,'>',
SDLK_COMMA,'<',
SDLK_BACKQUOTE,'~',
SDLK_BACKSPACE,8,
SDLK_TAB,9,
SDLK_DELETE,MYDELETE,
SDLK_RETURN,13,
SDLK_F1,MYF1+MYSHIFTED,
SDLK_F2,MYF2+MYSHIFTED,
SDLK_F3,MYF3+MYSHIFTED,
SDLK_F4,MYF4+MYSHIFTED,
SDLK_F5,MYF5+MYSHIFTED,
SDLK_F6,MYF6+MYSHIFTED,
SDLK_F7,MYF7+MYSHIFTED,
SDLK_F8,MYF8+MYSHIFTED,
SDLK_F9,MYF9+MYSHIFTED,
SDLK_F10,MYF10+MYSHIFTED,
SDLK_ESCAPE,0x1b,
SDLK_LEFT,MYLEFT+MYSHIFTED,
SDLK_RIGHT,MYRIGHT+MYSHIFTED,
SDLK_UP,MYUP+MYSHIFTED,
SDLK_DOWN,MYDOWN+MYSHIFTED,
SDLK_PAGEUP,MYPAGEUP,
SDLK_PAGEDOWN,MYPAGEDOWN,
SDLK_SPACE,' ',
SDLK_HOME,MYHOME,
SDLK_END,MYEND,
SDLK_LALT,MYALTL,
SDLK_RALT,MYALTR,
ENDMARK
};
static int looklist(int code,int *list)
{
while((unsigned int)*list!=ENDMARK) {
if(*list==code)
return list[1];
list+=2;
}
return -1;
}
static int mapkey(int code,int qual)
{
if(qual & KMOD_SHIFT)
code=looklist(code,sdlinoutshifted);
else
code=looklist(code,sdlinoutnormal);
if(code<0) return -1;
if(qual & KMOD_ALT)
code|=MYALTED;
return code;
}
static void markkey(int code,int status)
{
int i;
int *ip;
if(status)
{
if(numdown<KEYMAX)
downcodes[numdown++]=code;
ip=pressedcodes;
i=numpressed;
while(i)
if(*ip++==code) break;
else i--;
if(!i && numpressed<KEYMAX)
pressedcodes[numpressed++]=code;
} else
{
i=numpressed;
ip=pressedcodes;
while(i)
if(*ip++==code)
{
*--ip=pressedcodes[--numpressed];
break;
} else i--;
}
}
void pollinput(void)
{
SDL_PollEvent(0);
}
void scaninput(void)
{
SDL_Event event;
int key,mod;
static int bs=0;
numdown=0;
buttondown=0;
while(SDL_PollEvent(&event))
{
switch(event.type)
{
case SDL_KEYDOWN:
key=event.key.keysym.sym;
mod=event.key.keysym.mod;
markkey(mapkey(key,mod),1);
break;
case SDL_KEYUP:
key=event.key.keysym.sym;
mod=event.key.keysym.mod;
markkey(mapkey(key,mod),0);
break;
case SDL_MOUSEBUTTONUP:
bs&=~(1<<(event.button.button-1));
mousex=event.button.x>>1;
mousey=event.button.y>>1;
mouseb=bs;
break;
case SDL_MOUSEBUTTONDOWN:
bs|=1<<(event.button.button-1);
mousex=event.button.x>>1;
mousey=event.button.y>>1;
mouseb=bs;
break;
case SDL_MOUSEMOTION:
mousex=event.motion.x>>1;
mousey=event.motion.y>>1;
break;
case SDL_QUIT:
exitflag = 1;
break;
}
}
}
/*
void scaninput()
{
int i,*ip,code;
numdown=0;
buttondown=0;
while(XCheckMaskEvent(dp,~0,&event))
switch(event.type)
{
case KeyPress:
code=XLookupKeysym(keyevent,0);
if(numdown<KEYMAX)
downcodes[numdown++]=code;
ip=pressedcodes;
i=numpressed;
while(i)
if(*ip++==code) break;
else i--;
if(!i && numpressed<KEYMAX)
pressedcodes[numpressed++]=code;
break;
case KeyRelease:
code=XLookupKeysym(keyevent,0);
i=numpressed;
ip=pressedcodes;
while(i)
if(*ip++==code)
{
*--ip=pressedcodes[--numpressed];
break;
} else i--;
break;
case ButtonPress:
i=1<<buttonevent->button;
buttonstate|=i;
buttondown|=i;
break;
case ButtonRelease:
buttonstate&=~(1<<buttonevent->button);
break;
case MotionNotify:
mxpos=motionevent->x;
mypos=motionevent->y;
break;
case Expose:
copyup();
needwhole=0;
break;
case FocusOut:
numpressed=0;
break;
}
}
*/
static void drawrect(int x,int y,int xs,int ys,int c)
{
uchar *p;
gfxlock();
p=videomem+y*stride+x;
while(ys--)
{
memset(p,c,xs);
p+=stride;
}
}
void greyrect(int x,int y,int xsize,int ysize)
{
static int greycolor=-1;
if(greycolor==-1)
greycolor=bestmatch(0,0,0x70);
drawrect(x,y,xsize,ysize,greycolor);
}
void clear()
{
int j;
uchar *p;
gfxlock();
p=videomem;
for(j=0;j<IYSIZE;++j)
{
memset(p,0,IXSIZE);
p+=stride;
}
}
void clearrect(int x,int y,int xsize,int ysize)
{
drawrect(x,y,xsize,ysize,0);
}
void gfxlock(void)
{
if(locked || !mustlock) return;
if ( SDL_LockSurface(thescreen) < 0 )
{
fprintf(stderr, "Couldn't lock display surface: %s\n",
SDL_GetError());
}
locked=1;
}
void gfxunlock(void)
{
if(!locked || !mustlock) return;
SDL_UnlockSurface(thescreen);
locked=0;
}

69
gfx.h
View File

@ -1,69 +0,0 @@
#ifndef GFX_H
#define GFX_H
#define KEYMAX 128
extern int usedcolors;
extern uchar mymap[];
extern int screen;
extern int fontbase,fontysize;
extern char *imageloc;
extern long map2[];
extern uchar fmap[128];
extern int buttonstate,buttondown;
extern int mxpos,mypos;
extern int pressedcodes[KEYMAX],downcodes[KEYMAX],numpressed,numdown;
void opengfx(int argc, char **argv);
void gfxlock(void);
void gfxunlock(void);
void pollinput(void);
int takedown(void);
void closegfx(void);
void greyrect(int x,int y,int xsize,int ysize);
void clearrect(int x,int y,int xsize,int ysize);
void solidfetch(gfxset *gs,solid *dest);
extern void dumpgfx(void);
extern void createinout(struct gfxset *);
extern void getcolors(void);
extern void gfxfetch(struct gfxset *,struct figure *,int);
extern void puttile(int destx,int desty,int source);
extern void store(int x,int y,int which);
extern void restore(int x,int y,int which);
extern void copyup(void);
extern void copyupxy(int x,int y);
extern void copyupxysize(int x,int y,int xsize,int ysize);
extern void getfigures(void);
extern unsigned long getcolor(char *name); /* unsigned long */
extern int checkpressed(int code);
extern int checkdown(int code);
extern int checkbutton(int button);
extern int checkbuttondown(int button);
extern int anydown(void);
extern int firstdown(void);
extern void scaninput(void);
extern void fontinit(void);
extern void writechar(int x,int y,uchar ch);
extern void clear(void);
extern void drawbox(int x,int y,int size,int color);
extern void drawbox2(int x,int y,int sizex,int sizey,int color);
extern void drawfillrect(int x,int y,int size,int color);
extern void bigpixel(int x,int y,int color);
extern void invert(int x,int y);
extern int getmousex(void);
extern int getmousey(void);
extern void drawsquare(int x,int y,uchar *source);
extern void colormapon(void);
extern void colormapoff(void);
extern void palette(uchar *pal);
extern void drawfigure(int x,int y,figure *fig);
extern void drawfigureany(int x,int y,figure *fig,solid *dest);
void solidcopy(solid *src,int destx,int desty,int sizex,int sizey);
void solidcopyany(solid *src,solid *dest,int destx,int desty,int sizex,int sizey);
#endif // GFXX_H

61
list.h
View File

@ -1,61 +0,0 @@
#ifndef LIST_H
#define LIST_H
/* from linux kernel */
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
/**
* list_entry - get the struct for this entry
* @ptr: the &struct list_head pointer.
* @type: the type of the struct this is embedded in.
* @member: the name of the list_struct within the struct.
*/
#define list_entry(ptr, type, member) container_of(ptr, type, member)
void alloc_things(void);
void *_allocentry(size_t size);
#define allocentry(type) (type*) _allocentry(sizeof(type))
void freeentry(void *ptr);
void list_add_tail(listhead *header, listhead *entry);
#define addtail(head, entry) list_add_tail(head, &(entry->list));
/* remove entry from list */
void list_del(listhead *entry);
#define removeitem(entry) list_del(&(entry->list));
void list_init_head(listhead *head);
void things_list_clear(listhead *head); /* listhead member must be the first member */
/**
* list_for_each_entry - iterate over list of given type
* @pos: the type * to use as a loop cursor.
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*/
#define list_for_each_entry(pos, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member); \
/* prefetch(pos->member.next), */ \
&pos->member != (head); \
pos = list_entry(pos->member.next, typeof(*pos), member))
/**
* list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
* @pos:<-->the type * to use as a loop cursor.
* @n:<><-->another type * to use as temporary storage
* @head:<->the head for your list.
* @member:>the name of the list_struct within the struct.
*/
#define list_for_each_entry_safe(pos, n, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member), \
n = list_entry(pos->member.next, typeof(*pos), member); \
&pos->member != (head); \
pos = n, n = list_entry(n->member.next, typeof(*n), member))
#define list_empty(head) ((head) == (head)->next)
#endif

392
matcher.c
View File

@ -1,392 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/uio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/timeb.h>
#include <sys/time.h>
#include <time.h>
#include <signal.h>
#include <fcntl.h>
#define MAXMSG 256
#define PORT 5521
#define TIMETOLIVE 600 // seconds
typedef unsigned char uchar;
char logging=0;
unsigned char mesg[MAXMSG];
int lastsize;
int network;
char masterhostname[256];
#define PKT_REGISTER 16
#define PKT_ACK 24
#define PKT_INFO 40
#define PKT_QUERY 32
#define MAXMATCHES 16
struct registration
{
uchar id;
uchar unique[4];
uchar password[4];
uchar version[4];
uchar name[16];
uchar status;
};
struct query
{
uchar id;
uchar password[4];
uchar version[4];
};
struct gamehost
{
struct gamehost *next,*prev;
uchar machine[4];
uchar port[2];
struct registration reg;
long timeout;
};
struct gamehost *freehosts=0,*activehosts=0;
int udpsocket,myport;
struct sockaddr_in myname={0},mastername={0};
socklen_t senderlength;
struct sockaddr_in sender={0};
long longtime(void)
{
struct timeb tb;
ftime(&tb);
return tb.time;
}
char *timestr()
{
static char timestring[80];
time_t t;
int l;
time(&t);
strcpy(timestring,ctime(&t));
l=strlen(timestring);
if(l && timestring[l-1]=='\n') timestring[l-1]=0;
return timestring;
}
int putmsg(struct sockaddr_in *toname,unsigned char *msg,int len)
{
int status;
status=sendto(udpsocket,msg,len,0,
(struct sockaddr *)toname,sizeof(struct sockaddr_in));
return status;
}
void ack()
{
uchar copy[256];
*copy=PKT_ACK;
memmove(copy+1,mesg,lastsize);
putmsg(&sender,copy,lastsize+1);
}
int getmsg(int seconds)
{
int size;
lastsize=-1;
memset(&sender,0,sizeof(sender));
senderlength=sizeof(sender);
if(seconds)
{
struct timeval timeout;
fd_set readfds;
int res;
timeout.tv_sec=seconds;
timeout.tv_usec=0;
FD_ZERO(&readfds);
FD_SET(udpsocket,&readfds);
res=select(udpsocket+1,&readfds,0,0,&timeout);
if(res<=0) return -1;
}
lastsize=size=recvfrom(udpsocket,mesg,MAXMSG,0,
(struct sockaddr *)&sender,&senderlength);
return size;
}
long longind(unsigned char *p)
{
return (p[0]<<24L) | (p[1]<<16L) | (p[2]<<8) | p[3];
}
short shortind(unsigned char *p)
{
return (p[0]<<8L) | p[1];
}
void openport(int portwant)
{
int status;
myport=portwant;
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(myport);
status=bind(udpsocket,(struct sockaddr *) &myname,sizeof(myname));
if(status==-1)
{
perror("bind()");
exit(1);
}
}
#define PERBLOCK 512
struct gamehost *newhost()
{
struct gamehost *h,*block;
int i;
if(!freehosts)
{
block=malloc(sizeof(struct gamehost)*PERBLOCK);
if(!block) return 0;
freehosts=block;
i=PERBLOCK-1;
while(i--)
{
block->next=block+1;
++block;
}
block->next=0;
}
h=freehosts;
freehosts=freehosts->next;
memset(h,0,sizeof(struct gamehost));
return h;
}
void freehost(struct gamehost *h)
{
h->next=freehosts;
freehosts=h;
}
struct gamehost *findmatch(struct registration *key)
{
struct gamehost *h;
h=activehosts;
while(h)
{
if(!memcmp(&h->reg,key,sizeof(struct registration)-1))
return h;
h=h->next;
}
return 0;
}
void insert(struct gamehost *h)
{
if(activehosts)
{
h->next=activehosts;
h->prev=activehosts->prev;
activehosts->prev=h;
activehosts=h;
} else
{
h->next=h->prev=0;
activehosts=h;
}
}
void delete(struct gamehost *h)
{
if(h->prev)
h->prev->next=h->next;
else
activehosts=h->next;
if(h->next)
h->next->prev=h->prev;
freehost(h);
}
void doreg()
{
struct registration *new;
struct gamehost *match;
long now;
new=(struct registration *)mesg;
match=findmatch(new);
if(logging)
{
unsigned addr=ntohl(sender.sin_addr.s_addr);
unsigned short port=ntohs(sender.sin_port);
printf("reg :%s:%d.%d.%d.%d:%d %c%lx '%s'\n",timestr(),
(addr>>24)&255,(addr>>16)&255,(addr>>8)&255,addr&255,port,
new->status ? '+' : '-',(long)match,new->name);
fflush(stdout);
}
if(!match && !new->status) {ack();return;}
if(match && new->status) {ack();return;}
if(!match && new->status)
{
match=newhost();
if(!match) return; // No memory, what can we do?
memmove(match->machine,&sender.sin_addr.s_addr,4);
memmove(match->port,&sender.sin_port,2);
match->reg=*new;
now=longtime();
match->timeout=now+TIMETOLIVE;
ack();
insert(match);
return;
} else // match && !new->status
{
delete(match);
ack();
return;
}
}
void doquery()
{
uchar *password;
uchar *version;
struct gamehost *h;
uchar response[2048],*rput,*countersave;
int counter;
if(logging)
{
unsigned addr=ntohl(sender.sin_addr.s_addr);
unsigned short port=ntohs(sender.sin_port);
printf("query:%s:%d.%d.%d.%d:%d\n",timestr(),
(addr>>24)&255,(addr>>16)&255,(addr>>8)&255,addr&255,port);
fflush(stdout);
}
password=mesg+1;
version=mesg+5;
h=activehosts;
rput=response;
*rput++=PKT_INFO;
memmove(rput,password,4);
rput+=4;
memmove(rput,version,4);
rput+=4;
countersave=rput;
*rput++=0;
*rput++=0;
counter=0;
while(h)
{
if(!memcmp(password,h->reg.password,4) &&
!memcmp(version,h->reg.version,4) && counter<MAXMATCHES)
{
++counter;
memmove(rput,h->reg.unique,4);
rput+=4;
memmove(rput,h->machine,4);
rput+=4;
memmove(rput,h->port,2);
rput+=2;
memmove(rput,h->reg.name,sizeof(h->reg.name));
rput+=sizeof(h->reg.name);
}
h=h->next;
}
*countersave++=counter>>8;
*countersave++=counter;
putmsg(&sender,response,rput-response);
}
void purge(long cutoff)
{
struct gamehost *h,*h2;
h=activehosts;
while(h)
{
h2=h;
h=h->next;
if(cutoff-h2->timeout>0)
{
delete(h2);
}
}
}
int main(int argc,char **argv)
{
int i;
int want;
int size;
long purgetime;
long now;
want=PORT;
if(argc>1)
{
for(i=1;i<argc;++i)
if(!strncmp(argv[i],"-p",2))
{
if(strlen(argv[i])>2) want=atoi(argv[i]+2);
else if(i+1<argc) want=atoi(argv[i+1]);
}
}
freehosts=0;
openport(want);
purgetime=longtime()+TIMETOLIVE;
for(;;)
{
size=getmsg(10);
if(size>=1)
switch(*mesg)
{
case PKT_REGISTER:
if(size<sizeof(struct registration)) continue;
doreg();
break;
case PKT_QUERY:
if(size<sizeof(struct query)) continue;
doquery();
break;
}
now=longtime();
if(now-purgetime>0) // avoid year 203x bug...
{
purge(purgetime);
purgetime+=TIMETOLIVE;
}
}
}

402
menu.c
View File

@ -1,402 +0,0 @@
#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"
GameOptions configopts = { 2, 1, 0, 2 };
/* Generic menu */
typedef enum {
MENU_ANY = -1,
MENU_MAIN = 0,
MENU_CONFIG = 2,
MENU_JOIN = 3
} menuname;
#define MENU_SELECT(x) ((menuname) (-x-1))
static int menuhistory[32]={0};
static char menustring[1024];
static char *menuput,*menuitems[40],*menutitle;
static int menunum, menuexit;
static 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(menuname whichmenu, int (*pause)(void)) {
char redraw;
int selected;
int mcount=0;
if(whichmenu>=0)
selected=menuhistory[whichmenu];
else
selected=-whichmenu-1;
if (!pause) pause=mypause;
redraw=1;
clearspritelist();
while(!exitflag) {
if(redraw) {
drawmenu(selected);
redraw=0;
}
if (!pause()) return -1;
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 (MENU_MAIN == whichmenu && menuexit != selected) {
selected = menuexit;
redraw = 1;
break;
}
menudelta = 1;
return menuexit;
}
}
}
menudelta = 0;
return menuexit;
}
static void menustart() {
menunum=-1;
menuput=menustring;
*menuput=0;
menuexit = 0;
}
static void additem_s(char *item, int len) {
if (len < 0 || (menustring+sizeof(menustring)-menuput <= len)) return;
if(menunum<0)
menutitle=menuput;
else
menuitems[menunum]=menuput;
++menunum;
memcpy(menuput,item,len+1);
menuput += len+1;
}
static void additem(char *item,...) {
char output[256];
va_list ap;
int len;
va_start(ap, item);
len = vsnprintf(output,sizeof(output),item,ap);
if (len >= 256) len = 255; /* truncated string */
additem_s(output, len);
}
static void addexit(char *item,...) {
char output[256];
va_list ap;
int len;
va_start(ap, item);
len = vsnprintf(output,sizeof(output),item,ap);
if (len >= 256) len = 255; /* truncated string */
menuexit = menunum;
additem_s(output, len);
}
/* end generic menu */
/* game menues */
static const char *densities[]={"PACKED","HIGH","MEDIUM","LOW"};
static const char *generosities[]={"LOW","MEDIUM","HIGH","RIDICULOUS"};
static const char *dis_en_abled[]={"DISABLED","ENABLED"};
static void config_menu(void) {
int sel;
while (!exitflag) {
menustart();
additem("GAME OPTIONS");
additem("RETURN TO MAIN MENU");
additem("DENSITY: %s",densities[configopts.density]);
additem("GENEROSITY: %s",generosities[configopts.generosity]);
additem("INITIAL FLAME LENGTH: %d",configopts.flames+1);
additem("INITIAL NUMBER OF BOMBS: %d",configopts.bombs+1);
additem("SOUND: %s", dis_en_abled[sound_enabled]);
sel=domenu(MENU_CONFIG, NULL);
switch (sel) {
case 0:
return;
case 1:
configopts.density+=menudelta;
configopts.density&=3;
break;
case 2:
configopts.generosity+=menudelta;
configopts.generosity&=3;
break;
case 3:
configopts.flames+=menudelta;
configopts.flames&=7;
break;
case 4:
configopts.bombs+=menudelta;
configopts.bombs&=7;
break;
case 5:
sound_enabled = 1 - sound_enabled;
break;
}
}
}
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;
snprintf(temp,sizeof(temp)," %d %s",i+1,name);
drawbigstring(M3X,M3Y+(i+2)*bigfontyspace,temp);
}
copyup();
}
static void host_game(void) {
create_seed_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();
return;
case ' ':
case 13:
unregistergame();
if (begin_network_game()) {
run_network_game();
return;
}
send_invites();
draw_host_game();
}
}
if (!handle_joins()) continue;
send_invites();
draw_host_game();
}
}
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;
snprintf(temp,sizeof(temp)," %d %s",i+1,name);
drawbigstring(JX,JY+(i+1)*bigfontyspace,temp);
}
}
static int tryjoin(int which) {
int res;
if (0 == (res = send_join(&gamelistentries[which].netname, playername))) {
return 0;
}
while (!exitflag) {
switch (res) {
case 1:
failure("Game closed");
return 0;
case 2:
drawjoinscreen();
copyup();
break;
case 3: return 1;
default: break;
}
scaninput();
while(anydown()) {
switch(takedown()) {
case 0x1b:
send_quit();
return 0;
}
}
res=scaninvite(200);
}
return 0;
}
static int join_game_pause(void) {
if (find_more_games()) return 0;
mypause();
return 1;
}
static void join_game(void) {
int i;
int sel = -1;
if (!searchgames()) {
return;
}
menuhistory[MENU_JOIN] = 0;
while (-1 == sel) {
menustart();
if (gamelistsize == 0) {
additem("JOIN NETWORK GAME - NO GAMES AVAILABLE");
addexit("EXIT");
} else {
additem("JOIN NETWORK GAME");
for (i = 0; i < gamelistsize; i++) {
additem(gamelistentries[i].name);
}
addexit("EXIT");
}
sel = domenu(MENU_JOIN, join_game_pause);
if (menudelta < 0) sel = -1;
}
stop_search();
if(menuexit == sel || !gamelistsize) {
return;
}
if(!tryjoin(sel)) {
return;
}
run_network_game();
}
void mainloop(void) {
int sel;
exitflag = 0;
while(!exitflag) {
menustart();
additem("BOMBER MAIN MENU");
additem("EXIT GAME");
additem("START SINGLE PLAYER GAME");
additem("OPTIONS");
// additem("REMAP MOVEMENT KEYS");
additem("START NETWORK GAME");
additem("JOIN NETWORK GAME");
sel=domenu(MENU_MAIN, NULL);
if (menudelta < 0) sel = -1;
switch (sel) {
case 0:
return;
case 1:
run_single_player();
break;
case 2:
config_menu();
break;
case 3:
host_game();
break;
case 4:
join_game();
break;
}
}
}

75
meson.build Normal file
View File

@ -0,0 +1,75 @@
project(
'sdlbomber',
'c',
version: '1.0.10',
default_options: [
'warning_level=3',
'buildtype=debugoptimized',
],
)
avahi_client_dep = dependency(
'avahi-client',
)
sdl_dep = dependency(
'sdl',
)
executable(
'sdlbomber',
'src/announce.c',
'src/bomber.c',
'src/draw.c',
'src/game.c',
'src/gfx.c',
'src/list.c',
# 'src/matcher.c',
'src/menu.c',
'src/network.c',
'src/sound.c',
'src/utils.c',
override_options: [
'c_std=c17',
],
install: true,
dependencies: [
avahi_client_dep,
sdl_dep,
]
)
install_data(
'data/bigfont.pcx',
'data/blocks1.pcx',
'data/blocks1x.pcx',
'data/blocks2.pcx',
'data/blocks2x.pcx',
'data/blocks3.pcx',
'data/blocks3x.pcx',
'data/bomb1.pcx',
'data/bomb1.raw',
'data/bomb2.pcx',
'data/bomb2.raw',
'data/death.raw',
'data/death1.pcx',
'data/death2.pcx',
'data/death3.pcx',
'data/drop.raw',
'data/field0.pcx',
'data/flames.pcx',
'data/font.pcx',
'data/pal0.pcx',
'data/pal1.pcx',
'data/pal2.pcx',
'data/pal3.pcx',
'data/pal4.pcx',
'data/pal5.pcx',
'data/pal6.pcx',
'data/pal7.pcx',
'data/pal8.pcx',
'data/pal9.pcx',
'data/power1.raw',
'data/power2.raw',
'data/tiles.pcx',
'data/walk.pcx',
)

190
sound.c
View File

@ -1,190 +0,0 @@
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <SDL_audio.h>
#include <SDL_error.h>
#include "sound.h"
#ifndef DATADIR
#define DATADIR "data"
#endif
int sound_enabled = 1;
static char dirlist[]=DATADIR;
static int readsound(int num);
#define NUMSOUNDS ((int)(sizeof(soundnames)/sizeof(char*)))
#define MIXMAX 16
#define SOUND_QUIET -1
static const char *soundnames[] = {
"bomb1.raw",
"power1.raw",
"death.raw",
"drop.raw",
"bomb2.raw",
"power2.raw",
};
typedef struct sample
{
char *data;
int len;
} sample;
#define SNDFRAGMENT 1024
static sample samples[NUMSOUNDS];
static int soundworking=0;
static int fragment;
// static int soundwrite,soundread;
static int *soundbuffer;
static int soundbufferlen;
static unsigned char sndclip[8192];
#define MAXSOUNDCOMMANDS 32
static char soundcommands[MAXSOUNDCOMMANDS];
static int soundtake,soundput;
static int sndplaying[MIXMAX],sndposition[MIXMAX];
static void fillaudio(void *udata,Uint8 *buffer,int len)
{
char com,*p;
int i,j,*ip;
int which;
while(soundtake!=soundput)
{
com=soundcommands[soundtake];
soundtake=(soundtake+1)&(MAXSOUNDCOMMANDS-1);
if(com==SOUND_QUIET) {memset(sndposition,0,sizeof(sndposition));continue;}
if(com<NUMSOUNDS)
{
for(i=0;i<MIXMAX;++i)
if(!sndposition[i])
{
sndposition[i]=1;
sndplaying[i]=com;
break;
}
}
}
memset(soundbuffer,0,soundbufferlen);
for(i=0;i<MIXMAX;++i)
{
if(!sndposition[i]) continue;
which=sndplaying[i];
if(sndposition[i]==samples[which].len)
{
sndposition[i]=0;
continue;
}
p=samples[which].data;
if(!p) continue;
p+=len*(sndposition[i]++ -1);
ip=soundbuffer;
j=len;
while(j--) *ip++ += *p++;
}
j=len;
ip=soundbuffer;;
while(j--) *buffer++ = sndclip[4096+*ip++];
}
int soundopen(void) {
SDL_AudioSpec wanted;
int i,j;
soundtake=soundput=0;
memset(sndposition,0,sizeof(sndposition));
memset(sndplaying,0,sizeof(sndplaying));
fragment=SNDFRAGMENT<<1;
soundbufferlen=fragment*sizeof(int);
soundbuffer=malloc(soundbufferlen);
if(!soundbuffer) return -2;
memset(&wanted,0,sizeof(wanted));
wanted.freq=22050;
wanted.channels=2;
wanted.format=AUDIO_U8;
wanted.samples=fragment>>1;
wanted.callback=fillaudio;
wanted.userdata=0;
if(SDL_OpenAudio(&wanted,0)<0)
{
fprintf(stderr,"Couldn't open audio: %s\n",SDL_GetError());
return -1;
}
soundworking=1;
for(i=0;i<8192;i++)
{
j=i-4096;
sndclip[i]=j > 127 ? 255 : (j<-128 ? 0 : j+128);
}
for(i=0;i<NUMSOUNDS;++i)
readsound(i);
SDL_PauseAudio(0);
return 0;
}
void soundclose(void) {
if(soundworking)
{
SDL_CloseAudio();
soundworking=0;
}
}
int readsound(int num) {
char name[256],*p1,*p2,ch;
int file,size,len;
p1=dirlist;
for(;;)
{
p2=name;
while(*p1 && (ch=*p1++)!=',')
*p2++=ch;
if(p2>name && p2[-1]!='/') *p2++='/';
strcpy(p2,soundnames[num]);
file=open(name,O_RDONLY);
if(file>=0) break;
if(!*p1)
{
samples[num].len=-1;
return 0;
}
}
size=lseek(file,0,SEEK_END);
lseek(file,0,SEEK_SET);
len=samples[num].len=(size+fragment-1)/fragment;
len*=fragment;
p1=samples[num].data=malloc(len);
if(p1)
{
read(file,p1,size);
if(len-size) memset(p1+size,0,len-size);
while(size--) *p1++ ^= 0x80;
} else
samples[num].data=0;
close(file);
return 0;
}
void playsound(int n) {
if (sound_enabled) {
soundcommands[soundput]=n;
soundput=(soundput+1)&(MAXSOUNDCOMMANDS-1);
}
}

View File

@ -2,12 +2,12 @@
#include "announce.h"
#include "network.h"
#include <time.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <avahi-client/client.h>
#include <avahi-client/lookup.h>
@ -38,7 +38,7 @@ 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)));
fprintf(stderr, "Error in: %s\n (%s)", s, avahi_strerror(avahi_client_errno(c)));
}
static void create_services(AvahiClient* c);
@ -50,8 +50,7 @@ static void entry_group_callback(AvahiEntryGroup *g, AvahiEntryGroupState state,
case AVAHI_ENTRY_GROUP_ESTABLISHED:
break;
case AVAHI_ENTRY_GROUP_COLLISION :
{
case AVAHI_ENTRY_GROUP_COLLISION: {
char* n = avahi_alternative_service_name(name);
avahi_free(name);
name = n;
@ -90,8 +89,7 @@ again:
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_version, NULL)) < 0) {
if (ret == AVAHI_ERR_COLLISION)
goto collision;
if (ret == AVAHI_ERR_COLLISION) goto collision;
fprintf(stderr, "Failed to add " SERVICE_TYPE ": %s\n", avahi_strerror(ret));
goto fail;
@ -105,8 +103,7 @@ again:
return;
collision:
{
collision : {
char* n = avahi_alternative_service_name(name);
avahi_free(name);
name = n;
@ -119,6 +116,8 @@ fail:
}
static void client_callback(AvahiClient* c, AvahiClientState state, void* userdata) {
(void) userdata;
client = c;
switch (state) {
case AVAHI_CLIENT_S_RUNNING:
@ -130,9 +129,7 @@ static void client_callback(AvahiClient *c, AvahiClientState state, void * userd
break;
case AVAHI_CLIENT_S_COLLISION:
case AVAHI_CLIENT_S_REGISTERING:
if (group) {
avahi_entry_group_reset(group);
}
if (group) { avahi_entry_group_reset(group); }
break;
case AVAHI_CLIENT_CONNECTING:
break;
@ -178,11 +175,26 @@ static void remove_game_with_name(const char *name) {
}
}
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) {
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;
(void) interface;
(void) host_name;
(void) flags;
(void) userdata;
assert(r);
if (protocol != AVAHI_PROTO_INET) goto done; /* ignore non IPv4 for now */
@ -195,7 +207,13 @@ static void resolve_callback(AvahiServiceResolver *r, AvahiIfIndex interface, Av
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))));
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: {
@ -227,8 +245,17 @@ 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) {
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) {
(void) flags;
assert(b);

View File

@ -1,35 +1,35 @@
#include <fcntl.h>
#include <netdb.h>
#include <signal.h>
#include <stdarg.h>
#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 <sys/types.h>
#include <unistd.h>
#include "bomber.h"
#include "gfx.h"
#include "announce.h"
#include "sound.h"
#include "menu.h"
#include "utils.h"
#include "network.h"
#include "game.h"
#include "bomber.h"
#include "draw.h"
#include "game.h"
#include "gfx.h"
#include "menu.h"
#include "network.h"
#include "sound.h"
#include "utils.h"
int main(int argc,char **argv) {
int main(void) {
char* p;
strcpy(playername, "ANONYMOUS");
p = getenv("USER");
if(p) strncpy(playername,p,sizeof(playername));
if (p) strncpy(playername, p, sizeof(playername) - 1);
create_seed_unique();
opengfx(argc, argv);
opengfx();
getsocket();
if (!initannouncer()) exit(1);

View File

@ -1,7 +1,8 @@
#ifndef BOMBER_H
#define BOMBER_H
#include "SDL.h"
#include "list.h"
#include <SDL.h>
typedef unsigned char uchar;
extern int xcolors[256];
@ -54,11 +55,6 @@ typedef struct solid {
uchar* graphics;
} solid;
typedef struct listhead listhead;
struct listhead {
listhead *prev, *next;
};
typedef struct player {
listhead list, list_all_players;
int xpos, ypos;
@ -200,7 +196,6 @@ enum tile_types {
#define CODE_ALLDEAD 2
#define MAXTHINGS 500
#define MAXSETS 8
#define MAXSPRITES 256

482
src/draw.c Normal file
View File

@ -0,0 +1,482 @@
#include <fcntl.h>
#include <netdb.h>
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.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 const unsigned char* remapstring = (const unsigned char*) "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;
snprintf(tname, sizeof(tname), DATADIR "/%s", name);
ihand = open(tname, O_RDONLY);
if (ihand < 0) {
char tname2[260];
snprintf(tname2, sizeof(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;
}
void drawstring(int xpos, int ypos, const char* str) {
char ch;
while ((ch = *str++)) {
drawfigure(xpos, ypos, font + asciiremap[toupper(ch)]);
xpos += fontxsize;
}
}
void drawbigstring(int xpos, int ypos, const char* str) {
char ch;
while ('\0' != (ch = *str++)) {
drawfigure(xpos, ypos, bigfont + asciiremap[toupper(ch)]);
xpos += bigfontxsize;
}
}
void centerbig(int y, const 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);
vsnprintf(output, sizeof(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;
const unsigned 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 < NUMCHARACTERS) asciiremap[(int) *p++] = i++;
}
void loadgfx() {
gfxset* gs;
gfxset* colorgs;
int err;
int i;
char name[267];
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) {
snprintf(name, sizeof(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");
}
void failure(char* str, ...) {
char output[256];
va_list ap;
int len;
long now;
va_start(ap, str);
len = vsnprintf(output, sizeof(output), str, ap);
if (len >= 256) len = 255; /* truncated string */
clear();
drawbigstring((IXSIZE - len * bigfontxsize) / 2, (IYSIZE - bigfontysize) / 2, output);
copyup();
now = longtime();
while (!exitflag && longtime() - now < 3) {
scaninput();
if (anydown()) {
takedown();
return;
}
}
}

View File

@ -37,6 +37,7 @@ extern int arraynumx, arraynumy, arraystartx, arraystarty, arrayspacex, arrayspa
#define NUMDEATHFRAMES 41
extern figure blocks[3], blocksx[9], bombs1[MAXSETS][NUMBOMBFRAMES], bombs2[MAXSETS][NUMBOMBFRAMES], flamefigs[MAXSETS][NUMFLAMEFRAMES], tiles[15], death[NUMDEATHFRAMES];
extern figure blocks[3], blocksx[9], bombs1[MAXSETS][NUMBOMBFRAMES], bombs2[MAXSETS][NUMBOMBFRAMES], flamefigs[MAXSETS][NUMFLAMEFRAMES], tiles[15],
death[NUMDEATHFRAMES];
#endif

951
src/game.c Normal file
View File

@ -0,0 +1,951 @@
#include "game.h"
#include "bomber.h"
#include "draw.h"
#include "gfx.h"
#include "list.h"
#include "menu.h"
#include "network.h"
#include "sound.h"
#include "utils.h"
static int gameframe;
static listhead activebombs;
static listhead activedecays;
static listhead activebonus;
static listhead activegeneric;
static listhead detonatebombs;
static listhead activeflames;
static listhead activeplayers;
static listhead allplayers;
figure walking[MAXSETS][NUMWALKFRAMES];
solid background, backgroundoriginal;
/* The playfield array, contains FIELD_* equates */
unsigned char field[32][32];
void* info[32][32];
volatile char exitflag = 0;
static int framecount = 0;
char playername[16];
static int mycount;
static int bonustotal;
static const int bonuschances[] = {TILE_BOMB, 20, TILE_FLAME, 20, TILE_TRIGGER, 2, TILE_GOLDFLAME, 2, TILE_SKATES, 20, TILE_TURTLE, 5, TILE_NONE, 160};
static GameOptions gameoptions;
static const unsigned char playerpositions[MAXNETNODES * 3] = {
/* 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 resetplayer(player* pl, int color, int x, int y) {
pl->speed = SPEEDSTART;
pl->flags = 0;
pl->flamelength = gameoptions.flames + 1;
pl->bombsavailable = gameoptions.bombs + 1;
pl->color = color;
pl->xpos = arraytoscreenx(x);
pl->ypos = arraytoscreeny(y);
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;
addtail(&activeplayers, pl);
}
static void initplayer(int color, int x, int y, int controller) {
player* pl;
pl = allocentry(player);
if (!pl) nomem("Couldn't get player structure (allocentry())");
list_add_tail(&allplayers, &pl->list_all_players);
pl->controller = controller;
pl->fixx = -4;
pl->fixy = -40;
pl->kills = pl->deaths = 0;
resetplayer(pl, color, x, y);
}
static void initplayers(void) {
int i;
const unsigned char* p;
int c, x, y;
if (NETWORK_NONE == 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 resetplayers(void) {
const unsigned char* p;
int c, x, y;
player* pl;
p = playerpositions;
list_for_each_entry(pl, &allplayers, list_all_players) {
c = *p++;
x = *p++;
y = *p++;
resetplayer(pl, c, x, y);
}
}
static void firstzero(void) {
alloc_things();
list_init_head(&activebombs);
list_init_head(&detonatebombs);
list_init_head(&activeflames);
list_init_head(&activedecays);
list_init_head(&activebonus);
list_init_head(&activeplayers);
list_init_head(&activegeneric);
list_init_head(&allplayers);
mycount = mydatacount = 0;
memset(latestactions, 0, sizeof(latestactions));
memset(latestcounts, 0, sizeof(latestcounts));
memset(actionblock, 0, sizeof(actionblock));
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;
things_list_clear(&activebombs);
things_list_clear(&detonatebombs);
things_list_clear(&activeflames);
things_list_clear(&activedecays);
things_list_clear(&activebonus);
list_init_head(&activeplayers);
things_list_clear(&activegeneric);
p = bonuschances;
bonustotal = 0;
for (;;) {
i = *p++;
if (i == TILE_NONE) break;
bonustotal += *p++;
}
bonustotal += 64 * (3 - gameoptions.generosity);
memset(field, 0, sizeof(field));
comp = gameoptions.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);
resetplayers();
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();
}
static void addflame(player* owner, int px, int py) {
flame *fl, *fl2;
fl = allocentry(flame);
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(bomb);
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 adddecay(int px, int py) {
brickdecay* bd;
int xpos, ypos;
bd = allocentry(brickdecay);
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(bonustile);
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;
list_del(&bonus->list);
freeentry(bonus);
}
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;
removeitem(bmb);
addtail(&detonatebombs, bmb);
}
static void processbombs() {
bomb *bmb, *next;
list_for_each_entry_safe(bmb, next, &activebombs, list) {
++(bmb->figcount);
++bmb->timer;
switch (bmb->type) {
case BOMB_NORMAL:
if (bmb->timer == BOMBLIFE) adddetonate(bmb);
break;
case BOMB_CONTROLLED:
if (bmb->timer == BOMB_CONTROLLED_LIFE) {
bmb->timer = 0;
bmb->type = BOMB_NORMAL;
}
break;
}
}
}
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;
list_del(&bmb->list);
freeentry(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;
bomb* bmb;
while (!list_empty(&detonatebombs)) {
bmb = (bomb*) detonatebombs.next;
++i;
detonatebomb(bmb);
}
if (i) playsound((myrand() & 1) ? 0 : 4);
}
static void processflames(void) {
flame *fl, *next;
list_for_each_entry_safe(fl, next, &activeflames, list) {
++(fl->timer);
if (fl->timer == FLAMELIFE) {
field[fl->py][fl->px] = FIELD_EMPTY;
info[fl->py][fl->px] = 0;
list_del(&fl->list);
freeentry(fl);
}
}
}
static void processdecays() {
brickdecay *bd, *next;
list_for_each_entry_safe(bd, next, &activedecays, list) {
++(bd->timer);
if (bd->timer == DECAYLIFE) {
field[bd->py][bd->px] = FIELD_EMPTY;
trybonus(bd->px, bd->py);
list_del(&bd->list);
freeentry(bd);
}
}
}
static void drawbombs(void) {
int j;
bomb* bmb;
struct figure* figtab;
int color;
int xpos, ypos;
list_for_each_entry(bmb, &activebombs, list) {
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);
}
}
static void drawflames(void) {
flame* fl;
int xpos, ypos;
/* no player specific flame sprites yet */
/* int color; */
int fig;
list_for_each_entry(fl, &activeflames, list) {
/* 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);
}
}
static void drawdecays() {
brickdecay* bd;
list_for_each_entry(bd, &activedecays, list) {
addsprite(tovideox(bd->xpos), tovideoy(bd->ypos), blocksx + (bd->timer * 9) / DECAYLIFE);
}
}
static void drawbonus() {
bonustile* bonus;
list_for_each_entry(bonus, &activebonus, list) {
addsprite(tovideox(bonus->xpos), tovideoy(bonus->ypos), tiles + bonus->type);
}
}
static void drawplayers() {
player* pl;
int xpos, ypos;
list_for_each_entry(pl, &activeplayers, list) {
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);
}
}
}
static void detonatecontrolled(player* pl) {
bomb *bmb, *next;
list_for_each_entry_safe(bmb, next, &activebombs, list) {
if (bmb->owner == pl && bmb->type == BOMB_CONTROLLED) adddetonate(bmb);
}
}
static void playonce(generic* gen) {
if (gen->timer == gen->data1) {
list_del(&gen->list);
freeentry(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(generic);
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->deaths++;
pl->flags |= FLG_DEAD;
playsound(2);
adddeath(pl);
detonatecontrolled(pl);
}
static void processgenerics(void) {
generic *gen, *next;
list_for_each_entry_safe(gen, next, &activegeneric, list) {
++(gen->timer);
gen->process(gen);
}
}
static void drawgenerics(void) {
generic* gen;
list_for_each_entry(gen, &activegeneric, list) {
gen->draw(gen);
}
}
static void drawstats(void) {
player* pl;
int p = 0;
const char* n;
char buf[17];
solidcopy(&background, 0, 0, IXSIZE, arraystarty);
list_for_each_entry(pl, &allplayers, list_all_players) {
if (pl->controller >= 0) {
n = netnodes[pl->controller].name;
} else {
n = playername;
}
snprintf(buf, sizeof(buf), "%-8.8s %2i/%2i", n, pl->kills % 100, pl->deaths % 100);
drawstring(11 + (p / 2) * (15 * fontxsize + 7), 11 + (p % 2) * (fontysize + 2), buf);
p++;
}
}
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:
if (pl->bombsavailable < 9) ++(pl->bombsavailable);
break;
case TILE_FLAME:
if (pl->flamelength < maxflame) ++(pl->flamelength);
break;
case TILE_GOLDFLAME:
pl->flamelength = maxflame;
break;
case TILE_TRIGGER:
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);
list_del(&pl->list_all_players);
return;
}
if (there == FIELD_BONUS) {
playsound((myrand() & 1) ? 1 : 5);
applybonus(pl, info[py][px]);
} else if (there == FIELD_FLAME) {
flame* fl = info[py][px];
if (fl->owner == pl) {
pl->kills--;
} else {
fl->owner->kills++;
}
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, *next;
list_for_each_entry_safe(pl, next, &activeplayers, list) {
doplayer(pl);
}
}
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;
}
static int iterate(void) {
int i;
int gountil; /* destination tick */
static int deathcount = 0;
mypause();
scaninput();
erasesprites();
clearspritelist();
gfxunlock();
myaction = getaction();
if (NETWORK_NONE == network && myaction == ACT_QUIT) return CODE_QUIT;
if (NETWORK_NONE == network) {
gountil = mycount + 1; /* single step in singly player mode */
} else {
gountil = networktraffic(); /* as master single step, as slave as many as we can do */
}
while (mycount < gountil) { /* simulate ticks up to gountil */
++mycount;
if (NETWORK_NONE != network) {
i = gountil - mycount;
if (i >= ACTIONHIST) // too far behind
goto leave_game;
memcpy(actions, actionblock + i * MAXNETNODES, MAXNETNODES);
if (actions[myslot] == ACT_QUIT) return CODE_QUIT;
}
processbombs();
dodetonations();
processdecays();
processflames();
processgenerics();
processquits();
processplayers();
}
/*
if(!(rand()&127))
{
i=gtime();
while(gtime()-i<100);
}
*/
drawbombs();
drawbonus();
drawgenerics();
drawdecays();
drawflames();
drawplayers();
drawstats();
plotsprites();
copyup();
if (list_empty(&activegeneric)) {
player* pl;
int deadplayers = 0;
i = 0;
list_for_each_entry(pl, &activeplayers, list) {
if (!(pl->flags & FLG_DEAD))
++i;
else
deadplayers++;
}
if (deadplayers > 0 && (!i || (NETWORK_NONE != network && i == 1))) {
++deathcount;
if (deathcount == 25) return CODE_ALLDEAD;
} else
deathcount = 0;
}
return CODE_CONT;
leave_game: /* client disconnect/timeout: send ACT_QUIT to master */
myaction = ACT_QUIT;
networktraffic();
return CODE_QUIT;
}
void set_game_options(GameOptions* options) {
gameoptions = *options;
}
void run_single_player(void) {
int code;
network = NETWORK_NONE;
firstzero();
initplayers();
do {
initgame();
while (!(code = iterate()) && !exitflag) ++framecount;
} while (code != CODE_QUIT && !exitflag);
}
void run_network_game(void) {
int code;
firstzero();
initplayers();
do {
initgame();
while (!(code = iterate()) && !exitflag) ++framecount;
} while (code != CODE_QUIT && !exitflag);
}

View File

@ -1,6 +1,8 @@
#ifndef GAME_H
#define GAME_H
#include "bomber.h"
#define FRACTION 9
#define SPEEDDELTA (1 << (FRACTION - 1))
#define SPEEDMAX (10 << FRACTION)

923
src/gfx.c Normal file
View File

@ -0,0 +1,923 @@
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "bomber.h"
#include "gfx.h"
#define MAXCOLORS 256
int usedcolors = 0;
SDL_Surface* thescreen;
SDL_Color themap[256];
uchar* videomem;
int stride;
int mousex, mousey, mouseb;
uchar mustlock = 0, locked = 0;
uchar* block64;
int buttonstate = 0, buttondown = 0;
int mxpos, mypos;
int pressedcodes[KEYMAX], downcodes[KEYMAX], numpressed, numdown;
void dumpgfx() {
usedcolors = 0;
}
static int bestmatch(int red, int green, int blue) {
int i;
int bestcolor, bestdelta = 0;
int rdelta, gdelta, bdelta;
int delta;
i = 0;
bestcolor = -1;
while (i < usedcolors) {
rdelta = themap[i].r;
rdelta -= red;
rdelta *= rdelta;
gdelta = themap[i].g;
gdelta -= green;
gdelta *= gdelta;
bdelta = themap[i].b;
bdelta -= blue;
bdelta *= bdelta;
delta = rdelta + gdelta + bdelta;
if (bestcolor < 0 || delta < bestdelta) {
bestdelta = delta;
bestcolor = i;
}
i++;
}
return bestcolor;
}
static void updatemap(void) {
SDL_SetColors(thescreen, themap, 0, 256);
}
void createinout(gfxset* gs) {
uchar* p;
int i, j, counts[256];
uchar red, green, blue;
int cnt;
p = gs->gs_pic;
for (i = 0; i < 256; i++) counts[i] = 0;
i = gs->gs_xsize * gs->gs_ysize;
while (i--) counts[*p++]++;
cnt = 0;
gs->gs_inout[0] = 0;
for (i = 1; i < 256; i++) {
if (counts[i]) {
cnt++;
p = gs->gs_colormap + i + i + i;
red = *p++;
green = *p++;
blue = *p++;
for (j = 0; j < usedcolors; j++) {
if (red == themap[j].r && green == themap[j].g && blue == themap[j].b) {
gs->gs_inout[i] = j;
break;
}
}
if (j == usedcolors) {
if (usedcolors < MAXCOLORS) {
themap[j].r = red;
themap[j].g = green;
themap[j].b = blue;
gs->gs_inout[i] = usedcolors;
++usedcolors;
} else
gs->gs_inout[i] = bestmatch(red, green, blue);
}
}
}
updatemap();
}
static uchar* compressfig(uchar* put, gfxset* gs, int sourcex, int sourcey, int sizex, int sizey) {
int j, gswidth;
uchar *p, *p2, pixel, *map1;
int dx, dy;
gswidth = gs->gs_xsize;
map1 = gs->gs_inout;
p = gs->gs_pic + sourcex + gswidth * sourcey;
for (dy = 0; dy < sizey; dy++) {
p2 = p;
j = 0;
for (dx = 0; dx <= sizex; dx++) {
if (dx < sizex)
pixel = *p2;
else
pixel = 0;
++p2;
if (pixel)
++j;
else if (j) {
*put++ = j;
*put++ = dx - j;
*put++ = dy;
p2 -= j + 1;
while (j) *put++ = map1[*p2++], --j;
++p2;
}
}
p += gswidth;
}
*put++ = 0;
return put;
}
static void gfxfetchsingle(figure* fig, gfxset* gs, int sourcex, int sourcey, int sizex, int sizey) {
uchar *p, *p2;
int dx, dy;
/* uchar *map1; */
int gswidth;
int minx, miny, maxx, maxy;
int tx, ty;
/* map1=gs->gs_inout; */
gswidth = gs->gs_xsize;
p = gs->gs_pic + sourcex + gswidth * sourcey;
minx = miny = maxx = maxy = -1;
for (dy = 0; dy < sizey; dy++) {
p2 = p;
ty = sourcey + dy;
for (dx = 0; dx < sizex; dx++) {
if (!*p2++) continue;
if (miny == -1 || ty < miny) miny = ty;
if (maxy == -1 || ty > maxy) maxy = ty;
tx = sourcex + dx;
if (minx == -1 || tx < minx) minx = tx;
if (maxx == -1 || tx > maxx) maxx = tx;
}
p += gswidth;
}
if (minx == -1) {
minx = maxx = sourcex;
miny = maxy = sourcey;
}
fig->xdelta = minx - sourcex;
fig->ydelta = miny - sourcey;
sourcex = minx;
sourcey = miny;
fig->xsize = sizex = maxx - minx + 1;
fig->ysize = sizey = maxy - miny + 1;
p = compressfig(block64, gs, sourcex, sourcey, sizex, sizey);
fig->graphics = malloc(p - block64);
if (fig->graphics) memcpy(fig->graphics, block64, p - block64);
}
//(gfxset *gs,figure *fig,int sourcex,int sourcey,int sizex,int sizey)
void gfxfetch(gfxset* gs, figure* fig, int num) {
int x, y;
int xsize, ysize;
int fxsize, fysize;
unsigned char *p, *p2;
xsize = gs->gs_xsize;
ysize = gs->gs_ysize;
p2 = p = gs->gs_pic + xsize + 1;
fxsize = 2;
while (*p++ == 0) ++fxsize;
fysize = 2;
while (*p2 == 0) ++fysize, p2 += xsize;
x = fxsize;
y = 0;
while (num--) {
gfxfetchsingle(fig, gs, x, y, fxsize, fysize);
x += fxsize;
if (x > xsize - fxsize) {
x = 0;
y += fysize;
if (y > ysize - fysize) y = 0;
}
fig++;
}
}
void solidfetch(gfxset* gs, solid* dest) {
int xsize, ysize;
int i;
unsigned char *p, *map;
uchar* gfx;
memset(dest, 0, sizeof(solid));
xsize = gs->gs_xsize;
ysize = gs->gs_ysize;
i = xsize * ysize;
gfx = dest->graphics = malloc(i);
if (!gfx) return;
dest->xsize = xsize;
dest->ysize = ysize;
map = gs->gs_inout;
memcpy(gfx, gs->gs_pic, i);
p = gfx;
while (i--) {
if (*p) *p = map[*p];
++p;
}
}
void solidcopyany(solid* src, solid* dest, int destx, int desty, int sizex, int sizey) {
int xmax, ymax;
int j;
uchar *p1, *p2;
int w;
xmax = src->xsize;
ymax = src->ysize;
if (destx >= xmax || desty >= ymax || destx + sizex <= 0 || desty + sizey <= 0) return;
if (destx < 0) {
sizex += destx;
destx = 0;
}
if (desty < 0) {
sizey += desty;
desty = 0;
}
if (destx + sizex > xmax) sizex = xmax - destx;
if (desty + sizey > ymax) sizey = ymax - desty;
if (dest) {
w = dest->xsize;
p1 = dest->graphics + desty * w + destx;
} else {
gfxlock();
w = stride;
p1 = videomem + desty * stride + destx;
}
p2 = src->graphics + desty * xmax + destx;
for (j = 0; j < sizey; ++j) {
memcpy(p1, p2, sizex);
p1 += w;
p2 += xmax;
}
}
void solidcopy(solid* solid, int destx, int desty, int sizex, int sizey) {
solidcopyany(solid, 0, destx, desty, sizex, sizey);
}
void drawfigureany(int x, int y, figure* fig, solid* dest) {
int run;
int dx, dy;
int xsize, ysize;
int clipx, clipy, w;
unsigned char *pc, *p, *p2, *take;
take = fig->graphics;
if (dest) {
w = clipx = dest->xsize;
clipy = dest->ysize;
pc = dest->graphics;
} else {
gfxlock();
w = stride;
clipx = IXSIZE;
clipy = IYSIZE;
pc = videomem;
}
dx = fig->xdelta;
dy = fig->ydelta;
xsize = fig->xsize;
ysize = fig->ysize;
x += dx;
y += dy;
if (x >= 0 && y >= 0 && x <= clipx - xsize && y <= clipy - ysize) {
while ((run = *take++)) {
dx = *((signed char*) take);
++take;
dy = *((signed char*) take);
++take;
p = pc + w * (y + dy) + x + dx;
while (run--) *p++ = *take++;
}
} else {
while ((run = *take++)) {
dx = *((signed char*) take);
++take;
dy = *((signed char*) take);
++take;
dx += x;
dy += y;
p2 = take;
take += run;
if (dy < 0 || dy >= clipy) continue;
if (dx >= clipx) continue;
if (dx < 0) {
p2 -= dx;
run += dx;
dx = 0;
} else if (dx + run > clipx)
run = clipx - dx;
p = pc + w * dy + dx;
if (run) memcpy(p, p2, run);
}
}
}
void drawfigure(int destx, int desty, figure* fig) {
drawfigureany(destx, desty, fig, 0);
}
void copyup() {
gfxunlock();
SDL_UpdateRect(thescreen, 0, 0, 0, 0);
needwhole = 0;
}
void copyupxy(int x, int y) {
gfxunlock();
SDL_UpdateRect(thescreen, x, y, 24, 24);
}
void copyupxysize(int x, int y, int xsize, int ysize) {
gfxunlock();
SDL_UpdateRect(thescreen, x, y, xsize, ysize);
}
// 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(void) {
unsigned long videoflags;
themap[0].r = 0;
themap[0].g = 0;
themap[0].b = 0;
usedcolors = 1;
block64 = malloc(65536);
if (!block64) {
printf("Couldn't allocate block64\n");
exit(50);
}
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_AUDIO) < 0) {
fprintf(stderr, "Couldn't initialize SDL: %s\n", SDL_GetError());
exit(1);
}
videoflags = SDL_SWSURFACE | SDL_HWPALETTE; //|SDL_FULLSCREEN;
thescreen = SDL_SetVideoMode(IXSIZE, IYSIZE, 8, videoflags);
if (thescreen == NULL) {
fprintf(stderr, "Couldn't set display mode: %s\n", SDL_GetError());
SDL_Quit();
exit(5);
}
stride = thescreen->pitch;
videomem = thescreen->pixels;
mustlock = SDL_MUSTLOCK(thescreen);
locked = 0;
SDL_ShowCursor(0);
}
void closegfx(void) {
SDL_Quit();
}
int checkpressed(int code) {
int *p, i;
i = numpressed;
p = pressedcodes;
while (i--)
if (*p++ == code) return 1;
return 0;
}
int checkdown(int code) {
int *p, i;
i = numdown;
p = downcodes;
while (i--)
if (*p++ == code) return 1;
return 0;
}
int checkbutton(int button) {
return buttonstate & (1 << button);
}
int checkbuttondown(int button) {
return buttondown & (1 << button);
}
int anydown(void) {
return numdown;
}
int takedown(void) {
int res = 0;
if (numdown) {
res = *downcodes;
--numdown;
if (numdown) memmove(downcodes, downcodes + 1, numdown * sizeof(int));
}
return res;
}
int firstdown(void) {
return *downcodes;
}
#define ENDMARK 0xaabacada
int sdlinoutnormal[] = {
SDLK_0,
'0',
SDLK_1,
'1',
SDLK_2,
'2',
SDLK_3,
'3',
SDLK_4,
'4',
SDLK_5,
'5',
SDLK_6,
'6',
SDLK_7,
'7',
SDLK_8,
'8',
SDLK_9,
'9',
SDLK_a,
'a',
SDLK_b,
'b',
SDLK_c,
'c',
SDLK_d,
'd',
SDLK_e,
'e',
SDLK_f,
'f',
SDLK_g,
'g',
SDLK_h,
'h',
SDLK_i,
'i',
SDLK_j,
'j',
SDLK_k,
'k',
SDLK_l,
'l',
SDLK_m,
'm',
SDLK_n,
'n',
SDLK_o,
'o',
SDLK_p,
'p',
SDLK_q,
'q',
SDLK_r,
'r',
SDLK_s,
's',
SDLK_t,
't',
SDLK_u,
'u',
SDLK_v,
'v',
SDLK_w,
'w',
SDLK_x,
'x',
SDLK_y,
'y',
SDLK_z,
'z',
SDLK_MINUS,
'-',
SDLK_EQUALS,
'=',
SDLK_LEFTBRACKET,
'[',
SDLK_RIGHTBRACKET,
']',
SDLK_SEMICOLON,
';',
SDLK_QUOTE,
'\'',
SDLK_SLASH,
'/',
SDLK_PERIOD,
'.',
SDLK_COMMA,
',',
SDLK_BACKQUOTE,
'`',
SDLK_BACKSPACE,
8,
SDLK_TAB,
9,
SDLK_DELETE,
MYDELETE,
SDLK_RETURN,
13,
SDLK_F1,
MYF1,
SDLK_F2,
MYF2,
SDLK_F3,
MYF3,
SDLK_F4,
MYF4,
SDLK_F5,
MYF5,
SDLK_F6,
MYF6,
SDLK_F7,
MYF7,
SDLK_F8,
MYF8,
SDLK_F9,
MYF9,
SDLK_F10,
MYF10,
SDLK_ESCAPE,
0x1b,
SDLK_LEFT,
MYLEFT,
SDLK_RIGHT,
MYRIGHT,
SDLK_UP,
MYUP,
SDLK_DOWN,
MYDOWN,
SDLK_PAGEUP,
MYPAGEUP,
SDLK_PAGEDOWN,
MYPAGEDOWN,
SDLK_SPACE,
' ',
SDLK_HOME,
MYHOME,
SDLK_END,
MYEND,
SDLK_LALT,
MYALTL,
SDLK_RALT,
MYALTR,
ENDMARK};
int sdlinoutshifted[] = {
SDLK_0,
')',
SDLK_1,
'!',
SDLK_2,
'@',
SDLK_3,
'#',
SDLK_4,
'$',
SDLK_5,
'%',
SDLK_6,
'^',
SDLK_7,
'&',
SDLK_8,
'*',
SDLK_9,
'(',
SDLK_a,
'A',
SDLK_b,
'B',
SDLK_c,
'C',
SDLK_d,
'D',
SDLK_e,
'E',
SDLK_f,
'F',
SDLK_g,
'G',
SDLK_h,
'H',
SDLK_i,
'I',
SDLK_j,
'J',
SDLK_k,
'K',
SDLK_l,
'L',
SDLK_m,
'M',
SDLK_n,
'N',
SDLK_o,
'O',
SDLK_p,
'P',
SDLK_q,
'Q',
SDLK_r,
'R',
SDLK_s,
'S',
SDLK_t,
'T',
SDLK_u,
'U',
SDLK_v,
'V',
SDLK_w,
'W',
SDLK_x,
'X',
SDLK_y,
'Y',
SDLK_z,
'Z',
SDLK_MINUS,
'_',
SDLK_EQUALS,
'+',
SDLK_LEFTBRACKET,
'{',
SDLK_RIGHTBRACKET,
'}',
SDLK_SEMICOLON,
':',
SDLK_QUOTE,
'"',
SDLK_SLASH,
'?',
SDLK_PERIOD,
'>',
SDLK_COMMA,
'<',
SDLK_BACKQUOTE,
'~',
SDLK_BACKSPACE,
8,
SDLK_TAB,
9,
SDLK_DELETE,
MYDELETE,
SDLK_RETURN,
13,
SDLK_F1,
MYF1 + MYSHIFTED,
SDLK_F2,
MYF2 + MYSHIFTED,
SDLK_F3,
MYF3 + MYSHIFTED,
SDLK_F4,
MYF4 + MYSHIFTED,
SDLK_F5,
MYF5 + MYSHIFTED,
SDLK_F6,
MYF6 + MYSHIFTED,
SDLK_F7,
MYF7 + MYSHIFTED,
SDLK_F8,
MYF8 + MYSHIFTED,
SDLK_F9,
MYF9 + MYSHIFTED,
SDLK_F10,
MYF10 + MYSHIFTED,
SDLK_ESCAPE,
0x1b,
SDLK_LEFT,
MYLEFT + MYSHIFTED,
SDLK_RIGHT,
MYRIGHT + MYSHIFTED,
SDLK_UP,
MYUP + MYSHIFTED,
SDLK_DOWN,
MYDOWN + MYSHIFTED,
SDLK_PAGEUP,
MYPAGEUP,
SDLK_PAGEDOWN,
MYPAGEDOWN,
SDLK_SPACE,
' ',
SDLK_HOME,
MYHOME,
SDLK_END,
MYEND,
SDLK_LALT,
MYALTL,
SDLK_RALT,
MYALTR,
ENDMARK};
static int looklist(int code, int* list) {
while ((unsigned int) *list != ENDMARK) {
if (*list == code) return list[1];
list += 2;
}
return -1;
}
static int mapkey(int code, int qual) {
if (qual & KMOD_SHIFT)
code = looklist(code, sdlinoutshifted);
else
code = looklist(code, sdlinoutnormal);
if (code < 0) return -1;
if (qual & KMOD_ALT) code |= MYALTED;
return code;
}
static void markkey(int code, int status) {
int i;
int* ip;
if (status) {
if (numdown < KEYMAX) downcodes[numdown++] = code;
ip = pressedcodes;
i = numpressed;
while (i)
if (*ip++ == code)
break;
else
i--;
if (!i && numpressed < KEYMAX) pressedcodes[numpressed++] = code;
} else {
i = numpressed;
ip = pressedcodes;
while (i)
if (*ip++ == code) {
*--ip = pressedcodes[--numpressed];
break;
} else
i--;
}
}
void pollinput(void) {
SDL_PollEvent(0);
}
void scaninput(void) {
SDL_Event event;
int key, mod;
static int bs = 0;
numdown = 0;
buttondown = 0;
while (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_KEYDOWN:
key = event.key.keysym.sym;
mod = event.key.keysym.mod;
markkey(mapkey(key, mod), 1);
break;
case SDL_KEYUP:
key = event.key.keysym.sym;
mod = event.key.keysym.mod;
markkey(mapkey(key, mod), 0);
break;
case SDL_MOUSEBUTTONUP:
bs &= ~(1 << (event.button.button - 1));
mousex = event.button.x >> 1;
mousey = event.button.y >> 1;
mouseb = bs;
break;
case SDL_MOUSEBUTTONDOWN:
bs |= 1 << (event.button.button - 1);
mousex = event.button.x >> 1;
mousey = event.button.y >> 1;
mouseb = bs;
break;
case SDL_MOUSEMOTION:
mousex = event.motion.x >> 1;
mousey = event.motion.y >> 1;
break;
case SDL_QUIT:
exitflag = 1;
break;
}
}
}
/*
void scaninput()
{
int i,*ip,code;
numdown=0;
buttondown=0;
while(XCheckMaskEvent(dp,~0,&event))
switch(event.type)
{
case KeyPress:
code=XLookupKeysym(keyevent,0);
if(numdown<KEYMAX)
downcodes[numdown++]=code;
ip=pressedcodes;
i=numpressed;
while(i)
if(*ip++==code) break;
else i--;
if(!i && numpressed<KEYMAX)
pressedcodes[numpressed++]=code;
break;
case KeyRelease:
code=XLookupKeysym(keyevent,0);
i=numpressed;
ip=pressedcodes;
while(i)
if(*ip++==code)
{
*--ip=pressedcodes[--numpressed];
break;
} else i--;
break;
case ButtonPress:
i=1<<buttonevent->button;
buttonstate|=i;
buttondown|=i;
break;
case ButtonRelease:
buttonstate&=~(1<<buttonevent->button);
break;
case MotionNotify:
mxpos=motionevent->x;
mypos=motionevent->y;
break;
case Expose:
copyup();
needwhole=0;
break;
case FocusOut:
numpressed=0;
break;
}
}
*/
static void drawrect(int x, int y, int xs, int ys, int c) {
uchar* p;
gfxlock();
p = videomem + y * stride + x;
while (ys--) {
memset(p, c, xs);
p += stride;
}
}
void greyrect(int x, int y, int xsize, int ysize) {
static int greycolor = -1;
if (greycolor == -1) greycolor = bestmatch(0, 0, 0x70);
drawrect(x, y, xsize, ysize, greycolor);
}
void clear() {
int j;
uchar* p;
gfxlock();
p = videomem;
for (j = 0; j < IYSIZE; ++j) {
memset(p, 0, IXSIZE);
p += stride;
}
}
void clearrect(int x, int y, int xsize, int ysize) {
drawrect(x, y, xsize, ysize, 0);
}
void gfxlock(void) {
if (locked || !mustlock) return;
if (SDL_LockSurface(thescreen) < 0) { fprintf(stderr, "Couldn't lock display surface: %s\n", SDL_GetError()); }
locked = 1;
}
void gfxunlock(void) {
if (!locked || !mustlock) return;
SDL_UnlockSurface(thescreen);
locked = 0;
}

69
src/gfx.h Normal file
View File

@ -0,0 +1,69 @@
#ifndef GFX_H
#define GFX_H
#define KEYMAX 128
extern int usedcolors;
extern uchar mymap[];
extern int screen;
extern int fontbase, fontysize;
extern char* imageloc;
extern long map2[];
extern uchar fmap[128];
extern int buttonstate, buttondown;
extern int mxpos, mypos;
extern int pressedcodes[KEYMAX], downcodes[KEYMAX], numpressed, numdown;
void opengfx(void);
void gfxlock(void);
void gfxunlock(void);
void pollinput(void);
int takedown(void);
void closegfx(void);
void greyrect(int x, int y, int xsize, int ysize);
void clearrect(int x, int y, int xsize, int ysize);
void solidfetch(gfxset* gs, solid* dest);
extern void dumpgfx(void);
extern void createinout(struct gfxset*);
extern void getcolors(void);
extern void gfxfetch(struct gfxset*, struct figure*, int);
extern void puttile(int destx, int desty, int source);
extern void store(int x, int y, int which);
extern void restore(int x, int y, int which);
extern void copyup(void);
extern void copyupxy(int x, int y);
extern void copyupxysize(int x, int y, int xsize, int ysize);
extern void getfigures(void);
extern unsigned long getcolor(char* name); /* unsigned long */
extern int checkpressed(int code);
extern int checkdown(int code);
extern int checkbutton(int button);
extern int checkbuttondown(int button);
extern int anydown(void);
extern int firstdown(void);
extern void scaninput(void);
extern void fontinit(void);
extern void writechar(int x, int y, uchar ch);
extern void clear(void);
extern void drawbox(int x, int y, int size, int color);
extern void drawbox2(int x, int y, int sizex, int sizey, int color);
extern void drawfillrect(int x, int y, int size, int color);
extern void bigpixel(int x, int y, int color);
extern void invert(int x, int y);
extern int getmousex(void);
extern int getmousey(void);
extern void drawsquare(int x, int y, uchar* source);
extern void colormapon(void);
extern void colormapoff(void);
extern void palette(uchar* pal);
extern void drawfigure(int x, int y, figure* fig);
extern void drawfigureany(int x, int y, figure* fig, solid* dest);
void solidcopy(solid* src, int destx, int desty, int sizex, int sizey);
void solidcopyany(solid* src, solid* dest, int destx, int desty, int sizex, int sizey);
#endif // GFXX_H

View File

@ -1,6 +1,6 @@
#include "bomber.h"
#include "list.h"
#include "bomber.h"
#include "utils.h"
typedef union genericlistitem genericlistitem;
@ -31,9 +31,7 @@ void alloc_things(void) {
}
if (!things) nomem("Trying to allocate thing memory");
for (i=0; i < MAXTHINGS - 1; ++i) {
things[i].next = &things[i + 1];
}
for (i = 0; i < MAXTHINGS - 1; ++i) { things[i].next = &things[i + 1]; }
things[i].next = 0;
free_things = things;
count_used = 0;
@ -81,7 +79,7 @@ void things_list_clear(listhead *head) {
genericlistitem* entry;
while (head->next != head) {
entry = container_of(head->next, typeof(*entry), list);
entry = container_of(head->next, __typeof__(*entry), list);
list_del(head->next);
freeentry(entry);
}

63
src/list.h Normal file
View File

@ -0,0 +1,63 @@
#ifndef LIST_H
#define LIST_H
#include <stddef.h>
/* from linux kernel (with some changes for "iso" c) */
typedef struct listhead listhead;
struct listhead {
listhead *prev, *next;
};
#define container_of(ptr, type, member) ((type*) ((char*) (__typeof__(((type*) 0)->member)*) (ptr) -offsetof(type, member)))
/**
* list_entry - get the struct for this entry
* @ptr: the &struct list_head pointer.
* @type: the type of the struct this is embedded in.
* @member: the name of the list_struct within the struct.
*/
#define list_entry(ptr, type, member) container_of(ptr, type, member)
void alloc_things(void);
void* _allocentry(size_t size);
#define allocentry(type) (type*) _allocentry(sizeof(type))
void freeentry(void* ptr);
void list_add_tail(listhead* header, listhead* entry);
#define addtail(head, entry) list_add_tail(head, &(entry->list));
/* remove entry from list */
void list_del(listhead* entry);
#define removeitem(entry) list_del(&(entry->list));
void list_init_head(listhead* head);
void things_list_clear(listhead* head); /* listhead member must be the first member */
/**
* list_for_each_entry - iterate over list of given type
* @pos: the type * to use as a loop cursor.
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*/
#define list_for_each_entry(pos, head, member) \
for (pos = list_entry((head)->next, __typeof__(*pos), member); /* prefetch(pos->member.next), */ \
&pos->member != (head); \
pos = list_entry(pos->member.next, __typeof__(*pos), member))
/**
* list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
* @pos:<-->the type * to use as a loop cursor.
* @n:<><-->another type * to use as temporary storage
* @head:<->the head for your list.
* @member:>the name of the list_struct within the struct.
*/
#define list_for_each_entry_safe(pos, n, head, member) \
for (pos = list_entry((head)->next, __typeof__(*pos), member), n = list_entry(pos->member.next, __typeof__(*pos), member); &pos->member != (head); \
pos = n, n = list_entry(n->member.next, __typeof__(*n), member))
#define list_empty(head) ((head) == (head)->next)
#endif

357
src/matcher.c Normal file
View File

@ -0,0 +1,357 @@
#include <arpa/inet.h>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/timeb.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <time.h>
#define MAXMSG 256
#define PORT 5521
#define TIMETOLIVE 600 // seconds
typedef unsigned char uchar;
char logging = 0;
unsigned char mesg[MAXMSG];
int lastsize;
int network;
char masterhostname[256];
#define PKT_REGISTER 16
#define PKT_ACK 24
#define PKT_INFO 40
#define PKT_QUERY 32
#define MAXMATCHES 16
struct registration {
uchar id;
uchar unique[4];
uchar password[4];
uchar version[4];
uchar name[16];
uchar status;
};
struct query {
uchar id;
uchar password[4];
uchar version[4];
};
struct gamehost {
struct gamehost *next, *prev;
uchar machine[4];
uchar port[2];
struct registration reg;
long timeout;
};
struct gamehost *freehosts = 0, *activehosts = 0;
int udpsocket, myport;
struct sockaddr_in myname = {0}, mastername = {0};
socklen_t senderlength;
struct sockaddr_in sender = {0};
long longtime(void) {
struct timeb tb;
ftime(&tb);
return tb.time;
}
char* timestr() {
static char timestring[80];
time_t t;
int l;
time(&t);
strcpy(timestring, ctime(&t));
l = strlen(timestring);
if (l && timestring[l - 1] == '\n') timestring[l - 1] = 0;
return timestring;
}
int putmsg(struct sockaddr_in* toname, unsigned char* msg, int len) {
int status;
status = sendto(udpsocket, msg, len, 0, (struct sockaddr*) toname, sizeof(struct sockaddr_in));
return status;
}
void ack() {
uchar copy[256];
*copy = PKT_ACK;
memmove(copy + 1, mesg, lastsize);
putmsg(&sender, copy, lastsize + 1);
}
int getmsg(int seconds) {
int size;
lastsize = -1;
memset(&sender, 0, sizeof(sender));
senderlength = sizeof(sender);
if (seconds) {
struct timeval timeout;
fd_set readfds;
int res;
timeout.tv_sec = seconds;
timeout.tv_usec = 0;
FD_ZERO(&readfds);
FD_SET(udpsocket, &readfds);
res = select(udpsocket + 1, &readfds, 0, 0, &timeout);
if (res <= 0) return -1;
}
lastsize = size = recvfrom(udpsocket, mesg, MAXMSG, 0, (struct sockaddr*) &sender, &senderlength);
return size;
}
long longind(unsigned char* p) {
return (p[0] << 24L) | (p[1] << 16L) | (p[2] << 8) | p[3];
}
short shortind(unsigned char* p) {
return (p[0] << 8L) | p[1];
}
void openport(int portwant) {
int status;
myport = portwant;
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(myport);
status = bind(udpsocket, (struct sockaddr*) &myname, sizeof(myname));
if (status == -1) {
perror("bind()");
exit(1);
}
}
#define PERBLOCK 512
struct gamehost* newhost() {
struct gamehost *h, *block;
int i;
if (!freehosts) {
block = malloc(sizeof(struct gamehost) * PERBLOCK);
if (!block) return 0;
freehosts = block;
i = PERBLOCK - 1;
while (i--) {
block->next = block + 1;
++block;
}
block->next = 0;
}
h = freehosts;
freehosts = freehosts->next;
memset(h, 0, sizeof(struct gamehost));
return h;
}
void freehost(struct gamehost* h) {
h->next = freehosts;
freehosts = h;
}
struct gamehost* findmatch(struct registration* key) {
struct gamehost* h;
h = activehosts;
while (h) {
if (!memcmp(&h->reg, key, sizeof(struct registration) - 1)) return h;
h = h->next;
}
return 0;
}
void insert(struct gamehost* h) {
if (activehosts) {
h->next = activehosts;
h->prev = activehosts->prev;
activehosts->prev = h;
activehosts = h;
} else {
h->next = h->prev = 0;
activehosts = h;
}
}
void delete (struct gamehost* h) {
if (h->prev)
h->prev->next = h->next;
else
activehosts = h->next;
if (h->next) h->next->prev = h->prev;
freehost(h);
}
void doreg() {
struct registration* new;
struct gamehost* match;
long now;
new = (struct registration*) mesg;
match = findmatch(new);
if (logging) {
unsigned addr = ntohl(sender.sin_addr.s_addr);
unsigned short port = ntohs(sender.sin_port);
printf(
"reg :%s:%d.%d.%d.%d:%d %c%lx '%s'\n",
timestr(),
(addr >> 24) & 255,
(addr >> 16) & 255,
(addr >> 8) & 255,
addr & 255,
port,
new->status ? '+' : '-',
(long) match,
new->name);
fflush(stdout);
}
if (!match && !new->status) {
ack();
return;
}
if (match && new->status) {
ack();
return;
}
if (!match && new->status) {
match = newhost();
if (!match) return; // No memory, what can we do?
memmove(match->machine, &sender.sin_addr.s_addr, 4);
memmove(match->port, &sender.sin_port, 2);
match->reg = *new;
now = longtime();
match->timeout = now + TIMETOLIVE;
ack();
insert(match);
return;
} else // match && !new->status
{
delete (match);
ack();
return;
}
}
void doquery() {
uchar* password;
uchar* version;
struct gamehost* h;
uchar response[2048], *rput, *countersave;
int counter;
if (logging) {
unsigned addr = ntohl(sender.sin_addr.s_addr);
unsigned short port = ntohs(sender.sin_port);
printf("query:%s:%d.%d.%d.%d:%d\n", timestr(), (addr >> 24) & 255, (addr >> 16) & 255, (addr >> 8) & 255, addr & 255, port);
fflush(stdout);
}
password = mesg + 1;
version = mesg + 5;
h = activehosts;
rput = response;
*rput++ = PKT_INFO;
memmove(rput, password, 4);
rput += 4;
memmove(rput, version, 4);
rput += 4;
countersave = rput;
*rput++ = 0;
*rput++ = 0;
counter = 0;
while (h) {
if (!memcmp(password, h->reg.password, 4) && !memcmp(version, h->reg.version, 4) && counter < MAXMATCHES) {
++counter;
memmove(rput, h->reg.unique, 4);
rput += 4;
memmove(rput, h->machine, 4);
rput += 4;
memmove(rput, h->port, 2);
rput += 2;
memmove(rput, h->reg.name, sizeof(h->reg.name));
rput += sizeof(h->reg.name);
}
h = h->next;
}
*countersave++ = counter >> 8;
*countersave++ = counter;
putmsg(&sender, response, rput - response);
}
void purge(long cutoff) {
struct gamehost *h, *h2;
h = activehosts;
while (h) {
h2 = h;
h = h->next;
if (cutoff - h2->timeout > 0) { delete (h2); }
}
}
int main(int argc, char** argv) {
int i;
int want;
int size;
long purgetime;
long now;
want = PORT;
if (argc > 1) {
for (i = 1; i < argc; ++i)
if (!strncmp(argv[i], "-p", 2)) {
if (strlen(argv[i]) > 2)
want = atoi(argv[i] + 2);
else if (i + 1 < argc)
want = atoi(argv[i + 1]);
}
}
freehosts = 0;
openport(want);
purgetime = longtime() + TIMETOLIVE;
for (;;) {
size = getmsg(10);
if (size >= 1) switch (*mesg) {
case PKT_REGISTER:
if (size < sizeof(struct registration)) continue;
doreg();
break;
case PKT_QUERY:
if (size < sizeof(struct query)) continue;
doquery();
break;
}
now = longtime();
if (now - purgetime > 0) // avoid year 203x bug...
{
purge(purgetime);
purgetime += TIMETOLIVE;
}
}
}

387
src/menu.c Normal file
View File

@ -0,0 +1,387 @@
#include "menu.h"
#include "announce.h"
#include "bomber.h"
#include "draw.h"
#include "game.h"
#include "gfx.h"
#include "network.h"
#include "sound.h"
#include "utils.h"
GameOptions configopts = {2, 1, 0, 2};
/* Generic menu */
typedef enum { MENU_ANY = -1, MENU_MAIN = 0, MENU_CONFIG = 2, MENU_JOIN = 3 } menuname;
#define MENU_SELECT(x) ((menuname)(-x - 1))
static int menuhistory[32] = {0};
static char menustring[1024];
static char *menuput, *menuitems[40], *menutitle;
static int menunum, menuexit;
static 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(menuname whichmenu, int (*pause)(void)) {
char redraw;
int selected;
int mcount = 0;
if (whichmenu >= 0)
selected = menuhistory[whichmenu];
else
selected = -whichmenu - 1;
if (!pause) pause = mypause;
redraw = 1;
clearspritelist();
while (!exitflag) {
if (redraw) {
drawmenu(selected);
redraw = 0;
}
if (!pause()) return -1;
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 (MENU_MAIN == whichmenu && menuexit != selected) {
selected = menuexit;
redraw = 1;
break;
}
menudelta = 1;
return menuexit;
}
}
}
menudelta = 0;
return menuexit;
}
static void menustart() {
menunum = -1;
menuput = menustring;
*menuput = 0;
menuexit = 0;
}
static void additem_s(char* item, int len) {
if (len < 0 || (menustring + sizeof(menustring) - menuput <= len)) return;
if (menunum < 0)
menutitle = menuput;
else
menuitems[menunum] = menuput;
++menunum;
memcpy(menuput, item, len + 1);
menuput += len + 1;
}
static void additem(char* item, ...) {
char output[256];
va_list ap;
int len;
va_start(ap, item);
len = vsnprintf(output, sizeof(output), item, ap);
if (len >= 256) len = 255; /* truncated string */
additem_s(output, len);
}
static void addexit(char* item, ...) {
char output[256];
va_list ap;
int len;
va_start(ap, item);
len = vsnprintf(output, sizeof(output), item, ap);
if (len >= 256) len = 255; /* truncated string */
menuexit = menunum;
additem_s(output, len);
}
/* end generic menu */
/* game menues */
static const char* densities[] = {"PACKED", "HIGH", "MEDIUM", "LOW"};
static const char* generosities[] = {"LOW", "MEDIUM", "HIGH", "RIDICULOUS"};
static const char* dis_en_abled[] = {"DISABLED", "ENABLED"};
static void config_menu(void) {
int sel;
while (!exitflag) {
menustart();
additem("GAME OPTIONS");
additem("RETURN TO MAIN MENU");
additem("DENSITY: %s", densities[configopts.density]);
additem("GENEROSITY: %s", generosities[configopts.generosity]);
additem("INITIAL FLAME LENGTH: %d", configopts.flames + 1);
additem("INITIAL NUMBER OF BOMBS: %d", configopts.bombs + 1);
additem("SOUND: %s", dis_en_abled[sound_enabled]);
sel = domenu(MENU_CONFIG, NULL);
switch (sel) {
case 0:
return;
case 1:
configopts.density += menudelta;
configopts.density &= 3;
break;
case 2:
configopts.generosity += menudelta;
configopts.generosity &= 3;
break;
case 3:
configopts.flames += menudelta;
configopts.flames &= 7;
break;
case 4:
configopts.bombs += menudelta;
configopts.bombs &= 7;
break;
case 5:
sound_enabled = 1 - sound_enabled;
break;
}
}
}
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;
snprintf(temp, sizeof(temp), " %d %s", i + 1, name);
drawbigstring(M3X, M3Y + (i + 2) * bigfontyspace, temp);
}
copyup();
}
static void host_game(void) {
create_seed_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();
return;
case ' ':
case 13:
unregistergame();
if (begin_network_game()) {
run_network_game();
return;
}
send_invites();
draw_host_game();
}
}
if (!handle_joins()) continue;
send_invites();
draw_host_game();
}
}
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;
snprintf(temp, sizeof(temp), " %d %s", i + 1, name);
drawbigstring(JX, JY + (i + 1) * bigfontyspace, temp);
}
}
static int tryjoin(int which) {
int res;
if (0 == (res = send_join(&gamelistentries[which].netname, playername))) { return 0; }
while (!exitflag) {
switch (res) {
case 1:
failure("Game closed");
return 0;
case 2:
drawjoinscreen();
copyup();
break;
case 3:
return 1;
default:
break;
}
scaninput();
while (anydown()) {
switch (takedown()) {
case 0x1b:
send_quit();
return 0;
}
}
res = scaninvite(200);
}
return 0;
}
static int join_game_pause(void) {
if (find_more_games()) return 0;
mypause();
return 1;
}
static void join_game(void) {
int i;
int sel = -1;
if (!searchgames()) { return; }
menuhistory[MENU_JOIN] = 0;
while (-1 == sel) {
menustart();
if (gamelistsize == 0) {
additem("JOIN NETWORK GAME - NO GAMES AVAILABLE");
addexit("EXIT");
} else {
additem("JOIN NETWORK GAME");
for (i = 0; i < gamelistsize; i++) { additem(gamelistentries[i].name); }
addexit("EXIT");
}
sel = domenu(MENU_JOIN, join_game_pause);
if (menudelta < 0) sel = -1;
}
stop_search();
if (menuexit == sel || !gamelistsize) { return; }
if (!tryjoin(sel)) { return; }
run_network_game();
}
void mainloop(void) {
int sel;
exitflag = 0;
while (!exitflag) {
menustart();
additem("BOMBER MAIN MENU");
additem("EXIT GAME");
additem("START SINGLE PLAYER GAME");
additem("OPTIONS");
// additem("REMAP MOVEMENT KEYS");
additem("START NETWORK GAME");
additem("JOIN NETWORK GAME");
sel = domenu(MENU_MAIN, NULL);
if (menudelta < 0) sel = -1;
switch (sel) {
case 0:
return;
case 1:
run_single_player();
break;
case 2:
config_menu();
break;
case 3:
host_game();
break;
case 4:
join_game();
break;
}
}
}

View File

View File

@ -1,11 +1,11 @@
#include "bomber.h"
#include "network.h"
#include "announce.h"
#include "bomber.h"
#include "draw.h"
#include "game.h"
#include "menu.h"
#include "network.h"
#include "utils.h"
#include "draw.h"
#define MAXMSG 4096
@ -65,10 +65,7 @@ enum reject_reason {
#define _REJECT_LAST REJECT_VERSION
const char *reject_reason_str[] = {
"Server full",
"Version mismatch"
};
const char* reject_reason_str[] = {"Server full", "Version mismatch"};
/* all bytes stored MSB first */
@ -143,8 +140,7 @@ outmsgs() {
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));
sendto(udpsocket, message[i].msg, message[i].len, 0, message[i].to, sizeof(struct sockaddr_in));
}
}
}
@ -167,11 +163,9 @@ static int putmsg(struct sockaddr_in *toname,unsigned char *msg,int len) {
}
return 0;
#else
status=sendto(udpsocket,msg,len,0,
(struct sockaddr *)toname,sizeof(struct sockaddr_in));
status = sendto(udpsocket, msg, len, 0, (struct sockaddr*) toname, sizeof(struct sockaddr_in));
return status;
#endif
}
static int getmsg(int msec) {
@ -192,8 +186,7 @@ static int getmsg(int msec) {
res = select(udpsocket + 1, &readfds, 0, 0, &timeout);
if (res <= 0) return -1;
}
size=recvfrom(udpsocket,mesg,MAXMSG,0,
(struct sockaddr *)&sender,&senderlength);
size = recvfrom(udpsocket, mesg, MAXMSG, 0, (struct sockaddr*) &sender, &senderlength);
return size;
}
@ -236,17 +229,12 @@ static int isvalidmsg_from_slave() {
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;
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;
}
static int isvalidmsg_from_master() {
if (sender.sin_family != mastername.sin_family
|| sender.sin_addr.s_addr != mastername.sin_addr.s_addr
|| sender.sin_port != mastername.sin_port) return 0;
if (sender.sin_family != mastername.sin_family || sender.sin_addr.s_addr != mastername.sin_addr.s_addr || sender.sin_port != mastername.sin_port) return 0;
return 1;
}
@ -293,13 +281,11 @@ int networktraffic(void) {
actions[0] = myaction;
if (myaction == ACT_QUIT) {
for (i = 1; i < MAXNETNODES; ++i) {
if (netnodes[i].used)
actions[i] = ACT_QUIT;
if (netnodes[i].used) actions[i] = ACT_QUIT;
}
} else {
for (i = 1; i < MAXNETNODES; ++i) {
if (netnodes[i].used)
actions[i] &= ACT_MASK; /* only keep direction */
if (netnodes[i].used) actions[i] &= ACT_MASK; /* only keep direction */
}
now = gtime();
for (;;) {
@ -326,8 +312,7 @@ int networktraffic(void) {
for (i = 1; i < MAXNETNODES; ++i) {
if (netnodes[i].used) {
sendactions(i); /* send actions to every active node */
if (actions[i] == ACT_QUIT)
netnodes[i].used = 0; /* remove disconnected clients */
if (actions[i] == ACT_QUIT) netnodes[i].used = 0; /* remove disconnected clients */
}
}
return actioncount;
@ -464,8 +449,7 @@ void send_config() {
int i;
build_config();
for (i = 1; i < MAXNETNODES; ++i)
if (netnodes[i].used)
send_config1(i);
if (netnodes[i].used) send_config1(i);
}
static void send_reject(struct sockaddr_in* toname, Uint32 network_join_unique, unsigned char reason) {
@ -473,7 +457,7 @@ static void send_reject(struct sockaddr_in *toname, Uint32 network_join_unique,
memcpy(mesg + 1, &network_join_unique, sizeof(network_join_unique));
write_version(mesg + 5);
mesg[9] = reason;
putmsg(&sender,mesg,10);
putmsg(toname, mesg, 10);
}
static void send_accept(Uint32 network_join_unique) {
@ -516,9 +500,7 @@ void cancel_network_game() {
mesg[5] = 0xff;
for (i = 1; i < MAXNETNODES; ++i) {
if(netnodes[i].used) {
putmsg(&netnodes[i].netname,mesg,6);
}
if (netnodes[i].used) { putmsg(&netnodes[i].netname, mesg, 6); }
}
}
@ -526,7 +508,7 @@ int handle_joins() {
int size;
int i, j;
unsigned char temp[64];
Uint32 network_join_unique;
Uint32 network_join_unique = 0;
size = getmsg(40);
switch (*mesg) {
@ -556,10 +538,8 @@ int handle_joins() {
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;
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;
}
@ -580,10 +560,8 @@ int handle_joins() {
}
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);
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;
memcpy(netnodes[i].name, mesg + 9, 16);
@ -603,12 +581,14 @@ static int read_inform(unsigned char** pbuf, int *psize) {
int i;
if (size < 1) return 0;
myslot = *buf++; size--;
myslot = *buf++;
size--;
if (0xff == myslot) return 1;
if (size < 1) return 0;
while (0xff != *buf) {
i = *buf++; size--;
i = *buf++;
size--;
if (size < 17 || i >= MAXNETNODES) return 0;
netnodes[i].used = 1;
memcpy(netnodes[i].name, buf, 16);
@ -723,7 +703,6 @@ void send_quit() {
size = getmsg(1000);
if (size < 6) continue;
if (mesg[0] != PKT_ACK || mesg[1] != PKT_QUIT) continue;
if (isvalidunique(mesg+2))
break;
if (isvalidunique(mesg + 2)) break;
}
}

View File

@ -1,13 +1,11 @@
#ifndef NETWORK_H
#define NETWORK_H
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
enum {
MAXNETNODES = 8
};
enum { MAXNETNODES = 8 };
struct netnode {
struct sockaddr_in netname;

179
src/sound.c Normal file
View File

@ -0,0 +1,179 @@
#include <SDL_audio.h>
#include <SDL_error.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "sound.h"
#ifndef DATADIR
#define DATADIR "data"
#endif
int sound_enabled = 1;
static char dirlist[] = DATADIR;
static int readsound(int num);
#define NUMSOUNDS ((int) (sizeof(soundnames) / sizeof(char*)))
#define MIXMAX 16
#define SOUND_QUIET -1
static const char* soundnames[] = {
"bomb1.raw",
"power1.raw",
"death.raw",
"drop.raw",
"bomb2.raw",
"power2.raw",
};
typedef struct sample {
char* data;
int len;
} sample;
#define SNDFRAGMENT 1024
static sample samples[NUMSOUNDS];
static int soundworking = 0;
static int fragment;
// static int soundwrite,soundread;
static int* soundbuffer;
static int soundbufferlen;
static unsigned char sndclip[8192];
#define MAXSOUNDCOMMANDS 32
static char soundcommands[MAXSOUNDCOMMANDS];
static int soundtake, soundput;
static int sndplaying[MIXMAX], sndposition[MIXMAX];
static void fillaudio(void* udata, Uint8* buffer, int len) {
char com, *p;
int i, j, *ip;
int which;
(void) udata;
while (soundtake != soundput) {
com = soundcommands[soundtake];
soundtake = (soundtake + 1) & (MAXSOUNDCOMMANDS - 1);
if (com == SOUND_QUIET) {
memset(sndposition, 0, sizeof(sndposition));
continue;
}
if (com < NUMSOUNDS) {
for (i = 0; i < MIXMAX; ++i)
if (!sndposition[i]) {
sndposition[i] = 1;
sndplaying[i] = com;
break;
}
}
}
memset(soundbuffer, 0, soundbufferlen);
for (i = 0; i < MIXMAX; ++i) {
if (!sndposition[i]) continue;
which = sndplaying[i];
if (sndposition[i] == samples[which].len) {
sndposition[i] = 0;
continue;
}
p = samples[which].data;
if (!p) continue;
p += len * (sndposition[i]++ - 1);
ip = soundbuffer;
j = len;
while (j--) *ip++ += *p++;
}
j = len;
ip = soundbuffer;
;
while (j--) *buffer++ = sndclip[4096 + *ip++];
}
int soundopen(void) {
SDL_AudioSpec wanted;
int i, j;
soundtake = soundput = 0;
memset(sndposition, 0, sizeof(sndposition));
memset(sndplaying, 0, sizeof(sndplaying));
fragment = SNDFRAGMENT << 1;
soundbufferlen = fragment * sizeof(int);
soundbuffer = malloc(soundbufferlen);
if (!soundbuffer) return -2;
memset(&wanted, 0, sizeof(wanted));
wanted.freq = 22050;
wanted.channels = 2;
wanted.format = AUDIO_U8;
wanted.samples = fragment >> 1;
wanted.callback = fillaudio;
wanted.userdata = 0;
if (SDL_OpenAudio(&wanted, 0) < 0) {
fprintf(stderr, "Couldn't open audio: %s\n", SDL_GetError());
return -1;
}
soundworking = 1;
for (i = 0; i < 8192; i++) {
j = i - 4096;
sndclip[i] = j > 127 ? 255 : (j < -128 ? 0 : j + 128);
}
for (i = 0; i < NUMSOUNDS; ++i) readsound(i);
SDL_PauseAudio(0);
return 0;
}
void soundclose(void) {
if (soundworking) {
SDL_CloseAudio();
soundworking = 0;
}
}
int readsound(int num) {
char name[256], *p1, *p2, ch;
int file, size, len;
p1 = dirlist;
for (;;) {
p2 = name;
while (*p1 && (ch = *p1++) != ',') *p2++ = ch;
if (p2 > name && p2[-1] != '/') *p2++ = '/';
strcpy(p2, soundnames[num]);
file = open(name, O_RDONLY);
if (file >= 0) break;
if (!*p1) {
samples[num].len = -1;
return 0;
}
}
size = lseek(file, 0, SEEK_END);
lseek(file, 0, SEEK_SET);
len = samples[num].len = (size + fragment - 1) / fragment;
len *= fragment;
p1 = samples[num].data = malloc(len);
if (p1) {
read(file, p1, size);
if (len - size) memset(p1 + size, 0, len - size);
while (size--) *p1++ ^= 0x80;
} else
samples[num].data = 0;
close(file);
return 0;
}
void playsound(int n) {
if (sound_enabled) {
soundcommands[soundput] = n;
soundput = (soundput + 1) & (MAXSOUNDCOMMANDS - 1);
}
}

View File

@ -1,13 +1,13 @@
#include "bomber.h"
#include "utils.h"
#include "bomber.h"
#include "gfx.h"
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
int volatile hc = 0;
@ -35,9 +35,18 @@ static void surf(Uint32 out[8], const Uint32 in[12], const Uint32 seed[32]) {
for (loop = 0; loop < 2; ++loop) {
for (r = 0; r < 16; ++r) {
sum += 0x9e3779b9;
MUSH(0, 5); MUSH(1, 7); MUSH(2, 9); MUSH(3, 13);
MUSH(4, 5); MUSH(5, 7); MUSH(6, 9); MUSH(7, 13);
MUSH(8, 5); MUSH(9, 7); MUSH(10, 9); MUSH(11, 13);
MUSH(0, 5);
MUSH(1, 7);
MUSH(2, 9);
MUSH(3, 13);
MUSH(4, 5);
MUSH(5, 7);
MUSH(6, 9);
MUSH(7, 13);
MUSH(8, 5);
MUSH(9, 7);
MUSH(10, 9);
MUSH(11, 13);
}
for (i = 0; i < 8; ++i) out[i] ^= t[i + 4];
}
@ -62,10 +71,14 @@ static Uint32 surf_init(void) {
if (-1 == fd) {
Uint32 genseed[4][8];
surf_seed[0] = surf_seed[1] = gtime();
surf_in[0]++; surf(genseed[0], surf_in, surf_seed);
surf_in[0]++; surf(genseed[1], surf_in, surf_seed);
surf_in[0]++; surf(genseed[2], surf_in, surf_seed);
surf_in[0]++; surf(genseed[3], surf_in, surf_seed);
surf_in[0]++;
surf(genseed[0], surf_in, surf_seed);
surf_in[0]++;
surf(genseed[1], surf_in, surf_seed);
surf_in[0]++;
surf(genseed[2], surf_in, surf_seed);
surf_in[0]++;
surf(genseed[3], surf_in, surf_seed);
memcpy(surf_seed, genseed[0], 32);
memcpy(surf_seed, genseed[1], 32);
memcpy(surf_seed, genseed[2], 32);
@ -86,7 +99,8 @@ static Uint32 surf_init(void) {
static Uint32 surf_random(void) {
if (surf_left == 0) {
int i;
for (i = 0; (i < 12) && !(++surf_in[i]); i++) ;
for (i = 0; (i < 12) && !(++surf_in[i]); i++)
;
surf_left = 8;
surf(surf_out, surf_in, surf_seed);
}
@ -235,6 +249,5 @@ void hexdump(unsigned char *p, int len) {
else
fprintf(stderr, "0x%X ", p[i]);
}
if (i % 16)
fprintf(stderr, "\n");
if (i % 16) fprintf(stderr, "\n");
}

View File

@ -1,6 +1,8 @@
#ifndef UTILS_H
#define UTILS_H
#include <SDL.h>
Uint32 gtime(void);
Uint32 longtime(void);