/* $Id: sxsame.c,v 1.1 1996/05/04 19:08:18 yoneyama Exp yoneyama $ */ /************************************************************************ * SameGame for X Window (sxsame) * * Copyleft (c) 1994-1996 Software Research Academy * * Original idea Eiji Fukumoto (fukumoto@yh.ntts.co.jp) * * Produced by Y.YONEYAMA * * Special thanks Tetsu Satoh (tetu-s@is.aist-nara.ac.jp), * * Yoh Asami (asami@dv1.nnes.nec.co.jp) * ************************************************************************/ char *program_name = "SameGame"; char *program_version = "3.02"; #include #include #include #include #include #include #include #include #ifndef LOCAL_XPM_H # include #else /* LOCAL_XPM_H */ # include "xpm.h" #endif /* LOCAL_XPM_H */ #include "config.h" #include "sxsame.h" #ifdef ENABLE_HISCORE # include "hiscore.h" #endif /* ENABLE_HISCORE */ #include "data/sameicon.xpm" char *same_dir = SAME_DIR; extern SameData data_struct[]; char *display = NULL; char *same_font = NULL; Display *dpy; Colormap cmap; Window root; Window win; Window same; #define BUTTON_NUM 5 Window button[BUTTON_NUM]; Window scorewin; Window lastscore; Window button5; char *button_item[BUTTON_NUM] = { "Quit", "NewGame", "Undo", "Size", "Pictures" }; struct { int x; int y; int width; int height; int lock; } button_struct[BUTTON_NUM]; int size_small( #if NeedFunctionPrototypes void #endif ); int size_normal( #if NeedFunctionPrototypes void #endif ); int size_large( #if NeedFunctionPrototypes void #endif ); int size_huge( #if NeedFunctionPrototypes void #endif ); int pic_marble( #if NeedFunctionPrototypes void #endif ); int pic_head( #if NeedFunctionPrototypes void #endif ); int pic_face( #if NeedFunctionPrototypes void #endif ); int pic_other( #if NeedFunctionPrototypes void #endif ); struct item_struct size_item[] = { /* string lock function */ { "Small" , 0, size_small }, { "Normal" , 0, size_normal}, { "Large" , 0, size_large }, { "Huge" , 0, size_huge }, { 0 , 0, 0 } }; struct item_struct pictures_item[] = { { "Marble" , 0, pic_marble }, { "Head" , 0, pic_head }, { "Face" , 0, pic_face }, { "" , 0, 0 }, { "(other)", 1, pic_other }, { 0 , 0, 0 } }; #define SXS_MAX_X 30 #define SXS_MAX_Y 20 SameGame game; DataFile **datafiles; int ndatafile; GC gc; Font font; int char_width; int char_height = 14; XpmAttributes xpm_attr; int bits[MAX_WIDTH][MAX_HEIGHT]; int sbits[MAX_WIDTH][MAX_HEIGHT]; int save_bits[MAX_WIDTH][MAX_HEIGHT]; unsigned long black, white, gray; unsigned int box_color; /* Frame data of B&W BMP */ #define bwf_x 8 #define bwf_y 8 static char bwf_bits[] = { 0xd5, 0xaa, 0xd5, 0xaa, 0xd5, 0xaa, 0xd5, 0xff}; int score; int rest; int same_size = -1; int same_width, same_height; int same_pic = 1; int game_over; int entry_score; int hi_num = 5; int same_other_pic = 0; int hisc_width = 176; #ifdef ENABLE_HISCORE int hisc_height = 128; #else /* !ENABLE_HISCORE */ int hisc_height = 80; #endif /* !ENABLE_HISCORE */ int ReadInitFile(int* width, int* height, int* same_pic); int SaveInitFile(int width, int height, int same_pic); int CheckSameDataFile(DataFile ***); int LoadBMPSameData(Display *dpy, Colormap cmap, SameGame *, char *); int LoadSameData(ImportSameData *, char *); int CheckSelectSame(int sx, int sy); static int Access(const char* path) { return access(path, R_OK); } # define access(x) Access(x) void main(argc, argv) int argc; char **argv; { int i; char *prg_name; /* get my name */ if((prg_name = (char *)strrchr(argv[0], '/'))!=0) prg_name++; else prg_name = argv[0]; for(i=1;i= BUILTIN_NDATA) { same_other_pic = same_pic - BUILTIN_NDATA; if(same_other_pic >= ndatafile) { fprintf(stderr,"Warning: unknown data file.\n"); same_other_pic = -1; } same_pic = 1; } else same_other_pic = -1; game.bit_width = data_struct[same_pic].width; game.bit_height = data_struct[same_pic].height; win_width = game.bit_width*same_width + bd_left + bd_right; win_height = game.bit_height*same_height+ bd_top + bd_bottom; win = XCreateSimpleWindow(dpy, root, 0, 0, win_width, win_height, 1, black, white); XSelectInput(dpy, win, ButtonPressMask); same = XCreateSimpleWindow(dpy, win, bd_left, bd_top, game.bit_width*same_width, game.bit_height*same_height, 0, black, white); XSelectInput(dpy, same, ExposureMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | EnterWindowMask | LeaveWindowMask); att.win_gravity = NorthWestGravity; XChangeWindowAttributes(dpy, same, CWWinGravity, &att); for(button_pos=0, i=0;i= 0 && same_pic <= BUILTIN_NDATA) { if(CreateData(&data_struct[same_pic])==-1) CreateData(&data_struct[1]); } else { if(CreateDataFromFile(datafiles[same_other_pic]->fname) == -1) { datafiles[same_other_pic]->lock = 1; same_pic = 1; CreateData(&data_struct[1]); } } resize_game: if(same_width == 15 && same_height == 8) same_size = 0; else if(same_width == 20 && same_height == 10) same_size = 1; else if(same_width == 25 && same_height == 15) same_size = 2; else if(same_width == 30 && same_height == 20) same_size = 3; else same_size = -1; XSetWindowBackgroundPixmap(dpy, win, game.frame_xpm); XClearWindow(dpy, win); XSetWindowBackgroundPixmap(dpy, same, game.bg_xpm); XClearWindow(dpy, same); XSetWindowBorderPixmap(dpy, lastscore, game.frame_xpm); sh.min_width = game.bit_width*same_width + bd_left + bd_right; sh.min_height = game.bit_height*same_height+ bd_top + bd_bottom; sh.max_width = sh.min_width; sh.max_height = sh.min_height; sh.flags = PMinSize | PMaxSize; XSetNormalHints(dpy, win, &sh); win_width = game.bit_width*same_width + bd_left + bd_right; win_height = game.bit_height*same_height+ bd_top + bd_bottom; XResizeWindow(dpy, win, win_width, win_height); XResizeWindow(dpy, same, game.bit_width*same_width, game.bit_height*same_height); #ifdef ENABLE_HISCORE if(win_height > 250) { hi_num = 10; hisc_height = 208; } else { hi_num = 5; hisc_height = 128; } XResizeWindow(dpy, lastscore, hisc_width, hisc_height); #endif /* ENABLE_HISCORE*/ XFlush(dpy); new_game: /* Initialize */ srand((int)time((time_t *)NULL)); for(i=0;i= 0 && sy >= 0 && (sx != old_sx || sy != old_sy) && sbits[sx][sy] == 0) { DrawSameRect(same_width, same_height, sx, sy); } old_sx = sx; old_sy = sy; XNextEvent(dpy, &e); switch(e.type) { case Expose: if(e.xany.window == same) { while(XCheckWindowEvent(dpy, same, ExposureMask, &e)==True); if(game_over) DrawAllBits(same_width, same_height, 2); else DrawAllBits(same_width, same_height, 0); break; } if(e.xany.window == lastscore) { DrawLastScore(); DrawLastScoreButton(); break; } if(e.xany.window == scorewin) { DrawScore(); break; } for(i=0;i= 0) sx = mx / game.bit_width; else sx = -1; if(my >= 0) sy = my / game.bit_height; else sy = -1; } break; case LeaveNotify: for(i=0;ibox; game.bit_pat[0] = 1; game.bit_pat[1] = data->selected; game.bit_pat[2] = data->pushed; game.bit_width = data->width; game.bit_height = data->height; if(game.bit_box) { if((box_color = GetColor(data->box_color)) == 0) box_color = white; } for(i=0;i<3;i++) { for(j=0;j<5;j++) { if(data->xpm_data[i][j] != 0) { val = XpmCreatePixmapFromData(dpy, root, data->xpm_data[i][j], &game.bits_xpm[i][j], NULL, &xpm_attr); if(val != XpmSuccess) goto error_return; } else game.bits_xpm[i][j] = 0; } } val = XpmCreatePixmapFromData(dpy, root, data->bg_data, &game.bg_xpm, NULL, &xpm_attr); if(val != XpmSuccess) goto error_return; val = XpmCreatePixmapFromData(dpy, root, data->frame_data, &game.frame_xpm, NULL, &xpm_attr); if(val != XpmSuccess) goto error_return; return(0); error_return: fprintf(stderr,"Error: can't create pixmap from data.\n"); return(-1); } int CreateDataFromFile(fname) char *fname; { ImportSameData data; int i, j, val, ncol; char tmpfname[MAXPATHLEN]; if(strlen(fname)>4) /* check Windows data file... */ { if(strcmp(&fname[strlen(fname)-4],".bmp") == 0 || strcmp(&fname[strlen(fname)-4],".BMP") == 0) { if((ncol = LoadBMPSameData(dpy, cmap, &game, fname)) == -1) goto error_return; if(ncol == 2) /* B&W BMP */ { game.frame_xpm = XCreatePixmapFromBitmapData(dpy, root, bwf_bits, bwf_x, bwf_y, black, white, DefaultDepth(dpy, 0)); } else { val = XpmCreatePixmapFromData(dpy, root, data_struct[0].frame_data, &game.frame_xpm, NULL, &xpm_attr); if(val != XpmSuccess) { game.frame_xpm = XCreatePixmapFromBitmapData(dpy, root, bwf_bits, bwf_x, bwf_y, black, white, DefaultDepth(dpy, 0)); } } return(0); } } if(LoadSameData(&data, fname) == -1) goto error_return; game.bit_box = data.box; game.bit_pat[0] = 1; game.bit_pat[1] = data.selected; game.bit_pat[2] = data.pushed; game.bit_width = data.width; game.bit_height = data.height; if(game.bit_box) { if((box_color = GetColor(data.box_color)) == 0) box_color = white; free(data.box_color); } for(i=0;i<3;i++) { for(j=0;j<5;j++) { if(game.bit_pat[i]) { if(!access(data.xpm_data[i][j])) strcpy(tmpfname,data.xpm_data[i][j]); else { if (MAXPATHLEN <= snprintf(tmpfname, MAXPATHLEN, "%s/%s",same_dir, data.xpm_data[i][j])) { goto xpm_error; } } val = XpmReadFileToPixmap(dpy, root, tmpfname, &game.bits_xpm[i][j], NULL, &xpm_attr); free(data.xpm_data[i][j]); if(val != XpmSuccess) goto xpm_error; } else { game.bits_xpm[i][j] = 0; } } } if(!access(data.bg_data)) strcpy(tmpfname,data.bg_data); else if (MAXPATHLEN <= snprintf(tmpfname, MAXPATHLEN, "%s/%s",same_dir, data.bg_data)) { goto xpm_error; } val = XpmReadFileToPixmap(dpy, root, tmpfname, &game.bg_xpm, NULL, &xpm_attr); free(data.bg_data); if(val != XpmSuccess) goto xpm_error; if(!access(data.frame_data)) strcpy(tmpfname,data.frame_data); else sprintf(tmpfname,"%s/%s",same_dir, data.frame_data); if (MAXPATHLEN <= snprintf(tmpfname, MAXPATHLEN, "%s/%s",same_dir, data.frame_data)) { goto xpm_error; } val = XpmReadFileToPixmap(dpy, root, tmpfname, &game.frame_xpm, NULL, &xpm_attr); free(data.frame_data); if(val != XpmSuccess) goto xpm_error; return(0); xpm_error: fprintf(stderr,"Error: can't create pixmap from '%s'.\n", tmpfname); error_return: return(-1); } void FreeData() { int i,j; for(i=0;i<3;i++) for(j=0;j<5;j++) if(game.bits_xpm[i][j] != 0 && game.bit_pat[i]) XFreePixmap(dpy, game.bits_xpm[i][j]); XFreePixmap(dpy, game.bg_xpm); XFreePixmap(dpy, game.frame_xpm); /* * XUninstallColormap(dpy, cmap); * XFreeColormap(dpy, cmap); * cmap = XCreateColormap(dpy, root, DefaultVisual(dpy, 0), AllocNone); * XInstallColormap(dpy, cmap); * black = GetColor("black"); * white = GetColor("white"); * gray = GetColor("gray"); * xpm_attr.colormap = cmap; */ } int DrawButton(b) int b; { XSetFont(dpy, gc, font); if(button_struct[b].lock) XSetForeground(dpy, gc, gray); else XSetForeground(dpy, gc, black); XSetBackground(dpy, gc, white); XClearWindow(dpy, button[b]); XDrawImageString(dpy, button[b], gc, 2, 12, button_item[b], strlen(button_item[b])); XSetFillStyle(dpy, gc, FillSolid); return(0); } int EnterButton(b) int b; { if(!button_struct[b].lock) { XSetForeground(dpy, gc, black); XDrawRectangle(dpy, button[b], gc, 0, 0, button_struct[b].width-1, button_struct[b].height-1); } return(0); } int DrawScore() { char tmp[256]; XSetFont(dpy, gc, font); XSetForeground(dpy, gc, black); XSetBackground(dpy, gc, white); sprintf(tmp, "Gets%6d Rests%6d Total%7d", score, rest, score - rest); XDrawImageString(dpy, scorewin, gc, 2, 12, tmp, strlen(tmp)); return(0); } int DrawLastScore() { #ifdef ENABLE_HISCORE struct Hiscore hiscore; int i; int my = 10; static int failent = 0; #endif /* ENABLE_HISCORE */ char tmp[256]; XSetFont(dpy, gc, font); XSetForeground(dpy, gc, black); XSetBackground(dpy, gc, white); XClearWindow(dpy, lastscore); #ifdef ENABLE_HISCORE if(game_over == 1 && entry_score == 0 && same_size != -1) { entry_score = 1; my = EntryHiscore(score - rest, same_size, entry_score); if(my == -1) failent = 1; else failent = 0; } if(game_over == 0) failent = 0; if(my != -1 && same_size != -1 && GetHiscore(&hiscore, same_size) != -1 && failent == 0) { XResizeWindow(dpy, lastscore, hisc_width, hisc_height); XDrawString(dpy, lastscore, gc, 16, 14, "*** High Score ***", 18); for(i=0;i%2d. %s", i+1, hiscore.entry[i].name); else sprintf(tmp, " %2d. %s", i+1, hiscore.entry[i].name); XDrawString(dpy, lastscore, gc, 8,16*i+30, tmp, strlen(tmp)); sprintf(tmp, "%6d", hiscore.entry[i].score); XDrawString(dpy, lastscore, gc, 116, 16*i+30, tmp, strlen(tmp)); } return(0); } XResizeWindow(dpy, lastscore, 160, 80); #endif /* ENABLE_HISCORE */ sprintf(tmp, "Gets %6d", score); XDrawString(dpy, lastscore, gc, 24, 16, tmp, strlen(tmp)); sprintf(tmp, "Rests %6d", -rest); XDrawString(dpy, lastscore, gc, 24, 32, tmp, strlen(tmp)); XDrawLine(dpy, lastscore, gc, 16, 34, 131, 34); sprintf(tmp, "Total %6d", score - rest); XDrawString(dpy, lastscore, gc, 24, 48, tmp, strlen(tmp)); return(0); } int DrawLastScoreButton() { XSetFont(dpy, gc, font); XSetForeground(dpy, gc, black); XClearWindow(dpy, button5); if(game_over == 0) XDrawString(dpy, button5, gc, 2, 12, "Continue", 8); else XDrawString(dpy, button5, gc, 2, 12, "New Game", 8); return(0); } int DrawAllBits(x, y, pat) int x; int y; int pat; { int i, j; for(i=0;i=0;j--) { if(bits[i][j] == 0) break; if(CheckSame(x, y, i, j)==1) return(1); } } return(0); } int CheckSame(x, y, sx, sy) int x; int y; int sx; int sy; { if(bits[sx][sy] == 0) return(0); if(sx>0) if(bits[sx][sy] == bits[sx-1][sy]) return(1); if(sx0) if(bits[sx][sy] == bits[sx][sy-1]) return(1); if(sy 0 && c == bits[sx-1][sy] && sbits[sx-1][sy] == 0) { DrawNextSameRect(x, y, sx-1, sy); } if(sx < x - 1 && c == bits[sx+1][sy] && sbits[sx+1][sy] == 0) { DrawNextSameRect(x, y, sx+1, sy); } if(sy > 0 && c == bits[sx][sy-1] && sbits[sx][sy-1] == 0) { DrawNextSameRect(x, y, sx, sy-1); } if(sy < y - 1 && c == bits[sx][sy+1] && sbits[sx][sy+1] == 0) { DrawNextSameRect(x, y, sx, sy + 1); } return(0); } int CheckSelectSame(sx, sy) int sx; int sy; { int i, j; for(j=0;j= 2) { rest -= num; score += (num-2)*(num-2); } for(i=x-1;i>=0&&bits[i][y-1]==0;i--); if(i < 0) /* perfect game */ { #ifdef BONUS1000 score += 1000; /* original bonus points */ #else /* !BONUS1000 */ score += same_width * same_height; /* bonus points */ #endif /* BONUS1000 */ } else { for(;i>=0;i--) { if(bits[i][y-1] == 0) PushBits(x, y, i); } } return(num); } int DeleteBit(sx, sy) int sx; int sy; { int i; for(i=sy;i>0;i--) { bits[sx][i] = bits[sx][i-1]; sbits[sx][i] = sbits[sx][i-1]; DrawBit(sx, i, 0); } bits[sx][0] = 0; sbits[sx][0] = 0; DrawBit(sx, 0, 0); return(0); } int PushBits(x, y, sx) int x; int y; int sx; { int i, j; for(i=sx;i menu_width) menu_width = strlen(item[i].name); } nmenu = i; menu_width ++; XSetFont(dpy, gc, font); pull_width = char_width*(menu_width + 2) + 4; pull_height = char_height*nmenu + 6; pulldown = XCreateSimpleWindow(dpy, win, pos_x, pos_y, pull_width, pull_height, 1, black, white); XSelectInput(dpy, pulldown, ExposureMask | ButtonPressMask | LeaveWindowMask | ButtonReleaseMask | PointerMotionMask); XMapWindow(dpy, pulldown); XRaiseWindow(dpy, pulldown); while(1) { XPeekEvent(dpy, &e); if(e.xany.window != pulldown && e.xany.window != button[btn]) { /* if(e.type == LeaveNotify) */ if(e.type == Expose || e.type == ButtonPress) { sel = -1; goto select_return; } XNextEvent(dpy, &e); continue; } XNextEvent(dpy, &e); switch(e.type) { case Expose: DrawMenuItem(pulldown, def, sel, nmenu, menu_width, item); break; case EnterNotify: if(btn_count == 1) { btn_count = 0; continue; } case ButtonPress: if(e.xany.window == button[btn]) { sel = -1; } goto select_return; break; case LeaveNotify: if(e.xany.window == button[btn]) { if(btn_count == 1) goto select_return; btn_count ++; } /*break;*/ case MotionNotify: XQueryPointer(dpy, pulldown, &dmyw, &dmyw, &rx, &ry, &mx, &my, &mask); sel = (my - 3) / char_height; if(mx < 0 || mx > pull_width || my < 0 || my > pull_height) sel = -1; if(sel != old_sel) DrawMenuItem(pulldown, def, sel, nmenu, menu_width, item); old_sel = sel; break; } } select_return: if((sel >= nmenu) || (sel >= 0 && (item[sel].lock || item[sel].name[0] == '\0'))) sel = -1; if(sel != -1 && item[sel].func != 0 ) { sel = (item[sel].func)(); } XUnmapWindow(dpy, pulldown); XDestroyWindow(dpy, pulldown); return(sel); } int DrawMenuItem(pulldown, def, sel, nmenu, menu_width, item) Window pulldown; int def; int sel; int nmenu; int menu_width; struct item_struct *item; { int i, j; char *menutmp; if((menutmp = (char *)malloc(menu_width + 3)) == NULL) { fprintf(stderr,"%s: can't allocate memory.\n", program_name); return(-1); } for(i=0;ititle) > menu_width) menu_width = strlen(datafiles[i]->title); } nmenu = i; menu_width += 2; XSetFont(dpy, gc, font); pull_width = char_width*(menu_width) + 4; pull_height = char_height*nmenu + 6; pulldown = XCreateSimpleWindow(dpy, win, mx, my, pull_width, pull_height, 1, black, white); XSelectInput(dpy, pulldown, ExposureMask | ButtonPressMask | LeaveWindowMask | ButtonReleaseMask | PointerMotionMask); XMapWindow(dpy, pulldown); XRaiseWindow(dpy, pulldown); XFlush(dpy); while(1) { XPeekEvent(dpy, &e); if(e.xany.window != pulldown) { if(e.type == Expose || e.type == ButtonPress) { sel = -1; goto select_return; } XNextEvent(dpy, &e); continue; } XNextEvent(dpy, &e); switch(e.type) { case Expose: DrawSimpleMenuItem(pulldown, sel, nmenu, menu_width, datafiles); break; case ButtonPress: if(sel >= 0 && sel < nmenu) same_pic = -1; else sel = -1; goto select_return; break; case LeaveNotify: sel = -1; break; case MotionNotify: XQueryPointer(dpy, pulldown, &dmyw, &dmyw, &rx, &ry, &mx, &my, &mask); sel = (my - 3) / char_height; if(mx < 0 || mx > pull_width || my < 0 || my > pull_height) sel = -1; if(sel != old_sel) { DrawSimpleMenuItem(pulldown, sel, nmenu, menu_width, datafiles); } old_sel = sel; break; } XFlush(dpy); } select_return: if((sel >= nmenu) || (sel >= 0 && datafiles[sel]->lock)) sel = -1; XUnmapWindow(dpy, pulldown); XDestroyWindow(dpy, pulldown); same_other_pic = sel; return(sel); } void DrawSimpleMenuItem(pulldown, sel, nmenu, menu_width, datafiles) Window pulldown; int sel; int nmenu; int menu_width; DataFile **datafiles; { char tmpstr[256]; int i,j; for(i=0;ilock) { XSetForeground(dpy, gc, gray); XSetBackground(dpy, gc, white); } else if(i == sel) { XSetForeground(dpy, gc, white); XSetBackground(dpy, gc, black); } else { XSetForeground(dpy, gc, black); XSetBackground(dpy, gc, white); } sprintf(tmpstr," %s",datafiles[i]->title); for(j=strlen(tmpstr);j<=menu_width;j++) tmpstr[j] = ' '; XDrawImageString(dpy, pulldown, gc, 2, 12 + i*char_height + 3, tmpstr, menu_width); } } #ifdef DEBUG int DisplayWindowName(w) Window w; { if(w == win) printf("win\n"); else if(w == same) printf("same\n"); else printf("0x%x\n", w); return(0); } #endif /* DEBUG */