Split source in more files, changed network behavior to prepare for direct connect.
This commit is contained in:
parent
69a7bcafc7
commit
c5aa13ac27
22
Makefile
22
Makefile
@ -1,4 +1,4 @@
|
||||
#DBG = -g
|
||||
DBG = -g
|
||||
CC = gcc
|
||||
WARNFLAGS = -Wall -Wmissing-declarations -Wdeclaration-after-statement -Wcast-align -Winline -Wsign-compare -Wnested-externs -Wpointer-arith -Wformat-security
|
||||
override CFLAGS += -D_REENTRANT -O2 $(shell sdl-config --cflags) $(DBG) $(WARNFLAGS)
|
||||
@ -6,18 +6,30 @@ override CFLAGS += -D_REENTRANT -O2 $(shell sdl-config --cflags) $(DBG) $(WARNFL
|
||||
.PHONY: all clean install
|
||||
all: sdlbomber
|
||||
|
||||
sdlbomber: bomber.o gfx.o sound.o announce.o
|
||||
gcc -o sdlbomber bomber.o gfx.o sound.o announce.o $(shell sdl-config --libs) -lavahi-common -lavahi-client $(DBG)
|
||||
sdlbomber: announce.o bomber.o draw.o game.o gfx.o sound.o list.o network.o menu.o utils.o
|
||||
gcc -o $@ $^ $(shell sdl-config --libs) -lavahi-common -lavahi-client $(DBG)
|
||||
|
||||
matcher: matcher.c
|
||||
|
||||
bomber.o: bomber.c bomber.h gfx.h announce.h sound.h
|
||||
announce.o: announce.c announce.h
|
||||
|
||||
bomber.o: bomber.c announce.h bomber.h draw.h game.h gfx.h list.h menu.h network.h sound.h utils.h
|
||||
|
||||
draw.o: draw.c draw.h bomber.h gfx.h
|
||||
|
||||
game.o: game.c announce.h bomber.h draw.h game.h gfx.h list.h menu.h network.h sound.h utils.h
|
||||
|
||||
gfx.o: gfx.c gfx.h bomber.h
|
||||
|
||||
list.o: list.c bomber.h list.h utils.h
|
||||
|
||||
menu.o: menu.c announce.h bomber.h draw.h game.h gfx.h list.h menu.h network.h sound.h utils.h
|
||||
|
||||
network.o: network.c announce.h bomber.h game.h menu.h network.h utils.h
|
||||
|
||||
sound.o: sound.c sound.h
|
||||
|
||||
announce.o: announce.c announce.h
|
||||
utils.o: utils.c bomber.h utils.h gfx.h
|
||||
|
||||
clean:
|
||||
rm -f *.o matcher sdlbomber
|
||||
|
34
README
34
README
@ -55,40 +55,6 @@ There isn't much point in playing the game alone (single player). In that
|
||||
case the only thing to avoid is accidentally killing yourself. Big deal...
|
||||
It's really a multiplayer game.
|
||||
|
||||
----------------- Left to do: -------------------
|
||||
Come up with a better scheme for internet play, as it is any latency will
|
||||
kill the game playability. Works fine on LAN though.
|
||||
|
||||
Figure out why matching doesn't work through a firewall...
|
||||
[Specific case is 2 machines on my LAN cannot be matched by a machine that
|
||||
is outside the firewall, and the firewall machine is doing IP masquerading.
|
||||
Net result is matcher gets remapped IP addresses and these mean nothing
|
||||
inside the LAN, only make sense when used from the outside world]
|
||||
|
||||
Score.
|
||||
|
||||
Remap movement keys not implemented.
|
||||
|
||||
Allow game hoster to set network game options and have them visible to players
|
||||
who have joined the game.
|
||||
|
||||
Alternate gfx sets.
|
||||
|
||||
Better handling of 8 bit mode with limited palette.
|
||||
|
||||
Computer controlled things that can kill you.
|
||||
|
||||
Other bonus types that can be harmful, such as skull.
|
||||
|
||||
Internet play where everything is asynchronous, thus playable with a fixed
|
||||
latency. As it is now slaves send to master, then master sends back to
|
||||
slaves, and this data xfer must complete before the game can advance a step.
|
||||
For internet this would be intolerable. I've never tried though...
|
||||
|
||||
Better docs, online explanations, attract mode...
|
||||
|
||||
Single player with computer controlled figures that must be killed/avoided.
|
||||
|
||||
----------------
|
||||
Direct comments, complaints and questions to dash@xdr.com
|
||||
This code is GPL.
|
||||
|
34
TODO
34
TODO
@ -0,0 +1,34 @@
|
||||
----------------- Left to do: -------------------
|
||||
Come up with a better scheme for internet play, as it is any latency will
|
||||
kill the game playability. Works fine on LAN though.
|
||||
|
||||
Figure out why matching doesn't work through a firewall...
|
||||
[Specific case is 2 machines on my LAN cannot be matched by a machine that
|
||||
is outside the firewall, and the firewall machine is doing IP masquerading.
|
||||
Net result is matcher gets remapped IP addresses and these mean nothing
|
||||
inside the LAN, only make sense when used from the outside world]
|
||||
|
||||
Score.
|
||||
|
||||
Remap movement keys not implemented.
|
||||
|
||||
Allow game hoster to set network game options and have them visible to players
|
||||
who have joined the game.
|
||||
|
||||
Alternate gfx sets.
|
||||
|
||||
Better handling of 8 bit mode with limited palette.
|
||||
|
||||
Computer controlled things that can kill you.
|
||||
|
||||
Other bonus types that can be harmful, such as skull.
|
||||
|
||||
Internet play where everything is asynchronous, thus playable with a fixed
|
||||
latency. As it is now slaves send to master, then master sends back to
|
||||
slaves, and this data xfer must complete before the game can advance a step.
|
||||
For internet this would be intolerable. I've never tried though...
|
||||
|
||||
Better docs, online explanations, attract mode...
|
||||
|
||||
Single player with computer controlled figures that must be killed/avoided.
|
||||
|
24
announce.c
24
announce.c
@ -26,7 +26,7 @@ static AvahiEntryGroup *group = NULL;
|
||||
static char* name = NULL;
|
||||
|
||||
static uint16_t port = 0;
|
||||
static uint32_t unique = 0, version = 0;
|
||||
static uint32_t version = 0;
|
||||
|
||||
static volatile int all_for_now;
|
||||
|
||||
@ -82,10 +82,9 @@ static void create_services(AvahiClient *c) {
|
||||
|
||||
again:
|
||||
if (avahi_entry_group_is_empty(group)) {
|
||||
char buf_unique[128], buf_version[128];
|
||||
snprintf(buf_unique, sizeof(buf_unique), "unique=%X", (unsigned int) unique);
|
||||
char buf_version[128];
|
||||
snprintf(buf_version, sizeof(buf_version), "version=%X", (unsigned int) version);
|
||||
if ((ret = avahi_entry_group_add_service(group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, name, SERVICE_TYPE, NULL, NULL, port, buf_unique, buf_version, NULL)) < 0) {
|
||||
if ((ret = avahi_entry_group_add_service(group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, name, SERVICE_TYPE, NULL, NULL, port, buf_version, NULL)) < 0) {
|
||||
|
||||
if (ret == AVAHI_ERR_COLLISION)
|
||||
goto collision;
|
||||
@ -136,12 +135,11 @@ static void client_callback(AvahiClient *c, AvahiClientState state, void * userd
|
||||
}
|
||||
}
|
||||
|
||||
int registergame(char *playername, uint16_t p, uint32_t uniq, unsigned char v[4]) {
|
||||
int registergame(const char *playername, uint16_t p, const unsigned char v[4]) {
|
||||
if (name) avahi_free(name);
|
||||
name = avahi_strdup(playername);
|
||||
|
||||
port = p;
|
||||
unique = htonl(uniq);
|
||||
memcpy(&version, v, 4);
|
||||
version = htonl(version);
|
||||
|
||||
@ -180,20 +178,17 @@ static void resolve_callback(AvahiServiceResolver *r, AvahiIfIndex interface, Av
|
||||
|
||||
case AVAHI_RESOLVER_FOUND: {
|
||||
gamelistentry *ge;
|
||||
unsigned int uniq, version;
|
||||
int have_unique = 0, have_version = 0;
|
||||
unsigned int version;
|
||||
int have_version = 0;
|
||||
AvahiStringList *psl;
|
||||
for (psl = txt ; psl ; psl = psl->next) {
|
||||
if (0 == strncmp("unique=", (const char*) psl->text, 7)) {
|
||||
sscanf((const char*) psl->text, "unique=%X", &uniq);
|
||||
have_unique = 1;
|
||||
} else if (0 == strncmp("version=", (const char*) psl->text, 8)) {
|
||||
if (0 == strncmp("version=", (const char*) psl->text, 8)) {
|
||||
sscanf((const char*) psl->text, "version=%X", &version);
|
||||
if (version != want_version) goto done; /* version mismatch */
|
||||
have_version = 1;
|
||||
}
|
||||
}
|
||||
if (!have_unique || !have_version) goto done;
|
||||
if (!have_version) goto done;
|
||||
i = gamelistsize++;
|
||||
ge = &gamelistentries[i];
|
||||
memset(ge, 0, sizeof(*ge));
|
||||
@ -201,7 +196,6 @@ static void resolve_callback(AvahiServiceResolver *r, AvahiIfIndex interface, Av
|
||||
ge->netname.sin_family = AF_INET;
|
||||
ge->netname.sin_port = port;
|
||||
ge->name = avahi_strdup(name);
|
||||
ge->unique = ntohl(uniq);
|
||||
}
|
||||
}
|
||||
|
||||
@ -257,7 +251,7 @@ static void freefoundgames() {
|
||||
gamelistsize = 0;
|
||||
}
|
||||
|
||||
int searchgames(unsigned char version[4]) {
|
||||
int searchgames(const unsigned char version[4]) {
|
||||
int i;
|
||||
AvahiServiceBrowser *sb = NULL;
|
||||
uint32_t gameversion;
|
||||
|
@ -7,12 +7,11 @@ typedef struct gamelistentry gamelistentry;
|
||||
struct gamelistentry {
|
||||
struct sockaddr_in netname;
|
||||
char *name;
|
||||
uint32_t unique;
|
||||
};
|
||||
|
||||
int registergame(char *playername, uint16_t port, uint32_t unique, unsigned char version[4]);
|
||||
int registergame(const char *playername, uint16_t port, const unsigned char version[4]);
|
||||
void unregistergame();
|
||||
int searchgames(unsigned char version[4]);
|
||||
int searchgames(const unsigned char version[4]);
|
||||
|
||||
int initannouncer();
|
||||
void freeannouncer();
|
||||
|
78
bomber.h
78
bomber.h
@ -84,27 +84,22 @@ typedef struct player
|
||||
#define FLG_DEAD 2
|
||||
|
||||
|
||||
|
||||
typedef struct sprite
|
||||
{
|
||||
typedef struct sprite {
|
||||
int flags;
|
||||
int xpos,ypos;
|
||||
figure *fig;
|
||||
} sprite;
|
||||
|
||||
typedef struct damage
|
||||
{
|
||||
typedef struct damage {
|
||||
int xpos,ypos;
|
||||
int xsize,ysize;
|
||||
} damage;
|
||||
|
||||
typedef struct list
|
||||
{
|
||||
typedef struct list {
|
||||
void *next;
|
||||
} list;
|
||||
|
||||
typedef struct bomb
|
||||
{
|
||||
typedef struct bomb {
|
||||
struct bomb *next;
|
||||
int type;
|
||||
int xpos,ypos;
|
||||
@ -123,8 +118,7 @@ typedef struct bomb
|
||||
#define FLAMELIFE 15
|
||||
#define DECAYLIFE 15
|
||||
|
||||
typedef struct flame
|
||||
{
|
||||
typedef struct flame {
|
||||
struct flame *next;
|
||||
int xpos,ypos;
|
||||
int px,py;
|
||||
@ -138,16 +132,23 @@ typedef struct flame
|
||||
#define FL_LEFT 1
|
||||
#define FL_RIGHT 4
|
||||
|
||||
typedef struct brickdecay
|
||||
{
|
||||
typedef struct brickdecay {
|
||||
struct brickdecay *next;
|
||||
int xpos,ypos;
|
||||
int px,py;
|
||||
int timer;
|
||||
} brickdecay;
|
||||
|
||||
typedef struct generic
|
||||
{
|
||||
typedef union listitem listitem;
|
||||
union listitem {
|
||||
listitem *next;
|
||||
bomb b;
|
||||
flame f;
|
||||
brickdecay bc;
|
||||
player p;
|
||||
};
|
||||
|
||||
typedef struct generic {
|
||||
struct generic *next;
|
||||
int xpos,ypos;
|
||||
int px,py;
|
||||
@ -158,13 +159,12 @@ typedef struct generic
|
||||
int data1,data2;
|
||||
} generic;
|
||||
|
||||
typedef struct bonustile
|
||||
{
|
||||
typedef struct bonustile {
|
||||
struct bonustile *next;
|
||||
int xpos,ypos;
|
||||
int px,py;
|
||||
int type;
|
||||
}bonustile;
|
||||
} bonustile;
|
||||
|
||||
#define TILE_NONE -1
|
||||
#define TILE_BOMB 5
|
||||
@ -210,48 +210,8 @@ typedef struct bonustile
|
||||
|
||||
extern char exitflag;
|
||||
|
||||
extern player players[];
|
||||
extern sprite sprites[];
|
||||
extern gfxset gfxsets[NUMGFX];
|
||||
extern uchar needwhole;
|
||||
extern figure walking[MAXSETS][60];
|
||||
extern damage damages[];
|
||||
extern bomb bombs[];
|
||||
|
||||
extern void centerx(player *pl);
|
||||
extern void centery(player *pl);
|
||||
extern void dropbomb(player *pl,int px,int py,int type);
|
||||
extern void adddetonate(bomb *bmb);
|
||||
extern void flameshaft(player *owner,int px,int py,int dx,int dy,int power);
|
||||
extern void detonatebomb(bomb *bmb);
|
||||
extern void initlist(void *first,int size,int num);
|
||||
extern void freeentry(void *entry);
|
||||
extern void addtail(void *header,void *entry);
|
||||
extern void delink(void *header,void *entry);
|
||||
extern void *allocentry();
|
||||
extern void adddecay(int px,int py);
|
||||
extern void trybonus(int px,int py);
|
||||
extern void addbonus(int px,int py,int type);
|
||||
extern void deletebonus(bonustile *bonus);
|
||||
extern void queuesequence(int xpos,int ypos,figure *fig,int count);
|
||||
extern void playonce(generic *gen);
|
||||
extern void processgenerics(void);
|
||||
extern void drawgenerics(void);
|
||||
extern void drawgeneric(generic *gen);
|
||||
extern void killplayer(player *pl);
|
||||
extern void adddeath(player *pl);
|
||||
extern void drawbigstring(int xpos,int ypos,char *str);
|
||||
extern void bigscrprintf(char *str, ...);
|
||||
extern void drawstring(int xpos,int ypos,char *str);
|
||||
extern void scrprintf(char *str, ...);
|
||||
extern int textx,texty,fontxsize,fontysize;
|
||||
extern void texthome(void);
|
||||
|
||||
extern unsigned char field[32][32];
|
||||
extern void *info[32][32];
|
||||
extern unsigned char singleoptions[10];
|
||||
extern unsigned char gameoptions[10];
|
||||
extern int getmsg(int);
|
||||
|
||||
#define GO_DENSITY 0
|
||||
#define GO_FLAMES 1
|
||||
@ -261,7 +221,7 @@ extern int getmsg(int);
|
||||
// network packet types
|
||||
// slave -> master packets
|
||||
#define PKT_MYDATA 0 // 4 bytes unique #,4 bytes frame #, 1 byte data
|
||||
#define PKT_JOIN 1 // 4 bytes unique #,16 bytes name
|
||||
#define PKT_JOIN 1 // 4 bytes version #,16 bytes name
|
||||
// master -> slave packets
|
||||
#define PKT_INVITE 9 // 4 bytes unique #, any # of 1:slot,16:name sets (-1 end)
|
||||
#define PKT_BEGIN 10 // clone of INVITE
|
||||
|
448
draw.c
Normal file
448
draw.c
Normal file
@ -0,0 +1,448 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <netdb.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <signal.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "bomber.h"
|
||||
#include "draw.h"
|
||||
#include "game.h"
|
||||
#include "gfx.h"
|
||||
#include "utils.h"
|
||||
|
||||
#ifndef DATADIR
|
||||
#define DATADIR "data"
|
||||
#endif
|
||||
|
||||
#define NUMCHARACTERS 50
|
||||
|
||||
static figure font[NUMCHARACTERS];
|
||||
static figure bigfont[NUMCHARACTERS];
|
||||
|
||||
gfxset gfxsets[NUMGFX];
|
||||
static char walkingname[256];
|
||||
static char colorsetname[256];
|
||||
static char backgroundname[256];
|
||||
static char blocksname[256];
|
||||
static char blocksxname[256];
|
||||
static char bombs1name[256];
|
||||
static char bombs2name[256];
|
||||
static char flamesname[256];
|
||||
static char tilesname[256];
|
||||
static char deathname[256];
|
||||
static char fontname[256];
|
||||
static char bigfontname[256];
|
||||
|
||||
figure blocks[3];
|
||||
figure blocksx[9];
|
||||
figure bombs1[MAXSETS][NUMBOMBFRAMES];
|
||||
figure bombs2[MAXSETS][NUMBOMBFRAMES];
|
||||
figure flamefigs[MAXSETS][NUMFLAMEFRAMES];
|
||||
figure tiles[15];
|
||||
figure death[NUMDEATHFRAMES];
|
||||
|
||||
int fontxsize,fontysize;
|
||||
int bigfontxsize,bigfontysize,bigfontyspace;
|
||||
|
||||
static int textx,texty;
|
||||
|
||||
static char *remapstring="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ.:!?\177/\\*-,>< =";
|
||||
static char asciiremap[256];
|
||||
|
||||
/* On screen array variables */
|
||||
int arraynumx=15;
|
||||
int arraynumy=11;
|
||||
int arraystartx=20;
|
||||
int arraystarty=70;
|
||||
int arrayspacex=40;
|
||||
int arrayspacey=36;
|
||||
|
||||
static sprite sprites[MAXSPRITES];
|
||||
static int spritesused=0;
|
||||
|
||||
#define IBUFFLEN 1024
|
||||
int ileft=0,ihand=0,byteswide;
|
||||
unsigned char ibuff[IBUFFLEN],*itake;
|
||||
|
||||
static void freegfxset(gfxset *gs) {
|
||||
if(gs->gs_pic) free(gs->gs_pic);
|
||||
gs->gs_pic=0;
|
||||
}
|
||||
|
||||
static int myci() {
|
||||
if (!ileft) {
|
||||
ileft=read(ihand,ibuff,IBUFFLEN);
|
||||
|
||||
if(!ileft) return -1;
|
||||
itake=ibuff;
|
||||
}
|
||||
ileft--;
|
||||
return *itake++;
|
||||
}
|
||||
|
||||
static int dopcxreal(char *name,gfxset *gs) {
|
||||
int xs,ys;
|
||||
int i,j,k;
|
||||
int totalsize;
|
||||
int width,height;
|
||||
unsigned char *bm,*lp;
|
||||
char tname[256];
|
||||
|
||||
memset(gs,0,sizeof(gfxset));
|
||||
ileft=0;
|
||||
sprintf(tname,DATADIR "/%s",name);
|
||||
ihand=open(tname,O_RDONLY);
|
||||
if(ihand<0) {
|
||||
char tname2[256];
|
||||
sprintf(tname2,"%s.pcx",tname);
|
||||
ihand=open(tname2,O_RDONLY);
|
||||
if(ihand<0)
|
||||
return 1;
|
||||
}
|
||||
if(myci()!=10) {close(ihand);return 2;} // 10=zsoft .pcx
|
||||
if(myci()!=5) {close(ihand);return 3;} // version 3.0
|
||||
if(myci()!=1) {close(ihand);return 4;} //encoding method
|
||||
if(myci()!=8) {close(ihand);return 5;} //bpp
|
||||
xs=myci();
|
||||
xs|=myci()<<8;
|
||||
ys=myci();
|
||||
ys|=myci()<<8;
|
||||
width=myci();
|
||||
width|=myci()<<8;
|
||||
height=myci();
|
||||
height|=myci()<<8;
|
||||
width=width+1-xs;
|
||||
height=height+1-ys;
|
||||
for(i=0;i<48+4;++i) myci();
|
||||
myci();
|
||||
if(myci()!=1) {close(ihand);return 6;} // # of planes
|
||||
byteswide=myci();
|
||||
byteswide|=myci()<<8;
|
||||
i=myci();
|
||||
i|=myci()<<8;
|
||||
// if(i!=1) {close(ihand);return 7;} // 1=color/bw,2=grey
|
||||
for(i=0;i<58;++i) myci();
|
||||
totalsize=height*byteswide;
|
||||
bm=malloc(totalsize+1);
|
||||
if(!bm) {close(ihand);return 8;} // no memory
|
||||
gs->gs_pic=bm;
|
||||
gs->gs_xsize=width;
|
||||
gs->gs_ysize=height;
|
||||
while(height--) {
|
||||
lp=bm;
|
||||
i=byteswide;
|
||||
while(i>0) {
|
||||
j=myci();
|
||||
if(j<0xc0) {
|
||||
*lp++=j;
|
||||
--i;
|
||||
} else {
|
||||
j&=0x3f;
|
||||
k=myci();
|
||||
while(j-- && i) {
|
||||
*lp++=k;
|
||||
--i;
|
||||
}
|
||||
}
|
||||
}
|
||||
bm+=width;
|
||||
}
|
||||
lseek(ihand,-0x300,SEEK_END);
|
||||
read(ihand,gs->gs_colormap,0x300);
|
||||
close(ihand);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dopcx(char *name,gfxset *gs) {
|
||||
int err;
|
||||
|
||||
err=dopcxreal(name,gs);
|
||||
if(err)
|
||||
printf("Error loading \"%s\":code %d\n",name,err);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void getgroup(char *name,gfxset *colorgs,figure *fig,int count) {
|
||||
int err;
|
||||
int i;
|
||||
gfxset gs;
|
||||
|
||||
err=dopcx(name,&gs);
|
||||
if(err) exit(1000+err);
|
||||
createinout(&gs);
|
||||
for(i=0;i<MAXSETS;++i,fig+=count,++colorgs) {
|
||||
if(!colorgs->gs_pic) continue;
|
||||
memmove(gs.gs_colormap,colorgs->gs_colormap,
|
||||
sizeof(gs.gs_colormap));
|
||||
createinout(&gs);
|
||||
gfxfetch(&gs,fig,count);
|
||||
}
|
||||
freegfxset(&gs);
|
||||
}
|
||||
|
||||
static void getsingle(char *name,figure *fig,int count) {
|
||||
gfxset gs;
|
||||
int err;
|
||||
|
||||
err=dopcx(name,&gs);
|
||||
if(err) exit(1000+err);
|
||||
createinout(&gs);
|
||||
gfxfetch(&gs,fig,count);
|
||||
freegfxset(&gs);
|
||||
}
|
||||
|
||||
static void texthome(void) {
|
||||
textx=texty=10;
|
||||
}
|
||||
|
||||
// static void drawstring(int xpos,int ypos,char *str) {
|
||||
// char ch;
|
||||
//
|
||||
// while((ch=*str++)) {
|
||||
// drawfigure(xpos,ypos,font+asciiremap[toupper(ch)]);
|
||||
// xpos+=fontxsize;
|
||||
// }
|
||||
// }
|
||||
|
||||
void drawbigstring(int xpos,int ypos,char *str) {
|
||||
char ch;
|
||||
|
||||
while('\0' != (ch=*str++)) {
|
||||
drawfigure(xpos,ypos,bigfont+asciiremap[toupper(ch)]);
|
||||
xpos+=bigfontxsize;
|
||||
}
|
||||
}
|
||||
|
||||
void centerbig(int y,char *str) {
|
||||
int w;
|
||||
|
||||
w=strlen(str)*bigfontxsize;
|
||||
drawbigstring((IXSIZE-w)>>1,y,str);
|
||||
}
|
||||
|
||||
// static void scrprintf(char *str,...) {
|
||||
// char output[256],*p,*p2;
|
||||
// va_list ap;
|
||||
//
|
||||
// va_start(ap, str);
|
||||
//
|
||||
// vsprintf(output,str,ap);
|
||||
// p=output;
|
||||
// for(;;) {
|
||||
// p2=p;
|
||||
// while(*p2 && *p2!='\n') ++p2;
|
||||
// if(*p2) {
|
||||
// *p2=0;
|
||||
// drawstring(textx,texty,p);
|
||||
// texty+=fontysize;
|
||||
// textx=10;
|
||||
// p=p2+1;
|
||||
// } else {
|
||||
// drawstring(textx,texty,p);
|
||||
// textx+=fontxsize*(p2-p);
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// copyup();
|
||||
// }
|
||||
|
||||
static void bigscrprintf(char *str,...) {
|
||||
char output[256],*p,*p2;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, str);
|
||||
vsprintf(output,str,ap);
|
||||
p=output;
|
||||
for(;;) {
|
||||
p2=p;
|
||||
while(*p2 && *p2!='\n') ++p2;
|
||||
if(*p2) {
|
||||
*p2=0;
|
||||
drawbigstring(textx,texty,p);
|
||||
texty+=bigfontysize;
|
||||
textx=10;
|
||||
p=p2+1;
|
||||
} else {
|
||||
drawbigstring(textx,texty,p);
|
||||
textx+=bigfontxsize*(p2-p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
copyup();
|
||||
}
|
||||
|
||||
void addsprite(int x,int y,figure *fig) {
|
||||
sprite *sp;
|
||||
|
||||
if(spritesused==MAXSPRITES) return;
|
||||
sp=sprites+spritesused++;
|
||||
sp->flags=0;
|
||||
sp->xpos=x;
|
||||
sp->ypos=y;
|
||||
sp->fig=fig;
|
||||
}
|
||||
|
||||
void plotsprites(void) {
|
||||
int i;
|
||||
sprite *sp;
|
||||
|
||||
sp=sprites;
|
||||
for(i=0;i<spritesused;++i) {
|
||||
drawfigure(sp->xpos,sp->ypos,sp->fig);
|
||||
++sp;
|
||||
}
|
||||
}
|
||||
|
||||
void erasesprites(void) {
|
||||
int i;
|
||||
sprite *sp;
|
||||
figure *fig;
|
||||
|
||||
sp=sprites;
|
||||
for(i=0;i<spritesused;++i) {
|
||||
fig=sp->fig;
|
||||
|
||||
solidcopy(&background,
|
||||
sp->xpos+fig->xdelta,sp->ypos+fig->ydelta,
|
||||
fig->xsize,fig->ysize);
|
||||
++sp;
|
||||
}
|
||||
}
|
||||
|
||||
void clearsprites(void) {
|
||||
int i;
|
||||
sprite *sp;
|
||||
figure *fig;
|
||||
|
||||
sp=sprites;
|
||||
for(i=0;i<spritesused;++i) {
|
||||
fig=sp->fig;
|
||||
|
||||
clearrect(sp->xpos+fig->xdelta,sp->ypos+fig->ydelta,
|
||||
fig->xsize,fig->ysize);
|
||||
++sp;
|
||||
}
|
||||
}
|
||||
|
||||
void clearspritelist(void) {
|
||||
spritesused=0;
|
||||
}
|
||||
|
||||
int tovideox(int x) {
|
||||
return (x>>FRACTION)+arraystartx;
|
||||
}
|
||||
|
||||
int tovideoy(int y) {
|
||||
return (y>>FRACTION)+arraystarty;
|
||||
}
|
||||
|
||||
int screentoarrayx(int x) {
|
||||
x+=arrayspacex << (FRACTION+2);
|
||||
return ((x>>FRACTION)+(arrayspacex>>1))/arrayspacex-4;
|
||||
}
|
||||
|
||||
int screentoarrayy(int y) {
|
||||
y+=arrayspacey << (FRACTION+2);
|
||||
return ((y>>FRACTION)+(arrayspacey>>1))/arrayspacey-4;
|
||||
}
|
||||
|
||||
int arraytoscreenx(int x) {
|
||||
return arrayspacex*x<<FRACTION;
|
||||
}
|
||||
|
||||
int arraytoscreeny(int y) {
|
||||
return arrayspacey*y<<FRACTION;
|
||||
}
|
||||
|
||||
static void loadfonts(void) {
|
||||
int i,j;
|
||||
char *p;
|
||||
|
||||
getsingle(fontname,font,NUMCHARACTERS);
|
||||
getsingle(bigfontname,bigfont,NUMCHARACTERS);
|
||||
fontxsize=8;
|
||||
fontysize=12;
|
||||
bigfontxsize=16;
|
||||
bigfontysize=24;
|
||||
bigfontyspace=32;
|
||||
p=remapstring;
|
||||
j=0;while(*p && *p!=' ') ++p,++j;
|
||||
memset(asciiremap,j,sizeof(asciiremap));
|
||||
p=remapstring;
|
||||
i=0;
|
||||
while(*p && i<40)
|
||||
asciiremap[(int)*p++]=i++;
|
||||
}
|
||||
|
||||
void loadgfx() {
|
||||
gfxset *gs;
|
||||
gfxset *colorgs;
|
||||
int err;
|
||||
int i;
|
||||
char name[256];
|
||||
|
||||
strcpy(walkingname,"walk");
|
||||
strcpy(colorsetname,"pal");
|
||||
strcpy(backgroundname,"field0");
|
||||
strcpy(blocksname,"blocks3");
|
||||
strcpy(blocksxname,"blocks3x");
|
||||
strcpy(bombs1name,"bomb1");
|
||||
strcpy(bombs2name,"bomb2");
|
||||
strcpy(flamesname,"flames");
|
||||
strcpy(tilesname,"tiles");
|
||||
strcpy(deathname,"death1");
|
||||
strcpy(fontname,"font");
|
||||
strcpy(bigfontname,"bigfont");
|
||||
|
||||
gs=malloc((MAXSETS+1)*sizeof(gfxset));
|
||||
if(!gs)
|
||||
nomem("loadgfx");
|
||||
colorgs=gs+1;
|
||||
|
||||
for(i=0;i<MAXSETS;++i) {
|
||||
sprintf(name,"%s%d",colorsetname,i);
|
||||
err=dopcx(name,colorgs+i);
|
||||
if(err) continue;
|
||||
}
|
||||
|
||||
loadfonts();
|
||||
texthome();
|
||||
bigscrprintf("Loading graphics...\n");
|
||||
|
||||
err=dopcx(backgroundname,gs);
|
||||
if(err) exit(1000+err);
|
||||
createinout(gs);
|
||||
solidfetch(gs,&background);
|
||||
solidfetch(gs,&backgroundoriginal);
|
||||
freegfxset(gs);
|
||||
|
||||
bigscrprintf("Loading blocks\n");
|
||||
getsingle(blocksname,blocks,3);
|
||||
bigscrprintf("Loading block explosions\n");
|
||||
getsingle(blocksxname,blocksx,9);
|
||||
bigscrprintf("Loading walking figures\n");
|
||||
getgroup(walkingname,colorgs,walking[0],NUMWALKFRAMES);
|
||||
bigscrprintf("Loading normal bombs\n");
|
||||
getgroup(bombs1name,colorgs,bombs1[0],NUMBOMBFRAMES);
|
||||
bigscrprintf("Loading controlled bombs\n");
|
||||
getgroup(bombs2name,colorgs,bombs2[0],NUMBOMBFRAMES);
|
||||
bigscrprintf("Loading flames\n");
|
||||
// getgroup(flamesname,colorgs,flamefigs[0],NUMFLAMEFRAMES);
|
||||
getsingle(flamesname,flamefigs[0],NUMFLAMEFRAMES);
|
||||
bigscrprintf("Loading bonus tiles\n");
|
||||
getsingle(tilesname,tiles,15);
|
||||
bigscrprintf("Loading death sequence\n");
|
||||
getsingle(deathname,death,NUMDEATHFRAMES);
|
||||
|
||||
for(i=0;i<MAXSETS;++i)
|
||||
freegfxset(colorgs+i);
|
||||
free(gs);
|
||||
bigscrprintf("Done loading graphics\n");
|
||||
}
|
38
draw.h
Normal file
38
draw.h
Normal file
@ -0,0 +1,38 @@
|
||||
#ifndef DRAW_H
|
||||
#define DRAW_H
|
||||
|
||||
void loadgfx(void);
|
||||
|
||||
void drawbigstring(int xpos,int ypos,char *str);
|
||||
|
||||
void centerbig(int y,char *str);
|
||||
|
||||
void addsprite(int x,int y,figure *fig);
|
||||
void plotsprites(void);
|
||||
void erasesprites(void);
|
||||
void clearsprites(void);
|
||||
void clearspritelist(void);
|
||||
|
||||
int tovideox(int x);
|
||||
int tovideoy(int y);
|
||||
|
||||
int screentoarrayx(int x);
|
||||
int screentoarrayy(int y);
|
||||
int arraytoscreenx(int x);
|
||||
int arraytoscreeny(int y);
|
||||
|
||||
extern int bigfontxsize,bigfontysize,bigfontyspace;
|
||||
|
||||
/* On screen array variables */
|
||||
extern int arraynumx, arraynumy, arraystartx, arraystarty, arrayspacex, arrayspacey;
|
||||
|
||||
/* Animation specific #defines */
|
||||
#define NUMBOMBFRAMES 10
|
||||
#define NUMWALKFRAMES 60
|
||||
#define NUMFLAMEFRAMES 80
|
||||
#define NUMDEATHFRAMES 41
|
||||
|
||||
|
||||
extern figure blocks[3], blocksx[9], bombs1[MAXSETS][NUMBOMBFRAMES], bombs2[MAXSETS][NUMBOMBFRAMES], flamefigs[MAXSETS][NUMFLAMEFRAMES], tiles[15], death[NUMDEATHFRAMES];
|
||||
|
||||
#endif
|
944
game.c
Normal file
944
game.c
Normal file
@ -0,0 +1,944 @@
|
||||
|
||||
#include "bomber.h"
|
||||
#include "game.h"
|
||||
#include "gfx.h"
|
||||
#include "network.h"
|
||||
#include "draw.h"
|
||||
#include "utils.h"
|
||||
#include "sound.h"
|
||||
#include "menu.h"
|
||||
#include "list.h"
|
||||
|
||||
static int gameframe;
|
||||
|
||||
static list activebombs;
|
||||
static list activedecays;
|
||||
static list activebonus;
|
||||
static list activegeneric;
|
||||
|
||||
static bomb *detonated[MAXBOMBSDETONATED];
|
||||
static int detonateput=0;
|
||||
static int detonatetake=0;
|
||||
|
||||
static list activeflames;
|
||||
static list activeplayers;
|
||||
|
||||
#define REGISTERLEN (1+4+4+4+16+1)
|
||||
|
||||
figure walking[MAXSETS][NUMWALKFRAMES];
|
||||
solid background,backgroundoriginal;
|
||||
|
||||
/* The playfield array, contains FIELD_* equates */
|
||||
unsigned char field[32][32];
|
||||
void *info[32][32];
|
||||
|
||||
int gamemode = 0;
|
||||
char exitflag = 0;
|
||||
static int framecount = 0;
|
||||
|
||||
char playername[16];
|
||||
|
||||
static int gountil, mycount;
|
||||
|
||||
static int bonustotal;
|
||||
static const int bonuschances[]= {
|
||||
TILE_BOMB,20,
|
||||
TILE_FLAME,20,
|
||||
TILE_CONTROL,2,
|
||||
TILE_GOLDFLAME,2,
|
||||
TILE_SKATES,20,
|
||||
TILE_TURTLE,5,
|
||||
TILE_NONE,160
|
||||
};
|
||||
|
||||
static unsigned char gameoptions[10];
|
||||
|
||||
static const unsigned char playerpositions[] = { /* color, x, y */
|
||||
2,0,0,
|
||||
3,14,10,
|
||||
4,14,0,
|
||||
5,0,10,
|
||||
1,6,0,
|
||||
6,8,10,
|
||||
7,0,6,
|
||||
8,14,4,
|
||||
};
|
||||
|
||||
static void initplayer(int color,int x,int y,int controller) {
|
||||
player *pl;
|
||||
|
||||
pl=allocentry();
|
||||
if(!pl)
|
||||
nomem("Couldn't get player structure (allocentry())");
|
||||
addtail(&activeplayers,pl);
|
||||
memset(pl,0,sizeof(player));
|
||||
pl->xpos=arraytoscreenx(x);
|
||||
pl->ypos=arraytoscreeny(y);
|
||||
pl->color=color;
|
||||
pl->speed=SPEEDSTART;
|
||||
pl->flags=0;
|
||||
pl->fixx=-4;
|
||||
pl->fixy=-40;
|
||||
pl->flamelength=gameoptions[GO_FLAMES]+1;
|
||||
pl->bombsavailable=gameoptions[GO_BOMBS]+1;
|
||||
pl->controller=controller;
|
||||
field[y][x]=FIELD_EMPTY;
|
||||
if(x) field[y][x-1]=FIELD_EMPTY;
|
||||
if(y) field[y-1][x]=FIELD_EMPTY;
|
||||
if(x<arraynumx-1) field[y][x+1]=FIELD_EMPTY;
|
||||
if(y<arraynumy-1) field[y+1][x]=FIELD_EMPTY;
|
||||
}
|
||||
|
||||
static void initplayers(void) {
|
||||
int i;
|
||||
const unsigned char *p;
|
||||
int c,x,y;
|
||||
|
||||
if(!network) {
|
||||
initplayer(2,0,0,-1);
|
||||
return;
|
||||
}
|
||||
p=playerpositions;
|
||||
for(i=0;i<MAXNETNODES;++i) {
|
||||
if(!netnodes[i].used) continue;
|
||||
c=*p++;
|
||||
x=*p++;
|
||||
y=*p++;
|
||||
initplayer(c,x,y,i);
|
||||
}
|
||||
}
|
||||
|
||||
static void firstzero(void) {
|
||||
gountil=mycount=mydatacount=0;
|
||||
memset(latestactions,0,sizeof(latestactions));
|
||||
memset(latestcounts,0,sizeof(latestcounts));
|
||||
actionput=actioncount=0;
|
||||
}
|
||||
|
||||
static void initgame() {
|
||||
int i,j;
|
||||
int x,y;
|
||||
int bl;
|
||||
const int *p;
|
||||
int comp;
|
||||
|
||||
if (network != NETWORK_SLAVE)
|
||||
set_game_options(configopts);
|
||||
gameframe=0;
|
||||
allocthings();
|
||||
initheader(&activebombs);
|
||||
initheader(&activeflames);
|
||||
initheader(&activedecays);
|
||||
initheader(&activebonus);
|
||||
initheader(&activeplayers);
|
||||
initheader(&activegeneric);
|
||||
|
||||
detonateput=detonatetake=0;
|
||||
|
||||
p=bonuschances;
|
||||
bonustotal=0;
|
||||
for(;;) {
|
||||
i=*p++;
|
||||
if(i==TILE_NONE) break;
|
||||
bonustotal+=*p++;
|
||||
}
|
||||
bonustotal += 64*(3-gameoptions[GO_GENEROSITY]);
|
||||
memset(field,0,sizeof(field));
|
||||
comp=gameoptions[GO_DENSITY];
|
||||
for(j=0;j<arraynumy;++j)
|
||||
for(i=0;i<arraynumx;++i) {
|
||||
/* if((i&j)&1) {
|
||||
field[j][i]=FIELD_BORDER;
|
||||
} else*/
|
||||
field[j][i]=
|
||||
(myrand()&3)>=comp ? FIELD_BRICK : FIELD_EMPTY;
|
||||
}
|
||||
|
||||
solidcopyany(&backgroundoriginal,&background,0,0,IXSIZE,IYSIZE);
|
||||
|
||||
initplayers();
|
||||
|
||||
for(j=0;j<arraynumy;++j) {
|
||||
y=arraystarty+j*arrayspacey;
|
||||
for(i=0;i<arraynumx;++i) {
|
||||
x=arraystartx+i*arrayspacex;
|
||||
bl=field[j][i];
|
||||
if(bl==FIELD_BORDER) bl=2;
|
||||
else if(bl==FIELD_BRICK) bl=1;
|
||||
else continue;
|
||||
drawfigureany(x,y,blocks+bl,&background);
|
||||
}
|
||||
}
|
||||
solidcopy(&background,0,0,IXSIZE,IYSIZE);
|
||||
copyup();
|
||||
}
|
||||
|
||||
|
||||
void run_single_player(void) {
|
||||
int code;
|
||||
network=0;
|
||||
|
||||
firstzero();
|
||||
do {
|
||||
initgame();
|
||||
while(!(code=iterate())) ++framecount;
|
||||
} while (code != CODE_QUIT);
|
||||
|
||||
gamemode=0;
|
||||
}
|
||||
|
||||
void run_network_game(void) {
|
||||
int code;
|
||||
|
||||
firstzero();
|
||||
do {
|
||||
initgame();
|
||||
while(!(code=iterate())) ++framecount;
|
||||
} while (code != CODE_QUIT);
|
||||
|
||||
network = 0;
|
||||
gamemode = 0;
|
||||
}
|
||||
|
||||
static void addflame(player *owner,int px,int py) {
|
||||
flame *fl,*fl2;
|
||||
|
||||
fl=allocentry();
|
||||
if(!fl) return;
|
||||
addtail(&activeflames,fl);
|
||||
field[py][px]=FIELD_FLAME;
|
||||
info[py][px]=fl;
|
||||
fl->px=px;
|
||||
fl->py=py;
|
||||
fl->xpos=arraytoscreenx(px);
|
||||
fl->ypos=arraytoscreeny(py);
|
||||
fl->owner=owner;
|
||||
if(px && field[py][px-1]==FIELD_FLAME) {
|
||||
fl2=info[py][px-1];
|
||||
fl->lurd|=FL_LEFT;
|
||||
fl2->lurd|=FL_RIGHT;
|
||||
}
|
||||
if(py && field[py-1][px]==FIELD_FLAME) {
|
||||
fl2=info[py-1][px];
|
||||
fl->lurd|=FL_UP;
|
||||
fl2->lurd|=FL_DOWN;
|
||||
}
|
||||
if(px<arraynumx-1 && field[py][px+1]==FIELD_FLAME) {
|
||||
fl2=info[py][px+1];
|
||||
fl->lurd|=FL_RIGHT;
|
||||
fl2->lurd|=FL_LEFT;
|
||||
}
|
||||
if(py<arraynumy-1 && field[py+1][px]==FIELD_FLAME) {
|
||||
fl2=info[py+1][px];
|
||||
fl->lurd|=FL_DOWN;
|
||||
fl2->lurd|=FL_UP;
|
||||
}
|
||||
}
|
||||
|
||||
static void dropbomb(player *pl,int px,int py,int type){
|
||||
bomb *bmb;
|
||||
|
||||
if(field[py][px]!=FIELD_EMPTY) return;
|
||||
bmb=allocentry();
|
||||
if(!bmb) return;
|
||||
playsound(3);
|
||||
addtail(&activebombs,bmb);
|
||||
|
||||
--(pl->bombsavailable);
|
||||
field[py][px]=FIELD_BOMB;
|
||||
info[py][px]=bmb;
|
||||
bmb->type=type;
|
||||
bmb->px=px;
|
||||
bmb->py=py;
|
||||
bmb->xpos=arraytoscreenx(px);
|
||||
bmb->ypos=arraytoscreeny(py);
|
||||
bmb->power=pl->flamelength;
|
||||
bmb->owner=pl;
|
||||
}
|
||||
|
||||
static void adddetonate(bomb *bmb) {
|
||||
if(bmb->type==BOMB_OFF) return;
|
||||
|
||||
bmb->type=BOMB_OFF;
|
||||
field[bmb->py][bmb->px]=FIELD_EXPLODING;
|
||||
info[bmb->py][bmb->px]=0;
|
||||
detonated[detonateput++]=bmb;
|
||||
detonateput%=MAXBOMBSDETONATED;
|
||||
}
|
||||
|
||||
static void processbombs() {
|
||||
bomb *bmb;
|
||||
|
||||
bmb=activebombs.next;
|
||||
while(bmb) {
|
||||
switch(bmb->type) {
|
||||
case BOMB_NORMAL:
|
||||
++bmb->timer;
|
||||
if(bmb->timer==BOMBLIFE)
|
||||
adddetonate(bmb);
|
||||
++(bmb->figcount);
|
||||
break;
|
||||
case BOMB_CONTROLLED:
|
||||
++(bmb->figcount);
|
||||
break;
|
||||
}
|
||||
bmb=bmb->next;
|
||||
}
|
||||
}
|
||||
|
||||
static void adddecay(int px,int py) {
|
||||
brickdecay *bd;
|
||||
int xpos,ypos;
|
||||
|
||||
bd=allocentry();
|
||||
if(!bd) return;
|
||||
field[py][px]=FIELD_EXPLODING;
|
||||
bd->xpos=arraytoscreenx(px);
|
||||
bd->ypos=arraytoscreeny(py);
|
||||
bd->px=px;
|
||||
bd->py=py;
|
||||
addtail(&activedecays,bd);
|
||||
xpos=tovideox(bd->xpos);
|
||||
ypos=tovideoy(bd->ypos);
|
||||
solidcopyany(&backgroundoriginal,&background,xpos,ypos,
|
||||
arrayspacex,arrayspacey);
|
||||
solidcopy(&background,xpos,ypos,arrayspacex,arrayspacey);
|
||||
}
|
||||
|
||||
static void addbonus(int px,int py,int type) {
|
||||
bonustile *bonus;
|
||||
|
||||
bonus=allocentry();
|
||||
if(!bonus) return;
|
||||
addtail(&activebonus,bonus);
|
||||
bonus->px=px;
|
||||
bonus->py=py;
|
||||
bonus->xpos=arraytoscreenx(px);
|
||||
bonus->ypos=arraytoscreeny(py);
|
||||
bonus->type=type;
|
||||
field[py][px]=FIELD_BONUS;
|
||||
info[py][px]=bonus;
|
||||
}
|
||||
|
||||
static void trybonus(int px,int py) {
|
||||
int i=0, r;
|
||||
const int *p;
|
||||
|
||||
if(field[py][px]!=FIELD_EMPTY) return;
|
||||
p=bonuschances;
|
||||
r=myrand()%bonustotal;
|
||||
while(r>=0) {
|
||||
i=*p++;
|
||||
r-=*p++;
|
||||
}
|
||||
if(i==TILE_NONE) return;
|
||||
addbonus(px,py,i);
|
||||
}
|
||||
|
||||
static void deletebonus(bonustile *bonus) {
|
||||
int px,py;
|
||||
|
||||
px=bonus->px;
|
||||
py=bonus->py;
|
||||
field[py][px]=0;
|
||||
info[py][px]=0;
|
||||
delink(&activebonus,bonus);
|
||||
}
|
||||
|
||||
static void flameshaft(player *owner,int px,int py,int dx,int dy,int power) {
|
||||
int there;
|
||||
bomb *bmb;
|
||||
|
||||
while(power--) {
|
||||
px+=dx;
|
||||
py+=dy;
|
||||
if(px<0 || py<0 || px>=arraynumx || py>=arraynumy) break;
|
||||
there=field[py][px];
|
||||
switch(there) {
|
||||
case FIELD_BOMB:
|
||||
bmb=info[py][px];
|
||||
adddetonate(bmb);
|
||||
break;
|
||||
case FIELD_EMPTY:
|
||||
addflame(owner,px,py);
|
||||
break;
|
||||
case FIELD_BRICK:
|
||||
adddecay(px,py);
|
||||
power=0;
|
||||
break;
|
||||
case FIELD_BONUS:
|
||||
deletebonus(info[py][px]);
|
||||
power=0;
|
||||
break;
|
||||
case FIELD_BORDER:
|
||||
case FIELD_EXPLODING:
|
||||
default:
|
||||
power=0;
|
||||
case FIELD_FLAME:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void detonatebomb(bomb *bmb) {
|
||||
int px,py;
|
||||
int power;
|
||||
player *owner;
|
||||
|
||||
++(bmb->owner->bombsavailable);
|
||||
px=bmb->px;
|
||||
py=bmb->py;
|
||||
power=bmb->power;
|
||||
owner=bmb->owner;
|
||||
delink(&activebombs,bmb);
|
||||
addflame(owner,px,py);
|
||||
flameshaft(owner,px,py,-1,0,power);
|
||||
flameshaft(owner,px,py,0,-1,power);
|
||||
flameshaft(owner,px,py,1,0,power);
|
||||
flameshaft(owner,px,py,0,1,power);
|
||||
}
|
||||
|
||||
static void dodetonations(void) {
|
||||
int i=0;
|
||||
|
||||
while(detonatetake!=detonateput) {
|
||||
++i;
|
||||
detonatebomb(detonated[detonatetake]);
|
||||
detonatetake=(detonatetake+1) % MAXBOMBSDETONATED;
|
||||
}
|
||||
if(i) playsound((myrand()&1) ? 0 : 4);
|
||||
}
|
||||
|
||||
static void processflames(void) {
|
||||
flame *fl,*fl2;
|
||||
|
||||
fl=activeflames.next;
|
||||
while(fl) {
|
||||
++(fl->timer);
|
||||
fl=fl->next;
|
||||
}
|
||||
fl=activeflames.next;
|
||||
while(fl) {
|
||||
if(fl->timer==FLAMELIFE)
|
||||
{
|
||||
field[fl->py][fl->px]=FIELD_EMPTY;
|
||||
info[fl->py][fl->px]=0;
|
||||
fl2=fl;
|
||||
fl=fl->next;
|
||||
delink(&activeflames,fl2);
|
||||
} else
|
||||
fl=fl->next;
|
||||
}
|
||||
}
|
||||
|
||||
static void processdecays() {
|
||||
brickdecay *bd,*bd2;
|
||||
|
||||
bd=activedecays.next;
|
||||
while(bd) {
|
||||
++(bd->timer);
|
||||
if(bd->timer==DECAYLIFE) {
|
||||
field[bd->py][bd->px]=FIELD_EMPTY;
|
||||
trybonus(bd->px,bd->py);
|
||||
bd2=bd;
|
||||
bd=bd->next;
|
||||
delink(&activedecays,bd2);
|
||||
} else
|
||||
bd=bd->next;
|
||||
}
|
||||
}
|
||||
|
||||
static void drawbombs(void) {
|
||||
int j;
|
||||
bomb *bmb;
|
||||
struct figure *figtab;
|
||||
int color;
|
||||
int xpos,ypos;
|
||||
|
||||
bmb=activebombs.next;
|
||||
while(bmb) {
|
||||
color=bmb->owner->color;
|
||||
figtab=(bmb->type==BOMB_NORMAL) ? bombs1[color] : bombs2[color];
|
||||
j=bmb->figcount % (NUMBOMBFRAMES<<1);
|
||||
if(j>=NUMBOMBFRAMES) j=(NUMBOMBFRAMES<<1)-j-1;
|
||||
xpos=tovideox(bmb->xpos);
|
||||
ypos=tovideoy(bmb->ypos)-3;
|
||||
|
||||
addsprite(xpos,ypos,figtab+j);
|
||||
bmb=bmb->next;
|
||||
}
|
||||
}
|
||||
|
||||
static void drawflames(void) {
|
||||
flame *fl;
|
||||
int xpos,ypos;
|
||||
int color;
|
||||
int fig;
|
||||
|
||||
fl=activeflames.next;
|
||||
while(fl) {
|
||||
color=fl->owner->color;
|
||||
xpos=tovideox(fl->xpos);
|
||||
ypos=tovideoy(fl->ypos);
|
||||
fig=(fl->timer*10)/FLAMELIFE;
|
||||
if(fig>=5) fig=9-fig;
|
||||
fig+=5*fl->lurd;
|
||||
addsprite(xpos,ypos,flamefigs[0/* color */]+fig);
|
||||
fl=fl->next;
|
||||
}
|
||||
}
|
||||
|
||||
static void drawdecays() {
|
||||
brickdecay *bd;
|
||||
|
||||
bd=activedecays.next;
|
||||
while(bd) {
|
||||
addsprite(tovideox(bd->xpos),tovideoy(bd->ypos),
|
||||
blocksx+(bd->timer*9)/DECAYLIFE);
|
||||
bd=bd->next;
|
||||
}
|
||||
}
|
||||
|
||||
static void drawbonus() {
|
||||
bonustile *bonus;
|
||||
|
||||
bonus=activebonus.next;
|
||||
while(bonus) {
|
||||
addsprite(tovideox(bonus->xpos),tovideoy(bonus->ypos),
|
||||
tiles+bonus->type);
|
||||
bonus=bonus->next;
|
||||
}
|
||||
}
|
||||
|
||||
static void drawplayers() {
|
||||
player *pl;
|
||||
int xpos,ypos;
|
||||
|
||||
pl=activeplayers.next;
|
||||
|
||||
while(pl) {
|
||||
if(!(pl->flags & FLG_DEAD)) {
|
||||
if(!pl->figure)
|
||||
pl->figure=walking[pl->color]+30;
|
||||
xpos=tovideox(pl->xpos)+pl->fixx;
|
||||
ypos=tovideoy(pl->ypos)+pl->fixy;
|
||||
addsprite(xpos,ypos,pl->figure);
|
||||
}
|
||||
pl=pl->next;
|
||||
}
|
||||
}
|
||||
|
||||
static void detonatecontrolled(player *pl) {
|
||||
bomb *bmb;
|
||||
|
||||
bmb=activebombs.next;
|
||||
while(bmb) {
|
||||
if(bmb->owner==pl && bmb->type==BOMB_CONTROLLED)
|
||||
adddetonate(bmb);
|
||||
bmb=bmb->next;
|
||||
}
|
||||
}
|
||||
|
||||
static void playonce(generic *gen) {
|
||||
if(gen->timer==gen->data1)
|
||||
delink(&activegeneric,gen);
|
||||
}
|
||||
|
||||
static void drawgeneric(generic *gen) {
|
||||
addsprite(gen->xpos,gen->ypos,((figure *)(gen->ptr1))+gen->timer);
|
||||
}
|
||||
|
||||
static void queuesequence(int xpos,int ypos,figure *fig,int count) {
|
||||
generic *gen;
|
||||
|
||||
gen=allocentry();
|
||||
if(!gen) return;
|
||||
gen->xpos=xpos;
|
||||
gen->ypos=ypos;
|
||||
gen->data1=count;
|
||||
gen->process=playonce;
|
||||
gen->draw=drawgeneric;
|
||||
gen->ptr1=fig;
|
||||
addtail(&activegeneric,gen);
|
||||
}
|
||||
|
||||
static void adddeath(player *pl) {
|
||||
int xpos,ypos;
|
||||
|
||||
xpos=tovideox(pl->xpos)+pl->fixx-10;
|
||||
ypos=tovideoy(pl->ypos)+pl->fixy;
|
||||
queuesequence(xpos,ypos,death,NUMDEATHFRAMES);
|
||||
}
|
||||
|
||||
static void killplayer(player *pl) {
|
||||
pl->flags|=FLG_DEAD;
|
||||
playsound(2);
|
||||
adddeath(pl);
|
||||
detonatecontrolled(pl);
|
||||
}
|
||||
|
||||
static void processgenerics(void) {
|
||||
generic *gen,*gen2;
|
||||
|
||||
gen=activegeneric.next;
|
||||
while(gen) {
|
||||
gen2=gen;
|
||||
gen=gen->next;
|
||||
++(gen2->timer);
|
||||
gen2->process(gen2);
|
||||
}
|
||||
}
|
||||
|
||||
static void drawgenerics(void) {
|
||||
generic *gen;
|
||||
|
||||
gen=activegeneric.next;
|
||||
while(gen) {
|
||||
gen->draw(gen);
|
||||
gen=gen->next;
|
||||
}
|
||||
}
|
||||