/* 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