home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus Extra 1996 #3 / AmigaPlus_CD-ROM-EXTRA_Nr.3.bin / aminet-spiele / denk&grübel / crazyclock / source / clockwindow.c < prev    next >
C/C++ Source or Header  |  1993-10-12  |  25KB  |  767 lines

  1. /*
  2.  * clockwindow.c V1.1
  3.  *
  4.  * clock window handling
  5.  *
  6.  * (c) 1992-1993 Holger Brunst
  7.  */
  8.  
  9. #include <CClock.h>
  10.  
  11. /* Coordinates of game elements */  
  12. struct Element {
  13.                 short x, y;
  14.                };
  15. /* Source coordinates of clock elements (foreground) */
  16. static const struct Element clkFor[24] = {
  17.                                             0,144,  64,144, 128,144, 192,144,
  18.                                             0,176,  64,176, 128,176, 192,176,
  19.                                             0,208,  64,208, 128,208, 192,208,
  20.                                           256,144, 448,208, 384,208, 320,208,
  21.                                           256,208, 448,176, 384,176, 320,176,
  22.                                           256,176, 448,144, 384,144, 320,144
  23.                                          };
  24. /* Source coordinates of clock elements (background) */
  25. static const struct Element clkBak[18] = {
  26.                                            32,16, 112,16, 192,16,  32,56,
  27.                                           112,56, 192,56,  32,96, 112,96,
  28.                                           192,96,
  29.                                           320,16, 400,16, 480,16, 320,56,
  30.                                           400,56, 480,56, 320,96, 400,96,
  31.                                           480,96
  32.                                          };
  33. /* Destination coordinates of clock elements */
  34. static const struct Element clkDst[9] = {
  35.                                          208, 44, 288, 44, 368, 44, 208, 84,
  36.                                          288, 84, 368, 84, 208,124, 288,124,
  37.                                          368,124
  38.                                         };
  39.  
  40. /* Source coordinates of button elements */
  41. static const struct Element butSrc[16] = {
  42.                                           512,144, 512,160, 544,160, 544,144,
  43.                                            88, 48,  88, 88, 168, 88, 168, 48,
  44.                                           456, 48, 456, 88, 376, 88, 376, 48,
  45.                                           544,176, 544,192, 512,192, 512,176
  46.                                          };
  47. /* Destination coordinates of button elements */
  48. static const struct Element butDst[8] = {
  49.                                          264,76, 264,116, 344,116, 344,76,
  50.                                          344,76, 344,116, 264,116, 264,76
  51.                                         };
  52.  
  53. /* Color pallete (all grey) */
  54. static const USHORT darknes[16] = {
  55.                                    0xaaa, 0xaaa, 0xaaa, 0xaaa,
  56.                                    0xaaa, 0xaaa, 0xaaa, 0xaaa,
  57.                                    0xaaa, 0xaaa, 0xaaa, 0xaaa,
  58.                                    0xaaa, 0xaaa, 0xaaa, 0xaaa
  59.                                   };
  60.  
  61. /* Menu data */
  62. #define MENU_NEW    0
  63. #define MENU_PAUSE  1
  64. #define MENU_HIGH   2
  65. #define MENU_ABOUT  3
  66. #define MENU_QUIT   4
  67.  
  68. #define MENU_SIDE1  5
  69. #define MENU_SIDE2  6
  70. #define MENU_RAND   7
  71. static const struct NewMenu mdata[] = {
  72.                                 {NM_TITLE,"Project"  , NULL, 0, ~0, NULL},
  73.                                 {NM_ITEM, "New game" , "N" , 0, ~0, MENU_NEW},
  74.                                 {NM_ITEM, "Pause"    , "P" , 0, ~0, MENU_PAUSE},
  75.                                 {NM_ITEM, "Highscore", "H" , 0, ~0, MENU_HIGH},
  76.                                 {NM_ITEM, NM_BARLABEL, NULL, 0, ~0, NULL},
  77.                                 {NM_ITEM, "About"    , NULL, 0, ~0, MENU_ABOUT},
  78.                                 {NM_ITEM, NM_BARLABEL, NULL, 0, ~0, NULL},
  79.                                 {NM_ITEM, "Quit..."  , "Q" , 0, ~0, MENU_QUIT},
  80.                                 {NM_TITLE,"Control"  , NULL, 0, ~0, NULL},
  81.                                 {NM_ITEM, "Side 1"   , "1" , 0, ~0, MENU_SIDE1},
  82.                                 {NM_ITEM, "Side 2"   , "2" , 0, ~0, MENU_SIDE2},
  83.                                 {NM_ITEM, NM_BARLABEL, NULL, 0, ~0, NULL},
  84.                                 {NM_ITEM, "Random"   , "R" , 0, ~0, MENU_RAND},
  85.                                 {NM_END}
  86.                                       };
  87.  
  88. /* Gadget data */
  89. #define GAD_CLK1L   0
  90. #define GAD_CLK2L   1
  91. #define GAD_CLK3L   2
  92. #define GAD_CLK4L   3
  93. #define GAD_CLK1R   4
  94. #define GAD_CLK2R   5
  95. #define GAD_CLK3R   6
  96. #define GAD_CLK4R   7
  97. #define GAD_BUT1    8
  98. #define GAD_BUT2    9
  99. #define GAD_BUT3    10
  100. #define GAD_BUT4    11
  101. #define GAD_TOGGLE  12
  102. #define SIMPLE_GADGET(next, x, y, width, height, id) {\
  103.                                             next, x, y, width, height\
  104.                                             GFLG_GADGHNONE,\
  105.                                             GACT_RELVERIFY,\
  106.                                             GTYP_BOOLGADGET,\
  107.                                             NULL, NULL, NULL, 0, NULL, id, NULL\
  108.                                                      }                        
  109.  
  110. static const struct Gadget gads[] = {
  111.                         SIMPLE_GADGET(&gads[1], 272,  76, 17, 10, GAD_BUT1),
  112.                         SIMPLE_GADGET(&gads[2], 272, 116, 17, 10, GAD_BUT2),
  113.                         SIMPLE_GADGET(&gads[3], 352, 116, 17, 10, GAD_BUT3),
  114.                         SIMPLE_GADGET(&gads[4], 352,  76, 17, 10, GAD_BUT4),
  115.                         SIMPLE_GADGET(&gads[5], 211,  46, 30, 29, GAD_CLK1L),
  116.                         SIMPLE_GADGET(&gads[6], 241,  46, 29, 29, GAD_CLK1R),
  117.                         SIMPLE_GADGET(&gads[7], 211, 126, 30, 29, GAD_CLK2L),
  118.                         SIMPLE_GADGET(&gads[8], 241, 126, 29, 29, GAD_CLK2R),
  119.                         SIMPLE_GADGET(&gads[9], 371, 126, 30, 29, GAD_CLK3L),
  120.                         SIMPLE_GADGET(&gads[10],401, 126, 29, 29, GAD_CLK3R),
  121.                         SIMPLE_GADGET(&gads[11],371,  46, 30, 29, GAD_CLK4L),
  122.                         SIMPLE_GADGET(&gads[12],401,  46, 29, 29, GAD_CLK4R),
  123.                         SIMPLE_GADGET(NULL,     291,  86, 59, 29, GAD_TOGGLE)
  124.                                     };
  125.  
  126. /* GT-gadget data */
  127. #define GAD_W       112
  128. #define GAD_H       13
  129.  
  130. #define CTRLBOX_X   20 
  131. #define CTRLBOX_Y   75
  132. #define CTRLBOX_W   GAD_W+16
  133. #define CTRLBOX_H   (GAD_H+2)*3+4+2
  134.  
  135. #define GAD_X       CTRLBOX_X+8
  136. #define GAD_Y1      CTRLBOX_Y+4
  137. #define GAD_Y2      GAD_Y1+GAD_H+2
  138. #define GAD_Y3      GAD_Y2+GAD_H+2
  139.  
  140. #define GAD_SIDE    13
  141. #define GAD_PAUSE   14
  142. #define GTGADS      GAD_SIDE    /* gadgetID starts not at zero! */ 
  143. #define GTGADNUM    2
  144.  
  145. static const char *sideLabels[]  = {"Side 2", "Side 1", NULL};
  146. static const char *pauseLabels[] = {"Pause", "Game", NULL};
  147.  
  148. static const struct TagItem sideTags[]  = {GTCY_Labels, sideLabels, TAG_DONE}; 
  149. static const struct TagItem pauseTags[] = {GTCY_Labels, pauseLabels, TAG_DONE}; 
  150.  
  151. static struct Gadget *gadList;
  152. static struct GadgetData gtGads[] = {
  153.         { NULL, CYCLE_KIND, 0, sideTags,  GAD_X, GAD_Y2, GAD_W, GAD_H, NULL},
  154.         { NULL, CYCLE_KIND, 0, pauseTags, GAD_X, GAD_Y3, GAD_W, GAD_H, NULL}, 
  155. }; 
  156.  
  157. /* Window data */
  158. #define WINDOW_IDCMP    (IDCMP_MENUPICK|IDCMP_GADGETUP|IDCMP_REFRESHWINDOW|\
  159.                          IDCMP_INTUITICKS|CYCLEIDCMP)
  160. static struct Window    *win;
  161. static struct Menu      *menu;
  162. static struct RastPort  *rast;
  163. static struct BitMap    *elements;
  164.  
  165. /* Window update flags */
  166. #define UD_SIMPLE       0
  167. #define UD_OPENHIGH     1
  168. #define UD_NEWGAME      2
  169. static short            updateCase = UD_SIMPLE;
  170. static BOOL             updatePause;
  171.  
  172. /* Time display data */
  173. static struct timeval gameTime, gameTimeBeg;
  174. static struct IntuiText time = {
  175.                         1, 0, JAM2, 0, 0, NULL, (UBYTE *) "0:00:00  ", NULL };
  176.  
  177. /* About requester data */
  178. static const struct EasyStruct infoES = {
  179.                                          sizeof (struct EasyStruct),
  180.                                          0,
  181.                                          GAME_NAME " Info",
  182.                                          GAME_NAME " " VERSION "." REVISION
  183.                                          " (" DATE ")\n"
  184.                                          "Freely ditributable\n" 
  185.                                          "© " CYEARS " Holger Brunst",
  186.                                          "Cancel"
  187.                                         };
  188.  
  189. /* Clock data */
  190. static short    clkPos[18];
  191. static BOOL     butPos[4];
  192. static const long fmask[4] = {0x0000081b, 0x000200d8, 0x000081b0, 0x00000236};
  193. static const long bmask[4] = {0x80006c01, 0x80036040, 0x8001b100, 0x80003604};
  194. static const short clkPause[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
  195.  
  196. /* Pointers to clock element data */
  197. static short    *clkp;
  198. static struct Element *clkf, *clkb, *buts, *butd;
  199.  
  200. /* Clock status flags */
  201. #define FRONT_SIDE      TRUE
  202. #define BACK_SIDE       !FRONT_SIDE
  203. #define BUTTON_UP       TRUE
  204. #define BUTTON_DOWN     !BUTTON_UP
  205. #define LEFT_DIRECTION  1
  206. #define RIGHT_DIRECTION -1
  207. #define ALL_IMAGES      0x1fff
  208. static BOOL  clockPaused = FALSE;
  209. static BOOL  clockSide = BACK_SIDE;  /* TurnClock() will show front side */ 
  210. static short clockNotCorrect; 
  211.  
  212. /* Control clock movement depending on buttons and clocks */ 
  213. static ULONG MoveClock(USHORT gad)
  214. {
  215.  /* Init changes to none */
  216.  ULONG changes = 0; 
  217.  
  218.  /* Clocks? */
  219.  if (gad < 8) {
  220.                 short i, d;
  221.                 ULONG buf;
  222.  
  223.                 /* Backside? */
  224.                 if (clockSide == BACK_SIDE)
  225.                  /* Yes, use reversed gadgetID */ 
  226.                  gad = 7 - gad;
  227.  
  228.                 /* Move to which direction? */
  229.                 if (gad < 4)
  230.                  d = RIGHT_DIRECTION;
  231.                 else {
  232.                  d = LEFT_DIRECTION;
  233.                  gad -= 4;
  234.                 }
  235.  
  236.                 /* Is corresponding button up? */
  237.                 if (butPos[gad] == BUTTON_UP) {
  238.                  /* Yes, find clocks to be moved */
  239.                  for (i = 0; i < 4; ++i)
  240.                   if (butPos[i] == BUTTON_UP)   /* Buttons up? */
  241.                    changes |= fmask[i];
  242.                 }
  243.                 else {
  244.                  /* No, find clocks to be moved */
  245.                  for (i = 0; i < 4; ++i)
  246.                   if (butPos[i] == BUTTON_DOWN) /* Buttons down? */
  247.                    changes |= bmask[i];
  248.                 }
  249.  
  250.                 /* Move selected clocks */
  251.                 clockNotCorrect = 0;    /* Set clockNotCorrect to FALSE */
  252.                 buf = changes;          /* Remember clocks to be updated */
  253.  
  254.                 /* Check all clocks */
  255.                 for (i = 0; i < 18; ++i) {
  256.                  /* Change-bit set? */ 
  257.                  if ((buf & 1)) {
  258.                   clkPos[i] += d;       /* Increase/decrease clock posions */
  259.                   if (clkPos[i] > 11)
  260.                    clkPos[i] = 0;
  261.                   if (clkPos[i] < 0)
  262.                    clkPos[i] = 11;
  263.                  }
  264.                  buf >>= 1;             /* Next change-bit */
  265.  
  266.                  /* If all clocks are at twelve clockNotCorrect is 0 */
  267.                  clockNotCorrect += clkPos[i];
  268.                 }
  269.   
  270.                 /* Are we on the frontside? */
  271.                 if (clockSide == FRONT_SIDE)
  272.                  /* Yes, clear backside signal bits */
  273.                  changes &= 0x1ff;
  274.                 else
  275.                  /* No, shift backside signal bits to relevant position */
  276.                  changes >>= 9;
  277.                }
  278.   
  279.  /* Buttons? */
  280.  else 
  281.  if (gad < 12) {
  282.                 /* Relate buttonID to 0 */
  283.                 gad -= 8;
  284.  
  285.                 /* Backside? */
  286.                 if (clockSide == BACK_SIDE)
  287.                  /* Yes, use reversed gadgetID */
  288.                  gad  = 3 - gad;
  289.  
  290.                 /* Signalize toggled button */
  291.                 changes |= 0x200 << gad;
  292.  
  293.                 /* toggle button */
  294.                 butPos[gad] = !butPos[gad];
  295.                }
  296.  return (changes); 
  297. }
  298.  
  299. /* Update clock graphics */
  300. static void UpdateClock(ULONG changes)
  301. {
  302.  short i;
  303.  
  304.  /* Do we have to update a clock? */
  305.  for (i = 0; i < 9; ++i) {
  306.   if (changes & 1) { 
  307.  
  308.    /* Yes, first we assemble the bachground and forground */
  309.    BltBitMap(elements, clkb[i].x, clkb[i].y,
  310.              elements, 576, 224,
  311.              64, 32, 0xc0, 0xf,
  312.              NULL); 
  313.    BltBitMap(elements, clkf[clkp[i]].x, clkf[clkp[i]].y,
  314.              elements, 576, 224,
  315.              64, 32, 0xe0, 0xf,
  316.              NULL);
  317.  
  318.    /* To avoid flickering we then make one single 'blit' */
  319.    BltBitMapRastPort(elements, 576, 224,
  320.                      rast, clkDst[i].x, clkDst[i].y,
  321.                      64, 32, 0xc0);
  322.   }
  323.   changes >>= 1;
  324.  }
  325.  /* And the buttons? */
  326.  for (i = 0; i < 4; ++i) {
  327.   if (changes & 1) { 
  328.  
  329.    /* Yes. Button up? */
  330.    if (butPos[i] == BUTTON_UP) {
  331.     BltBitMapRastPort(elements, buts[i].x, buts[i].y,
  332.                       rast, butd[i].x, butd[i].y,
  333.                       32, 16, 0xc0);
  334.    }
  335.    else {
  336.     BltBitMapRastPort(elements, buts[4+i].x, buts[4+i].y,
  337.                       rast, butd[i].x, butd[i].y,
  338.                       32, 16, 0xc0);
  339.    }
  340.   }
  341.   changes >>= 1;
  342.  }
  343. }
  344.  
  345. /* Turn clock to certain side.
  346.    Because of refreshing it is necessary to know 'who' wants
  347.    to turn the clock */
  348. static void TurnClock(BOOL side, USHORT who)
  349. {
  350.  /* Are we already on the right side? */
  351.  if (clockSide != side) {
  352.   /* No. We don't want to see the blitter work */
  353.   Zoom(Screen, darknes, 16);
  354.  
  355.   /* Blit frontside or backside clock image */
  356.   if (side == FRONT_SIDE) {
  357.    BltBitMapRastPort(elements,   0,  0, rast,  176, 28, 288, 144, 0xc0);
  358.    clkf = clkFor;
  359.    clkb = clkBak;
  360.    clkp = clkPos;
  361.    buts = butSrc;
  362.    butd = butDst;
  363.   }
  364.   else {
  365.    BltBitMapRastPort(elements, 288,  0, rast,  176, 28, 288, 144, 0xc0);
  366.    clkf = &clkFor[12];  
  367.    clkb = &clkBak[9];
  368.    clkp = &clkPos[9];  
  369.    buts = &butSrc[8];
  370.    butd = &butDst[4];
  371.   }
  372.  
  373.   /* Refresh side cycle gadget if necessary */
  374.   if (who != GAD_SIDE);
  375.    GT_SetGadgetAttrs(gtGads[GAD_SIDE-GTGADS].gadget, win, NULL,
  376.                      GTCY_Active, (side == FRONT_SIDE)? 0:1,
  377.                      TAG_DONE);
  378.  
  379.   /* Refresh each clock */
  380.   clockSide = side;
  381.   UpdateClock(ALL_IMAGES);
  382.  
  383.   /* Turn the light back on */
  384.   Zoom(Screen, (USHORT *) &elements->Planes[6], 16);
  385.  }
  386. }
  387.  
  388. /* Activate/deactivate clock */
  389. static void PauseClock(BOOL status, USHORT who)
  390. {
  391.  static struct timeval pauseBeg;
  392.  
  393.  /* Clock already at demanded status */
  394.  if (status != clockPaused) {
  395.   /* No. Pause clock? */
  396.   if (status) {
  397.    /* Yes, set pause flag */
  398.    clockPaused = status;
  399.  
  400.    /* Remember passed time */
  401.    GetSysTime(&pauseBeg);
  402.  
  403.    /* Deactivate clock controls */   
  404.    GT_SetGadgetAttrs(gtGads[GAD_SIDE-GTGADS].gadget, win, NULL,
  405.                      GA_Disabled, TRUE,
  406.                      TAG_DONE);
  407.    OffMenu(win, 0xffe1);
  408.  
  409.    /* Midnight */
  410.    clkp = clkPause;
  411.    UpdateClock(ALL_IMAGES);
  412.   }
  413.   else {
  414.    /* No, back to user's chaos */
  415.    if (clockSide == FRONT_SIDE)
  416.     clkp = clkPos;
  417.    else
  418.     clkp = &clkPos[9];
  419.    UpdateClock(ALL_IMAGES);
  420.  
  421.    /* Reactivate clock controls */
  422.    GT_SetGadgetAttrs(gtGads[GAD_SIDE-GTGADS].gadget, win, NULL,
  423.                      GA_Disabled, FALSE,
  424.                      TAG_DONE);
  425.    OnMenu(win, 0xffe1);
  426.  
  427.    /* Start time counter */
  428.    SubTime(&pauseBeg, &gameTimeBeg);
  429.    AddTime(&gameTime, &pauseBeg);
  430.    GetSysTime(&gameTimeBeg);
  431.  
  432.    /* Clear pause flag */
  433.    clockPaused = status;
  434.   }
  435.  
  436.   /* If necessary refresh 'pause cycle gadget' */
  437.   if (who != GAD_PAUSE)
  438.    GT_SetGadgetAttrs(gtGads[GAD_PAUSE-GTGADS].gadget, win, NULL,
  439.                      GTCY_Active, (clockPaused == TRUE)? 1:0,
  440.                      TAG_DONE);
  441.  }
  442. }
  443.  
  444. /* Move clocks to random positions */
  445. static void RandomClock(void)
  446. {
  447.  short  i;
  448.  long   sec, mic;
  449.  
  450.  /* Get start value for random function */
  451.  CurrentTime(&sec, &mic);
  452.  srand(mic);
  453.  
  454.  /* 50 changes should be enough */
  455.  for (i = 50; i > 0; i--) {
  456.   MoveClock(GAD_BUT1 + (rand() & 3));
  457.   MoveClock(GAD_CLK1L + (rand() & 3));
  458.  }
  459.  
  460.  /* Display changes */
  461.  UpdateClock(ALL_IMAGES);
  462. }
  463.  
  464. /* Reset clock to default */ 
  465. static void ResetClock(void)
  466. {
  467.  short i;
  468.  
  469.  /* Midnight */
  470.  for (i = 0; i < 18; i++) clkPos[i] = 0;
  471.  for (i = 0; i < 4; i++) butPos[i] = BUTTON_UP;
  472.  
  473.  /* Draw boxes */
  474.  DrawBevelBox(rast, GAD_X, GAD_Y1, GAD_W, GAD_H,
  475.               GT_VisualInfo, ScreenVI,
  476.               GTBB_Recessed, TRUE, 
  477.               TAG_DONE);
  478.  
  479.  /* Draw clock image */
  480.  if (clockSide == BACK_SIDE)
  481.   TurnClock(FRONT_SIDE, -1);
  482.  
  483.  /* Clocks to random position */
  484.  RandomClock();
  485.  
  486.  /* Reset & start game time */
  487.  PauseClock(FALSE, ~0);
  488.  GetSysTime(&gameTimeBeg);
  489.  gameTime.tv_secs = 0; gameTime.tv_micro = 0; 
  490. }
  491.  
  492. /* Open the clock */
  493. ULONG OpenClockWindow(void)
  494. {
  495.  /* Open clock gfx elements */ 
  496.  if (elements = OpenILBM(PIC_NAME)) {
  497.   /* Set colors */
  498.   LoadRGB4(&Screen->ViewPort, (USHORT *) &elements->Planes[6], 16); 
  499.   /* Create menus */
  500.   if (menu = CreateMenus(mdata, GTMN_FullMenu, TRUE, 
  501.                                 TAG_DONE)) {
  502.    /* Layout menus */ 
  503.    if (LayoutMenus(menu, ScreenVI, TAG_DONE))
  504.     /* Create gadgets */
  505.     if (gadList = CreateGadgetList(gtGads, GTGADNUM, GTGADS)) {
  506.      /* Open window */
  507.      if (win = OpenWindowTags(NULL, WA_Width, 640,
  508.                                     WA_Height, 200,
  509.                                     WA_PubScreen, Screen,
  510.                                     WA_Gadgets, gads,
  511.                                     WA_Flags, WFLG_BACKDROP|WFLG_SMART_REFRESH|
  512.                                               WFLG_BORDERLESS|WFLG_ACTIVATE,
  513.                                     WA_IDCMP, WINDOW_IDCMP,
  514.                                     TAG_DONE)) {
  515.       /* Set menu strip */
  516.       if (SetMenuStrip(win, menu)) {
  517.  
  518.        /* Add gadgets to window */
  519.        AddGList(win, gadList, ~0, ~0, NULL);
  520.        RefreshGList(gadList, win, NULL, ~0);
  521.        GT_RefreshWindow(win, NULL);
  522.  
  523.        /* Get rast-port */
  524.        rast = win->RPort;
  525.        
  526.        /* Draw signature */
  527.        BltBitMapRastPort(elements, 512, 208, rast,  580, 172, 60, 28, 0xc0);
  528.  
  529.        /* Init clocks */
  530.        ResetClock();
  531.  
  532.        /* Link IDCMP routine to window */ 
  533.        IDCMPPort = win->UserPort;
  534.        win->UserData = HandleClockWindowIDCMP;
  535.  
  536.        /* All done correctly. Return IDCMP signal mask */ 
  537.        return (1L << IDCMPPort->mp_SigBit);
  538.       }
  539.       CloseWindow(win);
  540.      }
  541.      FreeGadgets(gadList);
  542.     } 
  543.    FreeMenus(menu);
  544.   }
  545.   CloseILBM(elements);
  546.  }
  547.  /* fail */
  548.  return (NULL);
  549. }
  550.  
  551. /* Close all */
  552. void CloseClockWindow(void)
  553. {
  554.  RemoveGList(win, gadList, ~0);
  555.  ClearMenuStrip(win);
  556.  CloseWindow(win);
  557.  FreeGadgets(gadList);
  558.  FreeMenus(menu);
  559.  CloseILBM(elements);
  560.  
  561. /* Handle window idcmp messages */
  562. void *HandleClockWindowIDCMP(struct IntuiMessage *msg)
  563. {
  564.  switch (msg->Class) {
  565.  
  566.   /* Gadgets */
  567.   case IDCMP_GADGETUP: {
  568.    USHORT   gad = (((struct Gadget *) msg->IAddress)->GadgetID);
  569.  
  570.    /* Handle GT-gadgets */
  571.    switch (gad) {
  572.  
  573.     /* Toggle side? */
  574.     case GAD_SIDE:  TurnClock(!clockSide, GAD_SIDE);
  575.                     break;
  576.     /* Pause or activate game */
  577.     case GAD_PAUSE: PauseClock(!clockPaused, GAD_PAUSE);
  578.                     break;
  579.    }
  580.  
  581.    /* Handle standard boolean gadgets if game is not paused */
  582.    if (!clockPaused) {
  583.     switch (gad) {
  584.  
  585.      /* Toggle side? */
  586.      case GAD_TOGGLE: TurnClock(!clockSide, GAD_TOGGLE);
  587.                       break;
  588.  
  589.      /* Any clock or button pressed? */
  590.      default:         UpdateClock(MoveClock(gad));
  591.                       /* Clock ok.? */
  592.                       if (!clockNotCorrect) {
  593.                        struct timeval gameTimeEnd;
  594.  
  595.                        /* Calculate & remember passed time */
  596.                        clockPaused = TRUE;
  597.                        GetSysTime(&gameTimeEnd);
  598.                        SubTime(&gameTimeEnd, &gameTimeBeg);
  599.                        AddTime(&gameTime, &gameTimeEnd);
  600.  
  601.                        /* Is it a new highscore */
  602.                        if (AskHighScore(gameTime.tv_secs)) {
  603.                         /* Yes, init window update environment */
  604.                         UpdateWindow = UpdateClockWindow;
  605.                         updateCase = UD_OPENHIGH;
  606.  
  607.                         /* Did open namewindow succeed? */
  608.                         if (OpenNameWindow())
  609.                          /* Yes, disable clock window */
  610.                          DisableWindow(win);
  611.                         else {
  612.                          /* No, beep and update */  
  613.                          DisplayBeep(Screen);
  614.                          return ("MrS. NotEnoughMem");                                        
  615.                         }
  616.                        }
  617.                        else {
  618.                         /* No, show highscore */
  619.                         UpdateWindow = UpdateClockWindow;
  620.                         updateCase = UD_NEWGAME;
  621.  
  622.                         /* Did open highwindow succeed? */
  623.                         if (OpenHighWindow())
  624.                          /* Yes, disable clock window */
  625.                          DisableWindow(win);
  626.                         else {
  627.                          /* No, beep and update */  
  628.                          DisplayBeep(Screen);
  629.                          return (TRUE);
  630.                         }
  631.                        } 
  632.                       }
  633.                       break;
  634.     }
  635.    }
  636.    break;
  637.   }
  638.   /* Menus */
  639.   case IDCMP_MENUPICK: {
  640.    USHORT number = msg->Code;
  641.    struct MenuItem *item;
  642.  
  643.    /* Scan all menu events */
  644.    while (number != MENUNULL) {
  645.     item = ItemAddress(menu, number);  
  646.  
  647.     /* Which menu selected? */
  648.     switch (GTMENUITEM_USERDATA(item)) {
  649.  
  650.      case MENU_NEW:   ResetClock();
  651.                       break;
  652.  
  653.      case MENU_HIGH:  /* pause clock */
  654.                       updatePause = clockPaused;
  655.                       PauseClock(TRUE, ~0);
  656.  
  657.                       /* Open highwindow ok.? */
  658.                       if (OpenHighWindow()) {
  659.                        /* Yes, set update environment */
  660.                        DisableWindow(win);
  661.                        updateCase = UD_SIMPLE;
  662.                        UpdateWindow = UpdateClockWindow;
  663.                       }
  664.                       else {
  665.                        /* No, beep */
  666.                        DisplayBeep(Screen);
  667.                        PauseClock(updatePause, ~0);
  668.                       }
  669.                       break;
  670.  
  671.      case MENU_ABOUT: /* pause clock */
  672.                       updatePause = clockPaused;
  673.                       PauseClock(TRUE, ~0);
  674.  
  675.                       /* Open info requester */
  676.                       DisableWindow(win);
  677.                       EasyRequest(win, &infoES, NULL, NULL);
  678.                       EnableWindow(win, WINDOW_IDCMP);
  679.  
  680.                       PauseClock(updatePause, ~0);
  681.                       break;
  682.  
  683.      case MENU_QUIT:  /* First reply message */
  684.                       GT_ReplyIMsg(msg); 
  685.                       return (TRUE);
  686.  
  687.      case MENU_SIDE1: TurnClock(FRONT_SIDE, -1);
  688.                       break;
  689.  
  690.      case MENU_SIDE2: TurnClock(BACK_SIDE, -1);
  691.                       break;
  692.  
  693.      case MENU_RAND:  RandomClock();
  694.                       break;
  695.  
  696.      case MENU_PAUSE: PauseClock(!clockPaused, ~0);
  697.                       break;
  698.     }
  699.     number = item->NextSelect;
  700.    }
  701.    break;
  702.   }
  703.   /* Update time display */
  704.   case IDCMP_INTUITICKS: {
  705.                           ULONG secs, hour;
  706.                           struct timeval curr;
  707.  
  708.                           /* Game not paused? */
  709.                           if (!clockPaused) {
  710.  
  711.                            /* Calculate passed game time */
  712.                            GetSysTime(&curr);
  713.                            SubTime(&curr, &gameTimeBeg);
  714.                            AddTime(&curr, &gameTime);
  715.  
  716.                            /* I know stdio...
  717.                               but it's the easiest way to convert bin to dec */ 
  718.                            secs = curr.tv_secs;
  719.                            hour = secs / 3600;
  720.                            sprintf(time.IText, "%01ld:%02ld:%02ld  ",
  721.                                    hour,
  722.                                    secs / 60 - hour * 60,
  723.                                    secs % 60); 
  724.                            PrintIText(rast, &time, GAD_X+GAD_W/4, GAD_Y1+2);
  725.                           }
  726.                           break;
  727.                          }
  728.   /* Necessary because of GT */
  729.   case IDCMP_REFRESHWINDOW: GT_BeginRefresh(win);
  730.                             GT_EndRefresh(win, TRUE);
  731.                             break;
  732.  }
  733.  return (NULL);
  734. }
  735.  
  736. /* Update clock window */
  737. void UpdateClockWindow(void *data)
  738. {
  739.  switch (updateCase) {
  740.  
  741.   /* Simple update after a window has been closed */
  742.   case UD_SIMPLE:   UpdateWindow = NULL;
  743.                     EnableWindow(win, WINDOW_IDCMP); 
  744.                     PauseClock(updatePause, ~0);       
  745.                     break;
  746.  
  747.   /* Open the highscore window after new name has been entered */
  748.   case UD_OPENHIGH: InsertHighScore(data, gameTime.tv_secs);
  749.                     /* Open highscore window ok.? */
  750.                     if (OpenHighWindow()) {
  751.                      /* Yes */
  752.                      updateCase = UD_NEWGAME;
  753.                      break;                     
  754.                     }                    
  755.                     /* No */
  756.                     DisplayBeep(Screen);
  757.                     /* Run trough */                     
  758.  
  759.   /* Start new game after someone's been successful */
  760.   case UD_NEWGAME:  ResetClock();
  761.                     UpdateWindow = NULL;
  762.                     EnableWindow(win, WINDOW_IDCMP); 
  763.                     break;
  764.  }
  765. }
  766.