summaryrefslogtreecommitdiff
path: root/dash.c
diff options
context:
space:
mode:
Diffstat (limited to 'dash.c')
-rw-r--r--dash.c3400
1 files changed, 3400 insertions, 0 deletions
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 <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xos.h>
+#include <X11/Xatom.h>
+#include <X11/keysym.h>
+
+#include <curses.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#include <fcntl.h>
+#include <pwd.h>
+#include <math.h>
+#include <signal.h>
+
+#include <stdarg.h>
+
+#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)<UP) ? (LEFT) : ((d)-1))
+#define ROT_FLIP(d) (((d)+2)%4)
+
+struct
+ {
+ int x,y;
+ } move_tbl[4]=
+ {
+ {0,-1},
+ {1,0},
+ {0,1},
+ {-1,0}
+ };
+
+#define MAX_HISCORE 10
+#define HINAMELEN 32
+
+typedef struct
+ {
+ int score;
+ char name[HINAMELEN+1];
+ int level;
+ } hiscore;
+
+hiscore hisc[MAX_HISCORE]=
+ {
+ {10000,"Score 1",1},
+ {9000,"Score 2",2},
+ {8000,"Score 3",3},
+ {7000,"Score 4",4},
+ {6000,"Score 5",5},
+ {5000,"Score 6",6},
+ {4000,"Score 7",7},
+ {3000,"Score 8",8},
+ {2000,"Score 9",9},
+ {1000,"Score 10",10}
+ };
+
+int chsz=16;
+int slp=-1;
+int bw=False;
+int startlev=1;
+int cursesmode=False;
+
+double si[360];
+double co[360];
+
+int level=1;
+int score=0;
+int no_levels=0;
+int lives=3;
+int quit=False;
+int dead=False;
+Level lev;
+int fr_flag;
+int title_fr;
+#define AT(a,b) *((lev.data)+(a)+((lev.w)*(b)))
+
+
+/* Curses/X mode function calls */
+int (*TitlePage)()=NULL;
+int (*Cls)()=NULL; /* Cls(int colour) */
+int (*Put)()=NULL; /* Put(int x,y,SprNum) */
+int (*Centre)()=NULL; /* Centre(char *str;int y,col) */
+int (*Update)()=NULL;
+int (*Repaint)()=NULL; /* Repaint (int full_flag) */
+int (*Printf)()=NULL; /* Printf(x,y,col,fmt,....) */
+int (*IntroLevel)()=NULL;
+int (*PlayLevel)()=NULL;
+int (*LevelWon)()=NULL;
+int (*LevelLost)()=NULL;
+int (*GameWon)()=NULL;
+int (*GameLost)()=NULL;
+int (*Show)()=NULL; /* Show(int (*func)(),sleep_fl,quit_fl) */
+int (*EndWindowing)()=NULL;
+
+/* X Versions */
+int XTitle();
+/* int XCls(); */
+int PutX();
+int XCentre();
+int XUpdate();
+int XRepaint();
+/* int Xprintf(); */
+int XIntroLevel();
+int XPlayLevel();
+int LevelOk();
+int LevelNotOk();
+int XGameOverWon();
+int XGameOverLost();
+int DoTillPress();
+int XEndWindowing();
+
+/* Curses Versions */
+int CursesTitle();
+int CursesCls();
+int CursesPut();
+int CursesCentre();
+int CursesRedraw();
+int CursesRepaint();
+int CursesPrintf(int x, int y, int c, const char *fmt, ...);
+int CursesIntroLevel();
+int CursesPlayLevel();
+/* int LevelOk(); */
+/* int LevelNotOk(); */
+int CursesGameOverWon();
+int CursesGameOverLost();
+int CursesDoTillPress();
+int CursesEndWindowing();
+
+
+int main(argc,argv)
+int argc;
+char *argv[];
+
+{
+ int f;
+ XEvent event;
+ unsigned long evmask;
+ void IntrHandler();
+
+ umask(000);
+ signal(SIGINT,IntrHandler);
+
+ for(f=0;f<360;f++)
+ {
+ co[f]=cos((M_PI/180.0)*f);
+ si[f]=sin((M_PI/180.0)*f);
+ }
+
+ f=1;
+ while(f<argc)
+ {
+ if(!strcmp(argv[f],"-s"))
+ {
+ chsz=8;
+ f++;
+ }
+ else if (!strcmp(argv[f],"-d"))
+ {
+ slp=atoi(argv[f+1]);
+ f+=2;
+ }
+ else if (!strcmp(argv[f],"-l"))
+ {
+ startlev=atoi(argv[f+1]);
+ f+=2;
+ }
+ else if (!strcmp(argv[f],"-b"))
+ {
+ bw=True;
+ f++;
+ }
+ else if (!strcmp(argv[f],"-c"))
+ {
+ cursesmode=True;
+ f++;
+ }
+ else if (!strcmp(argv[f],"-h"))
+ {
+ LoadScores();
+ printf("%3s %7s %-*s %3s\n",
+ "Pos","Score",HINAMELEN,"Name","Level");
+
+ for(f=0;f<MAX_HISCORE;f++)
+ printf("%3d %7d %-*s %3d\n",
+ f+1,hisc[f].score,HINAMELEN,hisc[f].name,hisc[f].level);
+ Exit(0);
+ }
+ else
+ {
+ fprintf(stderr,"%s: usage %s [switches]\n",argv[0],argv[0]);
+ fprintf(stderr,"-s Use small version\n");
+ fprintf(stderr,"-b Use black and white sprites\n");
+ fprintf(stderr,"-d delay usleep() by delay for fast servers\n");
+ fprintf(stderr,"-l lev start from level lev\n");
+ fprintf(stderr,"-c use curses on tty (not yet perfect)\n");
+ fprintf(stderr,"-h Dump hi-score table\n");
+ Exit(1);
+ }
+ }
+
+ srand(getpid());
+
+ if (!cursesmode)
+ {
+ TitlePage=XTitle;
+ Cls=XCls;
+ Put=PutX;
+ Centre=XCentre;
+ Update=XUpdate;
+ Repaint=XRepaint;
+ Printf=Xprintf;
+ IntroLevel=XIntroLevel;
+ PlayLevel=XPlayLevel;
+ LevelWon=LevelOk;
+ LevelLost=LevelNotOk;
+ GameWon=XGameOverWon;
+ GameLost=XGameOverLost;
+ Show=DoTillPress;
+ EndWindowing=XEndWindowing;
+
+ size_hints.flags=PPosition|PSize|PMinSize|PMaxSize;
+ size_hints.x=WINX;
+ size_hints.y=WINY;
+ size_hints.width=size_hints.min_width=X(SCRX);
+ size_hints.height=size_hints.min_height=Y(SCRY);
+ size_hints.max_width=X(SCRX);
+ size_hints.max_height=Y(SCRY);
+
+ evmask=ButtonPressMask|KeyPressMask|KeyReleaseMask;
+
+ window=OpenWin(argc,argv,argv[0],
+ WINX,WINY,X(SCRX),Y(SCRY),
+ 0,0,
+ evmask,
+ &size_hints,&black,&white);
+
+ DisableDoubleBuffer();
+
+ disp=GetDisplay();
+
+ if (chsz==16)
+ font=XUseFont("8x13bold" /*"fixed-screen-b-14"*/);
+ else
+ font=XUseFont("5x8");
+
+ if (bw)
+ LoadSpritesBW();
+ else
+ LoadSprites();
+ }
+ else
+ {
+ chsz=1;
+ initscr();
+
+ if ((LINES<SCRY)||(COLS<SCRX))
+ {
+ endwin();
+ fprintf(stderr,"%s: expect at least a %dx%d terminal...\n",
+ argv[0],SCRX,SCRY);
+ Exit(1);
+ }
+
+ cbreak();
+ noecho();
+ nonl();
+ nodelay(stdscr,TRUE);
+ intrflush(stdscr, FALSE);
+ keypad(stdscr, TRUE);
+ clear();
+
+ TitlePage=XTitle;
+ Cls=CursesCls;
+ Put=CursesPut;
+ Centre=CursesCentre;
+ Update=CursesRedraw;
+ Repaint=CursesRepaint;
+ Printf=CursesPrintf;
+ IntroLevel=CursesIntroLevel;
+ PlayLevel=CursesPlayLevel;
+ LevelWon=LevelOk;
+ LevelLost=LevelNotOk;
+ GameWon=CursesGameOverWon;
+ GameLost=CursesGameOverLost;
+ Show=CursesDoTillPress;
+ EndWindowing=CursesEndWindowing;
+ }
+
+ LoadLevelNo();
+
+ lev.name=lev.data=NULL;
+
+ AutoOff();
+
+ (*Cls)(black);
+ title_fr=True;
+ (*Show)(TitlePage,False,True);
+
+ while(!quit)
+ {
+ level=startlev;
+ lives=3;
+ score=0;
+ dead=False;
+
+ do
+ {
+ LoadLevel(level);
+ (*Show)(IntroLevel,False,False);
+
+ fr_flag=True; /* Wish I had client data in my XFunc stuff... */
+
+ if ((*PlayLevel)())
+ {
+ if (lev.time>0)
+ while(lev.time)
+ {
+ lev.time--;
+ score+=5;
+ DrawScore();
+ (*Update)();
+ }
+
+ for(f=0;f<level*1000;f+=100)
+ {
+ score+=100;
+ DrawScore();
+ (*Update)();
+ }
+
+ level++;
+ (*Show)(LevelOk,True,False);
+ }
+ else
+ {
+ lives--;
+ if (lives>-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;f<MAX_HISCORE;f++)
+ read(fd,&hisc[f],sizeof(hiscore));
+
+ close(fd);
+}
+
+
+SaveScores()
+
+{
+ int fd,f;
+
+ if ((fd=open(GetLibPath("score"),O_CREAT|O_WRONLY|O_TRUNC,0666))==-1)
+ return;
+
+ for(f=0;f<MAX_HISCORE;f++)
+ write(fd,&hisc[f],sizeof(hiscore));
+
+ close(fd);
+}
+
+
+LoadSpritesBW()
+
+{
+ int f,w,h,x,y;
+
+ for(f=0;f<NOSPR;f++)
+ spr[f].p=GetBitmap(GetFXPath(spr[f].name),&w,&h,&x,&y);
+}
+
+
+LoadSprites()
+
+{
+ XColor xc[256];
+ XSprite s;
+ int f,w,h,x,y;
+
+ LoadColormap(GetFXPath("colormap"),xc);
+
+ /*
+ cm=XCreateColormap(disp,window,DefaultVisual(disp,0),AllocAll);
+ XSetWindowColormap(disp,window,cm);
+ XStoreColors(disp,cm,xc,256);
+ */
+
+ for(f=0;f<NOSPR;f++)
+ {
+ LoadSprite(GetFXPath(spr[f].name),&s,xc);
+ spr[f].p=s.data;
+ }
+}
+
+
+LoadLevelNo()
+
+{
+ FILE *fp;
+
+ if (!(fp=fopen(GetLevelPath("NO"),"r")))
+ {
+ fprintf(stderr,"Couldn't read %s\n",GetLevelPath("NO"));
+ Exit(1);
+ }
+
+ fscanf(fp,"%d",&no_levels);
+
+ fclose(fp);
+}
+
+
+LoadLevel(l)
+int l;
+
+{
+ char s[256];
+ FILE *fp;
+ int x,y,f,tg;
+ long oldpos;
+
+ sprintf(s,"%d",l);
+
+ if (!(fp=fopen(GetLevelPath(s),"r")))
+ {
+ fprintf(stderr,"Couldn't read LEVELS/%d\n",l);
+ AutoOn();
+ Exit(1);
+ }
+
+ if (lev.name)
+ {
+ free(lev.name);
+ free(lev.data);
+ }
+
+ no_enemy=0;
+ for(f=0;f<MAX_ENEMY;f++)
+ enemy[f].alive=False;
+
+ no_generator=0;
+
+ amoeba.alive=False;
+
+ fgets(s,256,fp);
+
+ s[strlen(s)-1]=NULL;
+ lev.name=strdup(s);
+
+ fgets(s,256,fp);
+ sscanf(s,"%d,%d",&lev.x,&lev.y);
+
+ fgets(s,256,fp);
+ sscanf(s,"%d",&lev.toget);
+ lev.no=0;
+
+ if (!lev.toget)
+ tg=True;
+ else
+ tg=False;
+
+ fgets(s,256,fp);
+ sscanf(s,"%d",&lev.time);
+
+ fgets(s,256,fp);
+ sscanf(s,"%d,%d",&max_amoeba_size,&amoeba_move_chance);
+
+ x=y=0;
+ lev.sx=lev.sy=-1;
+ lev.ex=lev.ey=-1;
+
+ oldpos=ftell(fp);
+
+ fgets(s,256,fp);
+ lev.w=strlen(s)-1;
+
+ lev.h=0;
+ fgets(s,256,fp);
+ while(!feof(fp))
+ {
+ lev.h++;
+ fgets(s,256,fp);
+ }
+
+ clearerr(fp);
+ fseek(fp,oldpos,0);
+
+ lev.data=(char *)malloc(lev.w*lev.h);
+
+ fgets(s,256,fp);
+
+ for(y=0;y<lev.h;y++)
+ {
+ s[strlen(s)-1]=NULL;
+ if (strlen(s)!=lev.w)
+ {
+ fprintf(stderr,"Corrupt level file!\n");
+ AutoOn();
+ Exit(1);
+ }
+
+ if (feof(fp))
+ {
+ fprintf(stderr,"Corrupt level file!\n");
+ AutoOn();
+ Exit(1);
+ }
+
+ x=0;
+ for(f=0;f<strlen(s);f++,x++)
+ switch (s[f])
+ {
+ case SPACEGLY:
+ AT(x,y)=SPACESPR;
+ break;
+ case EARTHGLY:
+ AT(x,y)=EARTHSPR;
+ break;
+ case ROCKGLY:
+ AT(x,y)=ROCKSPR;
+ break;
+ case TUFFWALLGLY:
+ AT(x,y)=TUFFWALLSPR;
+ break;
+ case WALLGLY:
+ AT(x,y)=WALLSPR;
+ break;
+ case GEMGLY:
+ AT(x,y)=GEMSPR;
+ if (tg)
+ lev.toget++;
+ break;
+ case HEROGLY:
+ AT(x,y)=EARTHSPR;
+ lev.sx=x;
+ lev.sy=y;
+ break;
+ case EXITGLY:
+ AT(x,y)=EXITSPR;
+ lev.ex=x;
+ lev.ey=y;
+ break;
+ case BUTTGLY:
+ AT(x,y)=BUTTSPR;
+ enemy[no_enemy].alive=True;
+ enemy[no_enemy].type=BUTTSPR;
+ 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 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 (++bln<TITLEBLKS)
+ {
+ x=title_bl[bln].x;
+ y=0;
+ }
+
+ if (bln<TITLEBLKS)
+ {
+ if (y)
+ (*Put)(x,y-1,SPACESPR);
+
+ (*Put)(x,y++,GEMSPR);
+ }
+
+ (*Update)();
+
+ return(XFUNCCONT);
+}
+
+/* --------------------------------------------------------------------- */
+
+#define INTROSPR 30
+
+struct
+ {
+ int x,y;
+ } ispr[INTROSPR];
+
+XIntroLevel()
+
+{
+ static int fr=True;
+ char s[100];
+ int f;
+
+ if (fr)
+ {
+ for(f=0;f<INTROSPR;f++)
+ {
+ ispr[f].x=X(RND(SCRX));
+ ispr[f].y=Y(RND(SCRY));
+ }
+
+ fr=False;
+ }
+
+ (*Cls)(black);
+
+ for(f=0;f<INTROSPR;f++)
+ {
+ XPut(spr[GEMSPR].p,0,0,chsz,chsz,ispr[f].x,ispr[f].y);
+
+ if ((ispr[f].y+=2)>Y(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<lev.w;x++)
+ for(y=0;y<lev.h;y++)
+ if (AT(x,y)==EARTHSPR)
+ AT(x,y)=SPACESPR;
+ }
+
+ DrawMess("Press Space");
+
+ (*Update)();
+
+ Gravity();
+}
+
+
+int LevelNotOk()
+
+{
+ static int ix=1;
+ int x,y;
+
+ if (fr_flag)
+ {
+ fr_flag=False;
+
+ ix=1;
+
+ LoadLevel(TRYAGAINLEV);
+
+ (*Repaint)(True);
+ }
+ else
+ (*Repaint)(False);
+
+ lev.x+=ix;
+
+ if ((lev.x==0)||(lev.x==lev.w-SCRX))
+ {
+ ix=-ix;
+
+ for(x=0;x<lev.w;x++)
+ for(y=0;y<lev.h;y++)
+ if (AT(x,y)==EARTHSPR)
+ AT(x,y)=SPACESPR;
+ }
+
+ DrawMess("Press Space");
+
+ (*Update)();
+
+ Gravity();
+}
+
+/* --------------------------------------------------------------------- */
+
+DrawMess(s)
+char *s;
+
+{
+ if (!cursesmode)
+ XFillBox(0,0,X(SCRX),Y(1)-1,black);
+
+ (*Centre)(s,((cursesmode) ? (0) : (Y(1)-2)),white);
+}
+
+
+DrawScore()
+
+{
+ if (!cursesmode)
+ {
+ XFillBox(0,0,X(SCRX),Y(1)-1,black);
+
+ (*Printf)(0,(Y(1)-2),white,
+ "Score %7d Collect %3d Got %3d Lives %2d Time %4d",
+ score,lev.toget,lev.no,lives,lev.time);
+ }
+ else
+ if (COLS>=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;y<SCRY;y++)
+ for(x=0;x<SCRX;x++)
+ scr[x][y]=VOIDSPR;
+ }
+ else
+ {
+ px=lx-lev.x;
+ py=ly-lev.y;
+
+ if (px==-1)
+ {
+ XCopy(X(1),Y(1),X(SCRX-1),Y(SCRY-1),X(0),Y(1));
+ for (x=1;x<SCRX;x++)
+ for(y=0;y<SCRY;y++)
+ scr[x-1][y]=scr[x][y];
+
+ for(y=0;y<SCRY;y++)
+ scr[SCRX-1][y]=VOIDSPR;
+ }
+
+ if (px==1)
+ {
+ XCopy(X(0),Y(1),X(SCRX-1),Y(SCRY-1),X(1),Y(1));
+ for (x=SCRX-1;x>0;x--)
+ for(y=0;y<SCRY;y++)
+ scr[x][y]=scr[x-1][y];
+
+ for(y=0;y<SCRY;y++)
+ scr[0][y]=VOIDSPR;
+ }
+
+ if (py==-1)
+ {
+ XCopy(X(0),Y(2),X(SCRX),Y(SCRY-2),X(0),Y(1));
+ for (x=0;x<SCRX;x++)
+ for(y=1;y<SCRY;y++)
+ scr[x][y-1]=scr[x][y];
+
+ for(x=0;x<SCRX;x++)
+ scr[x][SCRY-1]=VOIDSPR;
+ }
+
+ if (py==1)
+ {
+ XCopy(X(0),Y(1),X(SCRX),Y(SCRY-2),X(0),Y(2));
+ for (x=0;x<SCRX;x++)
+ for(y=SCRY-1;y>0;y--)
+ scr[x][y]=scr[x][y-1];
+
+ for(x=0;x<SCRX;x++)
+ scr[x][1]=VOIDSPR;
+ }
+ }
+
+ for(y=1;y<SCRY;y++)
+ for(x=0;x<SCRX;x++)
+ {
+ px=lev.x+x;
+ py=lev.y+y-1;
+
+ if ((px<lev.w)&&(py<lev.h)&&(px>-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;y<lev.h;y++)
+ for(x=0;x<lev.w;x++)
+ if (AT(x,y)==AMOEBASPR)
+ if (CheckAmoebaMove(x,y))
+ amoeba.could_move=True;
+
+ if (amoeba.size>max_amoeba_size)
+ {
+ for(y=0;y<lev.h;y++)
+ for(x=0;x<lev.w;x++)
+ if (AT(x,y)==AMOEBASPR)
+ AT(x,y)=ROCKSPR;
+ }
+ else
+ if (!amoeba.could_move)
+ {
+ for(y=0;y<lev.h;y++)
+ for(x=0;x<lev.w;x++)
+ if (AT(x,y)==AMOEBASPR)
+ AT(x,y)=GEMSPR;
+ }
+ }
+}
+
+
+/* --------------------------------------------------------------------- */
+
+GenerateMonsters(x,y,t)
+int x,y,t;
+
+{
+ if ((AT(x-1,y)==SPACESPR)&&(no_enemy<MAX_ENEMY))
+ {
+ AT(x-1,y)=t;
+ enemy[no_enemy].alive=True;
+ enemy[no_enemy].type=t;
+ enemy[no_enemy].x=x-1;
+ enemy[no_enemy].y=y;
+ enemy[no_enemy].dir=LEFT;
+ enemy[no_enemy].moved=False;
+ no_enemy++;
+ }
+
+ if ((AT(x+1,y)==SPACESPR)&&(no_enemy<MAX_ENEMY))
+ {
+ AT(x+1,y)=t;
+ enemy[no_enemy].alive=True;
+ enemy[no_enemy].type=t;
+ enemy[no_enemy].x=x+1;
+ enemy[no_enemy].y=y;
+ enemy[no_enemy].dir=RIGHT;
+ enemy[no_enemy].moved=False;
+ no_enemy++;
+ }
+
+ if ((AT(x,y+1)==SPACESPR)&&(no_enemy<MAX_ENEMY))
+ {
+ AT(x,y+1)=t;
+ enemy[no_enemy].alive=True;
+ enemy[no_enemy].type=t;
+ enemy[no_enemy].x=x;
+ enemy[no_enemy].y=y+1;
+ enemy[no_enemy].dir=DOWN;
+ enemy[no_enemy].moved=False;
+ no_enemy++;
+ }
+
+ if ((AT(x,y-1)==SPACESPR)&&(no_enemy<MAX_ENEMY))
+ {
+ AT(x,y-1)=t;
+ enemy[no_enemy].alive=True;
+ enemy[no_enemy].type=t;
+ enemy[no_enemy].x=x;
+ enemy[no_enemy].y=y-1;
+ enemy[no_enemy].dir=UP;
+ enemy[no_enemy].moved=False;
+ no_enemy++;
+ }
+}
+
+
+HandleGenerators()
+
+{
+ Generator *g;
+ int f;
+
+ for(f=0;f<no_generator;f++)
+ {
+ g=&generator[f];
+
+ AT(g->x,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;f<no_enemy;f++)
+ if (enemy[f].alive)
+ switch(enemy[f].type)
+ {
+ case BUTTSPR:
+ HandleButt(&enemy[f]);
+ break;
+
+ case CHSRSPR:
+ HandleChsr_V2(&enemy[f]);
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+HandleButt(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 (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.sy<e->y)
+ 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.sx<e->x)
+ 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<no_enemy;f++)
+ if (enemy[f].alive)
+ if ((enemy[f].x==lev.sx)&&(enemy[f].y==lev.sy))
+ switch(enemy[f].type)
+ {
+ case BUTTSPR:
+ for(x=-1;x<2;x++)
+ for(y=-1;y<2;y++)
+ if (AT(lev.sx+x,lev.sy+y)!=TUFFWALLSPR)
+ AT(lev.sx+x,lev.sy+y)=GEMFALLSPR;
+ return(False);
+ break;
+
+ case CHSRSPR:
+ for(x=-1;x<2;x++)
+ for(y=-1;y<2;y++)
+ if (AT(lev.sx+x,lev.sy+y)!=TUFFWALLSPR)
+ AT(lev.sx+x,lev.sy+y)=ROCKFALLSPR;
+ return(False);
+ break;
+
+ default:
+ break;
+ }
+
+ return(True);
+}
+
+
+Handle(c)
+int c;
+
+{
+ int x,y;
+
+ switch(c)
+ {
+ case SPACESPR:
+ break;
+
+ case EARTHSPR:
+ /* score+=10; */
+ break;
+
+ case ROCKSPR:
+ case ROCKFALLSPR:
+ case GEMFALLSPR:
+ for(x=-1;x<2;x++)
+ for(y=-1;y<2;y++)
+ if (AT(lev.sx+x,lev.sy+y)!=TUFFWALLSPR)
+ AT(lev.sx+x,lev.sy+y)=ROCKFALLSPR;
+ return(False);
+ break;
+
+ case WALLSPR:
+ break;
+
+ case GEMSPR:
+ score+=10;
+ lev.no++;
+ break;
+
+ case ROCKSWSPR:
+ for(x=0;x<lev.w;x++)
+ for(y=0;y<lev.h;y++)
+ switch (AT(x,y))
+ {
+ case ROCKSPR:
+ case ROCKFALLSPR:
+ AT(x,y)=WALLSPR;
+ break;
+ case WALLSPR:
+ AT(x,y)=ROCKSPR;
+ default:
+ break;
+ }
+ return(True);
+ break;
+
+ case ONEUPSPR:
+ lives++;
+ break;
+
+ case EXITSPR:
+ return(False);
+ break;
+
+ default:
+ break;
+
+ }
+
+ return(True);
+}
+
+
+HandlePush(d,x,y)
+int d,x,y;
+
+{
+ int c;
+ int lx,ly;
+
+ switch(c=AT(x,y))
+ {
+ case SPACESPR:
+ break;
+
+ case EARTHSPR:
+ AT(x,y)=SPACESPR;
+ break;
+
+ case ROCKSPR:
+ if ((d==LEFT)||(d==RIGHT))
+ if (AT(x+move_tbl[d].x,y+move_tbl[d].y)==SPACESPR)
+ {
+ AT(x+move_tbl[d].x,y+move_tbl[d].y)=ROCKSPR;
+ AT(x,y)=SPACESPR;
+ }
+ break;
+
+ case ROCKFALLSPR:
+ case GEMFALLSPR:
+ break;
+
+ case WALLSPR:
+ break;
+
+ case GEMSPR:
+ score+=10;
+ lev.no++;
+ AT(x,y)=SPACESPR;
+ break;
+
+ case ROCKSWSPR:
+ for(lx=0;lx<lev.w;lx++)
+ for(ly=0;ly<lev.h;ly++)
+ switch (AT(lx,ly))
+ {
+ case ROCKSPR:
+ case ROCKFALLSPR:
+ AT(lx,ly)=WALLSPR;
+ break;
+ case WALLSPR:
+ AT(lx,ly)=ROCKSPR;
+ default:
+ break;
+ }
+ AT(x,y)=SPACESPR;
+ break;
+
+ case ONEUPSPR:
+ lives++;
+ AT(x,y)=SPACESPR;
+ break;
+
+ case EXITSPR:
+ lev.sx=lev.ex;
+ lev.sy=lev.ey;
+ return(False);
+ break;
+
+ default:
+ break;
+
+ }
+
+ return(True);
+}
+
+
+#define ISSTOP(b) ((b==ROCKSPR)||(b==ROCKFALLSPR)|| \
+ (b==WALLSPR)||(b==TUFFWALLSPR)||(b==EARTHSPR)|| \
+ (b==GEMSPR)||(b==GEMFALLSPR)||(b==EXITSPR)||\
+ (b==AMOEBASPR)||(b==ROCKGENSPR)||(b==BUTTGENSPR)||\
+ (b==CHSRGENSPR))
+
+Gravity()
+
+{
+ int x,y,b,l,r,l2,r2;
+
+ for(y=lev.h-1;y>-1;y--)
+ for(x=0;x<lev.w;x++)
+ switch(AT(x,y))
+ {
+ case ROCKFALLSPR:
+ l=AT(x-1,y+1);
+ l2=AT(x-1,y);
+ r=AT(x+1,y+1);
+ r2=AT(x+1,y);
+ b=AT(x,y+1);
+
+ if (ISSTOP(b))
+ {
+ if (ISSTOP(r)&&(!ISSTOP(l))&&(l2==SPACESPR))
+ {
+ AT(x,y)=SPACESPR;
+ AT(x-1,y+1)=ROCKFALLSPR;
+ }
+ else if (ISSTOP(l)&&(!ISSTOP(r))&&(r2==SPACESPR))
+ {
+ AT(x,y)=SPACESPR;
+ AT(x+1,y+1)=ROCKFALLSPR;
+ }
+ else
+ AT(x,y)=ROCKSPR;
+ }
+ else
+ {
+ if (b!=FILTERSPR)
+ {
+ AT(x,y)=SPACESPR;
+ AT(x,y+1)=ROCKFALLSPR;
+ }
+ else
+ {
+ AT(x,y)=SPACESPR;
+ if (AT(x,y+2)==SPACESPR)
+ AT(x,y+2)=GEMFALLSPR;
+ }
+ }
+
+ break;
+
+ case GEMFALLSPR:
+ l=AT(x-1,y+1);
+ l2=AT(x-1,y);
+ r=AT(x+1,y+1);
+ r2=AT(x+1,y);
+ b=AT(x,y+1);
+
+ if (ISSTOP(b))
+ {
+ if (ISSTOP(r)&&(!ISSTOP(l))&&(l2==SPACESPR))
+ {
+ AT(x,y)=SPACESPR;
+ AT(x-1,y+1)=GEMFALLSPR;
+ }
+ else if (ISSTOP(l)&&(!ISSTOP(r))&&(r2==SPACESPR))
+ {
+ AT(x,y)=SPACESPR;
+ AT(x+1,y+1)=GEMFALLSPR;
+ }
+ else
+ AT(x,y)=GEMSPR;
+ }
+ else
+ {
+ if (b!=FILTERSPR)
+ {
+ AT(x,y)=SPACESPR;
+ AT(x,y+1)=GEMFALLSPR;
+ }
+ else
+ {
+ AT(x,y)=SPACESPR;
+ if (AT(x,y+2)==SPACESPR)
+ AT(x,y+2)=ROCKFALLSPR;
+ }
+ }
+
+ break;
+
+ case ROCKSPR:
+ l=AT(x-1,y+1);
+ l2=AT(x-1,y);
+ r=AT(x+1,y+1);
+ r2=AT(x+1,y);
+ b=AT(x,y+1);
+
+ if (b==SPACESPR)
+ {
+ AT(x,y)=SPACESPR;
+ AT(x,y+1)=ROCKFALLSPR;
+ }
+ else if ((r==SPACESPR)&&(r2==SPACESPR)&&
+ ((b==GEMSPR)||(b==ROCKSPR)||(b==WALLSPR)||
+ (b==TUFFWALLSPR)))
+ {
+ AT(x,y)=SPACESPR;
+ AT(x+1,y+1)=ROCKFALLSPR;
+ }
+ else if ((l==SPACESPR)&&(l2==SPACESPR)&&
+ ((b==GEMSPR)||(b==ROCKSPR)||(b==WALLSPR)||
+ (b==TUFFWALLSPR)))
+ {
+ AT(x,y)=SPACESPR;
+ AT(x-1,y+1)=ROCKFALLSPR;
+ }
+ break;
+
+ case GEMSPR:
+ l=AT(x-1,y+1);
+ l2=AT(x-1,y);
+ r=AT(x+1,y+1);
+ r2=AT(x+1,y);
+ b=AT(x,y+1);
+
+ if (b==SPACESPR)
+ {
+ AT(x,y)=SPACESPR;
+ AT(x,y+1)=GEMFALLSPR;
+ }
+ else if ((r==SPACESPR)&&(r2==SPACESPR)&
+ ((b==GEMSPR)||(b==ROCKSPR)||(b==WALLSPR)||
+ (b==TUFFWALLSPR)))
+ {
+ AT(x,y)=SPACESPR;
+ AT(x+1,y+1)=GEMFALLSPR;
+ }
+ else if ((l==SPACESPR)&&(l2==SPACESPR)&
+ ((b==GEMSPR)||(b==ROCKSPR)||(b==WALLSPR)||
+ (b==TUFFWALLSPR)))
+ {
+ AT(x,y)=SPACESPR;
+ AT(x-1,y+1)=GEMFALLSPR;
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+XPlayLevel()
+
+{
+ XEvent e;
+ int dir=NONE;
+ int x,y,ok,ls,kp,kpm,dt,ti;
+ int f,r;
+ int shiftmode,shiftrelease;
+ int pressed[4],released[4];
+
+ AT(lev.sx,lev.sy)=HEROSPR;
+ (*Cls)(black);
+ (*Repaint)(True);
+ DrawScore();
+ (*Update)();
+
+ ok=True;
+ dt=20;
+ ti=0;
+
+ for(f=0;f<4;f++)
+ {
+ pressed[f]=0;
+ released[f]=False;
+ }
+
+ shiftmode=False;
+ shiftrelease=False;
+
+ while(dt)
+ {
+ if (slp>-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<lev.w-SCRX)
+ lev.x++;
+
+ if (y<10)
+ if (lev.y)
+ lev.y--;
+
+ if (y>(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<lev.w;x++)
+ for(y=0;y<lev.h;y++)
+ if ((AT(x,y)!=SPACESPR)&&(AT(x,y)!=TUFFWALLSPR))
+ AT(x,y)=ROCKFALLSPR;
+ }
+ }
+ }
+ }
+
+ return((lev.sx==lev.ex)&&(lev.sy==lev.ey));
+}
+
+
+/* --------------------------------------------------------------------- */
+
+
+#define PAUSE_SX 30
+#define PAUSE_SY 5
+#define PAUSE_X 8
+#define PAUSE_Y 8
+
+char *start_pause_map[PAUSE_SY]=
+ {
+ /* 123456789012345678901234567890 */
+ " ## # # # ## ### ## ",
+ " # # # # # # # # # # ",
+ " ## ### # # # ## # # ",
+ " # # # # # # # # # ",
+ " # # # # ## ### ## "
+ };
+
+int pause_map[PAUSE_SX][PAUSE_SY];
+
+PauseFunc()
+
+{
+ int x,y;
+
+ (*Cls)(black);
+
+ for(x=0;x<PAUSE_SX;x++)
+ for(y=0;y<PAUSE_SY;y++)
+ if (pause_map[x][y])
+ {
+ (*Put)(PAUSE_X+x,PAUSE_Y+y,pause_map[x][y]++);
+
+ if (pause_map[x][y]==NOSPR)
+ pause_map[x][y]=1;
+ }
+
+ (*Update)();
+
+ return(XFUNCCONT);
+}
+
+
+DoPause()
+
+{
+ int x,y;
+
+ AutoOn();
+
+ for(x=0;x<PAUSE_SX;x++)
+ for(y=0;y<PAUSE_SY;y++)
+ if (*(start_pause_map[y]+x)=='#')
+ pause_map[x][y]=RND(NOSPR-1)+1;
+ else
+ pause_map[x][y]=0;
+
+ (*Show)(PauseFunc,True,False);
+
+ AutoOff();
+}
+
+
+/* --------------------------------------------------------------------- */
+
+
+DoXGameOverLost()
+
+{
+ (*Printf)(RND(X(SCRX)),RND(Y(SCRY)),white,"YOU'VE LOST!!!!!");
+
+ (*Update)();
+
+ return(XFUNCCONT);
+}
+
+
+XGameOverLost()
+
+{
+ (*Show)(DoXGameOverLost,False);
+}
+
+/* --------------------------------------------------------------------- */
+
+#define NO_GW_CAST 14
+#define NO_GW_INTRO 6
+#define NO_GW_LINES 12
+#define GW_SPR_RAD 5
+
+struct
+ {
+ int spr;
+ char *name;
+ } gw_cast[NO_GW_CAST]=
+ {
+ /* {SPACESPR,"The Empty Bits(?!?)"}, */
+ {EARTHSPR,"The Ground"},
+ {ROCKSPR,"Rock"},
+ {GEMSPR,"Diamond"},
+ {EXITSPR,"The Exit"},
+ {BUTTSPR,"Butterfly"},
+ {CHSRSPR,"Chaser"},
+ {AMOEBASPR,"The Amoeba"},
+ {ROCKSWSPR,"The Rock Switch"},
+ {ONEUPSPR,"The 1 UP!!!"},
+ {FILTERSPR,"The Filter"},
+ {ROCKGENSPR,"The Rock Generator"},
+ {BUTTGENSPR,"The Butterfly Generator"},
+ {CHSRGENSPR,"The Chaser Generator"},
+ {HEROSPR,"You!"}
+ };
+
+char *gw_intro[NO_GW_INTRO]=
+ {
+ "Starring",
+ "Starring",
+ "Special appearance by",
+ "Introducing",
+ "Guest appearance by",
+ "Special guest star"
+ };
+
+char *gw_text[NO_GW_LINES]=
+ {
+ "Congratulations!",
+ "You have completed",
+ "all the levels!!!",
+ " ",
+ "Thanks for playing!",
+ " ",
+ "DASH!",
+ "Written by",
+ "Noddybox",
+ " ",
+ "Visit me at",
+ "www.noddybox.demon.co.uk",
+ };
+
+int gw_cast_no;
+int gw_intro_no;
+int gw_cast_x;
+int gw_ang;
+int NO_GW_SPR;
+int gw_cast_inc;
+int gw_text_no;
+int gw_text_ti;
+
+DoXGameOverWonSmallScale()
+
+{
+ static int la=0;
+ static int lx=0;
+ int a;
+ double dy;
+ int f;
+
+ (*Cls)(black);
+
+ (*Centre)(gw_text[gw_text_no],Y(3),white);
+
+ if (++gw_text_ti==300)
+ {
+ gw_text_ti=0;
+ if (++gw_text_no==NO_GW_LINES)
+ gw_text_no=0;
+ }
+
+ (*Printf)(X(SCRX)-gw_cast_x,Y(SCRY-1),white,"%s %s",
+ gw_intro[gw_intro_no],gw_cast[gw_cast_no].name);
+
+ la=a=gw_ang;
+ lx=gw_cast_x;
+ for(f=0;f<NO_GW_SPR;f++)
+ {
+ dy=(double)(Y(15))-(double)(Y(GW_SPR_RAD))*si[a];
+
+ XPut( spr[gw_cast[gw_cast_no].spr].p,
+ 0,0,chsz,chsz,
+ gw_cast_x-X(f*2),
+ (int)dy);
+
+ if ((a+=20)>359)
+ 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;f<NO_GW_SPR;f++)
+ {
+ dx=(double)(X(SCRX/2))-(double)(X(GW_SPR_RAD))*si[a];
+ dy=(double)(Y(SCRY/2))-(double)(Y(GW_SPR_RAD))*co[a];
+
+ XFillBox((int)dx,(int)dy,chsz,chsz,black);
+
+ if ((a+=(360/NO_GW_SPR))>359)
+ 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;f<NO_GW_SPR;f++)
+ {
+ dx=(double)(X(SCRX/2))-(double)(X(GW_SPR_RAD))*si[a];
+ dy=(double)(Y(SCRY/2))-(double)(Y(GW_SPR_RAD))*co[a];
+
+ XPut( spr[gw_cast[gw_cast_no].spr].p,
+ 0,0,chsz,chsz,
+ (int)dx,
+ (int)dy);
+
+ if ((a+=(360/NO_GW_SPR))>359)
+ 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;f<MAX_HISCORE;f++)
+ (*Printf)(0,Y(5+f),white,"%3d %7d %-*s %3d",
+ f+1,hisc[f].score,HINAMELEN,hisc[f].name,hisc[f].level);
+
+ (*Update)();
+
+ return(b->score-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;f<MAX_HISCORE;f++)
+ (*Printf)(0,Y(5+f),white,"%3d %7d %-*s %3d",
+ f+1,hisc[f].score,HINAMELEN,hisc[f].name,hisc[f].level);
+
+ (*Centre)("Press Space to continue",Y(SCRY-2),white);
+
+ (*Update)();
+}
+
+
+EnterHiscore()
+
+{
+ LoadScores();
+
+ strncpy(hisc[MAX_HISCORE-1].name,getpwuid(getuid())->pw_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<SCRX;x++)
+ for(y=1;y<SCRY;y++)
+ mvaddch(y,x,' ');
+
+ for(y=1;y<SCRY;y++)
+ for(x=0;x<SCRX;x++)
+ {
+ px=lev.x+x;
+ py=lev.y+y-1;
+
+ if ((px<lev.w)&&(py<lev.h)&&(px>-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<lev.w-SCRX)
+ lev.x++;
+
+ if (y<10)
+ if (lev.y)
+ lev.y--;
+
+ if (y>(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<lev.w;x++)
+ for(y=0;y<lev.h;y++)
+ if ((AT(x,y)!=SPACESPR)&&(AT(x,y)!=TUFFWALLSPR))
+ AT(x,y)=ROCKFALLSPR;
+ }
+ }
+ }
+ }
+
+ return((lev.sx==lev.ex)&&(lev.sy==lev.ey));
+}
+
+
+int _CursesGameOverWon()
+{
+ static unsigned int c;
+
+ (*Cls)(black);
+
+ c++;
+
+ (*Centre)("Congratulations!!!",Y(2),white);
+ (*Centre)("You have completed",Y(3),white);
+ (*Centre)("dash in curses mode!!!",Y(4),white);
+
+ (*Centre)("A feat I never thought possible...",Y(12),white);
+ (*Centre)("Noddybox salutes you!",Y(13),white);
+ (*Centre)("www.noddybox.demon.co.uk",Y(15),white);
+
+ if ((c/10)%2)
+ (*Centre)("Press Space to continue",Y(SCRY-2),white);
+
+ (*Update)();
+}
+
+
+int CursesGameOverWon()
+{
+ (*Show)(_CursesGameOverWon,False,False);
+}
+
+
+int _CursesGameOverLost()
+{
+ static unsigned int c;
+
+ (*Cls)(black);
+
+ c++;
+
+ (*Centre)("Game Over",Y(6),white);
+
+ if ((c/10)%2)
+ (*Centre)("Press Space to continue",Y(SCRY-2),white);
+
+ (*Update)();
+}
+
+
+int CursesGameOverLost()
+{
+ (*Show)(_CursesGameOverLost,False,False);
+}
+
+
+int CursesDoTillPress(f,s,q)
+int (*f)();
+int s,q;
+
+{
+ chtype ch;
+
+ while(1)
+ {
+ switch(getch())
+ {
+ case ' ':
+ return;
+ break;
+ case 27:
+ if (q)
+ quit=True;
+ break;
+ default:
+ break;
+ }
+
+ (*f)();
+
+ if /* (s) */ (True)
+ USLEEP(slp);
+ }
+}
+
+
+CursesEndWindowing()
+{
+ (*Cls)(black);
+ (*Update)();
+ endwin();
+}
+
+
+/* --------------------------------------------------------------------- */
+
+int Exit(n)
+int n;
+
+{
+ if (EndWindowing)
+ (*EndWindowing)();
+ exit(n);
+}
+
+/* --------------------------------------------------------------------- */
+
+#ifdef NOUSLEEP
+
+LocalUsleep(u)
+int u;
+
+{
+ struct timeval tv;
+
+ tv.tv_sec=0;
+ tv.tv_usec=u;
+
+ (void)select(0,NULL,NULL,NULL,&tv);
+}
+
+#endif /* NOUSLEEP */