From 58b60d1455a6670cbfb1572257460065fe7e6207 Mon Sep 17 00:00:00 2001 From: Ian C Date: Wed, 13 May 2020 20:25:51 +0000 Subject: Builds (just) and runs. --- dash.c | 3400 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 3400 insertions(+) create mode 100644 dash.c (limited to 'dash.c') diff --git a/dash.c b/dash.c new file mode 100644 index 0000000..0c124ce --- /dev/null +++ b/dash.c @@ -0,0 +1,3400 @@ +/* + + Simple boulder dash clone for X11/xlib/curses + + Needs a fast-ish machine - uses quite a few raster scans of the level + on each game cycle. + + ...And the curses/X pointer code could be neater and better thought out... + + ... It is only a hack though :-) ... + +*/ + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "Xbit.h" + +#define WINX 100 +#define WINY 100 +#define WINW 640 +#define WINH 400 + +#define RND(x) ((rand())%(x)) + +/* Slightly roundabout, but allows us to test the op +*/ +#ifdef NOUSLEEP +# define USLEEP(x) LocalUsleep(x) +#else +# define USLEEP(x) usleep(x) +#endif + +XSizeHints size_hints; +ulong black,white; +Display *disp; +Window window; +Colormap cm; +XFontStruct *font; + +char *GetPath(), + *GetFXPath(), + *GetLevelPath(), + *GetLibPath(); + +#define SPACESPRNAME "space" +#define EARTHSPRNAME "earth" +#define ROCKSPRNAME "rock" +#define ROCKFALLSPRNAME ROCKSPRNAME +#define TUFFWALLSPRNAME "tuffwall" +#define WALLSPRNAME "wall" +#define GEMSPRNAME "diamond" +#define GEMFALLSPRNAME GEMSPRNAME +#define HEROSPRNAME "miner" +#define EXITSPRNAME "exit" +#define BUTTSPRNAME "butterfly" +#define CHSRSPRNAME "chaser" +#define ROCKSWSPRNAME "rockswitch" +#define ONEUPSPRNAME "oneup" +#define FILTERSPRNAME "filter" +#define AMOEBASPRNAME "amoeba" +#define ROCKGENSPRNAME "rockgen" +#define BUTTGENSPRNAME "butterflygen" +#define CHSRGENSPRNAME "chasergen" + +#define SPACEGLY ' ' +#define EARTHGLY '.' +#define ROCKGLY '@' +#define TUFFWALLGLY '%' +#define WALLGLY '#' +#define GEMGLY '*' +#define HEROGLY 'R' +#define EXITGLY 'E' +#define BUTTGLY 'B' +#define CHSRGLY 'C' +#define ROCKSWGLY '!' +#define ONEUPGLY '&' +#define FILTERGLY '$' +#define AMOEBAGLY 'A' +#define ROCKGENGLY 'r' +#define BUTTGENGLY 'b' +#define CHSRGENGLY 'c' + +#define SPACESPR 0 +#define EARTHSPR 1 +#define ROCKSPR 2 +#define TUFFWALLSPR 3 +#define WALLSPR 4 +#define GEMSPR 5 +#define HEROSPR 6 +#define EXITSPR 7 +#define ROCKFALLSPR 8 +#define GEMFALLSPR 9 +#define BUTTSPR 10 +#define CHSRSPR 11 +#define ROCKSWSPR 12 +#define ONEUPSPR 13 +#define FILTERSPR 14 +#define AMOEBASPR 15 +#define ROCKGENSPR 16 +#define BUTTGENSPR 17 +#define CHSRGENSPR 18 +#define NOSPR 19 + +#define VOIDSPR -1 + +#define X(x) ((x)*chsz) +#define Y(y) ((y)*chsz) + +#define SCRX 40 +#define SCRY 24 + +typedef struct + { + char *name; + Pixmap p; + } sprite; + +sprite spr[NOSPR]= + { + {SPACESPRNAME,0}, + {EARTHSPRNAME,0}, + {ROCKSPRNAME,0}, + {TUFFWALLSPRNAME,0}, + {WALLSPRNAME,0}, + {GEMSPRNAME,0}, + {HEROSPRNAME,0}, + {EXITSPRNAME,0}, + {ROCKFALLSPRNAME,0}, + {GEMFALLSPRNAME,0}, + {BUTTSPRNAME,0}, + {CHSRSPRNAME,0}, + {ROCKSWSPRNAME,0}, + {ONEUPSPRNAME,0}, + {FILTERSPRNAME,0}, + {AMOEBASPRNAME,0}, + {ROCKGENSPRNAME,0}, + {BUTTGENSPRNAME,0}, + {CHSRGENSPRNAME,0} + }; + +char glyph_map[NOSPR]= + { + /* SPACESPR */ ' ', + /* EARTHSPR */ '.', + /* ROCKSPR */ '@', + /* TUFFWALLSPR */ '#', + /* WALLSPR */ '+', + /* GEMSPR */ '*', + /* HEROSPR */ '&', + /* EXITSPR */ 'E', + /* ROCKFALLSPR */ '@', + /* GEMFALLSPR */ '*', + /* BUTTSPR */ '%', + /* CHSRSPR */ '"', + /* ROCKSWSPR */ '^', + /* ONEUPSPR */ '$', + /* FILTERSPR */ '=', + /* AMOEBASPR */ '~', + /* ROCKGENSPR */ '+', + /* BUTTGENSPR */ '+', + /* CHSRGENSPR */ '+' + }; + +#define MAX_ENEMY 2000 +#define MAX_GENERATOR 100 + +typedef struct + { + int alive; + int type; + int x,y; + int dir; + int moved; + } Enemy; + +typedef struct + { + int cycle; + int type; + int x,y; + } Generator; + +Enemy enemy[MAX_ENEMY]; +Generator generator[MAX_GENERATOR]; +int no_enemy; +int no_generator; + + +#define AMOEBA_COUNT 5 + +typedef struct + { + int alive; + int count; + int size; + int could_move; + } Amoeba; + +Amoeba amoeba; +int max_amoeba_size; +int amoeba_move_chance; + + +#define WELLDONELEV -1 +#define TRYAGAINLEV -2 + +typedef struct + { + int sx,sy; + int ex,ey; + int x,y; + int time; + int no; + int toget; + int w,h; + char *name; + char *data; + } Level; + + +#define NONE -1 +#define UP 0 +#define RIGHT 1 +#define DOWN 2 +#define LEFT 3 + +#define ROT_RIGHT(d) ((((d)+1)>LEFT) ? (UP) : ((d)+1)) +#define ROT_LEFT(d) ((((d)-1)0) + while(lev.time) + { + lev.time--; + score+=5; + DrawScore(); + (*Update)(); + } + + for(f=0;f-1) + (*Show)(LevelNotOk,True,False); + } + } while ((lives>-1)&&(level<=no_levels)); + + (*Cls)(black); + + if (lives==-1) + (*GameLost)(); + else + (*GameWon)(); + + if(score>hisc[MAX_HISCORE-1].score) + EnterHiscore(); + + (*Cls)(black); + title_fr=True; + (*Show)(TitlePage,False,True); + } + + AutoOn(); + + (*EndWindowing)(); +} + + +void IntrHandler() +{ + if (EndWindowing) + (*EndWindowing)(); + + AutoOn(); + + exit(0); +} + +/* --------------------------------------------------------------------- */ + + +AutoOff() + +{ + if (!cursesmode) + { + XAutoRepeatOff(disp); + (*Update)(); + } +} + + +AutoOn() + +{ + if (!cursesmode) + { + XAutoRepeatOn(disp); + (*Update)(); + } +} + + +/* --------------------------------------------------------------------- */ + +char *GetPath() +{ + static char *env=NULL; + char *p; + + if (!env) + { + if (p=getenv("DASHPATH")) + { + env=malloc(strlen(p)+5); + + strcpy(env,p); + + if (env[strlen(env)-1]!='/') + strcat(env,"/"); + } + else + env=strdup("./"); + } + + return(env); +} + + +char *GetFXPath(s) +char *s; + +{ + static char r[256]; + char *p; + + strcpy(r,GetPath()); + + if (bw) + { + if (chsz==16) + strcat(r,"GFX16/"); + else + strcat(r,"GFX8/"); + } + else + { + if (chsz==16) + strcat(r,"GFX16COL/"); + else + strcat(r,"GFX8COL/"); + } + + strcat(r,s); + + return(r); +} + + +char *GetLevelPath(s) +char *s; + +{ + static char r[256]; + char *p; + + strcpy(r,GetPath()); + + if (cursesmode) + strcat(r,"CLEVELS/"); + else + strcat(r,"XLEVELS/"); + + strcat(r,s); + + return(r); +} + + +char *GetLibPath(s) +char *s; + +{ + static char r[256]; + char *p; + + strcpy(r,GetPath()); + + strcat(r,"lib/"); + + strcat(r,s); + + return(r); +} + + +LoadScores() + +{ + int fd,f; + + if ((fd=open(GetLibPath("score"),O_RDONLY))==-1) + return; + + for(f=0;fMAX_ENEMY) + { + fprintf(stderr,"Error! To many enemies level file!\n"); + AutoOn(); + Exit(1); + } + break; + case CHSRGLY: + AT(x,y)=CHSRSPR; + enemy[no_enemy].alive=True; + enemy[no_enemy].type=CHSRSPR; + enemy[no_enemy].x=x; + enemy[no_enemy].y=y; + enemy[no_enemy].dir=UP; + enemy[no_enemy].moved=False; + if ((++no_enemy)>MAX_ENEMY) + { + fprintf(stderr,"Error! To many enemies level file!\n"); + AutoOn(); + Exit(1); + } + break; + case ROCKSWGLY: + AT(x,y)=ROCKSWSPR; + break; + case ONEUPGLY: + AT(x,y)=ONEUPSPR; + break; + case FILTERGLY: + AT(x,y)=FILTERSPR; + break; + case AMOEBAGLY: + AT(x,y)=AMOEBASPR; + if (amoeba.alive) + { + amoeba.size++; + } + else + { + amoeba.alive=True; + amoeba.size=1; + amoeba.count=AMOEBA_COUNT; + amoeba.could_move=False; + } + break; + case ROCKGENGLY: + AT(x,y)=ROCKGENSPR; + generator[no_generator].cycle=0; + generator[no_generator].type=ROCKGENSPR; + generator[no_generator].x=x; + generator[no_generator].y=y; + if ((++no_generator)>MAX_GENERATOR) + { + fprintf(stderr,"Error! To many generators!\n"); + AutoOn(); + Exit(1); + } + break; + case BUTTGENGLY: + AT(x,y)=BUTTGENSPR; + generator[no_generator].cycle=0; + generator[no_generator].type=BUTTGENSPR; + generator[no_generator].x=x; + generator[no_generator].y=y; + if ((++no_generator)>MAX_GENERATOR) + { + fprintf(stderr,"Error! To many generators!\n"); + AutoOn(); + Exit(1); + } + break; + case CHSRGENGLY: + AT(x,y)=CHSRGENSPR; + generator[no_generator].cycle=0; + generator[no_generator].type=CHSRGENSPR; + generator[no_generator].x=x; + generator[no_generator].y=y; + if ((++no_generator)>MAX_GENERATOR) + { + fprintf(stderr,"Error! To many generators!\n"); + AutoOn(); + Exit(1); + } + break; + default: + break; + } + + fgets(s,256,fp); + } + + if ((lev.sx==-1)) + { + fprintf(stderr,"Error! No miner in level file!\n"); + AutoOn(); + Exit(1); + } + + if ((lev.ex==-1)) + { + fprintf(stderr,"Error! No exit in level file!\n"); + AutoOn(); + Exit(1); + } +} + +PutX(x,y,n) + +{ + XPut(spr[n].p,0,0,chsz,chsz,X(x),Y(y)); +} + +XCentre(s,y,c) +char *s; +int y,c; + +{ + XPrint(X(SCRX)/2-strlen(s)*((font->max_bounds.width)>>1),y,s,c); +} + + +CursesCentre(s,y,c) +char *s; +int y,c; + +{ + /* mvaddstr(y,SCRX/2-strlen(s)/2,s); */ + mvaddstr(y,COLS/2-strlen(s)/2,s); +} + + +DoTillPress(f,s,qf) +int (*f)(); +int s,qf; + +{ + XEvent e; + + if(XPending(disp)) + XNextEvent(disp,&e); + + while(1) + { + if ((slp>-1)&&(s)) + USLEEP(slp); + + if(XPending(disp)) + { + XNextEvent(disp,&e); + + switch(e.type) + { + case KeyPress: + switch(XLookupKeysym((XKeyEvent *)&e,ShiftMapIndex)) + { + case XK_space: + return; + break; + + case XK_Escape: + if (qf) + { + quit=True; + return; + } + break; + + default: + break; + } + break; + + case ButtonPress: + return; + break; + default: + break; + } + } + + (*f)(); + } +} + +/* --------------------------------------------------------------------- */ + +#define TITLEBLKS 44 +#define TBX(x1,x2) (14+(x1*4)+x2) +#define TBY(y) (5+(y)) + +static struct + { + int x,y; + } title_bl[TITLEBLKS]= + { + {TBX(0,0), TBY(4)}, /* D */ + {TBX(0,1), TBY(4)}, /* D */ + {TBX(0,0), TBY(3)}, /* D */ + {TBX(0,2), TBY(3)}, /* D */ + {TBX(0,0), TBY(2)}, /* D */ + {TBX(0,2), TBY(2)}, /* D */ + {TBX(0,0), TBY(1)}, /* D */ + {TBX(0,2), TBY(1)}, /* D */ + {TBX(0,0), TBY(0)}, /* D */ + {TBX(0,1), TBY(0)}, /* D */ + + {TBX(1,0), TBY(4)}, /* A */ + {TBX(1,2), TBY(4)}, /* A */ + {TBX(1,0), TBY(3)}, /* A */ + {TBX(1,2), TBY(3)}, /* A */ + {TBX(1,0), TBY(2)}, /* A */ + {TBX(1,1), TBY(2)}, /* A */ + {TBX(1,2), TBY(2)}, /* A */ + {TBX(1,0), TBY(1)}, /* A */ + {TBX(1,2), TBY(1)}, /* A */ + {TBX(1,0), TBY(0)}, /* A */ + {TBX(1,1), TBY(0)}, /* A */ + {TBX(1,2), TBY(0)}, /* A */ + + {TBX(2,0), TBY(4)}, /* S */ + {TBX(2,1), TBY(4)}, /* S */ + {TBX(2,2), TBY(4)}, /* S */ + {TBX(2,2), TBY(3)}, /* S */ + {TBX(2,2), TBY(2)}, /* S */ + {TBX(2,1), TBY(2)}, /* S */ + {TBX(2,0), TBY(2)}, /* S */ + {TBX(2,0), TBY(1)}, /* S */ + {TBX(2,0), TBY(0)}, /* S */ + {TBX(2,1), TBY(0)}, /* S */ + {TBX(2,2), TBY(0)}, /* S */ + + {TBX(3,0), TBY(4)}, /* H */ + {TBX(3,2), TBY(4)}, /* H */ + {TBX(3,0), TBY(3)}, /* H */ + {TBX(3,2), TBY(3)}, /* H */ + {TBX(3,0), TBY(2)}, /* H */ + {TBX(3,1), TBY(2)}, /* H */ + {TBX(3,2), TBY(2)}, /* H */ + {TBX(3,0), TBY(1)}, /* H */ + {TBX(3,2), TBY(1)}, /* H */ + {TBX(3,0), TBY(0)}, /* H */ + {TBX(3,2), TBY(0)} /* H */ + }; + + +int XTitle() + +{ + static int fr=True; + static int bln=0; + static int x=0; + static int y=0; + static int sc=0; + static int sct=0; + char s[128]; + int f; + + if (title_fr) + { + x=title_bl[0].x; + y=0; + title_fr=False; + LoadScores(); + + sc=0; + bln=0; + sct=0; + + (*Centre)("ALL TIME DASHERS",Y(12),white); + + if (!cursesmode) + { + (*Printf)(0,Y(13),white,"%3s %7s %-*s %3s", + "Pos","Score",HINAMELEN,"Name","Level"); + + (*Centre)("Press Escape to quit",Y(SCRY-4),white); + } + else + (*Centre)("^C to quit",Y(SCRY-4),white); + + (*Centre)("Press Space to continue",Y(SCRY-2),white); + } + + if (!cursesmode) + { + XFillBox(0,Y(14),X(SCRX),Y(3),black); + + (*Printf)(0,Y(15),white,"%3d %7d %-*s %3d", + sc+1,hisc[sc].score,HINAMELEN,hisc[sc].name,hisc[sc].level); + } + else + { + (*Printf)(0,Y(15),white,"Pos : %-2d",sc+1); + (*Printf)(0,Y(16),white,"Name : %-*s",HINAMELEN,hisc[sc].name); + (*Printf)(0,Y(17),white,"Score : %-7d",hisc[sc].score); + (*Printf)(0,Y(18),white,"Level : %-3d",hisc[sc].level); + } + + if (sct++==100) + { + sct=0; + if (++sc==MAX_HISCORE) + sc=0; + } + + if (y>=title_bl[bln].y) + if (++blnY(SCRY)) + { + ispr[f].x=X(RND(SCRX)); + ispr[f].y=-chsz; + } + } + + sprintf(s,"Level %d",level); + (*Centre)(s,Y(3),white); + + sprintf(s,"'%s'",lev.name); + (*Centre)(s,Y(5),white); + + (*Centre)("Press Space to continue",Y(SCRY-2),white); + + (*Update)(); + + return(XFUNCCONT); +} + +/* --------------------------------------------------------------------- */ + +int LevelOk() + +{ + static int ix=1; + int x,y; + + if (fr_flag) + { + fr_flag=False; + + LoadLevel(WELLDONELEV); + + ix=1; + + (*Cls)(black); + (*Repaint)(True); + } + else + (*Repaint)(False); + + lev.x+=ix; + + if ((lev.x==0)||(lev.x==lev.w-SCRX)) + { + ix=-ix; + + for(x=0;x=80) + (*Printf)(0,0,white, + "Score %7d Collect %3d Got %3d Lives %2d Time %4d", + score,lev.toget,lev.no,lives,lev.time); + else + (*Printf)(0,0,white,"S:%-7d C:%-3d G:%-3d L:%-2d T:%-4d", + score,lev.toget,lev.no,lives,lev.time); +} + + +XUpdate() + +{ + Redraw(0,0); +} + + +XRepaint(full) + +{ + static char scr[SCRX][SCRY]; + static int lx,ly; + int x,y,px,py; + + if (full) + { + lx=lev.x; + ly=lev.y; + + for(y=0;y0;x--) + for(y=0;y0;y--) + scr[x][y]=scr[x][y-1]; + + for(x=0;x-1)&&(py>-1)) + { + if (scr[x][y]!=AT(px,py)) + { + (*Put)(x,y,AT(px,py)); + scr[x][y]=AT(px,py); + } + } + else + if (scr[x][y]!=SPACESPR) + { + (*Put)(x,y,SPACESPR); + scr[x][y]=SPACESPR; + } + } + + lx=lev.x; + ly=lev.y; +} + +/* --------------------------------------------------------------------- */ +#define MOVE_AMOEBA(x,y) ((AT(x,y)==SPACESPR)||(AT(x,y)==EARTHSPR)) + +CheckAmoebaMove(x,y) + +{ + int r=False; + + if (MOVE_AMOEBA(x-1,y)) + { + r=True; + if (RND(100)>amoeba_move_chance) + { + AT(x-1,y)=AMOEBASPR; + amoeba.size++; + } + } + + if (MOVE_AMOEBA(x+1,y)) + { + r=True; + if (RND(100)>amoeba_move_chance) + { + AT(x+1,y)=AMOEBASPR; + amoeba.size++; + } + } + + if (MOVE_AMOEBA(x,y-1)) + { + r=True; + if (RND(100)>amoeba_move_chance) + { + AT(x,y-1)=AMOEBASPR; + amoeba.size++; + } + } + + if (MOVE_AMOEBA(x,y+1)) + { + r=True; + if (RND(100)>amoeba_move_chance) + { + AT(x,y+1)=AMOEBASPR; + amoeba.size++; + } + } + + return(r); +} + +HandleAmoeba() + +{ + int f,x,y,d; + + if (amoeba.alive) + if (!(--amoeba.count)) + { + amoeba.count=AMOEBA_COUNT; + amoeba.could_move=False; + + for(y=0;ymax_amoeba_size) + { + for(y=0;yx,g->y)=g->type; /* Make generators 'indestructible' */ + + if (!((g->cycle++)%20)) + switch(g->type) + { + case ROCKGENSPR: + if (AT(g->x,g->y+1)==SPACESPR) + AT(g->x,g->y+1)=ROCKFALLSPR; + break; + + case BUTTGENSPR: + GenerateMonsters(g->x,g->y,BUTTSPR); + break; + + case CHSRGENSPR: + GenerateMonsters(g->x,g->y,CHSRSPR); + break; + + default: + break; + } + } +} + + +/* --------------------------------------------------------------------- */ + +CheckEnemyMove(e,d) +Enemy *e; +int d; + +{ + switch(AT((e)->x+move_tbl[(d)].x,(e)->y+move_tbl[(d)].y)) + { + case SPACESPR: + case HEROSPR: + return(True); + break; + default: + return(False); + break; + } +} + +#define ISDESTRUCT(c) \ + ((c==SPACESPR)|| \ + (c==EARTHSPR)|| \ + (c==ROCKSPR)|| \ + (c==WALLSPR)|| \ + (c==GEMSPR)|| \ + (c==HEROSPR)|| \ + (c==ROCKFALLSPR)|| \ + (c==GEMFALLSPR)|| \ + (c==BUTTSPR)|| \ + (c==CHSRSPR)) + +HandleEnemies() + +{ + int f; + + for(f=0;fx,e->y)) + { + case ROCKFALLSPR: + case GEMFALLSPR: + e->alive=False; + score+=20; + for(x=-1;x<2;x++) + for(y=-1;y<2;y++) + if (ISDESTRUCT(AT(e->x+x,e->y+y))) + AT(e->x+x,e->y+y)=GEMFALLSPR; + return; + break; + + default: + AT(e->x,e->y)=SPACESPR; + + if (CheckEnemyMove(e,e->dir)) + { + e->x+=move_tbl[e->dir].x; + e->y+=move_tbl[e->dir].y; + } + else + { + if (CheckEnemyMove(e,ROT_RIGHT(e->dir))) + e->dir=ROT_RIGHT(e->dir); + else + e->dir=ROT_LEFT(e->dir); + } + AT(e->x,e->y)=BUTTSPR; + } +} + + +HandleChsr(e) +Enemy *e; + +{ + int x,y,f,od,md; + + switch (AT(e->x,e->y)) + { + case ROCKFALLSPR: + case GEMFALLSPR: + e->alive=False; + score+=20; + for(x=-1;x<2;x++) + for(y=-1;y<2;y++) + if (ISDESTRUCT(AT(e->x+x,e->y+y))) + AT(e->x+x,e->y+y)=ROCKFALLSPR; + return; + break; + + default: + AT(e->x,e->y)=SPACESPR; + + if ((od=e->dir)==NONE) + { + od=UP; + e->moved=False; + } + + if (e->dir!=NONE) + if(!CheckEnemyMove(e,e->dir)) + { + e->dir=NONE; + e->moved=False; + } + + if(e->moved) + { + md=e->dir; + e->dir=NONE; + } + else + md=NONE; + + /* Try moving in the X plane towards the sprite */ + if (e->dir==NONE) + { + x=lev.sx-e->x; + + if (x<0) + e->dir=LEFT; + else + e->dir=RIGHT; + + if (e->dir!=NONE) + if(!CheckEnemyMove(e,e->dir)) + e->dir=NONE; + } + + if (md!=NONE) + if (md==ROT_FLIP(e->dir)) + e->dir=NONE; + + /* Try moving in the Y plane towards the sprite */ + if (e->dir==NONE) + { + y=lev.sy-e->y; + + if (y<0) + e->dir=UP; + else + e->dir=LEFT; + + if (e->dir!=NONE) + if(!CheckEnemyMove(e,e->dir)) + e->dir=NONE; + } + + if (md!=NONE) + if (md==ROT_FLIP(e->dir)) + { + e->dir=md; + e->moved=True; + } + + /* Try any other direction */ + if (e->dir==NONE) + { + if (CheckEnemyMove(e,ROT_RIGHT(od))) + { + e->dir=ROT_RIGHT(od); + e->moved=True; + } + + if (e->dir==NONE) + if (CheckEnemyMove(e,ROT_LEFT(od))) + { + e->dir=ROT_LEFT(od); + e->moved=True; + } + + if (e->dir==NONE) + if (CheckEnemyMove(e,ROT_FLIP(od))) + { + e->dir=ROT_LEFT(od); + e->moved=True; + } + } + + if (e->dir!=NONE) + { + e->x+=move_tbl[e->dir].x; + e->y+=move_tbl[e->dir].y; + } + + AT(e->x,e->y)=CHSRSPR; + break; + } +} + + +HandleChsr_V2(e) +Enemy *e; + +{ + int x,y,b; + + switch (AT(e->x,e->y)) + { + case ROCKFALLSPR: + case GEMFALLSPR: + e->alive=False; + score+=20; + for(x=-1;x<2;x++) + for(y=-1;y<2;y++) + if (AT(e->x+x,e->y+y)!=TUFFWALLSPR) + AT(e->x+x,e->y+y)=ROCKFALLSPR; + return; + break; + + default: + + if (e->moved) + { + e->moved--; + return; + } + + e->moved=3; + + AT(e->x,e->y)=SPACESPR; + + e->dir=NONE; + + if (lev.syy) + e->dir=UP; + else + if (lev.sy>e->y) + e->dir=DOWN; + + if (e->dir!=NONE) + { + b=AT(e->x+move_tbl[e->dir].x,e->y+move_tbl[e->dir].y); + + if ((b!=SPACESPR)&&(b!=HEROSPR)) + e->dir=NONE; + } + + if (e->dir==NONE) + { + if (lev.sxx) + e->dir=LEFT; + else + if (lev.sx>e->x) + e->dir=RIGHT; + + if (e->dir!=NONE) + { + b=AT(e->x+move_tbl[e->dir].x,e->y+move_tbl[e->dir].y); + + if ((b!=SPACESPR)&&(b!=HEROSPR)) + e->dir=NONE; + } + } + + if (e->dir!=NONE) + { + e->x+=move_tbl[e->dir].x; + e->y+=move_tbl[e->dir].y; + } + + AT(e->x,e->y)=CHSRSPR; + } +} + + +HandleChsr_V1(e) +Enemy *e; + +{ + switch (AT(e->x,e->y)) + { + case ROCKFALLSPR: + case GEMFALLSPR: + e->alive=False; + score+=20; + return; + break; + + default: + AT(e->x,e->y)=SPACESPR; + + e->x+=move_tbl[e->dir].x; + e->y+=move_tbl[e->dir].y; + + if ((AT(e->x,e->y)!=SPACESPR)&&(AT(e->x,e->y)!=HEROSPR)) + { + e->x-=move_tbl[e->dir].x; + e->y-=move_tbl[e->dir].y; + + if ((++e->dir)>LEFT) + e->dir=UP; + } + AT(e->x,e->y)=CHSRSPR; + } +} + + +/* --------------------------------------------------------------------- */ + +CanMove(d) + +{ + if (d==NONE) + return(False); + + switch(AT(lev.sx+move_tbl[d].x,lev.sy+move_tbl[d].y)) + { + case ROCKSPR: + if ((d==LEFT)||(d==RIGHT)) + { + if (AT(lev.sx+move_tbl[d].x*2,lev.sy+move_tbl[d].y*2)==SPACESPR) + { + AT(lev.sx+move_tbl[d].x*2,lev.sy+move_tbl[d].y*2)=ROCKSPR; + AT(lev.sx+move_tbl[d].x,lev.sy+move_tbl[d].y)=SPACESPR; + } + else + return(False); + } + else + return(False); + break; + + case TUFFWALLSPR: + case WALLSPR: + case ROCKFALLSPR: + case GEMFALLSPR: + case AMOEBASPR: + case FILTERSPR: + case ROCKGENSPR: + case BUTTGENSPR: + case CHSRGENSPR: + return(False); + break; + + case EXITSPR: + if (lev.no>=lev.toget) + return(True); + else + return(False); + + + default: + return(True); + break; + } +} + + +CheckEnemies() + +{ + int f,x,y; + + for(f=0;f-1;y--) + for(x=0;x-1) + USLEEP(slp); + + for(f=0;f<4;f++) + if (released[f]) + { + pressed[f]=0; + released[f]=False; + + if (f==dir) + dir=NONE; + } + + if (dir==NONE) + { + kp=-1; + kpm=0; + + for(f=0;f<4;f++) + if (pressed[f]>kpm) + { + kpm=pressed[f]; + kp=f; + } + + if (kp!=-1) + dir=kp; + } + + if (shiftrelease) + { + shiftmode=False; + shiftrelease=False; + } + + while(XPending(disp)) + { + XNextEvent(disp,&e); + + switch(e.type) + { + case KeyPress: + switch(XLookupKeysym((XKeyEvent *)&e,ShiftMapIndex)) + { + case XK_Shift_L: + case XK_Shift_R: + shiftmode=True; + break; + + case XK_Up: + for(f=0;f<4;f++) + if (pressed[f]>0) + pressed[f]++; + + pressed[UP]=1; + dir=UP; + break; + + case XK_Left: + for(f=0;f<4;f++) + if (pressed[f]>0) + pressed[f]++; + + pressed[LEFT]=1; + dir=LEFT; + break; + + case XK_Down: + for(f=0;f<4;f++) + if (pressed[f]>0) + pressed[f]++; + + pressed[DOWN]=1; + dir=DOWN; + break; + + case XK_Right: + for(f=0;f<4;f++) + if (pressed[f]>0) + pressed[f]++; + + pressed[RIGHT]=1; + dir=RIGHT; + break; + + case XK_Q: + case XK_q: + dir=NONE; + return(False); + break; + + case XK_P: + case XK_p: + DoPause(); + (*Repaint)(True); + break; + + default: + dir=NONE; + } + break; + + case KeyRelease: + switch(XLookupKeysym((XKeyEvent *)&e,ShiftMapIndex)) + { + case XK_Shift_L: + case XK_Shift_R: + shiftrelease=True; + break; + + case XK_Up: + released[UP]=True; + break; + + case XK_Left: + released[LEFT]=True; + break; + + case XK_Down: + released[DOWN]=True; + break; + + case XK_Right: + released[RIGHT]=True; + break; + + default: + break; + } + break; + + default: + break; + } + } + + if (ok) + { + ok=CheckEnemies(); + + if ((shiftmode)&&(dir!=NONE)) + { + ok=HandlePush(dir,lev.sx+move_tbl[dir].x, + lev.sy+move_tbl[dir].y); + if (ok) + ok=Handle(AT(lev.sx,lev.sy)); + } + else + { + if(CanMove(dir)) + { + if (AT(lev.sx,lev.sy)==HEROSPR) + AT(lev.sx,lev.sy)=SPACESPR; + + lev.sx+=move_tbl[dir].x; + lev.sy+=move_tbl[dir].y; + ok=Handle(AT(lev.sx,lev.sy)); + AT(lev.sx,lev.sy)=HEROSPR; + } + else + ok=Handle(AT(lev.sx,lev.sy)); + } + } + + x=lev.sx-lev.x; + y=lev.sy-lev.y; + + if (x<10) + if (lev.x) + lev.x--; + + if (x>SCRX-10) + if (lev.x(SCRY-10)) + if (lev.y<(lev.h-SCRY+1)) + lev.y++; + + HandleGenerators(); + HandleEnemies(); + HandleAmoeba(); + + Gravity(); + + if (ok) + ok=Handle(AT(lev.sx,lev.sy)); + + (*Repaint)(False); + DrawScore(); + (*Update)(); + + if (!ok) + { + if ((lev.sx==lev.ex)&&(lev.sy==lev.ey)) + dt=0; + else + dt--; + } + else + { + if (++ti==10) + { + ti=0; + if (!(--lev.time)) + { + ok=False; + dt=40; + + for(x=0;x359) + a-=360; + } + + if ((gw_ang+=1)>359) + gw_ang-=360; + + if ((gw_cast_x+=gw_cast_inc) > X(SCRX)+X(NO_GW_SPR*2)) + { + gw_cast_x=0; + gw_intro_no=RND(NO_GW_INTRO); + if (++gw_cast_no==NO_GW_CAST) + gw_cast_no=0; + } + + (*Update)(); + + return(XFUNCCONT); +} + + +DoXGameOverWonLargeScale() + +{ + static int la=0; + static char s[100]; + int a; + double dx,dy; + int f; + + XFillBox(0,Y(2),X(SCRX),Y(2),black); + XFillBox(0,Y(SCRY-2),X(SCRX),Y(2),black); + + a=la; + for(f=0;f359) + a-=360; + } + + (*Centre)(gw_text[gw_text_no],Y(3),white); + + if (++gw_text_ti==100) + { + gw_text_ti=0; + if (++gw_text_no==NO_GW_LINES) + gw_text_no=0; + } + + sprintf(s,"%s %s",gw_intro[gw_intro_no],gw_cast[gw_cast_no].name); + (*Centre)(s,Y(SCRY-1),white); + + la=a=gw_ang; + for(f=0;f359) + a-=360; + } + + if ((gw_ang+=1)>359) + gw_ang-=360; + + if (++gw_cast_x==100) + { + gw_cast_x=0; + gw_intro_no=RND(NO_GW_INTRO); + if (++gw_cast_no==NO_GW_CAST) + gw_cast_no=0; + } + + (*Update)(); + + return(XFUNCCONT); +} + + +XGameOverWon() + +{ + score+=lives*2000; + + gw_cast_no=0; + gw_cast_x=0; + gw_intro_no=RND(NO_GW_INTRO); + gw_ang=0; + + gw_text_no=0; + gw_text_ti=0; + + if (chsz==8) + { + NO_GW_SPR=20; + gw_cast_inc=1; + (*Show)(DoXGameOverWonSmallScale,False); + } + else + { + NO_GW_SPR=5; + gw_cast_inc=3; + (*Show)(DoXGameOverWonLargeScale,False); + } +} + +XEndWindowing() +{ + /* X11 cleans up on exit anyway... */ +} + +/* --------------------------------------------------------------------- */ + +int CmpHi(a,b) +hiscore *a,*b; + +{ + int f; + + (*Cls)(black); + + (*Centre)("YOU GOT A HISCORE!!!!!!",Y(1),white); + + (*Printf)(0,Y(3),white,"%3s %7s %-*s %3s", + "Pos","Score",HINAMELEN,"Name","Level"); + + for(f=0;fscore-a->score); +} + + +int ShowTable() + +{ + int f; + + (*Cls)(black); + + (*Centre)("YOU GOT A HISCORE!!!!!!",Y(1),white); + + (*Printf)(0,Y(3),white,"%3s %7s %-*s %3s", + "Pos","Score",HINAMELEN,"Name","Level"); + + for(f=0;fpw_name,HINAMELEN); + hisc[MAX_HISCORE-1].score=score; + hisc[MAX_HISCORE-1].level=level; + + qsort(hisc,MAX_HISCORE,sizeof(hiscore),CmpHi); + + SaveScores(); + + (*Show)(ShowTable,False); +} + +/* --------------------------------------------------------------------- */ + +int CursesCls(c) +int c; +{ + erase(); +} + + +int CursesPut(x,y,c) +int x,y,c; +{ + mvaddch(y,x,glyph_map[c]); +} + + +int CursesRedraw() +{ + move(LINES-1,COLS-1); + refresh(); +} + + +int CursesRepaint(full) +int full; + +{ + int x,y,px,py; + + if (full) + for(x=0;x-1)&&(py>-1)) + mvaddch(y,x,glyph_map[AT(px,py)]); + else + mvaddch(y,x,glyph_map[SPACESPR]); + } +} + + +int CursesPrintf(int x, int y, int c, const char *fmt, ...) +{ + char s[128]; + va_list l; + + va_start(l, fmt); + + vsprintf(s,fmt,l); + + mvaddstr(y,x,s); + + va_end(l); +} + + +int CursesIntroLevel() +{ + char s[128]; + + (*Cls)(black); + + sprintf(s,"Level %d",level); + (*Centre)(s,Y(3),white); + + sprintf(s,"'%s'",lev.name); + (*Centre)(s,Y(5),white); + + (*Centre)("Press Space to continue",Y(SCRY-2),white); + + (*Update)(); + + return(XFUNCCONT); +} + + +int CursesPlayLevel() +{ + int dir=NONE; + int x,y,ok,ls,kp,kpm,dt,ti; + int f,r; + int shiftmode; + + AT(lev.sx,lev.sy)=HEROSPR; + (*Cls)(black); + (*Repaint)(True); + DrawScore(); + (*Update)(); + + ok=True; + dt=20; + ti=0; + + while(dt) + { + if (slp>-1) + USLEEP(slp); + + shiftmode=False; + + switch(getch()) + { + case KEY_DOWN: + dir=DOWN; + shiftmode=False; + break; + case KEY_UP: + dir=UP; + shiftmode=False; + break; + case KEY_LEFT: + dir=LEFT; + shiftmode=False; + break; + case KEY_RIGHT: + dir=RIGHT; + shiftmode=False; + break; + + case 'X': + case 'x': + dir=DOWN; + shiftmode=True; + break; + case 'W': + case 'w': + dir=UP; + shiftmode=True; + break; + case 'A': + case 'a': + dir=LEFT; + shiftmode=True; + break; + case 'D': + case 'd': + dir=RIGHT; + shiftmode=True; + break; + + case 'p': + case 'P': + DoPause(); + break; + case 'q': + case 'Q': + return(False); + break; + default: + dir=NONE; + } + flushinp(); + + if (ok) + { + ok=CheckEnemies(); + + if (shiftmode) + { + if (dir!=NONE) + { + ok=HandlePush(dir,lev.sx+move_tbl[dir].x, + lev.sy+move_tbl[dir].y); + if (ok) + ok=Handle(AT(lev.sx,lev.sy)); + } + } + else + { + if(CanMove(dir)) + { + if (AT(lev.sx,lev.sy)==HEROSPR) + AT(lev.sx,lev.sy)=SPACESPR; + + lev.sx+=move_tbl[dir].x; + lev.sy+=move_tbl[dir].y; + ok=Handle(AT(lev.sx,lev.sy)); + AT(lev.sx,lev.sy)=HEROSPR; + } + else + ok=Handle(AT(lev.sx,lev.sy)); + } + } + + x=lev.sx-lev.x; + y=lev.sy-lev.y; + + if (x<10) + if (lev.x) + lev.x--; + + if (x>SCRX-10) + if (lev.x(SCRY-10)) + if (lev.y<(lev.h-SCRY+1)) + lev.y++; + + HandleGenerators(); + HandleEnemies(); + HandleAmoeba(); + + Gravity(); + + if (ok) + ok=Handle(AT(lev.sx,lev.sy)); + + (*Repaint)(False); + DrawScore(); + (*Update)(); + + if (!ok) + { + if ((lev.sx==lev.ex)&&(lev.sy==lev.ey)) + dt=0; + else + dt--; + } + else + { + if (++ti==10) + { + ti=0; + if (!(--lev.time)) + { + ok=False; + dt=40; + + for(x=0;x