/* Copyright status: this file is in the public domain. */ #define SPACING 2 #define BUTTON_BORDER 1 #define BUTTON_MARGIN 2 #define EDIT_SPACING 5 #define EDIT_BORDER 2 #define DIALOG_BORDER 1 #define DIALOG_MARGIN 2 #define MAXLNLEN 64 /* undefine this to get rid of the select() stuff in run(), though you will lose the use of -replay if you do so. */ #define REPLAY #include #include #include #include #include #ifdef REPLAY #include #include #endif #ifdef WEBSERVER #include #endif #include #include #include #include #include #include #define UNUSED_ARG(x) x __attribute__((__unused__)) #define NEW(t) ((t *)malloc(sizeof(t))) #define OLD(v) free((char *)(v)) #include "blockade.h" #include "blockade-pix.h" #include "blockade-lev.h" #include "blockade-info.h" #include "blockade-snd.h" const char *__progname; static XrmDatabase db; const char *defaults = "\ *Background: black\n\ *Foreground: white\n\ *BorderColour: white\n\ *BorderWidth: 1\n\ *Name: xblockade\n\ *IconName: blockade\n\ "; static char *displayname; static char *geometryspec; static char *background; static char *foreground; static char *bordercstr; static char *borderwstr; static char *name; static char *iconname; static char *fontname; static char *visualstr; static char *selkey; #ifdef WEBSERVER static char *webpref; #else #define webpref (0) #endif static int bw_flag; static int no_deflev; static int new_flag; static int dosounds; static int syncX; static char *levelstr; #ifdef REPLAY static int replay; static int replay_ms; static int replay_flags; #define RF_NXCTL 0x00000001 #define RF_CTL 0x00000002 #define RF_BLITZ 0x00000004 #endif static const char *resname = "xblockade"; static const char *resclass = "Game"; static char *xrmstr = 0; static int argc; static char **argv; static Display *disp; static Screen *scr; static int width; static int height; static int depth; static Window rootwin; static Colormap defcmap; static Visual *visual; static GC defgc; static int (*preverr)(Display *, XErrorEvent *); static int (*prevIOerr)(Display *); static int bw_mode; static int log_keystrokes; static XColor fgcolour; static XColor bgcolour; static XColor bdcolour; static XColor blackcolour; static XColor whitecolour; static XColor colours[B_NCOLOURS]; static GC wingc; static XGCValues winshadow; static Window topwin; static Window gamewin; static Window line1win; static Window line2win; static Window textwin; static Window textpanelwin; static Window creditwin; static Window helpwin; static Window helppanelwin; static Window helpwins[N_HELP]; static Window levprompt_win; static Window msgwin; static Window editwin; static Window g_buttonwin; static Window e_buttonwin; static Window g_buttonwin_s; static Window g_buttonwin_no_s; static Colormap wincmap; static Pixmap gray50; static int topw; static int toph; static int gamew; static int gameh; static int gamey; static int textw; static int texth; static int borderwidth; static XFontStruct *font; static XCharStruct maxdigitsize; static int deffont; static Font fontid; static char *levprompt_buf = 0; static int levprompt_fill; static int levprompt_len; static int levprompt_w; static int levprompt_h; static int levprompt_xoff; static int levprompt_xclr; static const char *levprompt_prompt = "Level: "; static char msg_buf[256]; static int msg_len; static int msg_w; static int msg_h; static int editw; static int edith; /* these are in no particular order */ static const char *atom_names[] = { "PRIMARY", #define AX_PRIMARY 0 "STRING", #define AX_STRING 1 "selprop", #define AX_selprop 2 }; #define AX__N 3 static Atom atoms[AX__N]; typedef struct button BUTTON; struct button { const char *text; void (*callback)(const char *); Window win; XCharStruct textbound; int w; int h; int x; int y; int textx; int texty; } ; static int button_h; static Time buttontime; static int pasting = 0; static void buttoncb_help(const char *); static void buttoncb_credits(const char *); static void buttoncb_paste(const char *); static void buttoncb_edit(const char *); static void buttoncb_quit(const char *); static void buttoncb_save(const char *); BUTTON buttons_no_s[] = { { "Help", buttoncb_help }, { "Credits", buttoncb_credits }, { "Paste", buttoncb_paste }, { "Edit", buttoncb_edit }, { "Quit", buttoncb_quit } }; #define NBUTTONS_NO_S (sizeof(buttons_no_s)/sizeof(buttons_no_s[0])) BUTTON buttons_s[] = { { "Help", buttoncb_help }, { "Credits", buttoncb_credits }, { "Paste", buttoncb_paste }, { "Edit", buttoncb_edit }, { "Save", buttoncb_save }, { "Quit", buttoncb_quit } }; #define NBUTTONS_S (sizeof(buttons_s)/sizeof(buttons_s[0])) static void buttoncb_e_junk(const char *); static void buttoncb_e_revert(const char *); static void buttoncb_e_abort(const char *); static void buttoncb_e_done(const char *); static void buttoncb_e_name(const char *); static void buttoncb_e_clone(const char *); BUTTON edit_buttons[] = { { "Junk level", buttoncb_e_junk }, { "Revert", buttoncb_e_revert }, { "Abort", buttoncb_e_abort }, { "Done", buttoncb_e_done }, { "Name", buttoncb_e_name }, { "Clone", buttoncb_e_clone } }; #define NEDITBUTTONS (sizeof(edit_buttons)/sizeof(edit_buttons[0])) extern int help_button_h; static void buttoncb_help1(const char *); static void buttoncb_help2(const char *); static void buttoncb_help3(const char *); static void buttoncb_help4(const char *); static void buttoncb_help5(const char *); static void buttoncb_helpret(const char *); BUTTON help_buttons[] = { { (char *)&help_button_bits[1], buttoncb_help1 }, { (char *)&help_button_bits[2], buttoncb_help2 }, { (char *)&help_button_bits[3], buttoncb_help3 }, { (char *)&help_button_bits[4], buttoncb_help4 }, { (char *)&help_button_bits[5], buttoncb_help5 }, { (char *)&help_button_bits[0], buttoncb_helpret } }; #define NHELPBUTTONS (sizeof(help_buttons)/sizeof(help_buttons[0])) typedef struct argfile ARGFILE; typedef struct level LEVEL; typedef struct level_seg LEVEL_SEG; typedef struct sql SQL; struct sql { SQL *link; unsigned char x; unsigned char y; unsigned char from; unsigned char seen; } ; struct argfile { char *filename; ARGFILE *link; } ; struct level { int levelno; LEVEL_SEG *seg; char *name; int namelen; XCharStruct namesize; char layout[BOARD_Y][BOARD_X]; } ; struct level_seg { int first; int num; int last; char *source; LEVEL **levels; int dirty; LEVEL_SEG *link; } ; static ARGFILE *argfiles; static ARGFILE **argfile_tail = &argfiles; static LEVEL_SEG *level_segs; static LEVEL_SEG **level_segs_tail = &level_segs; static SQL bsq[BOARD_X][BOARD_Y]; static const int dx[4] = { 0, -1, 1, 0 }; static const int dy[4] = { -1, 0, 0, 1 }; static const char cmdchar[4] = { 'k', 'h', 'l', 'j' }; #define OTHERWAY(dir) (3-(dir)) static int maxlevelno; static Pixmap pic_blank; static Pixmap pic_q_b; static Pixmap pic_q_y; static Pixmap pic_r_b; static Pixmap pic_r_y; static Pixmap pic_d_b; static Pixmap pic_d_y; static Pixmap pic_p_b; static Pixmap pic_p_y; static Pixmap pic_colour_b; static Pixmap pic_colour_y; static Pixmap pic_colour_flip; static Pixmap pic_wall; static Pixmap pic_mwall; static Pixmap pic_teleport; static Pixmap pic_mutate; static Pixmap pic_player; static Pixmap pic_stars[PIC_NSTARS]; static Pixmap *pic_ptrs[B_NPIX]; static char squaretype[BOARD_X][BOARD_Y]; #define SQ_BLANK 1 #define SQ_COLOUR_B 2 #define SQ_COLOUR_Y 3 #define SQ_COLOUR_F 4 #define SQ_WALL 5 #define SQ_TELEPORT 6 #define SQ_MUTATE 7 #define SQ_STARS 8 static char startype[BOARD_X][BOARD_Y]; /* used only when squaretype[][] == SQ_STARS */ static char blocktype[BOARD_X][BOARD_Y]; #define BLK_COLOUR 0x01 #define BLK_COLOUR_B 0x00 #define BLK_COLOUR_Y 0x01 #define BLK_SHAPE 0x0e #define BLK_SHAPE_Q 0x02 #define BLK_SHAPE_R 0x04 #define BLK_SHAPE_P 0x06 #define BLK_SHAPE_D 0x08 #define BLK_SHAPE_W 0x0a /* BLK_COLOUR bit ignored */ #define BLK_NONE 0 static int player_x; static int player_y; static char save_blocktype[BOARD_X][BOARD_Y]; static int save_player_x; static int save_player_y; static char sqdamaged[BOARD_X][BOARD_Y]; static char init_blocktype[BOARD_X][BOARD_Y]; static int init_player_x; static int init_player_y; static int curlevelno; static char stepconn_string[BOARD_X*BOARD_Y]; /* size is overkill */ static LEVEL *curlevel; static char lnbuf[MAXLNLEN+1]; static int lnfill; static const char *levelname = ""; static int levelname_len = 0; static int dispstate; #define DS_GAME 0 #define DS_CREDITS 1 #define DS_HELP 2 #define DS_ASKLEVEL 3 #define DS_MSG 4 #define DS_EDIT 5 #define DS_LEVNAME 6 static int helpscreen = 1; static int edit_damaged[B_NPIX]; static int editcurs_x; static int editcurs_y; static int edit_curpic = 0; #define EDIT_MX (EDIT_BORDER + PIC_W + EDIT_BORDER + EDIT_SPACING) #define EDIT_MY (EDIT_BORDER + PIC_H + EDIT_BORDER + EDIT_SPACING) #define EDIT_NCOLS (((PIC_W * BOARD_X) - EDIT_SPACING) / EDIT_MX) #define EDIT_NROWS ((B_NPIX + EDIT_NCOLS - 1) / EDIT_NCOLS) static int junk_direction; static int junk_ascent; static int junk_descent; #define XTE_JUNK &junk_direction,&junk_ascent,&junk_descent #define Cisalpha(x) isalpha((unsigned char)(x)) #define Cisdigit(x) isdigit((unsigned char)(x)) static char *deconst_(int x, ...) { char *rv; va_list ap; va_start(ap,x); rv = va_arg(ap,char *); va_end(ap); return(rv); } static char *deconst(const char *s) { return(deconst_(0,s)); } static void bugchk(const char *, ...) __attribute__((__format__(__printf__,1,2),__noreturn__)); static void bugchk(const char *fmt, ...) { va_list ap; fprintf(stderr,"INTERNAL ERROR: "); va_start(ap,fmt); vfprintf(stderr,fmt,ap); va_end(ap); fprintf(stderr,"\n"); abort(); } static void saveargv(int ac, char **av) { int i; int nc; char *abuf; argc = ac; argv = (char **) malloc((ac+1)*sizeof(char *)); nc = 1; for (i=0;ilink; af->filename = fn; } static void strappend(char **strp, const char *str) { char *new; int oldl; int sl; if (! *strp) { *strp = malloc(1); **strp = '\0'; } oldl = strlen(*strp); sl = strlen(str); new = malloc(oldl+sl+1); bcopy(*strp,new,oldl); bcopy(str,new+oldl,sl); new[oldl+sl] = '\0'; free(*strp); *strp = new; } static void handleargs(int ac, char **av) { int skip; int errs; skip = 0; errs = 0; for (ac--,av++;ac;ac--,av++) { if (skip > 0) { skip --; continue; } if (**av != '-') { addargfile(*av); continue; } if (0) { needarg:; fprintf(stderr,"%s: %s needs a following argument\n",__progname,*av); errs ++; continue; } #define WANTARG() do { if (++skip >= ac) goto needarg; } while (0) if (!strcmp(*av,"-display")) { WANTARG(); displayname = av[skip]; continue; } if (!strcmp(*av,"-geometry")) { WANTARG(); geometryspec = av[skip]; continue; } if (!strcmp(*av,"-background") || !strcmp(*av,"-bg")) { WANTARG(); background = av[skip]; continue; } if (!strcmp(*av,"-foreground") || !strcmp(*av,"-fg")) { WANTARG(); foreground = av[skip]; continue; } if (!strcmp(*av,"-bordercolour") || !strcmp(*av,"-bordercolor") || !strcmp(*av,"-bd")) { WANTARG(); bordercstr = av[skip]; continue; } if (!strcmp(*av,"-borderwidth") || !strcmp(*av,"-bw")) { WANTARG(); borderwstr = av[skip]; continue; } if (!strcmp(*av,"-name")) { WANTARG(); name = av[skip]; continue; } #ifdef WEBSERVER if (!strcmp(*av,"-web")) { WANTARG(); webpref = av[skip]; continue; } #endif if (!strcmp(*av,"-iconname")) { WANTARG(); iconname = av[skip]; continue; } if (!strcmp(*av,"-selkey")) { WANTARG(); selkey = av[skip]; continue; } if (!strcmp(*av,"-font") || !strcmp(*av,"-fn")) { WANTARG(); fontname = av[skip]; continue; } if (!strcmp(*av,"-visual")) { WANTARG(); visualstr = av[skip]; continue; } if (!strcmp(*av,"-resname")) { WANTARG(); resname = av[skip]; continue; } if (!strcmp(*av,"-resclass")) { WANTARG(); resclass = av[skip]; continue; } if (!strcmp(*av,"-xrm")) { WANTARG(); strappend(&xrmstr,"\n"); strappend(&xrmstr,av[skip]); continue; } if (!strcmp(*av,"-level")) { WANTARG(); levelstr = av[skip]; continue; } if (!strcmp(*av,"-file")) { WANTARG(); addargfile(av[skip]); continue; } if (!strcmp(*av,"-bwmode")) { bw_flag = 1; continue; } if (!strcmp(*av,"-log")) { log_keystrokes = 1; continue; } #ifdef REPLAY if (!strcmp(*av,"-replay")) { replay = 1; continue; } if (!strcmp(*av,"-speed")) { WANTARG(); replay_ms = atoi(av[skip]); continue; } #endif if (!strcmp(*av,"-sync")) { syncX = 1; continue; } if (!strcmp(*av,"-nodeflev") || !strcmp(*av,"-nostdlev")) { no_deflev = 1; continue; } if (!strcmp(*av,"-new")) { new_flag = 1; continue; } if (!strcmp(*av,"-sound")) { dosounds = 1; continue; } #undef WANTARG fprintf(stderr,"%s: unrecognized option `%s'\n",__progname,*av); errs ++; } if (errs) { exit(1); } } #define MAXDIST 1000 static int strdist(char *s1, char *s2) { int n1; int n2; char c1; char c2; int d; d = 0; while (1) { n1 = 0; for (;*s1&&!Cisalpha(*s1);s1++) n1 ++; n2 = 0; for (;*s2&&!Cisalpha(*s2);s2++) n2 ++; d += abs(n1-n2); c1 = *s1; c2 = *s2; if (!c1 && !c2) return(d); if (c1 != c2) d ++; if (c1) s1 ++; if (c2) s2 ++; } } static void setlevel(char *s) { int alldigits; char *cp; int bestdist; int d; LEVEL_SEG *ls; int i; if (*s == '\0') { curlevelno = 0; return; } alldigits = 1; for (cp=s;*cp;cp++) { if (! Cisdigit(*cp)) { alldigits = 0; break; } } if (alldigits) { curlevelno = atoi(s); } else { curlevelno = 0; bestdist = MAXDIST + 1; for (ls=level_segs;ls;ls=ls->link) { for (i=0;inum;i++) { d = strdist(s,ls->levels[i]->name); if (d < bestdist) { bestdist = d; curlevelno = ls->first + i; } } } } } static void maybeset(char **strp, char *str) { if (str && !*strp) *strp = str; } static LEVEL *fread_level(FILE *f) { static LEVEL *l = 0; int namelen; int i; int c; int x; int y; if (0) { fail:; return(0); } if (l == 0) { l = NEW(LEVEL); l->name = 0; } if (l->name) { free(l->name); l->name = 0; } if (fscanf(f,"%d",&namelen) != 1) goto fail; l->name = malloc(namelen); do { c = getc(f); if (c == EOF) goto fail; } while (isspace(c)); /* ignore errors in this next loop; eof/error gets noticed shortly */ for (i=0;iname[i] = getc(f); l->namelen = namelen; for (y=0;ylayout[y][x] = c; } } { LEVEL *rv; rv = l; l = 0; return(rv); } } static int read_level_file(char *fn, LEVEL ***levvp) { struct level_list_ { struct level_list_ *link; LEVEL *level; } ; typedef struct level_list_ LEVEL_LIST; LEVEL_LIST *levs; LEVEL_LIST **levtail; LEVEL_LIST *ll; int nlevs; LEVEL *lev; FILE *f; int i; f = fopen(fn,"r"); if (f == 0) { if (new_flag) { int x; int y; newlevelfile:; nlevs = 1; lev = NEW(LEVEL); *levvp = (LEVEL **) malloc(sizeof(LEVEL *)); **levvp = lev; lev->namelen = 8; lev->name = malloc(8); bcopy("Untitled",lev->name,8); for (y=0;ylayout[y][x] = PIC_BLANK; } } lev->layout[0][0] = PIC_PLAYER; lev->layout[0][1] = PIC_Q_B; lev->layout[0][2] = PIC_Q_Y; return(-1); } else { fprintf(stderr,"%s: can't read %s\n",__progname,fn); return(0); } } levtail = &levs; nlevs = 0; while ((lev=fread_level(f))) { ll = NEW(LEVEL_LIST); *levtail = ll; levtail = &ll->link; ll->level = lev; nlevs ++; } fclose(f); *levtail = 0; *levvp = (LEVEL **) malloc(nlevs*sizeof(LEVEL *)); for (i=0,ll=levs;ilink) levvp[0][i] = ll->level; while (levs) { ll = levs; levs = ll->link; OLD(ll); } if ((nlevs == 0) && new_flag) goto newlevelfile; return(nlevs); } static void setup_levels(void) { LEVEL_SEG *ls; ARGFILE *af; int lastlevel; int i; if (! no_deflev) { ls = NEW(LEVEL_SEG); *level_segs_tail = ls; level_segs_tail = &ls->link; ls->first = 1; ls->num = N_DEF_LEVELS; ls->last = N_DEF_LEVELS; ls->source = 0; ls->levels = malloc(N_DEF_LEVELS*sizeof(LEVEL *)); ls->levels[0] = malloc(N_DEF_LEVELS*sizeof(LEVEL)); ls->dirty = 0; for (i=1;ilevels[i] = ls->levels[0] + i; for (i=0;ilevels[i]; l->levelno = i + 1; l->seg = ls; l->name = deconst(b_l_builtin[i].name); bcopy(&b_l_builtin[i].layout,&l->layout,sizeof(l->layout)); l->namelen = strlen(l->name); } lastlevel = N_DEF_LEVELS; } else { lastlevel = 0; } *argfile_tail = 0; ls = 0; for (af=argfiles;af;af=af->link) { if (! ls) ls = NEW(LEVEL_SEG); ls->first = lastlevel + 1; ls->num = read_level_file(af->filename,&ls->levels); ls->dirty = 0; if (ls->num < 0) { ls->num = - ls->num; ls->dirty = 1; } if (ls->num > 0) { lastlevel = ls->first + ls->num - 1; ls->last = lastlevel; ls->source = af->filename; for (i=0;inum;i++) { LEVEL *l; l = ls->levels[i]; l->levelno = ls->first + i; l->seg = ls; } *level_segs_tail = ls; level_segs_tail = &ls->link; ls = 0; } } if (ls) OLD(ls); *level_segs_tail = 0; if (level_segs == 0) { fprintf(stderr,"%s: need to get some levels from somewhere!\n",__progname); exit(1); } maxlevelno = lastlevel; } static void setup_db(void) { char *str; char *home; XrmDatabase db2; db = XrmGetStringDatabase(defaults); str = XResourceManagerString(disp); if (str) { db2 = XrmGetStringDatabase(str); XrmMergeDatabases(db2,&db); } else { home = getenv("HOME"); if (home) { str = malloc(strlen(home)+1+10+1); sprintf(str,"%s/.Xdefaults",home); db2 = XrmGetFileDatabase(str); if (db2) { XrmMergeDatabases(db2,&db); } free(str); } } } static char *get_default_value(const char *name, const char *class) { char *type; XrmValue value; int nl; int cl; static int buflen = -1; static int rnlen = 0; static int rclen = 0; static char *nbuf; static char *cbuf; nl = strlen(name); cl = strlen(class); if ((nl+1+rnlen >= buflen) || (cl+1+rclen >= buflen)) { if (buflen < 0) { rnlen = strlen(resname); rclen = strlen(resclass); buflen = 10; nbuf = malloc(buflen); cbuf = malloc(buflen); } if (buflen <= nl+1+rnlen) buflen = nl+1+rnlen + 1; if (buflen <= cl+1+rclen) buflen = cl+1+rclen + 1; nbuf = realloc(nbuf,buflen); cbuf = realloc(cbuf,buflen); } sprintf(nbuf,"%s.%s",resname,name); sprintf(cbuf,"%s.%s",resclass,class); if (XrmGetResource(db,nbuf,cbuf,&type,&value) == False) return(0); return(value.addr); } static void getcolour(XColor *col) { while (1) { if (XAllocColor(disp,wincmap,col) == 0) { if (wincmap != defcmap) { fprintf(stderr,"%s: can't allocate colourmap cell\n",__progname); exit(1); } wincmap = XCopyColormapAndFree(disp,wincmap); continue; } break; } } static void setup_colour(char *str, XColor *col) { if (XParseColor(disp,wincmap,str,col) == 0) { fprintf(stderr,"%s: bad colour `%s'\n",__progname,str); exit(1); } getcolour(col); } static void setup_atoms(void) { int i; for (i=0;i*/ (j=B_NCOLOURS-1;j>=0;j--) { for (k=nc-1;k>=0;k--) if (cvec[k] == b_p_colours[j][i]) goto continue_colour/*continue <"colour">*/; cvec[nc++] = b_p_colours[j][i]; continue_colour:; } if (nc > dcmsize) dcmsize = nc; } v = 0; for (i=nvinf-1;i>=0;i--) { switch (vinf->class) { case StaticGray: case GrayScale: continue; break; case StaticColor: case TrueColor: if (vinf->bits_per_rgb < 4) continue; break; case PseudoColor: if (vinf->colormap_size < B_NCOLOURS+3) continue; break; case DirectColor: if (vinf->colormap_size < dcmsize) continue; break; } if ( (v == 0) || (vinf->visualid == defid) || (vinf->depth < v->depth) ) v = vinf; } if (v == 0) { if (visualstr) { fprintf(stderr,"%s: %s: can't find a suitable visual%s\n",__progname,visualstr,(ScreenCount(disp)==1)?"":" on this screen"); exit(1); } bwmode(); return; } } visual = v->visual; if (v->visualid == defid) { defcmap = XDefaultColormapOfScreen(scr); defgc = XDefaultGCOfScreen(scr); depth = XDefaultDepthOfScreen(scr); } else { defcmap = None; { Pixmap pm; /* Grrr - shouldn't have to bother creating the pixmap! */ pm = XCreatePixmap(disp,rootwin,1,1,v->depth); defgc = XCreateGC(disp,pm,0L,(XGCValues *)0); XFreePixmap(disp,pm); } depth = v->depth; } XFree(vinf); } static void setup_font(void) { int c; XCharStruct d; font = 0; deffont = 0; if (fontname) { font = XLoadQueryFont(disp,fontname); if (! font) { fprintf(stderr,"%s: can't load font %s, using server default\n",__progname,fontname); } else { fontid = font->fid; } } if (! font) { font = XQueryFont(disp,XGContextFromGC(defgc)); deffont = 1; fontid = None; } for (c=0;c<10;c++) { XTextExtents(font,"0123456789"+c,1,XTE_JUNK,&d); if (c == 0) { maxdigitsize = d; } else { #define TST(field,cmp) if (d.field cmp maxdigitsize.field) maxdigitsize.field = d.field TST(lbearing,<); TST(rbearing,>); TST(ascent,>); TST(descent,>); TST(width,>); #undef TST } } } static void setup_colours(void) { wincmap = (defcmap != None) ? defcmap : XCreateColormap(disp,rootwin,visual,AllocNone); if (bw_mode) { blackcolour.red = 0; blackcolour.green = 0; blackcolour.blue = 0; getcolour(&blackcolour); whitecolour.red = 65535; whitecolour.green = 65535; whitecolour.blue = 65535; getcolour(&whitecolour); } else { int i; for (i=0;i>3)*PIC_H]; static GC gc; int x; int y; int n; int acc; unsigned char *bp; if (i == 0) { i = XCreateImage(disp,visual,1,XYBitmap,0,(char *)&buf[0],PIC_W,PIC_H,8,(PIC_W+7)>>3); i->bitmap_unit = 8; i->bitmap_bit_order = MSBFirst; rv = XCreatePixmap(disp,rootwin,1,1,1); gc = XCreateGC(disp,rv,0L,(XGCValues *)0); XFreePixmap(disp,rv); XSetBackground(disp,gc,0L); XSetForeground(disp,gc,1L); } acc = 0; bp = &buf[0]; for (y=0;y 7) { *bp++ = acc; n = 0; } acc = (acc << 1) | b_p_pix_bw[inx][y][x]; n ++; } if (n > 0) { *bp++ = acc << (8 - n); } } rv = XCreatePixmap(disp,rootwin,PIC_W,PIC_H,1); XPutImage(disp,rv,gc,i,0,0,0,0,PIC_W,PIC_H); } else if (depth == 8) { static XImage *i = 0; static unsigned char buf[PIC_W*PIC_H]; static GC gc; int x; int y; unsigned char *bp; if (i == 0) { i = XCreateImage(disp,visual,8,ZPixmap,0,(char *)&buf[0],PIC_W,PIC_H,8,PIC_W); i->bitmap_unit = 8; rv = XCreatePixmap(disp,rootwin,1,1,8); gc = XCreateGC(disp,rv,0L,(XGCValues *)0); XFreePixmap(disp,rv); } bp = &buf[0]; for (y=0;y>3)*PIC_H]; static GC gc1; static GC gcn; static Pixmap tmp; int x; int y; int n; int acc; int m; int c; unsigned char *bp; if (i == 0) { i = XCreateImage(disp,visual,1,XYBitmap,0,(char *)&buf[0],PIC_W,PIC_H,8,(PIC_W+7)>>3); i->bitmap_unit = 8; i->bitmap_bit_order = MSBFirst; tmp = XCreatePixmap(disp,rootwin,PIC_W,PIC_H,1); gc1 = XCreateGC(disp,tmp,0L,(XGCValues *)0); XSetBackground(disp,gc1,0L); XSetForeground(disp,gc1,1L); rv = XCreatePixmap(disp,rootwin,1,1,depth); gcn = XCreateGC(disp,rv,0L,(XGCValues *)0); XSetBackground(disp,gcn,0L); XFreePixmap(disp,rv); } rv = XCreatePixmap(disp,rootwin,PIC_W,PIC_H,depth); XSetForeground(disp,gcn,0L); XSetFunction(disp,gcn,GXcopy); XFillRectangle(disp,rv,gcn,0,0,PIC_W,PIC_H); XSetFunction(disp,gcn,GXor); for (c=0;c 7) { *bp++ = acc; n = 0; } acc <<= 1; if (b_p_pix_colour[inx][y][x] == c) { acc |= 1; m ++; } n ++; } if (n > 0) { *bp++ = acc << (8 - n); } } if (m > 0) { XPutImage(disp,tmp,gc1,i,0,0,0,0,PIC_W,PIC_H); XSetForeground(disp,gcn,colours[c].pixel); XCopyPlane(disp,tmp,rv,gcn,0,0,PIC_W,PIC_H,0,0,1L); } } } return(rv); } static void setup_wingc(void) { Pixmap pm; pm = XCreatePixmap(disp,rootwin,1,1,depth); wingc = XCreateGC(disp,pm,0L,(XGCValues *)0); XFreePixmap(disp,pm); XGetGCValues(disp,wingc,GCFunction|GCForeground|GCBackground|GCLineWidth|GCFillStyle|GCTileStipXOrigin|GCTileStipYOrigin|GCClipXOrigin|GCClipYOrigin|GCPlaneMask,&winshadow); winshadow.tile = None; /* force change when first set */ winshadow.stipple = None; /* force change when first set */ winshadow.clip_mask = None; /* force change when first set */ winshadow.font = None; /* ie, the default font */ } static void setup_gc(long int bit, ...) { va_list ap; int setdeffont; unsigned long int gcmask; GC gc; XGCValues *shadow; XGCValues gcval; va_start(ap,bit); gc = wingc; shadow = &winshadow; setdeffont = 0; gcmask = 0; while (1) { switch (bit) { default: fprintf(stderr,"Bad bit 0x%lx to setup_gc\n",bit); abort(); break; case 0: va_end(ap); if (gcmask != 0) XChangeGC(disp,gc,gcmask,&gcval); if (setdeffont) XCopyGC(disp,defgc,GCFont,gc); return; break; #define CASE(mask,type,field) \ case mask: \ gcval.field = va_arg(ap,type); \ if (gcval.field != shadow->field) \ { gcmask |= mask; \ shadow->field = gcval.field; \ } \ break; CASE(GCFunction,int,function) CASE(GCForeground,unsigned long int,foreground) CASE(GCBackground,unsigned long int,background) CASE(GCLineWidth,int,line_width) CASE(GCTile,Pixmap,tile) CASE(GCStipple,Pixmap,stipple) CASE(GCFillStyle,int,fill_style) CASE(GCTileStipXOrigin,int,ts_x_origin) CASE(GCTileStipYOrigin,int,ts_y_origin) CASE(GCClipMask,Pixmap,clip_mask) CASE(GCClipXOrigin,int,clip_x_origin) CASE(GCClipYOrigin,int,clip_y_origin) CASE(GCPlaneMask,unsigned long int,plane_mask) case GCFont: gcval.font = va_arg(ap,Font); if (gcval.font != shadow->font) { if (gcval.font == None) { setdeffont = 1; gcmask &= ~GCFont; } else { gcmask |= GCFont; setdeffont = 0; } shadow->font = gcval.font; } break; } bit = va_arg(ap,long int); } } static void setup_pixmaps(void) { int i; #define FOO(var,inx) var = pmsetup(inx); pic_ptrs[inx] = &var; FOO(pic_blank,PIC_BLANK); FOO(pic_q_b,PIC_Q_B); FOO(pic_q_y,PIC_Q_Y); FOO(pic_r_b,PIC_R_B); FOO(pic_r_y,PIC_R_Y); FOO(pic_d_b,PIC_D_B); FOO(pic_d_y,PIC_D_Y); FOO(pic_p_b,PIC_P_B); FOO(pic_p_y,PIC_P_Y); FOO(pic_colour_b,PIC_COLOUR_B); FOO(pic_colour_y,PIC_COLOUR_Y); FOO(pic_colour_flip,PIC_COLOUR_FLIP); FOO(pic_wall,PIC_WALL); FOO(pic_mwall,PIC_MWALL); FOO(pic_teleport,PIC_TELEPORT); FOO(pic_mutate,PIC_MUTATE); FOO(pic_player,PIC_PLAYER); for (i=0;ilink) { for (i=0;inum;i++) { l = ls->levels[i]; XTextExtents(font,l->name,l->namelen,XTE_JUNK,&l->namesize); if (l->namelen > n) n = l->namelen; if ((i == 0) && (ls == level_segs)) { maxlns = l->namesize; } else { #define TST(field,cmp) if (l->namesize.field cmp maxlns.field) maxlns.field = l->namesize.field TST(lbearing,<); TST(rbearing,>); TST(ascent,>); TST(descent,>); TST(width,>); #undef TST } } } levprompt_len = n; for (n=maxlevelno,i=1;n>=10;n/=10,i++) ; if (i > levprompt_len) levprompt_len = i; d = maxdigitsize; d.width *= i; #define TST(field,cmp) if (d.field cmp maxlns.field) maxlns.field = d.field TST(lbearing,<); TST(rbearing,>); TST(ascent,>); TST(descent,>); TST(width,>); #undef TST XTextExtents(font,levprompt_prompt,strlen(levprompt_prompt),XTE_JUNK,&d); levprompt_w = DIALOG_BORDER + DIALOG_MARGIN + d.width + maxlns.width + DIALOG_MARGIN + DIALOG_BORDER; levprompt_h = DIALOG_BORDER + DIALOG_MARGIN + font->ascent + font->descent + DIALOG_MARGIN + DIALOG_BORDER; levprompt_xoff = DIALOG_BORDER + DIALOG_MARGIN + d.width; levprompt_xclr = DIALOG_BORDER + DIALOG_MARGIN + d.width + maxlns.lbearing; } static void setup_buttons(void) { int i; BUTTON *b; int a; int d; button_h = 0; for (i=0;itext,strlen(b->text),XTE_JUNK,&b->textbound); d = (b->textbound.descent > font->descent) ? b->textbound.descent : font->descent; a = (b->textbound.ascent > font->ascent) ? b->textbound.ascent : font->ascent; b->w = BUTTON_BORDER + BUTTON_MARGIN + b->textbound.width + BUTTON_MARGIN + BUTTON_BORDER; b->h = BUTTON_BORDER + BUTTON_MARGIN + a + d + BUTTON_MARGIN + BUTTON_BORDER; b->textx = BUTTON_BORDER + BUTTON_MARGIN; b->texty = BUTTON_BORDER + BUTTON_MARGIN + a; if (b->h > button_h) button_h = b->h; } for (i=0;itext,strlen(b->text),XTE_JUNK,&b->textbound); d = (b->textbound.descent > font->descent) ? b->textbound.descent : font->descent; a = (b->textbound.ascent > font->ascent) ? b->textbound.ascent : font->ascent; b->w = BUTTON_BORDER + BUTTON_MARGIN + b->textbound.width + BUTTON_MARGIN + BUTTON_BORDER; b->h = BUTTON_BORDER + BUTTON_MARGIN + a + d + BUTTON_MARGIN + BUTTON_BORDER; b->textx = BUTTON_BORDER + BUTTON_MARGIN; b->texty = BUTTON_BORDER + BUTTON_MARGIN + a; if (b->h > button_h) button_h = b->h; } for (i=0;itext); b->w = ucp[0]; b->h = help_button_h; b->x = (ucp[1] << 8) | ucp[2]; b->y = (ucp[3] << 8) | ucp[4]; } for (i=0;itext,strlen(b->text),XTE_JUNK,&b->textbound); d = (b->textbound.descent > font->descent) ? b->textbound.descent : font->descent; a = (b->textbound.ascent > font->ascent) ? b->textbound.ascent : font->ascent; b->w = BUTTON_BORDER + BUTTON_MARGIN + b->textbound.width + BUTTON_MARGIN + BUTTON_BORDER; b->h = BUTTON_BORDER + BUTTON_MARGIN + a + d + BUTTON_MARGIN + BUTTON_BORDER; b->textx = BUTTON_BORDER + BUTTON_MARGIN; b->texty = BUTTON_BORDER + BUTTON_MARGIN + a; if (b->h > button_h) button_h = b->h; } } static void place_msgwin(void) { XMoveResizeWindow(disp,msgwin,(topw-msg_w)/2,gamey+(gameh-msg_h)/2,msg_w,msg_h); } static void resize(int tw, int th) { int y; int dy; int yinc; int ny; int x; int dx; int xinc; int nx; #define BUMPY(inc) ((y += (inc) + (yinc = dy / ny)), (dy -= yinc), (ny --)) #define BUMPX(inc) ((x += (inc) + (xinc = dx / nx)), (dx -= xinc), (nx --)) int i; BUTTON *b; topw = tw; toph = th; gamew = BOARD_X * PIC_W; gameh = BOARD_Y * PIC_H; editw = EDIT_SPACING + (EDIT_NCOLS * (EDIT_BORDER + PIC_W + EDIT_BORDER + EDIT_SPACING)); edith = EDIT_SPACING + (EDIT_NROWS * (EDIT_BORDER + PIC_H + EDIT_BORDER + EDIT_SPACING)); textw = topw; texth = 2 * (font->ascent + font->descent); switch (dispstate) { case DS_EDIT: case DS_LEVNAME: dy = toph - (edith + borderwidth + gameh + borderwidth + texth + button_h); ny = 7; y = 0; BUMPY(0); XMoveResizeWindow(disp,editwin,(topw-editw)/2,y,editw,edith); BUMPY(edith); XMoveResizeWindow(disp,line1win,0,y,topw,borderwidth); BUMPY(borderwidth); break; default: dy = toph - (gameh + borderwidth + texth + button_h); ny = 5; y = 0; BUMPY(0); break; } gamey = y; XMoveResizeWindow(disp,gamewin,(topw-gamew)/2,y,gamew,gameh); XMoveResizeWindow(disp,levprompt_win,(topw-levprompt_w)/2,y+(gameh-levprompt_h)/2,levprompt_w,levprompt_h); if (dispstate == DS_MSG) place_msgwin(); BUMPY(gameh); XMoveResizeWindow(disp,line2win,0,y,topw,borderwidth); BUMPY(borderwidth); XMoveResizeWindow(disp,textwin,(topw-textw)/2,y,textw,texth); BUMPY(texth); XMoveResizeWindow(disp,g_buttonwin,0,y,topw,button_h); XMoveResizeWindow(disp,e_buttonwin,0,y,topw,button_h); XMoveResizeWindow(disp,g_buttonwin_s,0,0,topw,button_h); XMoveResizeWindow(disp,g_buttonwin_no_s,0,0,topw,button_h); dx = topw; for (i=0;ix = x; b->y = (button_h - b->h) / 2; XMoveResizeWindow(disp,b->win,b->x,b->y,b->w,b->h); BUMPX(b->w); } dx = topw; for (i=0;ix = x; b->y = (button_h - b->h) / 2; XMoveResizeWindow(disp,b->win,b->x,b->y,b->w,b->h); BUMPX(b->w); } dx = topw; for (i=0;ix = x; b->y = (button_h - b->h) / 2; XMoveResizeWindow(disp,b->win,b->x,b->y,b->w,b->h); BUMPX(b->w); } BUMPY(button_h); } #undef BUMPY #undef BUMPX static void setup_windows(void) { int x; int y; unsigned int w; unsigned int h; int bits; int i; BUTTON *b; unsigned long int attrmask; XSetWindowAttributes attr; XTextProperty wn_prop; XTextProperty in_prop; XSizeHints normal_hints; XWMHints wm_hints; XClassHint class_hints; w = borderwidth + SPACING + (BOARD_X * PIC_W) + SPACING + borderwidth; h = borderwidth + SPACING + (BOARD_Y * PIC_H) + SPACING + borderwidth + SPACING + (2 * (font->ascent + font->descent)) + SPACING + button_h + SPACING + borderwidth; x = (width - w) / 2; y = (height - h) / 2; normal_hints.min_width = w - (2 * borderwidth); normal_hints.min_height = h - (2 * borderwidth); bits = XParseGeometry(geometryspec,&x,&y,&w,&h); if (bits & XNegative) x = width + x - w; if (bits & YNegative) y = height + y - h; attrmask = 0; attr.background_pixel = bgcolour.pixel; attrmask |= CWBackPixel; attr.border_pixel = bdcolour.pixel; attrmask |= CWBorderPixel; attr.backing_store = NotUseful; attrmask |= CWBackingStore; attr.event_mask = StructureNotifyMask | KeyPressMask; attrmask |= CWEventMask; attr.do_not_propagate_mask = ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask | PointerMotionMask; attrmask |= CWDontPropagate; attr.colormap = wincmap; attrmask |= CWColormap; w -= 2 * borderwidth; h -= 2 * borderwidth; topwin = XCreateWindow(disp,rootwin,x,y,w,h,borderwidth,depth,InputOutput,visual,attrmask,&attr); wn_prop.value = (unsigned char *) name; wn_prop.encoding = XA_STRING; wn_prop.format = 8; wn_prop.nitems = strlen((char *)wn_prop.value); in_prop.value = (unsigned char *) iconname; in_prop.encoding = XA_STRING; in_prop.format = 8; in_prop.nitems = strlen((char *)in_prop.value); normal_hints.flags = PMinSize | PResizeInc; normal_hints.x = x; normal_hints.y = y; normal_hints.flags |= (bits & (XValue|YValue)) ? USPosition : PPosition; normal_hints.width = w; normal_hints.height = h; normal_hints.flags |= (bits & (WidthValue|HeightValue)) ? USSize : PSize; normal_hints.width_inc = 1; normal_hints.height_inc = 1; wm_hints.flags = InputHint; wm_hints.input = True; class_hints.res_name = deconst(resname); class_hints.res_class = deconst(resclass); XSetWMProperties(disp,topwin,&wn_prop,&in_prop,argv,argc,&normal_hints,&wm_hints,&class_hints); if (selkey) XChangeProperty(disp,topwin,XInternAtom(disp,"wm_selkey",False),XA_STRING,8,PropModeReplace,(unsigned char *)selkey,strlen(selkey)); attrmask = 0; attr.background_pixel = bgcolour.pixel; attrmask |= CWBackPixel; attr.backing_store = NotUseful; attrmask |= CWBackingStore; attr.event_mask = ExposureMask | ButtonPressMask | ButtonMotionMask; attrmask |= CWEventMask; gamewin = XCreateWindow(disp,topwin,0,0,1,1,0,depth,InputOutput,CopyFromParent,attrmask,&attr); XMapWindow(disp,gamewin); attrmask = 0; attr.background_pixel = bgcolour.pixel; attrmask |= CWBackPixel; attr.backing_store = NotUseful; attrmask |= CWBackingStore; attr.event_mask = ExposureMask; attrmask |= CWEventMask; levprompt_win = XCreateWindow(disp,topwin,0,0,1,1,0,depth,InputOutput,CopyFromParent,attrmask,&attr); attrmask = 0; attr.background_pixel = bgcolour.pixel; attrmask |= CWBackPixel; attr.backing_store = NotUseful; attrmask |= CWBackingStore; attr.event_mask = ExposureMask; attrmask |= CWEventMask; msgwin = XCreateWindow(disp,topwin,0,0,1,1,0,depth,InputOutput,CopyFromParent,attrmask,&attr); attrmask = 0; attr.background_pixmap = gray50; attrmask |= CWBackPixmap; attr.backing_store = NotUseful; attrmask |= CWBackingStore; attr.event_mask = ExposureMask | ButtonPressMask; attrmask |= CWEventMask; editwin = XCreateWindow(disp,topwin,0,0,1,1,0,depth,InputOutput,CopyFromParent,attrmask,&attr); attrmask = 0; attr.background_pixel = bgcolour.pixel; attrmask |= CWBackPixel; attr.backing_store = NotUseful; attrmask |= CWBackingStore; attr.event_mask = ExposureMask | ButtonPressMask; attrmask |= CWEventMask; textpanelwin = XCreateWindow(disp,gamewin,0,0,PIC_W*BOARD_X,PIC_H*BOARD_Y,0,depth,InputOutput,CopyFromParent,attrmask,&attr); attrmask = 0; attr.background_pixel = bgcolour.pixel; attrmask |= CWBackPixel; attr.backing_store = NotUseful; attrmask |= CWBackingStore; attr.event_mask = ExposureMask | ButtonPressMask; attrmask |= CWEventMask; creditwin = XCreateWindow(disp,textpanelwin,0,0,PIC_W*BOARD_X,PIC_H*BOARD_Y,0,depth,InputOutput,CopyFromParent,attrmask,&attr); XMapWindow(disp,creditwin); attrmask = 0; attr.background_pixel = bgcolour.pixel; attrmask |= CWBackPixel; attr.backing_store = NotUseful; attrmask |= CWBackingStore; attr.event_mask = ExposureMask | ButtonPressMask; attrmask |= CWEventMask; helpwin = XCreateWindow(disp,textpanelwin,0,0,PIC_W*BOARD_X,PIC_H*BOARD_Y,0,depth,InputOutput,CopyFromParent,attrmask,&attr); XMapWindow(disp,helpwin); attrmask = 0; attr.background_pixel = bgcolour.pixel; attrmask |= CWBackPixel; attr.backing_store = NotUseful; attrmask |= CWBackingStore; attr.event_mask = ExposureMask | ButtonPressMask; attrmask |= CWEventMask; helppanelwin = XCreateWindow(disp,helpwin,0,0,PIC_W*BOARD_X,PIC_H*BOARD_Y,0,depth,InputOutput,CopyFromParent,attrmask,&attr); XMapWindow(disp,helppanelwin); for (i=0;iwin = XCreateWindow(disp,g_buttonwin_no_s,0,0,1,1,0,depth,InputOutput,CopyFromParent,attrmask,&attr); XMapWindow(disp,b->win); } for (i=0;iwin = XCreateWindow(disp,g_buttonwin_s,0,0,1,1,0,depth,InputOutput,CopyFromParent,attrmask,&attr); XMapWindow(disp,b->win); } for (i=0;iwin = XCreateWindow(disp,helpwin,b->x,b->y,b->w,b->h,0,depth,InputOutput,CopyFromParent,attrmask,&attr); XMapWindow(disp,b->win); } attrmask = 0; attr.background_pixel = bgcolour.pixel; attrmask |= CWBackPixel; attr.backing_store = NotUseful; attrmask |= CWBackingStore; attr.event_mask = NoEventMask; attrmask |= CWEventMask; e_buttonwin = XCreateWindow(disp,topwin,0,0,1,1,0,depth,InputOutput,CopyFromParent,attrmask,&attr); XMapWindow(disp,e_buttonwin); for (i=0;iwin = XCreateWindow(disp,e_buttonwin,0,0,1,1,0,depth,InputOutput,CopyFromParent,attrmask,&attr); XMapWindow(disp,b->win); } XLowerWindow(disp,helppanelwin); XLowerWindow(disp,e_buttonwin); XRaiseWindow(disp,gamewin); XMapRaised(disp,topwin); resize(w,h); } static int set_sq_bl(int bi, int *sqp, int *blp, int *stp) { *sqp = SQ_BLANK; *blp = BLK_NONE; *stp = 0; switch (bi) { case PIC_BLANK: break; case PIC_Q_B: *blp = BLK_SHAPE_Q | BLK_COLOUR_B; break; case PIC_Q_Y: *blp = BLK_SHAPE_Q | BLK_COLOUR_Y; break; case PIC_R_B: *blp = BLK_SHAPE_R | BLK_COLOUR_B; break; case PIC_R_Y: *blp = BLK_SHAPE_R | BLK_COLOUR_Y; break; case PIC_D_B: *blp = BLK_SHAPE_D | BLK_COLOUR_B; break; case PIC_D_Y: *blp = BLK_SHAPE_D | BLK_COLOUR_Y; break; case PIC_P_B: *blp = BLK_SHAPE_P | BLK_COLOUR_B; break; case PIC_P_Y: *blp = BLK_SHAPE_P | BLK_COLOUR_Y; break; case PIC_COLOUR_B: *sqp = SQ_COLOUR_B; break; case PIC_COLOUR_Y: *sqp = SQ_COLOUR_Y; break; case PIC_COLOUR_FLIP: *sqp = SQ_COLOUR_F; break; case PIC_WALL: *sqp = SQ_WALL; break; case PIC_MWALL: *blp = BLK_SHAPE_W; break; case PIC_TELEPORT: *sqp = SQ_TELEPORT; break; case PIC_MUTATE: *sqp = SQ_MUTATE; break; case PIC_PLAYER: return(1); break; default: *stp = bi - PIC_STARS_A; if ((*stp < 0) || (*stp >= PIC_NSTARS)) *stp = 0; *sqp = SQ_STARS; break; } return(0); } static void pushsave(void) { int x; int y; for (x=0;xls->last);ls=ls->link) ; if (! ls) { curlevelno = 1; ls = level_segs; } l = ls->levels[curlevelno-ls->first]; st = 0; for (x=0;xlayout[y][x],&sq,&bl,&st)) { player_x = x; player_y = y; } squaretype[x][y] = sq; startype[x][y] = st; blocktype[x][y] = bl; init_blocktype[x][y] = bl; } } init_player_x = player_x; init_player_y = player_y; pushsave(); levelname = l->name; levelname_len = l->namelen; curlevel = l; if (! webpref) XRaiseWindow(disp,curlevel->seg->dirty?g_buttonwin_s:g_buttonwin_no_s); } static void setup_game(void) { curlevelno = 0; if (levelstr) setlevel(levelstr); if (curlevelno < 1) curlevelno = 1; initlevel(); dispstate = DS_GAME; } static void damage_gamewin(int x, int y, int w, int h) { int x0; int x1; int y1; x1 = x + w - 1; y1 = y + h - 1; x0 = x / PIC_W; y /= PIC_H; x1 /= PIC_W; y1 /= PIC_H; if (x0 < 0) x0 = 0; if (y < 0) y = 0; if (x1 >= BOARD_X) x1 = BOARD_X - 1; if (y1 >= BOARD_Y) y1 = BOARD_Y - 1; if ((x0 <= x1) && (y <= y1)) { for (;y<=y1;y++) { for (x=x0;x<=x1;x++) { sqdamaged[x][y] = 1; } } } } static int picnum_for_loc(int x, int y) { if ((x == player_x) && (y == player_y)) { return(PIC_PLAYER); } else { int bt; bt = blocktype[x][y]; if (bt == BLK_NONE) { switch (squaretype[x][y]) { case SQ_BLANK: return(PIC_BLANK); break; case SQ_COLOUR_B: return(PIC_COLOUR_B); break; case SQ_COLOUR_Y: return(PIC_COLOUR_Y); break; case SQ_COLOUR_F: return(PIC_COLOUR_FLIP); break; case SQ_WALL: return(PIC_WALL); break; case SQ_TELEPORT: return(PIC_TELEPORT); break; case SQ_MUTATE: return(PIC_MUTATE); break; case SQ_STARS: { int st; st = startype[x][y]; if ((st < 0) || (st >= PIC_NSTARS)) bugchk("invalid star number %d at (%d,%d)",st,x,y); return(PIC_STARS_A+st); } break; default: bugchk("invalid square type %d at (%d,%d)\n",squaretype[x][y],x,y); break; } } else { switch (bt & BLK_SHAPE) { case BLK_SHAPE_W: return(PIC_MWALL); break; case BLK_SHAPE_Q: return(((bt&BLK_COLOUR)==BLK_COLOUR_B)?PIC_Q_B:PIC_Q_Y); break; case BLK_SHAPE_R: return(((bt&BLK_COLOUR)==BLK_COLOUR_B)?PIC_R_B:PIC_R_Y); break; case BLK_SHAPE_P: return(((bt&BLK_COLOUR)==BLK_COLOUR_B)?PIC_P_B:PIC_P_Y); break; case BLK_SHAPE_D: return(((bt&BLK_COLOUR)==BLK_COLOUR_B)?PIC_D_B:PIC_D_Y); break; default: bugchk("invalid block %d at (%d,%d)",bt,x,y); break; } } } } static void drawsq(int x, int y) { int i; Pixmap pm; if (webpref) return; i = picnum_for_loc(x,y); pm = pic_ptrs[i][0]; if (bw_mode) { setup_gc(GCForeground,whitecolour.pixel,GCBackground,blackcolour.pixel,GCFunction,GXcopy,0L); XCopyPlane(disp,pm,gamewin,wingc,0,0,PIC_W,PIC_H,x*PIC_W,y*PIC_H,1L); } else { setup_gc(GCFunction,GXcopy,0L); XCopyArea(disp,pm,gamewin,wingc,0,0,PIC_W,PIC_H,x*PIC_W,y*PIC_H); } if ((dispstate == DS_EDIT) && (x == editcurs_x) && (y == editcurs_y)) { int xx; int yy; setup_gc(GCForeground,whitecolour.pixel,0L); xx = x * PIC_W; yy = y * PIC_H; XFillRectangle(disp,gamewin,wingc,xx,yy,PIC_W,3); XFillRectangle(disp,gamewin,wingc,xx,yy+PIC_H-3,PIC_W,3); XFillRectangle(disp,gamewin,wingc,xx,yy+3,3,PIC_H-6); XFillRectangle(disp,gamewin,wingc,xx+PIC_W-3,yy+3,3,PIC_H-6); } } static void fix_damage(void) { int x; int y; for (x=0;xascent); text_center(levelname,levelname_len,font->ascent+font->descent+font->ascent); } static void update_textpanel(Window win, unsigned char *bits, int x, int y, int w, int h) { static XImage *xi = 0; if (xi == 0) { xi = XCreateImage(disp,visual,1,XYBitmap,0,(char *)bits,PIC_W*BOARD_X,PIC_H*BOARD_Y,8,((PIC_W*BOARD_X)+7)>>3); xi->byte_order = LSBFirst; xi->bitmap_unit = 8; xi->bitmap_bit_order = LSBFirst; } xi->data = (char *)bits; setup_gc(GCForeground,fgcolour.pixel,GCBackground,bgcolour.pixel,GCFunction,GXcopy,0L); XPutImage(disp,win,wingc,xi,x,y,x,y,w,h); } static void update_textpanel_pix(Window win, int *pv) { if (bw_mode) { setup_gc(GCForeground,whitecolour.pixel,GCBackground,blackcolour.pixel,GCFunction,GXcopy,0L); while (pv[0] >= 0) { XCopyPlane(disp,*pic_ptrs[pv[0]],win,wingc,0,0,PIC_W,PIC_H,pv[1],pv[2],1L); pv += 3; } } else { setup_gc(GCFunction,GXcopy,0L); while (pv[0] >= 0) { XCopyArea(disp,*pic_ptrs[pv[0]],win,wingc,0,0,PIC_W,PIC_H,pv[1],pv[2]); pv += 3; } } } static void draw_levprompt(void) { setup_gc(GCFont,fontid,GCForeground,fgcolour.pixel,GCLineWidth,0,GCFillStyle,FillSolid,GCFunction,GXcopy,0L); XDrawRectangle(disp,levprompt_win,wingc,0,0,levprompt_w-1,levprompt_h-1); XDrawString(disp,levprompt_win,wingc,DIALOG_BORDER+DIALOG_MARGIN,DIALOG_BORDER+DIALOG_MARGIN+font->ascent,levprompt_prompt,strlen(levprompt_prompt)); XDrawString(disp,levprompt_win,wingc,levprompt_xoff,DIALOG_BORDER+DIALOG_MARGIN+font->ascent,levprompt_buf,levprompt_fill); } static void draw_msg(void) { setup_gc(GCFont,fontid,GCForeground,fgcolour.pixel,GCLineWidth,0,GCFillStyle,FillSolid,GCFunction,GXcopy,0L); XDrawRectangle(disp,msgwin,wingc,0,0,msg_w-1,msg_h-1); XDrawString(disp,msgwin,wingc,DIALOG_BORDER+DIALOG_MARGIN,DIALOG_BORDER+DIALOG_MARGIN+font->ascent,&msg_buf[0],msg_len); } static void damage_editwin(int x, int y, int w, int h) { int x1; int y1; int x0; int i; x1 = x + w - 1; y1 = y + h - 1; x /= EDIT_MX; y /= EDIT_MY; x1 /= EDIT_MX; y1 /= EDIT_MY; if (x1 >= EDIT_NCOLS) x1 = EDIT_NCOLS - 1; if (y1 >= EDIT_NCOLS) y1 = EDIT_NCOLS - 1; x0 = x; for (;y<=y1;y++) { i = (y * EDIT_NCOLS) + x0; for (x=x0;x<=x1;x++) { if (i < B_NPIX) edit_damaged[i] = 1; i ++; } } } static void fix_edit_damage(void) { int i; setup_gc(GCFunction,GXcopy,0L); for (i=0;iwin,wingc,0,0,b->w-1,b->h-1); XDrawString(disp,b->win,wingc,b->textx,b->texty,b->text,strlen(b->text)); } static void redraw_help_button(int i) { static XImage *xi = 0; BUTTON *b; b = &help_buttons[i]; if (xi == 0) { xi = XCreateImage(disp,visual,1,XYBitmap,0,deconst(b->text),1,help_button_h,8,1); xi->byte_order = LSBFirst; xi->bitmap_unit = 8; xi->bitmap_bit_order = LSBFirst; } /* 5 = # of overhead bytes before bitmap begins - see setup_buttons */ xi->data = 5 + *(char **)deconst(b->text); xi->width = b->w; xi->bytes_per_line = (b->w + 7) >> 3; setup_gc(GCForeground,fgcolour.pixel,GCBackground,bgcolour.pixel,GCFunction,GXcopy,0L); XPutImage(disp,b->win,wingc,xi,0,0,0,0,b->w,b->h); if (i+1 == helpscreen) { xi->data = deconst(&help_button_border_bits[0]); xi->width = b->w; xi->bytes_per_line = (b->w + 7) >> 3; setup_gc(GCForeground,fgcolour.pixel^bgcolour.pixel,GCBackground,0,GCFunction,GXxor,0L); XPutImage(disp,b->win,wingc,xi,0,0,0,0,b->w,b->h); } } static void redisplay(Window win, int x, int y, int w, int h, int count) { int i; if (win == gamewin) { damage_gamewin(x,y,w,h); if (count == 0) fix_damage(); } else if (win == textwin) { if (count == 0) redraw_text(); } else if (win == creditwin) { update_textpanel(creditwin,&credits_img_bits[0],x,y,w,h); if (count == 0) update_textpanel_pix(creditwin,&credits_pix[0]); } else if (win == levprompt_win) { if (count == 0) draw_levprompt(); } else if (win == msgwin) { if (count == 0) draw_msg(); } else if (win == editwin) { damage_editwin(x,y,w,h); if (count == 0) fix_edit_damage(); } else { for (i=0;i= BOARD_X) || (y >= BOARD_Y)); } static int steppable(int x, int y) { if (offboard(x,y)) return(0); switch (squaretype[x][y]) { case SQ_WALL: case SQ_STARS: return(0); } if (blocktype[x][y] != BLK_NONE) return(0); return(1); } static void floodfill(int x0, int y0) { SQL *active; SQL *new; int x; int y; for (y=0;ylink = 0; active->seen = 1; active->from = 4; while (active) { new = 0; while (active) { int i; SQL *t; for (i=0;i<4;i++) { x = active->x + dx[i]; y = active->y + dy[i]; if (! offboard(x,y)) { t = &bsq[x][y]; if (!t->seen && steppable(x,y)) { t->seen = 1; t->from = OTHERWAY(i); t->link = new; new = t; } } } t = active->link; active = t; } active = new; } } static int stepconnected(int x1, int y1, int x2, int y2) { SQL *t; int x; int y; int i; floodfill(x2,y2); if (! bsq[x1][y1].seen) return(0); x = x1; y = y1; i = 0; while (1) { t = &bsq[x][y]; if (t->from > 3) break; stepconn_string[i++] = cmdchar[t->from]; x += dx[t->from]; y += dy[t->from]; } stepconn_string[i] = '\0'; return(1); } static int makemove(int nx, int ny) { int ox; int oy; int bx; int by; int nbt; int bbt; ox = player_x; oy = player_y; bx = nx + nx - player_x; by = ny + ny - player_y; if (offboard(bx,by)) return(0); switch (squaretype[nx][ny]) { case SQ_WALL: case SQ_STARS: return(0); break; } nbt = blocktype[nx][ny]; bbt = blocktype[bx][by]; if (bbt == (nbt^BLK_COLOUR_B^BLK_COLOUR_Y)) { pushsave(); player_x = nx; player_y = ny; blocktype[nx][ny] = BLK_NONE; switch (bbt & BLK_SHAPE) { case BLK_SHAPE_Q: blocktype[bx][by] = BLK_NONE; playsound(SND_Q_Q); break; case BLK_SHAPE_R: blocktype[bx][by] = (bbt & ~BLK_SHAPE) | BLK_SHAPE_Q; playsound(SND_R_R); break; case BLK_SHAPE_P: blocktype[bx][by] = (bbt & ~BLK_SHAPE) | BLK_SHAPE_R; playsound(SND_P_P); break; case BLK_SHAPE_D: blocktype[bx][by] = (bbt & ~BLK_SHAPE) | BLK_SHAPE_P; playsound(SND_D_D); break; default: bugchk("bad block %d in block meeting",bbt); break; } drawsq(ox,oy); drawsq(nx,ny); drawsq(bx,by); } else if (bbt == BLK_NONE) { switch (squaretype[bx][by]) { case SQ_WALL: case SQ_STARS: return(0); break; } pushsave(); player_x = nx; player_y = ny; blocktype[bx][by] = nbt; blocktype[nx][ny] = BLK_NONE; if ((nbt & BLK_SHAPE) == BLK_SHAPE_W) { playsound(SND_SLIDE); } else { switch (squaretype[bx][by]) { case SQ_BLANK: playsound(SND_SLIDE); break; case SQ_COLOUR_B: blocktype[bx][by] = (nbt & ~BLK_COLOUR) | BLK_COLOUR_B; playsound(SND_COLOUR_B); break; case SQ_COLOUR_Y: blocktype[bx][by] = (nbt & ~BLK_COLOUR) | BLK_COLOUR_Y; playsound(SND_COLOUR_Y); break; case SQ_COLOUR_F: blocktype[bx][by] = nbt ^ BLK_COLOUR_B ^ BLK_COLOUR_Y; playsound(SND_COLOUR_F); break; case SQ_TELEPORT: do_teleport(bx,by); break; case SQ_MUTATE: switch (nbt & BLK_SHAPE) { case BLK_SHAPE_Q: blocktype[bx][by] = (nbt & ~BLK_SHAPE) | BLK_SHAPE_R; playsound(SND_MUTATE); break; case BLK_SHAPE_R: blocktype[bx][by] = (nbt & ~BLK_SHAPE) | BLK_SHAPE_P; playsound(SND_MUTATE); break; case BLK_SHAPE_P: blocktype[bx][by] = (nbt & ~BLK_SHAPE) | BLK_SHAPE_D; playsound(SND_MUTATE); break; default: playsound(SND_SLIDE); break; } break; default: bugchk("bad square type %d in block slide",squaretype[nx][ny]); break; } } drawsq(ox,oy); drawsq(nx,ny); drawsq(bx,by); } else { return(0); } return(1); } static int do_move(int dx, int dy) { int nx; int ny; stepconn_string[0] = '\0'; if ((dx == 0) && (dy == 0)) return(0); nx = player_x + dx; ny = player_y + dy; if ( offboard(nx,ny) || ( (abs(dx)+abs(dy) != 1) && (!steppable(nx,ny) || !stepconnected(player_x,player_y,nx,ny)) ) ) { return(1); } if (blocktype[nx][ny] == BLK_NONE) { switch (squaretype[nx][ny]) { case SQ_WALL: case SQ_STARS: return(1); break; } player_x = nx; player_y = ny; drawsq(nx-dx,ny-dy); drawsq(nx,ny); playsound(SND_MOVE); return(0); } else { if (makemove(nx,ny)) { if (boardisclear()) { nextlevel(); playsound(SND_UPLEVEL); } return(0); } return(1); } } static void logkey(const char *fmt, ...) { va_list ap; if (! log_keystrokes) return; va_start(ap,fmt); vprintf(fmt,ap); va_end(ap); putchar('\n'); } static void stepconn_dir(int dx, int dy) { if (dx < 0) stepconn_string[0] = 'h'; else if (dx > 0) stepconn_string[0] = 'l'; else if (dy < 0) stepconn_string[0] = 'k'; else stepconn_string[0] = 'j'; stepconn_string[1] = '\0'; } static void mousegame(int x, int y) { int oldlev; int dx; int dy; oldlev = curlevelno; x = ((x + PIC_W) / PIC_W) - 1; y = ((y + PIC_H) / PIC_H) - 1; dx = x - player_x; dy = y - player_y; if ((dx == 0) && (dy == 0)) return; if (do_move(dx,dy)) { playsound(SND_CANTMOVE); } else { if (! stepconn_string[0]) stepconn_dir(dx,dy); logkey("%s# Click [move to %d,%d]",&stepconn_string[0],x,y); } if (curlevelno != oldlev) logkey("# Level now %d",curlevelno); } static const char *layout_twochar(int lv) { switch (lv) { case PIC_BLANK: return("__"); break; case PIC_Q_B: return("QB"); break; case PIC_Q_Y: return("QY"); break; case PIC_R_B: return("RB"); break; case PIC_R_Y: return("RY"); break; case PIC_P_B: return("PB"); break; case PIC_P_Y: return("PY"); break; case PIC_D_B: return("DB"); break; case PIC_D_Y: return("DY"); break; case PIC_COLOUR_B: return("CB"); break; case PIC_COLOUR_Y: return("CY"); break; case PIC_COLOUR_FLIP: return("CF"); break; case PIC_WALL: return("WL"); break; case PIC_MWALL: return("MW"); break; case PIC_TELEPORT: return("TL"); break; case PIC_MUTATE: return("MU"); break; case PIC_PLAYER: return("PL"); break; case PIC_STARS_A: return("SA"); break; case PIC_STARS_B: return("SB"); break; case PIC_STARS_C: return("SC"); break; case PIC_STARS_D: return("SD"); break; case PIC_STARS_E: return("SE"); break; case PIC_STARS_F: return("SF"); break; case PIC_STARS_G: return("SG"); break; case PIC_STARS_H: return("SH"); break; case PIC_STARS_I: return("SI"); break; case PIC_STARS_J: return("SJ"); break; } return(0); } static void edit_set(const char *tag, int x, int y) { int sq; int bl; int st; int draw; char logmsg[64]; char *lmp; if (offboard(x,y)) return; lmp = &logmsg[0]; draw = 0; if (set_sq_bl(edit_curpic,&sq,&bl,&st)) { int ox; int oy; if ((x != player_x) || (y != player_y)) { ox = player_x; oy = player_y; player_x = x; player_y = y; drawsq(ox,oy); draw = 1; sprintf(lmp,"%d,%d <- %s",x,y,layout_twochar(PIC_PLAYER)); lmp += strlen(lmp); } } if ( (squaretype[x][y] != sq) || (startype[x][y] != st) || (blocktype[x][y] != bl) ) { squaretype[x][y] = sq; startype[x][y] = st; blocktype[x][y] = bl; draw = 1; sprintf(lmp,"%d,%d <- %s",x,y,layout_twochar(edit_curpic)); lmp += strlen(lmp); } if (draw) drawsq(x,y); if ( (blocktype[player_x][player_y] != BLK_NONE) || (squaretype[player_x][player_y] != SQ_BLANK) ) { int off; int i; int ox; int oy; ox = player_x; oy = player_y; off = (player_y * BOARD_X) + player_x; for (i=0;i= EDIT_SPACING) && (ry >= EDIT_SPACING)) { i = (qy * EDIT_NCOLS) + qx; if (i < B_NPIX) { edit_damaged[edit_curpic] = 1; edit_curpic = i; edit_damaged[edit_curpic] = 1; fix_edit_damage(); } } } static void sethelp(int n) { int o; if ((n > 0) && (n <= N_HELP)) { o = helpscreen; XRaiseWindow(disp,helpwins[n-1]); helpscreen = n; if (o != n) { redraw_help_button(o-1); redraw_help_button(n-1); } } } static void endhelp(void) { setdispstate(DS_GAME); } static void buttondown(Window win, int x, int y, UNUSED_ARG(unsigned int state), UNUSED_ARG(unsigned int button)) { int i; BUTTON *b; if (win == gamewin) { switch (dispstate) { default: setdispstate(DS_GAME); /* fall through */ case DS_GAME: mousegame(x,y); break; case DS_ASKLEVEL: break; case DS_MSG: logkey("## [msg] Click [return]"); setdispstate(DS_GAME); break; case DS_EDIT: mouseedit(x,y); break; } } else if (win == creditwin) { logkey("## [credits] Click [return]"); setdispstate(DS_GAME); } else if (win == levprompt_win) { if (dispstate == DS_ASKLEVEL) asklevel_done(); } else if (win == msgwin) { logkey("## [msg] Click [return]"); setdispstate(DS_GAME); } else if (win == editwin) { int oecp; oecp = edit_curpic; pickpic(x,y); if (edit_curpic != oecp) logkey("## [edit] Click [choose %s]",layout_twochar(edit_curpic)); } else { for (i=0;iwin) { (*b->callback)("## Click"); } } for (i=0;iwin) { (*b->callback)("## Click"); } } for (i=0;iwin) { (*b->callback)("## Click"); } } for (i=0;iwin) { (*b->callback)("## Click"); } } } } static void motion(Window win, int x, int y, UNUSED_ARG(unsigned int state)) { if (win == gamewin) { switch (dispstate) { case DS_GAME: mousegame(x,y); break; case DS_EDIT: mouseedit(x,y); break; } } } static void level_juggle(char (*bl)[BOARD_Y], int *pxp, int *pyp, int swap) { int tmp; int x; int y; for (x=0;x= BOARD_X) editcurs_x = BOARD_X - 1; if (editcurs_y < 0) editcurs_y = 0; else if (editcurs_y >= BOARD_Y) editcurs_y = BOARD_Y - 1; if ((editcurs_x != ox) || (editcurs_y != oy)) { drawsq(ox,oy); drawsq(editcurs_x,editcurs_y); } } static void change_curpic(int d) { edit_damaged[edit_curpic] = 1; edit_curpic += d; if (edit_curpic < 0) edit_curpic += B_NPIX; else if (edit_curpic >= B_NPIX) edit_curpic -= B_NPIX; edit_damaged[edit_curpic] = 1; fix_edit_damage(); } static void reset_sizes(void) { setup_sizes(); resize(topw,toph); } static void levname_done(int saveit) { setdispstate(DS_EDIT); if (saveit) { free(curlevel->name); curlevel->namelen = lnfill; curlevel->name = malloc(lnfill); bcopy(&lnbuf[0],curlevel->name,lnfill); curlevel->seg->dirty = 1; } levelname = curlevel->name; levelname_len = curlevel->namelen; reset_sizes(); XClearArea(disp,textwin,0,0,0,0,False); } static void docmd(KeySym ks, unsigned int state, int nc, char *str) { switch (dispstate) { case DS_GAME: if (state & ControlMask) { switch (ks) { case XK_H: case XK_h: buttoncb_help("^H"); break; case XK_C: case XK_c: buttoncb_credits("^C"); break; case XK_E: case XK_e: buttoncb_edit("^E"); break; /* case XK_P: case XK_p: buttoncb_save("^P"); break; */ case XK_S: case XK_s: buttoncb_save("^S"); break; case XK_Q: case XK_q: buttoncb_quit("^Q"); break; case XK_R: case XK_r: logkey("^R# reset level"); resetlevel(); break; case XK_Z: case XK_z: logkey("^Z# undo"); undopush(); break; case XK_P: case XK_p: logkey("^P# play level"); asklevel(); break; } } else { switch (ks) { case XK_H: case XK_h: cmd_move("H", -1, 0); break; case XK_J: case XK_j: cmd_move("J", 0, 1); break; case XK_K: case XK_k: cmd_move("K", 0,-1); break; case XK_L: case XK_l: cmd_move("L", 1, 0); break; case XK_Left: cmd_move("H# Left", -1, 0); break; case XK_Down: cmd_move("J# Down", 0, 1); break; case XK_Up: cmd_move("K# Up", 0,-1); break; case XK_Right: cmd_move("L# Right", 1, 0); break; } } break; case DS_CREDITS: logkey("## [credits] Any [return]"); setdispstate(DS_GAME); break; case DS_HELP: switch (ks) { case XK_1: logkey("1# [help]"); sethelp(1); break; case XK_2: logkey("2# [help]"); sethelp(2); break; case XK_3: logkey("3# [help]"); sethelp(3); break; case XK_4: logkey("4# [help]"); sethelp(4); break; case XK_5: logkey("5# [help]"); sethelp(5); break; case XK_6: logkey("6# [help]"); sethelp(6); break; case XK_7: logkey("7# [help]"); sethelp(7); break; case XK_8: logkey("8# [help]"); sethelp(8); break; case XK_9: logkey("9# [help]"); sethelp(9); break; case XK_space: if (helpscreen < N_HELP) { logkey(" # [help - %d]",helpscreen+1); sethelp(helpscreen+1); } else { logkey(" # [help - return]"); endhelp(); } break; case XK_Escape: logkey("^[# [help - return]"); endhelp(); break; case XK_R: case XK_r: logkey("R# [help - return]"); endhelp(); break; case XK_Return: logkey("^M# [help - return]"); endhelp(); break; } break; case DS_ASKLEVEL: if (nc > 0) { int i; for (i=0;i 0) { levprompt_fill --; XClearArea(disp,levprompt_win,levprompt_xclr,DIALOG_BORDER,levprompt_w-levprompt_xclr-DIALOG_BORDER,levprompt_h-(2*DIALOG_BORDER),True); } break; default: if (levprompt_fill >= levprompt_len) { bcopy(levprompt_buf+1,levprompt_buf,levprompt_len-1); levprompt_fill --; } levprompt_buf[levprompt_fill++] = str[i]; } } XClearArea(disp,levprompt_win,levprompt_xclr,DIALOG_BORDER,levprompt_w-levprompt_xclr-DIALOG_BORDER,levprompt_h-(2*DIALOG_BORDER),False); redisplay(levprompt_win,levprompt_xclr,DIALOG_BORDER,levprompt_w-levprompt_xclr-DIALOG_BORDER,levprompt_h-(2*DIALOG_BORDER),0); } break; case DS_MSG: logkey("## [msg] Any [return]"); setdispstate(DS_GAME); break; case DS_EDIT: if (state & ControlMask) { switch (ks) { case XK_J: case XK_j: buttoncb_e_junk("^J"); break; case XK_R: case XK_r: buttoncb_e_revert("^R"); break; case XK_A: case XK_a: buttoncb_e_abort("^A"); break; case XK_D: case XK_d: buttoncb_e_done("^D"); break; case XK_N: case XK_n: buttoncb_e_name("^N"); break; case XK_C: case XK_c: buttoncb_e_clone("^C"); break; } } else { switch (ks) { case XK_H: case XK_h: logkey("H# [edit]"); edit_move(-1, 0); break; case XK_J: case XK_j: logkey("J# [edit]"); edit_move( 0, 1); break; case XK_K: case XK_k: logkey("K# [edit]"); edit_move( 0,-1); break; case XK_L: case XK_l: logkey("L# [edit]"); edit_move( 1, 0); break; case XK_Left: logkey("H#Left [edit]"); edit_move(-1, 0); break; case XK_Down: logkey("J#Down [edit]"); edit_move( 0, 1); break; case XK_Up: logkey("K#Up [edit]"); edit_move( 0,-1); break; case XK_Right: logkey("L#Right [edit]"); edit_move( 1, 0); break; case XK_plus: logkey("+# [edit]"); change_curpic( 1); break; case XK_minus: logkey("-# [edit]"); change_curpic(-1); break; case XK_space: edit_set(" ",editcurs_x,editcurs_y); break; } } break; case DS_LEVNAME: if (nc > 0) { int i; for (i=0;i 0) { lnfill --; } break; default: if (lnfill < MAXLNLEN) { lnbuf[lnfill++] = str[i]; } else { XBell(disp,0); } break; } } levelname_len = lnfill; XClearArea(disp,textwin,0,0,0,0,False); redraw_text(); } break; } } static int replay_char(int c) { int rv; rv = 1; switch (c) { default: rv = 0; break; #define N(x) docmd(x,(replay_flags&RF_CTL)?ControlMask:0,0,0); break; #define A(x) docmd(x,0,0,0); break; case '^': replay_flags |= RF_NXCTL; break; case 'a': case 'A': N(XK_A) case 'c': case 'C': N(XK_C) case 'd': case 'D': N(XK_D) case 'e': case 'E': N(XK_E) case 'h': case 'H': N(XK_H) case 'j': case 'J': N(XK_J) case 'k': case 'K': N(XK_K) case 'l': case 'L': N(XK_L) case 'n': case 'N': N(XK_N) case 'p': case 'P': N(XK_P) case 'q': case 'Q': N(XK_Q) case 'r': case 'R': N(XK_R) case 's': case 'S': N(XK_S) case 'z': case 'Z': N(XK_Z) case '1': A(XK_1) case '2': A(XK_2) case '3': A(XK_3) case '4': A(XK_4) case '5': A(XK_5) case '6': A(XK_6) case '7': A(XK_7) case '8': A(XK_8) case '9': A(XK_9) case ' ': A(XK_space) case '+': A(XK_plus) case '-': A(XK_minus) #undef N #undef A } replay_flags &= ~RF_CTL; if (replay_flags & RF_NXCTL) { replay_flags &= ~RF_NXCTL; replay_flags |= RF_CTL; } return(rv); } static void selection_notify(Atom property) { Atom type; int format; unsigned long int nitems; unsigned long int bytes_after; unsigned char *data; long int offset; int i; if (! pasting) return; if (0) { err:; XBell(disp,0); return; } if (property == None) goto err; offset = 0; do { XGetWindowProperty(disp,gamewin,atoms[AX_selprop],offset,512L,True,AnyPropertyType,&type,&format,&nitems,&bytes_after,&data); if (type == None) goto err; nitems *= format >> 3; logkey("# pasted string = %.*s",nitems,(char *)data); for (i=0;i> 2; } while (bytes_after > 0); } static void handle_event(XEvent *e) { switch (e->type) { default: break; case ConfigureNotify: /* XConfigureEvent - xconfigure */ resize(e->xconfigure.width,e->xconfigure.height); break; case Expose: /* XExposeEvent - xexpose */ redisplay(e->xexpose.window,e->xexpose.x,e->xexpose.y,e->xexpose.width,e->xexpose.height,e->xexpose.count); break; case GraphicsExpose: /* XGraphicsExposeEvent - xgraphicsexpose */ redisplay(e->xgraphicsexpose.drawable,e->xgraphicsexpose.x,e->xgraphicsexpose.y,e->xgraphicsexpose.width,e->xgraphicsexpose.height,e->xgraphicsexpose.count); break; case ButtonPress: /* XButtonPressEvent - XButtonEvent - xbutton */ pasting = 0; buttontime = e->xbutton.time; buttondown(e->xbutton.window,e->xbutton.x,e->xbutton.y,e->xbutton.state,e->xbutton.button); break; case MotionNotify: /* XMotionEvent - xmotion */ motion(e->xmotion.window,e->xmotion.x,e->xmotion.y,e->xmotion.state); break; case KeyPress: /* XKeyPressedEvent - XKeyEvent - xkey */ { static XComposeStatus compose_status; KeySym ks; char string[256]; int nc; nc = XLookupString(&e->xkey,&string[0],256,&ks,&compose_status); pasting = 0; docmd(ks,e->xkey.state,nc,&string[0]); } break; case MappingNotify: /* XMappingEvent - xmapping */ XRefreshKeyboardMapping(&e->xmapping); break; case SelectionNotify: /* XSelectionEvent - xselection */ if (e->xselection.requestor == gamewin) { selection_notify(e->xselection.property); } break; } } static void set_msg_size(void) { XCharStruct d; XTextExtents(font,&msg_buf[0],msg_len,XTE_JUNK,&d); msg_w = DIALOG_BORDER + DIALOG_MARGIN + d.width + DIALOG_MARGIN + DIALOG_BORDER; msg_h = DIALOG_BORDER + DIALOG_MARGIN + font->ascent + font->descent + DIALOG_MARGIN + DIALOG_BORDER; } static void popmsg(const char *fmt, ...) { va_list ap; va_start(ap,fmt); vsprintf(&msg_buf[0],fmt,ap); va_end(ap); msg_len = strlen(&msg_buf[0]); set_msg_size(); place_msgwin(); setdispstate(DS_MSG); XMapRaised(disp,msgwin); } #ifdef REPLAY static void replay_cmd(const char *buf) { if (!strcmp(buf,"fast")) { replay_flags |= RF_BLITZ; } else if (!strcmp(buf,"slow")) { replay_flags &= ~RF_BLITZ; } } #endif #ifdef REPLAY static void inc_tv_by_ms(struct timeval *tv, unsigned int ms) { tv->tv_usec += 1000 * (ms % 1000); if (tv->tv_usec >= 1000000) { tv->tv_usec -= 1000000; tv->tv_sec ++; } tv->tv_sec += ms / 1000; } #endif #ifdef REPLAY static void run(void) { XEvent e; struct timeval nextchar; struct timeval now; struct timeval sleepfor; int c; fd_set fds; int lastlev; if (replay) { popmsg("Press any key to start replay..."); while (dispstate == DS_MSG) { XNextEvent(disp,&e); handle_event(&e); } lastlev = -1; } if (replay_ms < 1) replay_ms = 1000; gettimeofday(&nextchar,0); nextchar.tv_sec ++; while (1) { if (replay) { while (XPending(disp)) { XNextEvent(disp,&e); handle_event(&e); } if (curlevelno != lastlev) { XSync(disp,False); while (XPending(disp)) { XNextEvent(disp,&e); handle_event(&e); } lastlev = curlevelno; gettimeofday(&nextchar,0); inc_tv_by_ms(&nextchar,replay_ms); } gettimeofday(&now,0); if ( (nextchar.tv_sec < now.tv_sec) || ( (nextchar.tv_sec == now.tv_sec) && (nextchar.tv_usec <= now.tv_usec) ) ) { while (1) { c = getchar(); if (c == '#') { do { c = getchar(); } while ((c != '\n') && (c != EOF)); } else if (c == '{'/*}*/) { int len; int have; char *buf; buf = malloc(1); have = 0; len = 0; while (1) { c = getchar(); if (c == /*{*/'}') { buf[len] = '\0'; replay_cmd(buf); free(buf); break; } if (c == EOF) { free(buf); break; } while (have <= len) buf = realloc(buf,(have+=16)+1); buf[len++] = c; } } else { break; } } if (c == EOF) { replay = 0; continue; } if (replay_char(c)) { if (replay_flags & RF_BLITZ) { nextchar = now; } else { inc_tv_by_ms(&nextchar,replay_ms); } } } else { sleepfor.tv_sec = nextchar.tv_sec - now.tv_sec; if (nextchar.tv_usec >= now.tv_usec) { sleepfor.tv_usec = nextchar.tv_usec - now.tv_usec; } else { sleepfor.tv_usec = 1000000 + nextchar.tv_usec - now.tv_usec; sleepfor.tv_sec --; } FD_ZERO(&fds); FD_SET(XConnectionNumber(disp),&fds); select(FD_SETSIZE,&fds,0,0,&sleepfor); } } else { XNextEvent(disp,&e); handle_event(&e); } } } #else static void run(void) { XEvent e; while (1) { XNextEvent(disp,&e); handle_event(&e); } } #endif static void beginhelp(void) { setdispstate(DS_HELP); sethelp(helpscreen); XRaiseWindow(disp,helpwin); XMapWindow(disp,textpanelwin); } static void begin_edit(void) { if (curlevel->seg->source == 0) { popmsg("Can't edit built-in levels"); } else { setdispstate(DS_EDIT); XMapWindow(disp,editwin); XMapWindow(disp,line1win); XLowerWindow(disp,g_buttonwin); edit_ask_resize(); editcurs_x = init_player_x; editcurs_y = init_player_y; sqdamaged[editcurs_x][editcurs_y] = 1; resetlevel(); } } static void finish_edit(void) { int x; int y; setdispstate(DS_GAME); for (x=0;xseg->dirty = 1; for (x=0;xlayout[y][x] = pic; } } curlevel->layout[player_y][player_x] = PIC_PLAYER; initlevel(); } static void fwrite_level(FILE *f, LEVEL *l) { int x; int y; const char *s; fprintf(f,"%d:",l->namelen); fwrite(l->name,1,l->namelen,f); for (y=0;ylayout[y][x]); if (! s) bugchk("Bad value %d in layout[%d][%d] for level %d (from %s) in fwrite_level",l->layout[y][x],y,x,l->levelno,l->seg->source); fprintf(f,"%c%s",x?' ':'\n',s); } } fprintf(f,"\n"); } static void saveseg(LEVEL_SEG *seg) { FILE *f; int i; if (! seg->dirty) return; if (! seg->source) bugchk("Called saveseg on dirty built-in segment"); f = fopen(seg->source,"w"); if (f == 0) { popmsg("Can't open %s",seg->source); return; } for (i=0;inum;i++) { if (i) fprintf(f,"\n"); fwrite_level(f,seg->levels[i]); } fclose(f); seg->dirty = 0; XRaiseWindow(disp,g_buttonwin_no_s); popmsg("%s written",seg->source); } static void showcredits(void) { setdispstate(DS_CREDITS); XRaiseWindow(disp,creditwin); XMapWindow(disp,textpanelwin); } static void levname_begin(void) { setdispstate(DS_LEVNAME); lnfill = levelname_len; if (lnfill > MAXLNLEN) lnfill = MAXLNLEN; bcopy(levelname,&lnbuf[0],lnfill); XClearArea(disp,textwin,0,0,0,0,False); levelname = &lnbuf[0]; levelname_len = lnfill; redraw_text(); } static void clonelevel(void) { LEVEL_SEG *ls; LEVEL *l; int i; LEVEL **newlevels; int o; for (ls=curlevel->seg->link;ls;ls=ls->link) { ls->first ++; ls->last ++; for (i=0;inum;i++) ls->levels[i]->levelno = ls->first + i; } ls = curlevel->seg; newlevels = (LEVEL **) malloc((ls->num+1)*sizeof(LEVEL *)); o = curlevel->levelno - ls->first; for (i=0;i<=o;i++) newlevels[i] = ls->levels[i]; for (i=ls->num-1;i>o;i--) { l = ls->levels[i]; newlevels[i+1] = l; l->levelno ++; } l = NEW(LEVEL); newlevels[o+1] = l; *l = *newlevels[o]; l->name = malloc(l->namelen+7); bcopy(newlevels[o]->name,l->name,l->namelen); l->name[l->namelen++] = ' '; l->name[l->namelen++] = '('; l->name[l->namelen++] = 'c'; l->name[l->namelen++] = 'o'; l->name[l->namelen++] = 'p'; l->name[l->namelen++] = 'y'; l->name[l->namelen++] = ')'; l->levelno ++; curlevel = l; curlevelno = l->levelno; maxlevelno ++; ls->dirty = 1; ls->num ++; ls->last ++; free((char *)ls->levels); ls->levels = newlevels; reset_sizes(); initlevel(); XClearArea(disp,textwin,0,0,0,0,False); redraw_text(); } static void junklevel(void) { LEVEL_SEG *ls; int i; ls = curlevel->seg; if (ls->num < 2) { XBell(disp,0); return; } for (ls=ls->link;ls;ls=ls->link) { ls->first --; ls->last --; for (i=0;inum;i++) ls->levels[i]->levelno = ls->first + i; } ls = curlevel->seg; free(curlevel->name); OLD(curlevel); if (curlevelno == ls->last) { curlevelno --; } else { for (i=curlevelno+1-ls->first;inum;i++) { LEVEL *l; l = ls->levels[i]; ls->levels[i-1] = l; l->levelno --; } } ls->dirty = 1; ls->num --; ls->last --; reset_sizes(); initlevel(); redraw(); } static void buttoncb_e_junk(const char *tag) { logkey("%s# [edit - junk level]",tag); junklevel(); } static void buttoncb_e_revert(const char *tag) { logkey("%s# [edit - revert level]",tag); level_juggle(init_blocktype,&init_player_x,&init_player_y,0); } static void buttoncb_e_abort(const char *tag) { logkey("%s# [edit - abort edit]",tag); resetlevel(); setdispstate(DS_GAME); } static void buttoncb_e_done(const char *tag) { logkey("%s# [edit - done]",tag); finish_edit(); } static void buttoncb_e_name(const char *tag) { logkey("%s# [edit - name]",tag); levname_begin(); } static void buttoncb_e_clone(const char *tag) { logkey("%s# [edit - clone]",tag); clonelevel(); } static void buttoncb_help1(const char *tag) { logkey("%s# [help - 1]",tag); sethelp(1); } static void buttoncb_help2(const char *tag) { logkey("%s# [help - 2]",tag); sethelp(2); } static void buttoncb_help3(const char *tag) { logkey("%s# [help - 3]",tag); sethelp(3); } static void buttoncb_help4(const char *tag) { logkey("%s# [help - 4]",tag); sethelp(4); } static void buttoncb_help5(const char *tag) { logkey("%s# [help - 5]",tag); sethelp(5); } static void buttoncb_helpret(const char *tag) { logkey("%s# [help - return]",tag); setdispstate(DS_GAME); } static void buttoncb_help(const char *tag) { logkey("%s# [help]",tag); beginhelp(); } static void buttoncb_credits(const char *tag) { logkey("%s# [credits]",tag); showcredits(); } static void buttoncb_paste(const char *tag) { logkey("%s# [paste]",tag); XConvertSelection(disp,atoms[AX_PRIMARY],atoms[AX_STRING],atoms[AX_selprop],gamewin,buttontime); pasting = 1; } static void buttoncb_edit(const char *tag) { logkey("%s# [edit]",tag); begin_edit(); } static void buttoncb_save(const char *tag) { if (! curlevel->seg->dirty) return; logkey("%s# [save]",tag); saveseg(curlevel->seg); } static void buttoncb_quit(const char *tag) { logkey("%s# [quit]",tag); exit(0); } static Display *open_display(char *disp) { Display *rv; rv = XOpenDisplay(disp); if (rv == 0) { fprintf(stderr,"%s: can't open display %s\n",__progname,XDisplayName(disp)); exit(1); } return(rv); } static int err(Display *d, XErrorEvent *ee) { return((*preverr)(d,ee)); } static int ioerr(Display *d) { return((*prevIOerr)(d)); } #ifdef WEBSERVER typedef struct f_acc_priv F_ACC_PRIV; struct f_acc_priv { char *buf; int len; char **argptr; int *arglen; } ; static int fopen_acc_w(void *pv, const char *buf, int len) { F_ACC_PRIV *p; p = pv; p->buf = realloc(p->buf,p->len+len); bcopy(buf,p->buf+p->len,len); p->len += len; return(len); } static int fopen_acc_c(void *pv) { F_ACC_PRIV *p; p = pv; *p->argptr = p->buf; *p->arglen = p->len; free(p); return(0); } static FILE *fopen_acc(char **ptr, int *len) { F_ACC_PRIV *p; FILE *f; p = malloc(sizeof(F_ACC_PRIV)); if (! p) return(0); p->argptr = ptr; p->arglen = len; p->buf = 0; p->len = 0; f = funopen(p,0,fopen_acc_w,0,fopen_acc_c); if (! f) free(p); return(f); } static int decode_level(const char *s) { const char *s0; char *ep; long int l; int x; int y; s0 = s; if (s[0] != '/') return(0); if (s[1] == 'n') { curlevelno = atoi(s+2); initlevel(); return(1); } if (s[1] != 'p') return(0); l = strtol(s+2,&ep,10); curlevelno = l; s = ep; for (y=0;y= PIC_NSTARS)) return(0); startype[x][y] = l; break; } switch (*s) { case 'B': blocktype[x][y] = BLK_COLOUR_B; if (0) { case 'Y': blocktype[x][y] = BLK_COLOUR_Y; } switch (*++s) { case 'q': blocktype[x][y] |= BLK_SHAPE_Q; break; case 'r': blocktype[x][y] |= BLK_SHAPE_R; break; case 'p': blocktype[x][y] |= BLK_SHAPE_P; break; case 'd': blocktype[x][y] |= BLK_SHAPE_D; break; default: return(0); break; } s ++; break; case 'W': blocktype[x][y] = BLK_SHAPE_W; s ++; break; default: blocktype[x][y] = BLK_NONE; break; } } } l = *s++ - 'a'; if ((l < 0) || (l >= BOARD_X)) return(0); player_x = l; l = *s++ - 'a'; if ((l < 0) || (l >= BOARD_X)) return(0); player_y = l; if (*s) return(0); return(1); } static void gen_level_string(char *buf) { int x; int y; *buf++ = '/'; *buf++ = 'p'; sprintf(buf,"%d",curlevelno); buf += strlen(buf); for (y=0;yls->last);ls=ls->link) ; if (! ls) l = 1; sprintf(result,"/n%d",l); } else { gen_level_string(result); } level_juggle(save_blocktype,&save_player_x,&save_player_y,0); } } } static void gen_level_html(FILE *f) { int x; int y; char result[(BOARD_X*BOARD_Y*3)+16]; fprintf(f,"",BOARD_X*PIC_W,BOARD_Y*PIC_H); floodfill(player_x,player_y); for (y=0;y"); for (x=0;x"); try_move_to(x,y,&result[0]); if (result[0]) fprintf(f,"",webpref,&result[0]); fprintf(f,"",webpref,picnum_for_loc(x,y)); if (result[0]) fprintf(f,""); fprintf(f,""); } fprintf(f,""); } fprintf(f,"
\n"); } /* Note that we do not, strictly speaking, generate GIF files, because we don't lzw-compress the data. However, what we do do works with all known GIF decoders. */ static FILE *gif_f; static unsigned char gif_blk[255]; static int gif_blkn; static unsigned int gif_dbuf; static unsigned int gif_dbits; static unsigned int gif_lnc; static unsigned int gif_codew; static unsigned int gif_nextcode; static void gif_blkflush(void) { putc(gif_blkn,gif_f); fwrite(&gif_blk[0],1,gif_blkn,gif_f); gif_blkn = 0; } static void gif_blkbyte(unsigned char b) { gif_blk[gif_blkn++] = b; if (gif_blkn > 254) gif_blkflush(); } static void gen_gif_code(unsigned int c) { gif_dbuf |= c << gif_dbits; gif_dbits += gif_codew; while (gif_dbits >= 8) { gif_blkbyte(gif_dbuf&0xff); gif_dbuf >>= 8; gif_dbits -= 8; } } static unsigned int ceil_lg(unsigned int v) { unsigned int n; for (n=1;v>1;n++,v>>=1) ; return(n); } static void gen_gif_start(FILE *f, int w, int h) { unsigned char lsd[7]; unsigned char rgb[3]; unsigned char id[10]; int nc; int i; gif_f = f; gif_lnc = ceil_lg(B_NCOLOURS); nc = 1 << gif_lnc; fwrite("GIF87a",1,6,gif_f); lsd[0] = w & 0xff; /* width, lsb */ lsd[1] = w >> 8; /* width, msb */ lsd[2] = h & 0xff; /* height, lsb */ lsd[3] = h >> 8; /* height, ms */ /* 0xf0 = global colour table present, 8-bit colour, unsorted table */ lsd[4] = 0xf0 + (gif_lnc - 1); lsd[5] = 0; /* background pixel value */ lsd[6] = 0; /* pixel aspect ratio (not provided - 87a compat) */ fwrite(&lsd[0],1,7,gif_f); for (i=0;i> 8; rgb[1] = b_p_colours[i][1] >> 8; rgb[2] = b_p_colours[i][2] >> 8; } else { rgb[0] = 0; rgb[1] = 0; rgb[2] = 0; } fwrite(&rgb[0],1,3,gif_f); } id[0] = 0x2c; /* image descriptor marker */ id[1] = 0; /* x pos, lsb */ id[2] = 0; /* x pos, msb */ id[3] = 0; /* y pos, lsb */ id[4] = 0; /* y pos, msb */ id[5] = lsd[0]; /* width, lsb */ id[6] = lsd[1]; /* width, msb */ id[7] = lsd[2]; /* height, lsb */ id[8] = lsd[3]; /* height, msb */ /* 0x00 = no local colour table, no interlace, unsorted, MBZ, no LCT */ id[9] = 0x00; fwrite(&id[0],1,10,gif_f); putc(gif_lnc,gif_f); gif_dbuf = 0; gif_dbits = 0; gif_codew = ((gif_lnc < 2) ? 2 : gif_lnc) + 1; gif_nextcode = (1 << (gif_codew-1)) + 2; gif_blkn = 0; } static void gen_gif_pixel(int p) { if ((p < 0) || (p >= B_NCOLOURS)) bugchk("bad colour %d to gen_gif_pixel",p); gen_gif_code(p); gif_nextcode ++; if (! (gif_nextcode & (gif_nextcode+1))) { gen_gif_code(1<<(gif_codew-1)); gif_nextcode = (1 << (gif_codew-1)) + 2; } } static void gen_gif_done(void) { gen_gif_code((1<<(gif_codew-1))+1); if (gif_dbits) gif_blkbyte(gif_dbuf); gif_blkflush(); putc(0x00,gif_f); /* block terminator */ putc(0x3b,gif_f); /* trailer */ } static void gen_level_mini(FILE *f) { int cx; int cy; int px; int py; gen_gif_start(f,BOARD_X*PIC_SW,BOARD_Y*PIC_SH); for (cy=0;cyBlockade\n"); fprintf(f,"\

Sorry, you've asked for a Blockade page I don't know how to generate.\n\ If this occurred in normal use while playing, please report it as a bug.

\n\

Back to the level selection screen

\n\ ",webpref); fprintf(f,"\n"); } n = 1; setsockopt(0,SOL_SOCKET,SO_KEEPALIVE,&n,sizeof(n)); setsockopt(1,SOL_SOCKET,SO_KEEPALIVE,&n,sizeof(n)); do /*<"delim">*/ { for (n=0;n<64;n++) { c = getchar(); if (c == EOF) exit(0); if (c == ' ') goto break_delim/*break <"delim">*/; } exit(0); } while (0); break_delim:; do /*<"path">*/ { for (n=0;n*/; txtbuf[n] = c; } exit(0); } while (0); break_path:; txtbuf[n] = '\0'; nowtt = time(0); nowtm = gmtime(&nowtt); f = fopen_acc(&obuf,&olen); otype = "application/x-internal-error"; ocode = "200 OK"; if (! strcmp(&txtbuf[0],"/")) { LEVEL_SEG *ls; int i; otype = "text/html"; fprintf(f,"Blockade\n"); fprintf(f,"

Choose a level to play:

\n"); for (ls=level_segs;ls;ls=ls->link) { for (i=ls->first;i<=ls->last;i++) { fprintf(f,"

\"Level

\n",webpref,i,webpref,i,i); } } fprintf(f,"\n"); } else if (! strncmp(&txtbuf[0],"/i",2)) { switch (txtbuf[2]) { case 'f': curlevelno = atoi(&txtbuf[3]); initlevel(); gen_level_mini(f); otype = "image/gif"; break; case 'p': gen_piece(f,atoi(&txtbuf[3])); otype = "image/gif"; break; default: gen_404(f); break; } } else if (decode_level(&txtbuf[0])) { otype = "text/html"; fprintf(f,"\ \ \ Blockade\ \ \ \ \n"); curlevelno = atoi(&txtbuf[2]); gen_level_html(f); fprintf(f,"\n"); } else { gen_404(f); } fclose(f); printf("HTTP/1.0 %s\r\n",ocode); strftime(&txtbuf[0],sizeof(txtbuf),"%a, %d %b %Y %H:%M:%S GMT",nowtm); printf("Date: %s\r\n",&txtbuf[0]); printf("Server: Blockade/1.0\r\n"); printf("Content-Length: %d\r\n",olen); printf("Connection: close\r\n"); printf("Content-Type: %s\r\n",otype); printf("\r\n"); fwrite(obuf,1,olen,stdout); exit(0); } #endif int main(int, char **); int main(int ac, char **av) { if (__progname == 0) __progname = av[0]; saveargv(ac,av); handleargs(ac,av); setup_levels(); #ifdef WEBSERVER if (webpref) do_web(); #endif disp = open_display(displayname); if (syncX) XSynchronize(disp,True); preverr = XSetErrorHandler(err); prevIOerr = XSetIOErrorHandler(ioerr); scr = XDefaultScreenOfDisplay(disp); width = XWidthOfScreen(scr); height = XHeightOfScreen(scr); rootwin = XRootWindowOfScreen(scr); setup_db(); maybeset(&geometryspec,get_default_value("geometry","Geometry")); maybeset(&fontname,get_default_value("font","Font")); maybeset(&background,get_default_value("background","Background")); maybeset(&foreground,get_default_value("foreground","Foreground")); maybeset(&bordercstr,get_default_value("borderColour","BorderColour")); maybeset(&borderwstr,get_default_value("borderWidth","BorderWidth")); maybeset(&name,get_default_value("name","Name")); maybeset(&iconname,get_default_value("iconName","IconName")); maybeset(&visualstr,get_default_value("visual","Visual")); maybeset(&selkey,get_default_value("selkey","Selkey")); if (dosounds) setup_sound(); setup_atoms(); setup_visual(); setup_font(); setup_colours(); setup_numbers(); setup_wingc(); setup_pixmaps(); setup_sizes(); setup_buttons(); setup_windows(); setup_game(); run(); exit(0); }