home *** CD-ROM | disk | FTP | other *** search
/ Atari FTP / ATARI_FTP_0693.zip / ATARI_FTP_0693 / Games / shfflsrc.zoo / shuffle.c < prev    next >
C/C++ Source or Header  |  1991-03-16  |  15KB  |  535 lines

  1. /*
  2.     This is Shuffle, a puzzle game for the Atari ST
  3.     Copyright (C) 1991  by Robert Fischer
  4.  
  5.     This program costs no money; you may redistribute it and/or modify it
  6.     under the terms of the Lynxware General License as published by Robert
  7.     Fischer; either version 1, or (at your option) any later version. 
  8.  
  9.     This program is distributed in the hope that it will be useful,
  10.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.     Lynxware General License for more details.
  13.  
  14.     You should have received a copy of the Lynxware General License
  15.     along with this program; if not, write to the author.
  16.  
  17.     To contact the author, call or write:
  18.         Robert Fischer
  19.         80 Killdeer Road
  20.         Hamden, CT    06517
  21.         (203) 288-9599
  22.         E-mail: fischer-robert@cs.yale.edu
  23. */
  24. /* NOTE: Shuffle requires LynxLib to compile */
  25. long _stksize = 4000L;
  26. #define THE_RESOURCE "SHUFFLE.RSC"
  27. #include <stdio.h>
  28. #include <e_osbind.h>
  29. #include <picture.h>
  30. #include <gemdefs.h>
  31. #include <aesbind.h>
  32. #include <vdibind.h>
  33. #include <mygem.h>
  34. #include <nobdefs.h>
  35. #include "shuffle.h"
  36. /* ---------------------------------------------------------------- */
  37. /* Types & constants */
  38. typedef struct {
  39.     int hand;        /* the VDI handle */
  40.     xy size;        /* Width and height of device */
  41. } vdi_hand;
  42.  
  43. /* ---------------------------------------------------------------- */
  44. /* Global Variables */
  45. vdi_hand screen;    /* VDI virtual workstation handle */
  46. int intin[128];
  47. int intout[128];
  48. int ptsin[128];
  49. int ptsout[128];
  50. int contrl[12];
  51. /* ---------------------------------------------------------------- */
  52.  
  53. /* ---------------------------------------------------------------- */
  54. /* ---------------------------------------------------------------- */
  55. fix_sizebox()    /* Fixes up the size box */
  56. {
  57. OBJECT *d;
  58. int i;
  59.     rsrc_gaddr(0, SIZEBOX, &d);
  60.  
  61.     /* Change each thing from one char high to 1 char - 1 pixel */
  62.     for (i = ACRO1; i < ACRO64; i++)
  63.         d[i].ob_height -= 1;
  64.     for (i = DOWN1; i < DOWN50; i++)
  65.         d[i].ob_height -= 1;
  66. }
  67. /* ---------------------------------------------------------------- */
  68. BOOLEAN gem_puzsize(pic, x, y)    /* Asks the user for the puzzle size */
  69. /* Returns in x & y the number of pieces for that axis */
  70. pic_rec *pic;
  71. int *x, *y;
  72. {
  73. OBJECT *d;
  74. static index_to_across[] = {1, 2, 4, 5, 8, 10, 16, 20, 32, 40, 64, -1};
  75. static index_to_down[] = {1, 2, 4, 5, 8, 10, 20, 25, 40, 50, -1};
  76. register int *i;
  77. int index;
  78. int b;        /* Button used to exit */
  79.  
  80.     rsrc_gaddr(0, SIZEBOX, &d);
  81.     form_center(d, &b, &b, &b, &b);
  82.  
  83.     /* Set selected thing and clear all others */
  84.     for (i = index_to_down, index = DOWN1; *i != -1; i++, index++) {
  85.         if (*i == *y) {
  86.             d[index].ob_state |= SELECTED;
  87.         } else {
  88.             d[index].ob_state &= ~SELECTED;
  89.         }
  90.     }
  91.  
  92.     for (i = index_to_across, index = ACRO1; *i != -1; i++, index++) {
  93.         if (*i == *x) {
  94.             d[index].ob_state |= SELECTED;
  95.         } else {
  96.             d[index].ob_state &= ~SELECTED;
  97.         }
  98.     }
  99.  
  100.     draw_box(d);
  101.     do {
  102.         b = form_do(d, 0);
  103.         d[b].ob_state &= ~SELECTED;
  104.         objc_draw(d, b, 1, 0, 0, 0, 0);
  105.  
  106.         /* See if he wanted to see the picture */
  107.         if (b == PICLOOK) {
  108.             graf_mouse(M_OFF);
  109.             switch_pic(pic);
  110.             wait_mouse(LEFT_BUTTON);
  111.             switch_norm(pic);
  112.             graf_mouse(M_ON);
  113.             wait_mouse(0);
  114.         }
  115.     } while (b == PICLOOK);
  116.     undraw_box(d);
  117.  
  118.     /* Scan for selected one */
  119.     if (b == SBOK) {
  120.         for (index = ACRO1; (d[index].ob_state & SELECTED) == 0; index++);
  121.         *x = index_to_across[index - ACRO1];
  122.         for (index = DOWN1; (d[index].ob_state & SELECTED) == 0; index++);
  123.         *y = index_to_down[index - DOWN1];
  124.         return TRUE;
  125.     }
  126.     return FALSE;
  127. }
  128.  
  129. /* ---------------------------------------------------------------- */
  130. /* End of GEM stuff */
  131. /* ---------------------------------------------------------------- */
  132. static FDB f_screen = {0L, ACRO1 + 0, 0, 0, TRUE, 0, 0, 0, 0};    /* for bit blitting */
  133. blit_block(ioblock, ifdb, ofdb)
  134. xyxyxyxy ioblock;
  135. FDB *ifdb, *ofdb;
  136. {
  137.     vro_cpyfm(screen.hand, OPAQUE, &ioblock, ifdb, ofdb);
  138. }
  139. /* ---------------------------------------------------------------- */
  140. find_block(pos, squaresize)
  141. /* Finds the puzzle square that the mouse is in */
  142. register xyxy *pos;        /* Mouse position, also output */
  143. xy squaresize;            /* Size of each square */
  144. {
  145.     pos->x -= (pos->x % squaresize.x);
  146.     pos->y -= (pos->y % squaresize.y);
  147.     pos->x1 = pos->x + squaresize.x - 1;
  148.     pos->y1 = pos->y + squaresize.y - 1;
  149. }
  150. /* ---------------------------------------------------------------- */
  151. wait_mouse(state)    /* Awaits for the mouse buttons to enter the desired state */
  152. WORD state;
  153. {
  154. int i, mstate;
  155.     if (state == 0)
  156.         evnt_button(1, LEFT_BUTTON | RIGHT_BUTTON, 0, &i, &i, &i, &i);
  157.     else
  158.         evnt_button(1, state, 1, &i, &i, &i, &i);
  159. }
  160. /* ---------------------------------------------------------------- */
  161. graf_waitm(state)    /* Same as wait_mouse, only uses graf_mouse */
  162. WORD state;
  163. {
  164. int i, mstate;
  165.     do {
  166.         graf_mkstate(&i, &i, &mstate, &i);
  167.     } while (mstate != state);
  168. }
  169. /* ---------------------------------------------------------------- */
  170. BOOLEAN c_cmpmem(a, b, numlongs)
  171. register LONG *a, *b;
  172. register int numlongs;
  173. {
  174.     for (; numlongs > 0; numlongs --) {
  175.         if (*a++ != *b++) return FALSE;
  176.     }
  177.     return TRUE;
  178. }
  179. /* ---------------------------------------------------------------- */
  180. /* Generate a positive random number */
  181. unsigned int rnd(low, high)
  182. /* Generates a number between low & high, including low & excluding high */
  183. unsigned int low, high;
  184. {
  185.     return ((unsigned int)Random()) % (high - low) + low;
  186. }
  187. /* ---------------------------------------------------------------- */
  188. #ifdef NODEF
  189. func *old_etv_term;
  190. char *old_screen;
  191.  
  192. err_handler()
  193. {
  194.     SCREENPT = old_screen;
  195.     ETV_TERM = old_etv_term;
  196. }
  197.  
  198. install_err()
  199. {
  200. LONG usp;
  201.     usp = Super(0);
  202.     old_screen = V_BASE_AD;
  203.     old_etv_term = ETV_TERM;
  204.     ETV_TERM = &err_handler;
  205.     Super(usp);
  206. }
  207.  
  208. dinstall_err()
  209. {
  210. LONG usp;
  211.     usp = Super(0);
  212.     ETV_TERM = old_etv_term;
  213.     Super(usp);
  214. }
  215. #endif
  216. /* ----------------------------------------------------------- */
  217. int g_getkey()    /* Gets a key from GEM AES */
  218. /* Returns -1 if no key is available */
  219. {
  220. int i, key, event;
  221.  
  222.     event = evnt_multi(MU_KEYBD | MU_TIMER,
  223.         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  224.         &i, 0, 0, &i, &i, &i, &i, &key, &i);
  225.     if (event == MU_TIMER) return -1;
  226.     return key & 0xFF;
  227. }
  228. /* ---------------------------------------------------------------- */
  229. BOOLEAN puzzle_pic(pic, squaresize)        /* Puzzles on a picture */
  230. /* Returns TRUE if you should puzzle this picture again, but with */
  231. /* a different size */
  232. pic_rec *pic;        /* Picture to puzzle on */
  233. xy squaresize;        /* Size of puzzle squares to use */
  234. {
  235. xyxy ipos, opos;    /* Block position */
  236. WORD mstate;    /* Mouse button state */
  237. WORD kstate;    /* Keyboard shift state */
  238. int c;
  239.  
  240. pic_rec *messed_pic;        /* Picture which will be destroyed */
  241.  
  242. LONG usp;
  243. char stringg[80];
  244. LONG time;
  245. char s[2];
  246.  
  247. /* For blitting */
  248. FDB temp_fdb;        /* FDB of temporary storage area */
  249. WORD *temp;        /* Pointer to temporary storage area */
  250. xy lastxy;
  251. xyxyxyxy pline;
  252. int ystart, yend, xstart, xend, xincr, yincr;
  253. xy opos_offset;        /* opos.x - ipos.x, opos.y - ipos.y */
  254.  
  255.     /* Copy the original picture */
  256.     messed_pic = malloc(sizeof(pic_rec));
  257.     messed_pic->p_start = (char *)(((LONG)(messed_pic->p) + 255) & 0xFFFFFF00L);
  258.     memcpy(messed_pic->p_start, pic->p_start, SCR_SIZE);
  259.     messed_pic->rez = pic->rez;
  260.     for (c = 0; c < 16; c++) messed_pic->pal[c] = pic->pal[c];
  261.  
  262.     graf_mouse(M_OFF);    /* Put GEM into new picture */
  263.     switch_pic(messed_pic);
  264.  
  265.     /* Set up the temporary blit buffer */
  266.     temp_fdb.fd_w = squaresize.x;
  267.     temp_fdb.fd_h = squaresize.y;
  268.     temp_fdb.fd_wdwidth = (temp_fdb.fd_w + 15) >> 4;
  269.     temp_fdb.fd_stand = TRUE;
  270.     temp_fdb.fd_nplanes = (1 << (2 - Getrez()));
  271.     temp_fdb.fd_r1 = 0;
  272.     temp_fdb.fd_r2 = 0;
  273.     temp_fdb.fd_r3 = 0;
  274.     temp = (WORD *)malloc(temp_fdb.fd_wdwidth * temp_fdb.fd_h
  275.             * 2 * temp_fdb.fd_nplanes);
  276.     temp_fdb.fd_addr = (LONG)temp;
  277.  
  278.     /* Shuffle the picture */
  279.     lastxy.x = squaresize.x - 1;
  280.     lastxy.y = squaresize.y - 1;
  281.     for (ipos.y = 0; ipos.y < screen.size.y; ipos.y += squaresize.y)
  282.     for (ipos.x = 0; ipos.x < screen.size.x; ipos.x += squaresize.x) {
  283.         ipos.x1 = ipos.x + lastxy.x;
  284.         ipos.y1 = ipos.y + lastxy.y;
  285.  
  286.         opos.x = rnd(0, screen.size.x);
  287.         opos.y = rnd(0, screen.size.y);
  288.         find_block(&opos, squaresize);
  289.  
  290.         temp_fdb.fd_addr = (LONG)temp;
  291.         blit_block(opos, 0,0,lastxy, &f_screen, &temp_fdb);
  292.         blit_block(ipos, opos, &f_screen, &f_screen);
  293.         blit_block(0,0, lastxy, ipos, &temp_fdb, &f_screen);
  294.     }
  295.  
  296.  
  297.     graf_mouse(M_ON);
  298.  
  299.     /* Read clock */
  300.     usp = Super(0);
  301.     time = HZ_200;    /* Time when user started */
  302.     Super(usp);
  303.  
  304.     do {
  305.  
  306.  
  307.         /* Search for the RETURN key being pressed */
  308.         c = g_getkey();
  309.         switch(c) {
  310.             case '\r' :
  311.             case ' ' :
  312.                 graf_mouse(M_OFF);
  313.                 switch_norm(messed_pic);
  314.                 graf_mouse(M_ON);
  315.                 free(temp);
  316.                 free(messed_pic);
  317.                 return (c == ' ');
  318.         }
  319.  
  320.         /* Get a mouse button */
  321.         graf_mkstate(&ipos.x, &ipos.y, &mstate, &kstate);
  322.  
  323.         if (mstate != 0) {    /* Process the button event */
  324.             if (mstate & LEFT_BUTTON) {    /* User wants to move a block */
  325.                 if (kstate & (R_SHIFT | L_SHIFT)) {
  326.                     /* Let the user select a block */
  327.                     ipos.x -= (ipos.x % squaresize.x);
  328.                     ipos.y -= (ipos.y % squaresize.y);
  329.                     graf_rubbox(ipos.x, ipos.y, 0, 0, &ipos.x1, &ipos.y1);
  330.  
  331.                     /* Get size of user-selected box */
  332.                     ipos.x1 += ipos.x + squaresize.x - 1;
  333.                     ipos.x1 -= ((ipos.x1 % squaresize.x) + 1);
  334.                     ipos.y1 += ipos.y + squaresize.y - 1;
  335.                     ipos.y1 -= ((ipos.y1 % squaresize.y) + 1);
  336.  
  337.  
  338.                     graf_waitm(0);
  339.  
  340.                     /* Draw a box around area */
  341.                     pline.x = pline.x3 = ipos.x;
  342.                     pline.y = pline.y1 = ipos.y;
  343.                     pline.x1 = pline.x2 = ipos.x1;
  344.                     pline.y3 = pline.y2 = ipos.y1;
  345.                     vswr_mode(screen.hand, 3);
  346.                     vsm_type(screen.hand, 1);
  347.                     graf_mouse(M_OFF);
  348.                     v_pline(screen.hand, 4, &pline);
  349.                     graf_mouse(M_ON);
  350.  
  351.                     graf_waitm(LEFT_BUTTON);
  352.  
  353.                     /* Undraw the box */
  354.                     graf_mouse(M_OFF);
  355.                     v_pline(screen.hand, 4, &pline);
  356.                     graf_mouse(M_ON);
  357.  
  358.                     graf_mkstate(XY_PTR(lastxy), &mstate, &kstate);
  359.  
  360.                     /* Quit if user decided to quit */
  361.                     if (IBETWEEN(lastxy.x, ipos.x, ipos.x1) &&
  362.                         IBETWEEN(lastxy.y, ipos.y, ipos.y1)) ; else
  363.                         goto quit_drag;
  364.  
  365.                     /* Let user drag it */
  366.                     graf_dragbox(ipos.x1 - ipos.x, ipos.y1 - ipos.y,
  367.                         ipos.x, ipos.y, 0, 0, screen.size, XY_PTR(opos));
  368.                 } else {
  369.                     find_block(&ipos, squaresize);
  370.                     graf_dragbox(squaresize, ipos.x, ipos.y, 0,0,screen.size,
  371.                         &opos.x, &opos.y);
  372.                     graf_mkstate(&opos.x, &opos.y, &mstate, &kstate);
  373.                 }
  374.                 opos.x -= (opos.x % squaresize.x);
  375.                 opos.y -= (opos.y % squaresize.y);
  376.  
  377.                 /* Figure out which order to copy blocks in */
  378.                 if (ipos.x > opos.x) {
  379.                     xstart = ipos.x;
  380.                     xend = xstart + (ipos.x1 - ipos.x) + 1;
  381.                     xincr = squaresize.x;
  382.                 } else {
  383.                     xstart = ipos.x + (ipos.x1 - ipos.x) + 1 - squaresize.x;
  384.                     xend = ipos.x - squaresize.x;
  385.                     xincr = -squaresize.x;
  386.                 }
  387.                 if (ipos.y > opos.y) {
  388.                     ystart = ipos.y;
  389.                     yend = ystart + (ipos.y1 - ipos.y) + 1;
  390.                     yincr = squaresize.y;
  391.                 } else {
  392.                     ystart = ipos.y + (ipos.y1 - ipos.y) + 1 - squaresize.y;
  393.                     yend = ipos.y - squaresize.y;
  394.                     yincr = -squaresize.y;
  395.                 }
  396.  
  397.                 /* Blit each piece, one at a time */
  398.                 graf_mouse(M_OFF);
  399.                 vs_clip(screen.hand, FALSE, &pline);
  400.  
  401.                 lastxy.x = squaresize.x - 1;
  402.                 lastxy.y = squaresize.y - 1;
  403.                 opos_offset.x = opos.x - ipos.x;
  404.                 opos_offset.y = opos.y - ipos.y;
  405.                 for (ipos.y = ystart; ipos.y != yend; ipos.y += yincr)
  406.                 for (ipos.x = xstart; ipos.x != xend; ipos.x += xincr) {
  407.                     temp_fdb.fd_addr = (LONG)temp;
  408.                     ipos.x1 = ipos.x + lastxy.x;
  409.                     ipos.y1 = ipos.y + lastxy.y;
  410.  
  411.                     opos.x = ipos.x + opos_offset.x;
  412.                     opos.y = ipos.y + opos_offset.y;
  413.                     opos.x1 = ipos.x1 + opos_offset.x;
  414.                     opos.y1 = ipos.y1 + opos_offset.y;
  415.  
  416.                     blit_block(ipos, 0,0,lastxy, &f_screen, &temp_fdb);
  417.                     blit_block(opos, ipos, &f_screen, &f_screen);
  418.                     blit_block(0,0,lastxy, opos, &temp_fdb, &f_screen);
  419.                 }
  420.  
  421.                 /* Test to see if it's correct */
  422.                 if (c_cmpmem(pic->p_start, messed_pic->p_start, SCR_SIZE/4)) {
  423.                     usp = Super(0);
  424.                     time = HZ_200 - time;
  425.                     fitoa((int)((time/200)%60), 2, 10, s);
  426.                     Super(usp);
  427.                     sprintf(stringg,
  428.                         "[0][You finished!|Your time was|%d:%s][ Great! ]",
  429.                         (int)(time/12000), s);
  430.                     form_alert(1, stringg);
  431.  
  432.                     usp = Super(0);
  433.                     time = HZ_200;
  434.                     Super(usp);
  435.                 }
  436.  
  437.                 graf_mouse(M_ON);
  438.  
  439.             } else if (mstate & RIGHT_BUTTON) {
  440.                 graf_mouse(M_OFF);
  441.                 Setscreen(-1, pic->p_start, -1);
  442.                 graf_waitm(0);
  443.                 graf_waitm(RIGHT_BUTTON);
  444.                 graf_waitm(0);
  445.                 Setscreen(-1, messed_pic->p_start, -1);
  446.                 graf_mouse(M_ON);
  447.             }
  448.         }
  449. quit_drag: ;
  450.     } while (TRUE);
  451.  
  452. }
  453. /* ---------------------------------------------------------------- */
  454. do_puzzler()
  455. {
  456. static xy numsquares = {10, 10};    /* # squares in puzzle */
  457.  
  458. fle_name path;        /* For file selector */
  459. leaf_name name;
  460. fle_name fname;    /* Actual pathname selected */
  461. pic_rec *pic;
  462. int i;
  463. BOOLEAN b;
  464. OBJECT *d;
  465.     pic = malloc(sizeof(*pic));
  466.  
  467.     get_curdir(path);
  468.     strcat(path, "*.*");
  469.     name[0] = '\0';
  470.     while (TRUE) {
  471.         if (fsel_exinput(path, name, &i, "Select file to puzzle on") == 0) break;
  472.         if (i == 0) break;        /* User pressed Cancel */
  473.  
  474.         strcpy(fname, path);
  475.         trim_leaf(fname);
  476.         strcat(fname, name);
  477.  
  478.         /* Load the picture */
  479.         rsrc_gaddr(0, LOADING, &d);
  480.         form_center(d, &i, &i, &i, &i);
  481.         draw_box(d);
  482.         b = load_pic(pic, fname);
  483.         if (b) {
  484.             /* Convert to current resolution */
  485.             change_res(pic, Getrez());
  486.         }
  487.         undraw_box(d);
  488.  
  489.         if (b) {
  490.             /* Ask squaresize from user & puzzle on it */
  491.             while (gem_puzsize(pic,
  492.                         XY_PTR(numsquares)) &&
  493.                     puzzle_pic(pic,
  494.                         screen.size.x/numsquares.x,
  495.                         screen.size.y/numsquares.y)) ;
  496.         } else {
  497.             gem_err("Error loading picture!");
  498.         }
  499.     }
  500.  
  501.     free(pic);
  502. }
  503. /* ---------------------------------------------------------------- */
  504. main()
  505. {
  506. static int work_in[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2};
  507. int work_out[60];
  508. int i;
  509. OBJECT *d;
  510.     appl_init();
  511.     if (rsrc_load(THE_RESOURCE)) {
  512.  
  513.         /* Display introductory dialog box */
  514.         rsrc_gaddr(0, TITLE, &d);
  515.         form_center(d, &i, &i, &i, &i);
  516.         draw_box(d);
  517.         form_do(d, 0);
  518.         undraw_box(d);
  519.  
  520.         /* Fix up the size box */
  521.         fix_sizebox();
  522.  
  523.         screen.hand = graf_handle(&i, &i, &i, &i);
  524.         v_opnvwk(work_in, &screen.hand, work_out);
  525.         screen.size.x = work_out[0] + 1;
  526.         screen.size.y = work_out[1] + 1;
  527.  
  528.         vs_clip(screen.hand, FALSE, work_out);
  529.     
  530.         do_puzzler();
  531.         v_clsvwk(screen.hand);
  532.     }
  533.     appl_exit();
  534. }
  535.