home *** CD-ROM | disk | FTP | other *** search
/ Falcon 030 Power 2 / F030_POWER2.iso / ST_STE / MAGS / ICTARI10.ARJ / ictari.10 / C / BOINKOUT / BOINKOUT.C next >
C/C++ Source or Header  |  1987-04-22  |  25KB  |  1,056 lines

  1. /********************************************
  2. *        Boinkout program and acc            *
  3. *        Samuel Streeper 90/02/26            *
  4. *                                            *
  5. *    Copyright 1990 by Antic Publishing Inc.    *
  6. *                                            *
  7. * "what to do with all that wasted            *
  8. *    CPU time Part III"                        *
  9. ********************************************/
  10.  
  11. /* edited with tabsize = 4 */
  12.  
  13. extern int _app;
  14.  
  15.  
  16. /*    Compiler notes:        */
  17. /*    ---------------        */
  18. /*    This code compiles with Laser C and Mark Williams C                    */
  19. /*    version 2.0. It shouldn't be tough to get it to compile with other    */
  20. /*    things...                                                             */
  21. /*    There are just a few things to look out for when porting this        */
  22. /*    between compilers:                                                    */
  23.  
  24. /*    The blitter routines require a structure known as a memory form        */
  25. /*    descriptor block. Laser C and Alcyon C call this structure a        */
  26. /*    MFDB, while MWC calls this a FDB.                                    */
  27.  
  28. /*    Boinkout needs to know the address of the line-a variables.            */
  29. /*    Megamax does not supply a function to get this address, while        */
  30. /*    Laser C and MWC do, but the function has a different name. Further-    */
  31. /*    more, the MWC supplied function returns the wrong address with        */
  32. /*    tos 1.4. Consequently, I use inline assembly for laser,                */
  33. /*    and a simple assembly function in MWC.                                */
  34.  
  35. /*    This code will work as both a desk accessory or a program if you    */
  36. /*    link it with the proper startup module. The default Laser startup    */
  37. /*    module works ok. I recommend linking to the laser or                */
  38. /*    MWC startup code supplied with Start magazine October 89. This code    */
  39. /*    gives the smallest executable file, and will work as a program or    */
  40. /*    DA just by changing the file's extention from .prg to .acc            */
  41.  
  42. /*    When run as a program, boink has a 'fast mode' option which bounces    */
  43. /*    the ball without going through the evnt_multi() call. To take        */
  44. /*    optimal advantage of fast mode, the C library blitter function        */
  45. /*    vro_copyfm() should be replaced by an assembly language binding        */
  46. /*    which goes straight to the line-a blitter call without invoking        */
  47. /*    the AES (via trap #2). I have supplied such a binding which works    */
  48. /*    with Megamax and Laser C. This binding is transparent i.e. if        */
  49. /*    you link in the SVRO object file you get the custom binding,        */
  50. /*    otherwise you get the slower AES library binding.                    */
  51.  
  52. #include <obdefs.h>
  53. #include <gemdefs.h>
  54. #include <osbind.h>
  55. #include "boinkout.h"
  56.  
  57. #if MWC
  58. #define MFDB FDB
  59. #define Kbshift(a) Getshift(a)
  60. #endif
  61.  
  62. int n_redraws;
  63. RECT region[MAX_ANI];        /* a list of redraw regions */
  64. RECT tregion [MAX_ANI];        /* temporary clipping region */
  65. BALL_STRUCT bs[MAX_BALLS];
  66.  
  67. int num_balls;
  68.  
  69. char null[] = "";
  70.  
  71. /* The following arrays of gem OBJECTS were dumped from a resource    */
  72. /* file using the resource dumper from the START magazine            */
  73. /* October 89 issue. By including the resource file in the code        */
  74. /* we don't need to load it in at run-time (which is a bad idea        */
  75. /* for desk accessories...)                                            */
  76.  
  77. #define ABTBOINK 7
  78. #define WINDOPEN 16
  79. #define LOADPIC 17
  80. #define FAST 18
  81. #define FILEQUIT 20
  82.  
  83. OBJECT menu[] = {
  84. -1,1,5,G_IBOX,0,0,0x0L,0,0,0x50,0x19,
  85. 5,2,2,G_BOX,0,0,0x1100L,0,0,0x50,0x201,
  86. 1,0x3,0x4,G_IBOX,0,0,0x0L,2,0,0xC,0x301,
  87. 4,-1,-1,G_TITLE,0,0," Desk ",0,0,6,0x301,
  88. 2,-1,-1,G_TITLE,0,0," File ",6,0,6,0x301,
  89. 0,6,0xF,G_IBOX,0,0,0x0L,0,0x301,0x50,0x13,
  90. 0xF,0x7,0xE,G_BOX,0,0,0xFF1100L,2,0,0x14,8,
  91. 8,-1,-1,G_STRING,0,0,"  About BoinkOut...",0,0,0x14,1,
  92. 9,-1,-1,G_STRING,0,0x8,"--------------------",0,1,0x14,1,
  93. 0xA,-1,-1,G_STRING,0,0,null,0,2,0x14,1,
  94. 0xB,-1,-1,G_STRING,0,0,null,0,3,0x14,1,
  95. 0xC,-1,-1,G_STRING,0,0,null,0,4,0x14,1,
  96. 0xD,-1,-1,G_STRING,0,0,null,0,5,0x14,1,
  97. 0xE,-1,-1,G_STRING,0,0,null,0,6,0x14,1,
  98. 0x6,-1,-1,G_STRING,0,0,null,0,7,0x14,1,
  99. 5,0x10,0x14,G_BOX,0,0,0xFF1100L,8,0,0xF,5,
  100. 0x11,-1,-1,G_STRING,0,0,"  Open Window",0,0,0xF,1,
  101. 0x12,-1,-1,G_STRING,0,0,"  Load Pic...",0,1,0xF,1,
  102. 0x13,-1,-1,G_STRING,0,0,"  High Speed",0,2,0xF,1,
  103. 0x14,-1,-1,G_STRING,0,8,"---------------",0,3,0xF,1,
  104. 0xF,-1,-1,G_STRING,0x20,0,"  Quit",0,4,0xF,1
  105. };
  106.  
  107. TEDINFO ted0 = {
  108.     "by Samuel Streeper",
  109.     null,
  110.     null,
  111.     5, 6, 0, 0x1180, 0, 0xff, 19, 1        };
  112.  
  113. TEDINFO ted1 = {
  114.     "Runs as .prg or .acc",
  115.     null,
  116.     null,
  117.     5, 6, 0, 0x1180, 0, 0xff, 21, 1        };
  118.  
  119. #define DIALOK 10
  120. #define DIALLOAD 11
  121.  
  122. OBJECT dial[] = {
  123. -1,1,1,G_BOX,0,0x10,0x11142L,0,0,39,20,
  124. 0,2,11,G_BOX,0,0x20,0xff1100L,1,1,37,18,
  125. 3,-1,-1,G_STRING,0,0,"BoinkOut!",13,1,9,1,
  126. 4,-1,-1,G_TEXT,0,0,&ted0,3,2,14,1,
  127. 5,-1,-1,G_TEXT,0,0,&ted1,19,2,15,1,
  128. 6,-1,-1,G_STRING,0,0,"COPYRIGHT  1990",10,4,15,1,
  129. 7,-1,-1,G_STRING,0,0,"by Antic Publishing, Inc.",6,5,25,1,
  130. 8,-1,-1,G_STRING,0,0,"Antic Publishing",9,8,16,1,
  131. 9,-1,-1,G_STRING,0,0,"544 Second Street",9,9,17,1,
  132. 10,-1,-1,G_STRING,0,0,"San Francisco, CA 94107",6,10,23,1,
  133. 11,-1,-1,G_BUTTON,0x7,0,"OK",13,13,10,2,
  134. 1,-1,-1,G_BUTTON,0x65,0,"Load Pic...",9,16,18,1,
  135. };
  136.  
  137. #define WI_KIND    (MOVER|CLOSER|NAME)
  138.  
  139. extern int    gl_apid;
  140.  
  141. extern int monoballs[], monobricks[], mono_perm_bricks[], monopaddle[];
  142. extern int mono_digits[], mono_fuji[], monofuji_mask[], mono_eye[];
  143. extern int mono_leveltext[], mono_twobrick[], invis, magic_bottom;
  144. extern int medballs[], medbricks[], med_perm_bricks[], medpaddle[];
  145. extern int med_digits[], med_fuji[], medfuji_mask[], med_eye[];
  146. extern int med_leveltext[], med_twobrick[];
  147.  
  148. long old_base;
  149.  
  150. int    gl_hchar, gl_wchar, gl_wbox, gl_hbox;    /* sizes of system characters */
  151.  
  152. int    win_kind = WI_KIND;
  153. int    menu_id, paddle_x, paddle_y, pad_y_min, pad_y_max, pad_y_top;
  154.  
  155. int    phys_handle;    /* physical workstation handle */
  156. int    handle;            /* virtual workstation handle */
  157. int    w_hand;            /* window handle */
  158.  
  159. int    xdesk,ydesk,hdesk,wdesk;
  160. int    xold,yold,hold,wold;
  161. int    xwork,ywork,hwork,wwork;    /* desktop and work areas */
  162.  
  163. int    msgbuff[8];                    /* event message buffer */
  164. int    ret;
  165.  
  166. extern char brickmask[][63];
  167. int level;
  168.  
  169. extern int mode;
  170. int ani_count, num_bricks, cheat, fastmode;
  171. int    fulled;                        /* current state of window */
  172. int    ball_ht = 21;
  173. int win_ht = HEIGHT;
  174. int max_xspeed = 8;
  175. int min_yspeed = -8;
  176. int planes;            /* number of bit planes */
  177.  
  178. int btop = 44;        /* actual top of block of bricks */
  179. int btopm = 39;        /* measured top of bricks */
  180. int bth = 26;        /* total brick height, including space */
  181. int bh = 16;        /* brick height */
  182. int block_bot = 221;    /* block_top = btopm + 7 * bth */
  183. int bleft = 6;
  184. int btw = 48;
  185. int pady_offset = 25;
  186. int max_pad_dy = 16;
  187. int pad_ht = 19;
  188. int fuji_ht = 13;
  189. int fmask_ht = 15;
  190. int text_ht = 12;
  191.  
  192. int    *lineaptr;
  193. char brickcount[63];
  194.  
  195. #if MWC
  196. extern int *a_init();
  197. #endif
  198.  
  199. char title_bar[] = "  BoinkOut!  ";
  200.  
  201. long score, old_score, bonus_life, old_bonus;
  202. int lives, old_lives;
  203.  
  204. int    maxx, maxy, maxw, maxh;
  205. int    timer, ttimer, event_kind = MU_MESAG;
  206.  
  207. extern int int_in[], addr_in[], control[], int_out[];
  208.  
  209. int    contrl[12];
  210. int    intin[128];
  211. int    ptsin[128];
  212. int    intout[128];
  213. int    ptsout[128];
  214.  
  215. int work_in[11];
  216. int work_out[57];
  217.  
  218. int ballarray[8];            /* ball blit array */
  219. int paddlearray[8];            /* paddle blit array */
  220. int brickarray[8];
  221.  
  222. /* These buffers are big enough for a 440 x 362 pixel image */
  223. /* (slightly bigger than they need to be...) */
  224. char warray[20272];
  225. char parray[20272];
  226.  
  227. MFDB ballsource = {0L,144,20,144/16,0,1,0,0,0};
  228. MFDB paddlesource = {0L,64,19,64/16,0,1,0,0,0};
  229. MFDB bricksource = {0L,192,16,192/16,0,1,0,0,0};
  230. MFDB twobricksource = {0L,192,16,192/16,0,1,0,0,0};
  231. MFDB permbricksource = {0L,192,16,192/16,0,1,0,0,0};
  232. MFDB windsource = {0L,448,344,448/16,0,1,0,0,0};
  233. MFDB pic_buf = {0L,448,344,448/16,0,1,0,0,0};
  234. MFDB digitsource = {0L,5*16,12,5,0,1,0,0,0};
  235. MFDB fujisource = {0L,7*16,13,7,0,1,0,0,0};
  236. MFDB fmasksource = {0L,7*16,15,7,0,1,0,0,0};
  237. MFDB eyesource = {0L,144,20,144/16,0,1,0,0,0};
  238. MFDB levelsource = {0L,3*16,12,3,0,1,0,0,0};
  239. MFDB screen_fdb;
  240.  
  241. char path[80], name[14];
  242.  
  243.  
  244. /* the sound string is the yamaha sound chip parameter for the bouncing        */
  245. /* ball sound. The osound array resets the modified sound chip registers    */
  246. /* to their old values so that key click sounds will be normal when the        */
  247. /* program terminates.                                                        */
  248.  
  249. char sound[] =    {
  250.     0,0xf0,1,0x0f, 2,0xff, 3,0x0f, 4,0x00, 5,0, 6,0x1f, 7,0xdc,
  251.     8,0x10,9,0x10,10,0x10,11,0x00,12,25,13,0,0xff,0
  252.     };
  253.  
  254. int appear[] = {
  255.     0x040,0x102,0x242,0x302,0x400,0x500,0x61f,0x7dc,
  256.     0x810,0x910,0xA10,0xB00,0xC15,0xD0f,0xFF00
  257.     };
  258.  
  259. /* osound restores registers 9 and 10 for normal key click */
  260. char osound[] = { 9, 0, 10, 0, 0xff, 0    };
  261.  
  262.                 /*     012345678901234567890123456    */
  263. char *no_picture =    "Unable to open BOINKOUT.PI3 Degas picture\r\n";
  264.  
  265.             /*   0 123456 789012345678    */
  266. char *pic1 =    "\\boink\\boinkout.pi3";
  267. char *pic2 =    "\\boink\\boink.pi3";
  268.  
  269. /****************************************************************/
  270. /* open virtual workstation                                        */
  271. /****************************************************************/
  272. open_vwork()
  273. {
  274.     register int i;
  275.  
  276.     for(i=0;i<10;work_in[i++]=1);
  277.     work_in[10]=2;
  278.     handle=phys_handle;
  279.     v_opnvwk(work_in,&handle,work_out);
  280.  
  281.     init_fdb();
  282. }
  283.  
  284. /********************************************/
  285. /*        open window                            */
  286. /********************************************/
  287. int open_window()
  288. {
  289.     if ((w_hand=wind_create(win_kind,xdesk,ydesk,maxw,maxh)) < 0)
  290.         return -1;
  291.  
  292.     if (Kbshift(-1) & 1) cheat = TRUE;
  293.     else cheat = FALSE;
  294.  
  295.     wind_set(w_hand, WF_NAME,title_bar,0,0);
  296.     graf_growbox(xdesk,ydesk,gl_wbox,gl_hbox,xold,yold,wold,hold);
  297.     wind_open(w_hand,xold,yold,wold,hold);
  298.     wind_get(w_hand,WF_WORKXYWH,&xwork,&ywork,&wwork,&hwork);
  299.  
  300.     if (lives <= 0) new_game();
  301.     restart_level();
  302.  
  303.     event_kind = MU_MESAG | MU_TIMER;
  304.     ttimer = timer = 0;
  305.     screen_fdb.fd_addr = (long)Logbase();
  306.  
  307.     return 0;
  308. }
  309.  
  310. int hidden;        /* = FALSE */
  311. /****************************************************************/
  312. /* find and redraw all clipping rectangles            */
  313. /****************************************************************/
  314. do_redraw()
  315. {
  316.     register RECT *p;
  317.     RECT t;
  318.     register int i;
  319.     int array[8];
  320.     int x_pos,y_pos, mxmin, mxmax, mymin, mymax;
  321.  
  322.     if (fastmode)
  323.     {
  324.         fast_redraw();
  325.         return;
  326.     }
  327.  
  328.     x_pos = *(lineaptr - 301);
  329.     y_pos = *(lineaptr - 300);
  330.     if (*(lineaptr - 298)) ttimer = 200;
  331.     else ttimer = timer;
  332.  
  333.     mxmin = x_pos - 20;
  334.     mxmax = x_pos + 20;
  335.     mymin = y_pos - 20;
  336.     mymax = y_pos + 20;
  337.  
  338.     wind_update(TRUE);
  339.  
  340.     /* check all redraw regions for mouse interference */
  341.     for (i=0; i<n_redraws; i++)
  342.     {
  343.         p = ®ion[i];
  344.         if ((p->x < mxmax) && ((p->x + p->w) > mxmin) &&
  345.             (p->y < mymax) && ((p->y + p->h) > mymin))
  346.         {    HIDE_MOUSE;
  347.             hidden = TRUE;
  348.             break;
  349.         }
  350.     }
  351.  
  352.     /* clip all regions to screen size */
  353.     for (i=0; i<n_redraws; i++)
  354.     {
  355.         p = ®ion[i];
  356.         if ((p->x+p->w) > wdesk) p->w = wdesk - p->x;
  357.         if ((p->y+p->h) > maxy) p->h =maxy-p->y;
  358.     }
  359.  
  360.     wind_get(w_hand,WF_FIRSTXYWH,&t.x,&t.y,&t.w,&t.h);
  361.  
  362.     while (t.w && t.h)
  363.     {
  364.         for (i=0; i<n_redraws; i++)
  365.         {
  366.             p = &tregion[i];
  367.             *p = t;                /* copy this window rect */
  368.  
  369.             if (rc_intersect(®ion[i],p))
  370.             /* tregion[i] clipped to my redraw region */
  371.             {
  372.                 array[0] = p->x - xwork;
  373.                 array[1] = p->y - ywork;
  374.                 array[2] = p->x - xwork + p->w - 1;
  375.                 array[3] = p->y - ywork + p->h - 1;
  376.                 array[4] = p->x;
  377.                 array[5] = p->y;
  378.                 array[6] = p->x + p->w - 1;
  379.                 array[7] = p->y + p->h - 1;
  380.  
  381.                 vro_cpyfm(handle,3,array,&windsource,&screen_fdb);
  382.             }
  383.         }
  384.         wind_get(w_hand,WF_NEXTXYWH,&t.x,&t.y,&t.w,&t.h);
  385.     }
  386.  
  387.     if (hidden)
  388.     {    hidden = FALSE;
  389.         SHOW_MOUSE;
  390.     }
  391.  
  392.     wind_update(FALSE);
  393.     n_redraws = 0;
  394. }
  395.  
  396. /********************************/
  397. /*        MAIN()                     */
  398. /********************************/
  399. main()
  400. {
  401.     register BALL_STRUCT *p;
  402.     register int temp, dw, dh;
  403.     int fd, wx,wy,ww,wh, i;
  404.  
  405.  
  406. #if LASER
  407.     asm{    dc.w 0xa000
  408.             move.l D0,lineaptr
  409.        }
  410. #else
  411. #if MWC
  412.     lineaptr = a_init();
  413. #endif                        /* mwc */
  414. #endif                        /* laser */
  415.  
  416.     planes = *lineaptr;
  417.  
  418.     if (planes == 2)        /* color monitor */
  419.     {
  420.         ballsource.fd_nplanes = 2;
  421.         paddlesource.fd_nplanes = 2;
  422.         bricksource.fd_nplanes = 2;
  423.         twobricksource.fd_nplanes = 2;
  424.         permbricksource.fd_nplanes = 2;
  425.         windsource.fd_nplanes = 2;
  426.         pic_buf.fd_nplanes = 2;
  427.         digitsource.fd_nplanes = 2;
  428.         fujisource.fd_nplanes = 2;
  429.         fmasksource.fd_nplanes = 2;
  430.         eyesource.fd_nplanes = 2;
  431.         levelsource.fd_nplanes = 2;
  432.  
  433.         windsource.fd_h = 172;
  434.         ball_ht = 10;
  435.         win_ht = HEIGHT/2;
  436.         temp = '2';
  437.         no_picture[26] = temp;
  438.         pic1[18] = temp;
  439.         pic2[15] = temp;
  440.         min_yspeed = -4;
  441.         btop = 22;
  442.         btopm = 20;
  443.         bth = 13;
  444.         bh = 8;
  445.         block_bot = 111;
  446.         pady_offset = 12;
  447.         max_pad_dy = 8;
  448.         pad_ht = 10;
  449.         fuji_ht = 6;
  450.         fmask_ht = 8;
  451.         text_ht = 6;
  452.  
  453.         pad_y_min = 122;
  454.         pad_y_max = 159;
  455.  
  456.         ballsource.fd_addr = (long)medballs;
  457.         paddlesource.fd_addr = (long)medpaddle;
  458.         bricksource.fd_addr = (long)medbricks;
  459.         twobricksource.fd_addr = (long)med_twobrick;
  460.         permbricksource.fd_addr = (long)med_perm_bricks;
  461.         digitsource.fd_addr = (long)med_digits;
  462.         fujisource.fd_addr = (long)med_fuji;
  463.         fmasksource.fd_addr = (long)medfuji_mask;
  464.         eyesource.fd_addr = (long)med_eye;
  465.         levelsource.fd_addr = (long)med_leveltext;
  466.     }
  467.     else            /* mono monitor */
  468.     {
  469.         ballsource.fd_addr = (long)monoballs;
  470.         paddlesource.fd_addr = (long)monopaddle;
  471.         bricksource.fd_addr = (long)monobricks;
  472.         twobricksource.fd_addr = (long)mono_twobrick;
  473.         permbricksource.fd_addr = (long)mono_perm_bricks;
  474.         digitsource.fd_addr = (long)mono_digits;
  475.         fujisource.fd_addr = (long)mono_fuji;
  476.         fmasksource.fd_addr = (long)monofuji_mask;
  477.         eyesource.fd_addr = (long)mono_eye;
  478.         levelsource.fd_addr = (long)mono_leveltext;
  479.  
  480.         pad_y_min = 247;
  481.         pad_y_max = 323;
  482.     }
  483.  
  484.     windsource.fd_addr = (long)warray;
  485.     pic_buf.fd_addr = (long)parray;
  486.  
  487. /*    Find the degas picture and load it in    */
  488.  
  489.     fd = Fopen(pic1 + 7,0);
  490.     if (fd <= 0) fd = Fopen(pic1,0);
  491.     if (fd <= 0) fd = Fopen(pic2 + 7,0);
  492.     if (fd <= 0) fd = Fopen(pic2,0);
  493.  
  494.     if (fd > 0) do_load(fd);
  495.     else
  496.     {    Cconws(no_picture);
  497.         wait(2);
  498.     }
  499.  
  500.  
  501.     appl_init();
  502.  
  503.     if (!_app) menu_id=menu_register(gl_apid,"  BoinkOut! ");
  504.  
  505.     phys_handle=graf_handle(&gl_wchar,&gl_hchar,&gl_wbox,&gl_hbox);
  506.  
  507.     wind_get(0, WF_WORKXYWH, &xdesk, &ydesk, &wdesk, &hdesk);
  508.     wind_calc(1,win_kind,xdesk,ydesk,wdesk,hdesk,&wx,&wy,&ww,&wh);
  509.     dw = wdesk - ww;
  510.     dh = hdesk - wh;
  511.  
  512.     xold = xdesk + (wdesk - WIDTH) / 2;
  513.     yold = ydesk + (hdesk - win_ht) / 3;
  514.     wold = WIDTH;
  515.     hold = win_ht;
  516.  
  517.     maxx = xdesk + wdesk;
  518.     maxy = ydesk + hdesk;
  519.  
  520.     path[0] = Dgetdrv() + 'A';
  521.     path[1] = ':';
  522.     Dgetpath(path+2,Dgetdrv() + 1);
  523.     strcat(path,"\\*.PI?");
  524.     strcpy(name,null);
  525.  
  526.     w_hand=NO_WINDOW;
  527.  
  528.  
  529.     if (_app)
  530.     {
  531.         open_vwork();
  532.         dial[DIALLOAD].ob_flags = (LASTOB | HIDETREE);
  533.         dial[DIALOK].ob_height = 3;
  534.  
  535.         graf_mouse( ARROW, 0L);
  536.  
  537.         convert_resource(menu);
  538.  
  539.         menu_bar(menu, 1);    /* display the menu */
  540.     }
  541.  
  542.     convert_resource(dial);
  543.  
  544.     multi();            /* accessory will not return, program will */
  545.  
  546.     Dosound(osound);    /* fix key click sound */
  547.  
  548.     menu_bar(menu, 0);    /* erase the menu bar */
  549.  
  550.     v_clsvwk(handle);    /* close the window */
  551.  
  552.     appl_exit();
  553. }
  554.  
  555.  
  556. /****************************************************************/
  557. /* dispatches all accessory tasks                */
  558. /****************************************************************/
  559. multi()
  560. {
  561.     int event, newx, newy;
  562.     int sized = FALSE, done = FALSE;
  563.  
  564. /*    If run as a program in medium or high res,     */
  565. /*    open window when first run.                    */
  566.  
  567.     if (_app && (planes == 1 || planes == 2))
  568.     {
  569.         if (open_window() < 0) return;
  570.     }
  571.  
  572.  
  573. /*    The accessory will loop forever, the program loops until    */
  574. /*    the done variable is set to TRUE.                            */
  575.  
  576.     while ((!_app) || !done)
  577.     {
  578.  
  579.         event = evnt_multi(event_kind,
  580.             1,0,0,
  581.             0,0,0,0,0,
  582.             0,0,0,0,0,
  583.             msgbuff,ttimer,0,&ret,&ret,&ret,&ret,&ret,&ret);
  584.  
  585.  
  586.         if (event & MU_MESAG) switch (msgbuff[0])
  587.         {
  588.  
  589.         case MN_SELECTED:
  590.  
  591.         /* menu functions, program only */
  592.  
  593.             switch(msgbuff[4])
  594.             {
  595.  
  596.             case ABTBOINK:    boink_dial();
  597.                     break;
  598.  
  599.             case WINDOPEN:
  600.                 if (planes != 1 && planes != 2) break;
  601.                 if (w_hand != NO_WINDOW)
  602.                 {    wind_set(w_hand,WF_TOP,0,0,0,0);
  603.                     if (lives <= 0)
  604.                     {
  605.                         new_game();
  606.                         restart_level();
  607.                         event_kind = MU_MESAG | MU_TIMER;
  608.                     }
  609.                 }
  610.                 else open_window();
  611.                 break;
  612.  
  613.             case LOADPIC:
  614.                 load_pic();
  615.                 break;
  616.  
  617.             case FAST:
  618.                 fast_mode();
  619.                 break;
  620.  
  621.             case FILEQUIT:
  622.                 if (w_hand != NO_WINDOW)
  623.                 {    wind_close(w_hand);
  624.                     wind_delete(w_hand);
  625.                 }
  626.                 done = TRUE;
  627.                 break;
  628.             }
  629.  
  630.             menu_tnormal(menu, msgbuff[3], TRUE ); /* deselect menubar */
  631.             break;
  632.  
  633.         case WM_REDRAW:
  634.             if (msgbuff[3] == w_hand)
  635.             add_region(msgbuff[4],msgbuff[5],msgbuff[6],msgbuff[7]);
  636.             do_redraw();
  637.             break;
  638.  
  639.         case WM_NEWTOP:
  640.         case WM_TOPPED:
  641.             if (msgbuff[3] == w_hand)
  642.             {    wind_set(w_hand,WF_TOP,0,0,0,0);
  643.                 timer = 0;
  644.             }
  645.             break;
  646.  
  647.         case AC_CLOSE:
  648.             if((msgbuff[3] == menu_id) && (w_hand != NO_WINDOW))
  649.             {
  650.                 wind_update(TRUE);
  651.  
  652.                 v_clsvwk(handle);
  653.  
  654.                 w_hand = NO_WINDOW;
  655.                 Dosound(osound);
  656.                 event_kind = MU_MESAG;
  657.                 wind_update(FALSE);
  658.             }
  659.             break;
  660.  
  661.         case WM_CLOSED:
  662.             if(msgbuff[3] == w_hand)
  663.             {    wind_close(w_hand);
  664.                 graf_shrinkbox(xdesk,ydesk,gl_wbox,gl_hbox,
  665.                     xold,yold,wold,hold);
  666.                 wind_delete(w_hand);
  667.  
  668.                 if (!_app) v_clsvwk(handle);
  669.  
  670.                 w_hand = NO_WINDOW;
  671.                 Dosound(osound);
  672.                 event_kind = MU_MESAG;
  673.             }
  674.             break;
  675.  
  676.         case WM_MOVED:
  677.             if(msgbuff[3] != w_hand) break;
  678.  
  679.             xold = msgbuff[4];
  680.             yold = msgbuff[5];
  681.  
  682.             wind_set(w_hand,WF_CURRXYWH,msgbuff[4],
  683.                 msgbuff[5],wold,hold);
  684.             wind_get(w_hand,WF_WORKXYWH,&xwork,&ywork,&wwork,&hwork);
  685.  
  686.             break;
  687.  
  688.         case AC_OPEN:
  689.             if (msgbuff[4] == menu_id)
  690.             {
  691.                 if (Kbshift(-1) & 2)
  692.                 {    boink_dial();
  693.                     break;
  694.                 }
  695.                 if (planes != 1 && planes != 2) break;
  696.  
  697.                 if (w_hand == NO_WINDOW)
  698.                 {    open_vwork();
  699.  
  700.                     if (open_window() < 0)
  701.                     {
  702.                         v_clsvwk(handle);
  703.                         break;
  704.                     }
  705.                 }
  706.                 else
  707.                 {    wind_set(w_hand,WF_TOP,0,0,0,0);
  708.                     if (lives <= 0)
  709.                     {
  710.                         new_game();
  711.                         restart_level();
  712.                         event_kind = MU_MESAG | MU_TIMER;
  713.                     }
  714.                 }
  715.             }
  716.             break;
  717.  
  718.         } /* switch (msgbuff[0]) */
  719.  
  720.         if (event & MU_TIMER)
  721.         {    if (w_hand != NO_WINDOW)
  722.             {
  723.                 new_ball();
  724.             }
  725.         }
  726.  
  727.     } /* while (!_app || !done) */
  728.  
  729. }
  730.  
  731. long get_time()
  732. {
  733.     return *((long *)0x4ba);
  734. }
  735.  
  736. /* output a bouncing ball sound */
  737. bsound(pitch)
  738. {    int test;
  739.  
  740.     *(sound + 13) = pitch;
  741.     Dosound(sound);
  742.  
  743.     wind_get(w_hand,WF_TOP,&test,&ret,&ret,&ret);
  744.  
  745.     if (test == w_hand) timer = 0;
  746.     else timer = 1;
  747. }
  748.  
  749.  
  750. wait(sec)
  751. {    long alarm;
  752.  
  753.     alarm = Supexec(get_time) + (200 * sec);
  754.     while (Supexec(get_time) < alarm);
  755. }
  756.  
  757.  
  758. /* put up dialog box */
  759.  
  760. boink_dial()
  761. {
  762.     int xchoice,dial_x,dial_y,dial_w,dial_h;
  763.  
  764.     form_center(dial,&dial_x,&dial_y,&dial_w,&dial_h);
  765.     wind_update(TRUE);
  766.     objc_draw(dial,0,3,dial_x,dial_y,dial_w,dial_h);
  767.     xchoice = (form_do(dial, 0) & 0x7fff);
  768.     wind_update(FALSE);
  769.     dial[xchoice].ob_state &= ~SELECTED;
  770.  
  771.     /* accessory only */
  772.     if (xchoice == DIALLOAD) load_pic();
  773.  
  774.     form_dial(FMD_FINISH,0,0,10,10,dial_x,dial_y,dial_w,dial_h);
  775. }
  776.  
  777.  
  778. /* change an object array from character coordinates to pixel coordinates */
  779.  
  780. convert_resource(p)
  781. register OBJECT *p;
  782. {    register OBJECT *p2 = p;
  783.     register int ndx = 0;
  784.  
  785.     for (;;)
  786.     {    rsrc_obfix(p,ndx);
  787.         if (p2->ob_flags & 0x20) break;
  788.         ndx++;
  789.         p2++;
  790.     }
  791. }
  792.  
  793.  
  794. /*********************************************
  795. INIT_FDB() - init screen memory form definition block.
  796. In order to blit from one rectangle (our background picture)
  797. to another (the screen) we need to to give gem a memory form
  798. definition block for each rectangle. This structure describes the
  799. location of the rectangle, its width, height, and number of bit
  800. planes. For the background picture, the parameters are hard wired
  801. to the size of a Degas picture. We must ask gem to tell us the screen
  802. parameters so that the program will work on any monitor including
  803. large screen monitors.
  804. *********************************************/
  805. init_fdb()
  806. {
  807.     register MFDB *fdbp = &screen_fdb;
  808.     register int temp;
  809.  
  810.     fdbp->fd_addr    = Logbase();
  811.     fdbp->fd_w        = work_out[0] + 1;
  812.     fdbp->fd_h        = work_out[1] + 1;
  813.     fdbp->fd_wdwidth= fdbp->fd_w/16;
  814.     fdbp->fd_stand    = 0;
  815.  
  816.     switch(work_out[13])
  817.     {
  818.         case 16: temp = 4; break;
  819.         case 08: temp = 3; break;
  820.         case 04: temp = 2; break;
  821.         default: temp = 1; break;
  822.     }
  823.     fdbp->fd_nplanes = temp;
  824. }
  825.  
  826.  
  827. /* Allow the user access to a Gem file selector to pick a new */
  828. /* background picture */
  829.  
  830. load_pic()
  831. {    register int i, fd;
  832.     int button;
  833.     char complete[80];
  834.  
  835.     wind_update(TRUE);
  836.     fsel_input(path,name,&button);
  837.     if (!button) goto end;
  838.  
  839.     i = strlen(path) - 1;
  840.     while (i > 0 && (path[i] != '\\') && (path[i] != ':'))
  841.         i--;
  842.     strcpy(complete,path);
  843.     strcpy(&complete[i+1],name);
  844.  
  845.     fd = Fopen(complete,0);
  846.     if (fd <= 0) goto end;
  847.  
  848.     do_load(fd);
  849.  
  850.     if (w_hand != NO_WINDOW)
  851.     {
  852.         if (lives <= 0) new_game();
  853.         restart_level();
  854.         event_kind = MU_MESAG | MU_TIMER;
  855.     }
  856.  
  857. end:
  858.     wind_update(FALSE);
  859. }
  860.  
  861.  
  862. /* Handy C string functions */
  863.  
  864. strlen(a)
  865. register char *a;
  866. {    register int n = 0;
  867.     while (*a++) n++;
  868.     return n;
  869. }
  870.  
  871. strcpy(a,b)
  872. register char *a, *b;
  873. {    while (*a++ = *b++);
  874. }
  875.  
  876. strcat(a,b)
  877. register char *a, *b;
  878. {    while (*a) a++;
  879.     while (*a++ = *b++);
  880. }
  881.  
  882. bncpy(a,b,n)
  883. register char *a, *b;
  884. register int n;
  885. {    while (n--) *a++ = *b++;
  886. }
  887.  
  888. restart_level()
  889. {
  890.     register BALL_STRUCT *p;
  891.     register int x, y, image, ndx;
  892.     int i, ltemp = level % LEVELS;
  893.  
  894.     if (w_hand == NO_WINDOW) return;
  895.  
  896.     magic_bottom = 0;
  897.     score = old_score;
  898.     lives = old_lives;
  899.     bonus_life = old_bonus;
  900.     invis = FALSE;
  901.  
  902.     clear_areas();
  903.  
  904.     num_bricks = 0;
  905.     bncpy(warray,parray,20272);
  906.  
  907.     show_lives();
  908.     show_level();
  909.     show_score();
  910.  
  911.     brickarray[1] = 0;
  912.     brickarray[3] = bh-1;
  913.  
  914.     ndx = 0;
  915.     for (y=0; y<7; y++)
  916.     {
  917.         for (x=0; x < 9; x++)
  918.         {
  919.             brickarray[0] = 0;
  920.             brickarray[2] = 43;
  921.             brickarray[4] = bleft + x * btw;
  922.             brickarray[5] = btop + y * bth;
  923.             brickarray[6] = brickarray[4] + 43;
  924.             brickarray[7] = brickarray[5] + bh - 1;
  925.  
  926.             switch(brickmask[ltemp][ndx])
  927.             {
  928.                 case -1:        /* permanent */
  929.                     vro_cpyfm(handle,3,brickarray,&permbricksource,&windsource);
  930.                     break;
  931.  
  932.                 case 1:            /* normal */
  933.                     num_bricks++;
  934.                     break;
  935.  
  936.                 case 2:            /* magic */
  937.                     vro_cpyfm(handle,4,brickarray,&bricksource,&windsource);
  938.                     vro_cpyfm(handle,7,brickarray,&twobricksource,&windsource);
  939.                     num_bricks++;
  940.                     break;
  941.  
  942.                 case 3:
  943.                 case 4:
  944.                 case 5:
  945.                 case 6:
  946.                     num_bricks++;
  947.                     break;
  948.             }
  949.             ndx++;
  950.         }
  951.     }
  952.  
  953.     n_redraws = 0;
  954.     add_region(xwork,ywork,wwork,hwork);
  955.     do_redraw();
  956.  
  957.     evnt_timer(150,0);
  958.     Dosound(appear);
  959.     evnt_timer(250,0);
  960.  
  961.     for (image = 3; image >= 0; image--)
  962.     {
  963.         ndx = 0;
  964.         brickarray[0] = image * btw;
  965.         brickarray[2] = brickarray[0] + btw - 1;
  966.  
  967.         for (y=0; y<7; y++)
  968.         {
  969.             for (x=0; x < 9; x++)
  970.             {
  971.                 brickarray[4] = bleft + x * btw;
  972.                 brickarray[5] = btop + y * bth;
  973.                 brickarray[6] = brickarray[4] + btw - 1;
  974.                 brickarray[7] = brickarray[5] + bh - 1;
  975.  
  976.                 switch(brickmask[ltemp][ndx++])
  977.                 {
  978.                     case 1:
  979.                         vro_cpyfm(handle,7,brickarray,&bricksource,&windsource);
  980.                         break;
  981.                 case 3:
  982.                 case 4:
  983.                 case 5:
  984.                 case 6:
  985.                     if (image > 0) vro_cpyfm(handle,7,
  986.                         brickarray,&twobricksource,&windsource);
  987.                     break;
  988.                 }
  989.             }
  990.         }
  991.         add_region(xwork,ywork,wwork,hwork);
  992.         do_redraw();
  993.     }
  994.     evnt_timer(500,0);
  995.  
  996.     ani_count = 0;
  997.     paddle_x = 0;
  998.     paddle_y = pad_y_max;
  999.     paddlearray[4] = 0;
  1000.     paddlearray[5] = pad_y_max;
  1001.     paddlearray[6] = 52;
  1002.     paddlearray[7] = paddlearray[5] + pad_ht - 1;
  1003.  
  1004.     num_balls = 0;
  1005.  
  1006.     if (cheat)
  1007.     {
  1008.         for (x=0; x<3; x++)
  1009.             add_ball(0,pad_y_min - ball_ht,max_xspeed-x,-min_yspeed, TRUE);
  1010.     }
  1011.     else add_ball(0,pad_y_min - ball_ht,2,2, FALSE);
  1012.  
  1013.     mode = BNORMAL;
  1014.  
  1015.     for (x=0; x < 63; x++) brickcount[x] = brickmask[ltemp][x];
  1016. }
  1017.  
  1018. add_region(x,y,w,h)
  1019. {
  1020.     register RECT *p;
  1021.  
  1022.     /* this should never happen... */
  1023.     if (n_redraws >= MAX_ANI) return;
  1024.  
  1025.     p = ®ion[n_redraws];
  1026.     p->x = x;
  1027.     p->y = y;
  1028.     p->w = w;
  1029.     p->h = h;
  1030.     n_redraws++;
  1031. }
  1032.  
  1033. new_game()
  1034. {
  1035.     lives = old_lives = 3;
  1036.     score = old_score = 0;
  1037.     bonus_life = old_bonus = BONUS;
  1038.     pad_y_top = pad_y_min;
  1039.     level = 0;
  1040. }
  1041.  
  1042. clear(x,y,w,h)
  1043. {
  1044.     int arr[8];
  1045.  
  1046.     arr[0] = arr[1] = 0;
  1047.     arr[2] = w;
  1048.     arr[3] = h;
  1049.     arr[4] = x;
  1050.     arr[5] = y;
  1051.     arr[6] = x + w - 1;
  1052.     arr[7] = y + h - 1;
  1053.  
  1054.     vro_cpyfm(handle,0,arr,&pic_buf,&pic_buf);
  1055. }
  1056.