home *** CD-ROM | disk | FTP | other *** search
/ Crawly Crypt Collection 2 / crawlyvol2.bin / program / c / gemtris / gemtris.c < prev    next >
C/C++ Source or Header  |  1991-10-22  |  22KB  |  922 lines

  1. /* gemtris.c vom 21.10.91, 12:12 */
  2. /*                                */
  3. /*    Einige Fehler behoben        */
  4. /*                                */
  5. /*    HJ    22.09.91                */
  6.  
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <string.h>
  10. #include <vdi.h>
  11. #include <aes.h> 
  12. #include <tos.h>
  13. #include <time.h>
  14. #include <scancode.h>
  15. #include "gemtrrsc.h"
  16. #include "gemtrrsc.rsh"
  17.  
  18. int imin(int a, int b)
  19. {
  20.     return((a<b) ? a : b);    
  21. }
  22.  
  23. int imax(int a, int b)
  24. {
  25.     return((a>b) ? a : b);    
  26. }
  27.  
  28. int lmin(long a, long b)
  29. {
  30.     return((a<b) ? (int)a : (int)b);    
  31. }
  32.  
  33. int lmax(long a, long b)
  34. {
  35.     return((a>b) ? (int)a : (int)b);    
  36. }
  37.  
  38. extern int _app;
  39.  
  40. /* Fuer v_openvwk() */
  41. int work_in[12],
  42.     work_out[57]; /* enthaelt Infos ueber Bildschirm */
  43.     
  44. /* handle ist der fuer VDI-Aufrufe noetige Handle */
  45. int    handle,phys_handle;
  46.  
  47. /* Soll Hoehe und Breite von Buchstaben enthalten */
  48. int gl_hchar,gl_wchar,gl_hbox,gl_wbox;
  49.  
  50. /* Nummer der Applikation, z.B. um ein Accessory anzumelden */
  51. int gl_apid;
  52.  
  53. /* xy-Array */
  54. int pxyarr[4];
  55.  
  56. OBJECT *menu_tree; /* Enthaelt Resource-Adresse des Menues */
  57. int wi_handle; /* Handle des Fensters */
  58. int wi_x=0, wi_y=0;
  59. char wi_qname[]=" GEMtris+ ";
  60. char wi_sname[]=" GEMtris- ";
  61. char wi_name[40]="";
  62. char wi_info[40]="";
  63. int xdesk,ydesk,wdesk,hdesk; /* Groesse des gesamten 
  64.                                 Arbeitsbereiches */
  65.  
  66. /* Problemabhaengige Variablen */
  67. #define ELEMENTS (NAME|FULLER|MOVER|INFO)
  68. int xw,yw,hw,ww,xstein,ystein,hstein,wstein;
  69. int steinsize=8;
  70. int sit[18][28];    /* aktuelle Situation plus zwei Randfelder */
  71. int back[18][28];    /* aktuelle Situation ohne fallenden Stein */
  72. int st[4][4];    /* fallender Stein */
  73. int st1[4][4];
  74. int fig[7][4][4]=
  75.     {0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,
  76.      0,0,0,0,0,2,2,2,0,2,0,0,0,0,0,0,
  77.      0,0,0,0,3,3,3,0,0,0,3,0,0,0,0,0,
  78.      0,0,0,0,0,4,4,4,0,0,4,0,0,0,0,0,
  79.      0,0,0,0,0,0,5,5,0,5,5,0,0,0,0,0,
  80.      0,0,0,0,0,6,6,0,0,0,6,6,0,0,0,0,
  81.      0,0,0,0,0,7,7,0,0,7,7,0,0,0,0,0}
  82.      ;    /* moegliche Steine */
  83. int is,js;    /* Position des fallenden Steines */
  84. long delay,maxdelay=100,mindelay=0,speed;
  85. int ende;
  86. long punkte=0L,reihen=0L;
  87. #define MAXPUNKTE 99999999L
  88. #define MAXREIHEN 99999L
  89. char *scr_adr,*phys_adr;
  90. long scr_size;
  91. MFDB mfdb1,mfdb2;
  92. typedef char STRING[32]; 
  93. STRING namen[2][10];  /* Namen in Highscore */
  94. long score[2][10];
  95. unsigned char old_tast;
  96. int old_rate;
  97. int rep_rate=5,start_rep=5,t_faktor;
  98. int moved;  /* Stein zuletzt bewegt? */
  99. clock_t timer;
  100.  
  101. int open_vwork(void)
  102. /* Oeffnet den Bildschirm als Arbeitsstation */
  103. {    register int i;
  104.     if ((gl_apid=appl_init()) != -1)
  105.     {    for (i=1; i<10; work_in[i++]=1);
  106.         work_in[10]=2; /* Benutze Pixel-Koordinaten */
  107.         phys_handle=graf_handle(&gl_wchar,&gl_hchar,&gl_wbox,&gl_hbox);
  108.         work_in[0]=handle=phys_handle;
  109.         v_opnvwk(work_in,&handle,work_out);
  110.         if (handle > 0) return 1; /* Erfolg! */
  111.     }
  112.     return 0;
  113. }
  114.  
  115. int close_vwork(void)
  116. /* Schliesst Bildschirm als Arbeitsstation und meldet Applikation 
  117.     ab */
  118. {    v_clsvwk(handle);
  119.     if (appl_exit()==0) return 1;
  120.     return 0;
  121. }
  122.  
  123. void keyclr(void)
  124. /*    terminiert erst dann, wenn keine Taste mehr gedrückt ist */
  125. {
  126. unsigned int ev;
  127. int eb, ek, d;
  128. unsigned long delay;
  129.  
  130.     wind_update(BEG_UPDATE);
  131.     wind_update(BEG_MCTRL);
  132.     delay= Kbrate(-1, -1);
  133.     ek= (int)(delay & 0xff);
  134.     eb= (int)((delay>>8) & 0xff);
  135.     delay= imax(eb, ek);
  136.     delay= (delay*Tickcal()) + 10L;
  137.     do
  138.     {
  139.         evnt_timer(0, 0);
  140.         ev= evnt_multi(MU_KEYBD|MU_TIMER,
  141.             0, 0, 0,
  142.             0, 0,0,0,0,
  143.             0, 0,0,0,0,
  144.             NULL,
  145.             (int)(delay & 0xffff), (int)(delay>>16),
  146.             &d, &d, &eb, &ek, &d, &d);
  147.     } while ((ev & MU_KEYBD) || eb || ek);
  148.     wind_update(END_MCTRL);
  149.     wind_update(END_UPDATE);
  150. }
  151.  
  152. void kbufclr(void)
  153. /*    liest den Tastaturpuffer leer. */
  154. {
  155.     int evres, d;
  156.     wind_update(BEG_UPDATE);
  157.     wind_update(BEG_MCTRL);
  158.     evnt_timer(0, 0);
  159.     do
  160.     {
  161.         evres= evnt_multi(MU_KEYBD|MU_TIMER,
  162.                 0, 0, 0,
  163.                 0, 0,0,0,0,
  164.                 0, 0,0,0,0,
  165.                 NULL,
  166.                 0, 0,
  167.                 &d, &d, &d, &d, &d, &d);
  168.     } while (evres & MU_KEYBD);
  169.     wind_update(END_MCTRL);
  170.     wind_update(END_UPDATE);
  171. }
  172.  
  173. int dialog(int tree, int start)
  174. /* Dies ist ein einfaches Dialogprogramm, das ein Formular aufbaut,
  175.     zentriert, zeichnet, bearbeitet und wieder loescht */
  176. {    OBJECT *tree_addr;
  177.     int x,y,w,h,ret;
  178.     if (rsrc_gaddr(R_TREE,tree,&tree_addr)==0) return 0;
  179.     wind_update(BEG_UPDATE);
  180.     form_center(tree_addr,&x,&y,&w,&h);
  181.     form_dial(FMD_START,0,0,0,0,x,y,w,h);
  182.     form_dial(FMD_GROW,0,0,0,0,x,y,w,h); /* kann entfernt werden */
  183.     objc_draw(tree_addr,0,25,x,y,w,h);
  184.     keyclr();
  185.     ret=form_do(tree_addr,start) & 0xff;
  186.     keyclr();
  187.     tree_addr[ret].ob_state &= ~SELECTED; /* Exit-Object wieder auf
  188.             nicht selektiert umstellen */
  189.     form_dial(FMD_SHRINK,0,0,0,0,x,y,w,h); /* kann entfernt werden */
  190.     form_dial(FMD_FINISH,0,0,0,0,x,y,w,h);
  191.     wind_update(END_UPDATE);
  192.     return ret; /* Der Knopf mit dem das Formular verlassen wurde */
  193. }
  194.  
  195. void redraw_all(void)
  196. {    form_dial(FMD_FINISH,0,0,0,0,xdesk,ydesk,wdesk,hdesk);
  197. }
  198.  
  199. void show_info(void)
  200. /* Ruft die Programminformation auf, in die vorher das Erstellungs-
  201.     datum eingetragen wurde */
  202. {    OBJECT *info;
  203.     if (rsrc_gaddr(R_TREE,INFOF,&info)==0) return;
  204.     info[INFOVERS].ob_spec.free_string=__DATE__;
  205.     dialog(INFOF,0); /* Exit-Button interessiert nicht */
  206. }
  207.  
  208. void nowind_msg(void)
  209. {
  210.     wind_update(BEG_UPDATE);
  211.     form_alert(1, rs_frstr[WINDERR]);
  212.     wind_update(END_UPDATE);
  213. }
  214.  
  215. void size_window(void)
  216. {    int w,h;
  217.     wind_calc(1,ELEMENTS,xdesk,ydesk,wdesk,hdesk,&xw,&yw,&ww,&hw);
  218.     hw=imin(hw/20,steinsize)*20;
  219.     w=(((hw/20)*work_out[4])/work_out[3]+1)*10;
  220.     if (w>ww) ww=(ww/20)*20; 
  221.     else ww=w;
  222.     hstein=hw/20; wstein=ww/10;
  223.     wind_calc(0,ELEMENTS,xw,yw,ww,hw,&xw,&yw,&ww,&hw);
  224.     xw=imin(wi_x+ww,xdesk+wdesk)-ww;
  225.     yw=imin(wi_y+hw,ydesk+hdesk)-hw;
  226.     xw=(imax(xw,xdesk)+15) & ~15;
  227.     yw=imax(yw,ydesk);
  228.     wind_calc(1,ELEMENTS,xw,yw,ww,hw,&xstein,&ystein,&h,&w);
  229. }
  230.  
  231. int open_window(void)
  232. /* Oeffnet ein Fenster in maximaler Groesse, wenn noch nicht offen */
  233. {    if (wi_handle>0)
  234.     {    /* Fenster bereits offen */
  235.         wind_set(wi_handle,WF_TOP,wi_handle);
  236.         return 0;
  237.     }
  238.     wind_get(0,WF_WORKXYWH,&xdesk,&ydesk,&wdesk,&hdesk);
  239.     if ((wi_handle=wind_create(ELEMENTS,xdesk,ydesk,wdesk,hdesk))<=0)
  240.     { nowind_msg(); return 1;}
  241.     size_window() ;
  242.     wind_set(wi_handle,WF_NAME,wi_name);
  243.     wind_set(wi_handle,WF_INFO,wi_info);
  244.     wind_open(wi_handle,xw,yw,ww,hw); /* Oeffne Fenster */
  245.     pxyarr[0]=xdesk; pxyarr[1]=ydesk;
  246.     pxyarr[2]=xdesk+wdesk-1; pxyarr[3]=ydesk+hdesk-1;
  247.     vs_clip(handle,1,pxyarr);
  248.     return 0;
  249. }
  250.  
  251. void move_window(int hndl, int x, int y, int w, int h)
  252. /* Fenster verschieben */
  253. {    if ((hndl == wi_handle) && (wi_handle > 0))
  254.     {
  255.         x=imin(x+w,xdesk+wdesk)-w;
  256.         y=imin(y+h,ydesk+hdesk)-h;
  257.         x=(imax(x,xdesk)+15) & ~15;
  258.         y=imax(y,ydesk);
  259.         wind_set(wi_handle,WF_CURRXYWH,x,y,w,h);
  260.         wi_x=x;
  261.         wi_y=y;
  262.         wind_get(wi_handle,WF_WORKXYWH,&x,&y,&w,&h);
  263.         xstein=x;
  264.         ystein=y;
  265.     }
  266. }
  267.  
  268. void close_window(void)
  269. /* Schliesst Fenster und meldet es ab */
  270. {    if (wi_handle > 0)
  271.     {
  272.         wind_close(wi_handle); /* Schliessen */
  273.         wind_delete(wi_handle); /* Abmelden */
  274.         wi_handle=-1;
  275.     }
  276. }
  277.  
  278. void stein_size(int wh)
  279. {
  280.     if ((wh==wi_handle)&&(wi_handle>0))
  281.     {    if (steinsize<8) steinsize=8; else steinsize++;
  282.         size_window();
  283.         wind_set(wi_handle,WF_CURRXYWH,xw,yw,ww,hw);
  284.         form_dial(FMD_FINISH,xw,yw,ww,hw,xw,yw,ww,hw);
  285.         if (hstein<steinsize) steinsize=8;
  286.     }
  287. }
  288.  
  289. int rc_intersect(int x, int y, int w, int h,
  290.     int *x1, int *y1, int *w1, int *h1)
  291. /* Unterprogramm, das den Schnitt zweier Rechtecke ausrechnet */
  292. {    int x2,y2;
  293.     x2=imax(x,*x1);
  294.     y2=imax(y,*y1);
  295.     *w1=imin(x+w,*x1+*w1)-x2;
  296.     *h1=imin(y+h,*y1+*h1)-y2;
  297.     *x1=x2; *y1=y2;
  298.     return ((*w1>0)&&(*h1>0));
  299. }
  300.  
  301. void stein(int i,int j,int pattern)
  302. {    int box[4];
  303.     if (wi_handle <= 0) return;
  304.     box[0]=(i-4)*wstein+xstein;
  305.     box[1]=(j-4)*hstein+ystein;
  306.     box[2]=box[0]+wstein-1;
  307.     box[3]=box[1]+hstein-1;
  308.     vsf_perimeter(handle,1);
  309.     vsf_color(handle,1);
  310.     vsf_interior(handle,2);
  311.     vsf_style(handle,pattern);
  312.     v_bar(handle,box);
  313. }
  314.  
  315. void leer(int i,int j)
  316. {    int box[4];
  317.     if (wi_handle <= 0)    return;
  318.     box[0]=(i-4)*wstein+xstein;
  319.     box[1]=(j-4)*hstein+ystein;
  320.     box[2]=box[0]+wstein-1;
  321.     box[3]=box[1]+hstein-1;
  322.     vsf_color(handle,0);
  323.     vsf_interior(handle,1);
  324.     v_bar(handle,box);
  325. }
  326.  
  327. void draw_punkte(void)
  328. {    if (wi_handle<=0) return;
  329.     strcpy(wi_info,"  ");
  330.     ltoa(reihen,&(wi_info[strlen(wi_info)]),10);
  331.     strcat(wi_info," : ");
  332.     ltoa(punkte,&(wi_info[strlen(wi_info)]),10);
  333.     wind_set(wi_handle,WF_INFO,wi_info);
  334. }
  335.  
  336. void redraw(void)
  337. /* Neuzeichnung eines Fensters */
  338. {    int i,j;
  339.     for (i=4; i<14; i++)
  340.       for (j=4; j<24; j++)
  341.         if (back[i][j]) 
  342.             stein(i,j,back[i][j]);
  343.         else
  344.             leer(i,j);
  345. }
  346.  
  347. void top_redraw(void)
  348. /* zeichnet Top-Fenster neu */
  349. {    int w;
  350.     wind_update(BEG_UPDATE);
  351.     wind_get(0,WF_TOP,&w);
  352.     if ((w==wi_handle) && (wi_handle>0))
  353.     {
  354.         graf_mouse(M_OFF,NULL);
  355.         redraw();
  356.         graf_mouse(M_ON,NULL);
  357.     }
  358.     wind_update(END_UPDATE);
  359. }
  360.  
  361. void do_redraw(int whandle, int x, int y, int w, int h)
  362. /* Uebernimmt allgemein das Neuzeichnen von Fenstern. Ruft daher
  363. redraw auf. Die Fenster werden in Teilrechtecken neu gezeichnet. */
  364. {    int x1,y1,w1,h1;
  365.     if (whandle!=wi_handle) return;
  366.     wind_update(BEG_UPDATE); /* Sperre Bildschirmzugriff fuer GEM */
  367.     graf_mouse(M_OFF,0);
  368.     wind_get(whandle,WF_FIRSTXYWH,&x1,&y1,&w1,&h1);
  369.         /* erstes neu zu zeichnendes Rechteck */
  370.     while((w1>0)&&(h1>0))
  371.     {    if (rc_intersect(x,y,w,h,&x1,&y1,&w1,&h1))
  372.         {    pxyarr[0]=x1; pxyarr[1]=y1;
  373.             pxyarr[2]=w1+x1-1; pxyarr[3]=h1+y1-1;
  374.             vs_clip(handle,1,pxyarr);
  375.             redraw(); /* Zeichne neu */
  376.         }
  377.         wind_get(whandle,WF_NEXTXYWH,&x1,&y1,&w1,&h1);
  378.             /* Naechstes Rechteck */
  379.     }
  380.     pxyarr[0]=xdesk; pxyarr[1]=ydesk;
  381.     pxyarr[2]=xdesk+wdesk-1; pxyarr[3]=ydesk+hdesk-1;
  382.     vs_clip(handle,1,pxyarr);
  383.     graf_mouse(M_ON,0);
  384.     wind_update(END_UPDATE); /* Gib GEM wieder frei! */
  385. }
  386.  
  387. void select_stone(void)
  388. /* Waehlt einen der Steine per Zufall aus */
  389. {
  390. int i,j;
  391. int n = (int)(Random()%7);
  392.  
  393.     for (i=0; i<4; i++) 
  394.         for (j=0; j<4; j++)
  395.             st[j][i]=fig[n][i][j];
  396.     is=6; js=2;    /* Anfangsstellung */
  397. }
  398.  
  399. void turn_stone(void)
  400. /* dreht Stein */
  401. {    int i,j,h;
  402.     for (i=0; i<4; i++)
  403.         for (j=0; j<4; j++) st1[i][j]=st[i][j];
  404.     h=st[0][0]; st[0][0]=st[3][0]; st[3][0]=st[3][3]; 
  405.     st[3][3]=st[0][3]; st[0][3]=h;
  406.     h=st[0][1]; st[0][1]=st[2][0]; st[2][0]=st[3][2]; 
  407.     st[3][2]=st[1][3]; st[1][3]=h;
  408.     h=st[0][2]; st[0][2]=st[1][0]; st[1][0]=st[3][1]; 
  409.     st[3][1]=st[2][3]; st[2][3]=h;
  410.     h=st[1][1]; st[1][1]=st[2][1]; st[2][1]=st[2][2]; 
  411.     st[2][2]=st[1][2]; st[1][2]=h;
  412. }
  413.  
  414. void turn_back(void)
  415. {    int i,j;
  416.     for (i=0; i<4; i++)
  417.         for (j=0; j<4; j++) st[i][j]=st1[i][j];
  418. }
  419.  
  420. int try_stone(void)
  421. /* versucht, ob der Stein an die Stelle (is,js) passt */
  422. {    int i,j;
  423.     for (i=0; i<4; i++)
  424.         for (j=0; j<4; j++)
  425.             if ((st[i][j]!=0)&&(back[is+i][js+j]!=0)) return 0;
  426.     return 1;
  427. }
  428.  
  429. void waitfor(long del)
  430. {    long t=clock();
  431.     if (del>0) while (clock()<(t+del)) ;
  432. }
  433.  
  434. void do_moveredraw(int whandle,int xd,int yd,int wd,int hd)
  435. {    int x,y,w,h,i,j;
  436.     wind_update(BEG_UPDATE);
  437.     if ((whandle==wi_handle)&&(wi_handle>0))
  438.     {    graf_mouse(M_OFF,0);
  439.         wind_get(wi_handle,WF_FIRSTXYWH,&x,&y,&w,&h);
  440.         while((w>0)&&(h>0))
  441.         {    if (rc_intersect(xd,yd,wd,hd,&x,&y,&w,&h))
  442.             {    pxyarr[0]=x; pxyarr[1]=y;
  443.                 pxyarr[2]=w+x-1; pxyarr[3]=h+y-1;
  444.                 vs_clip(handle,1,pxyarr);
  445.                 
  446.                 for (i=4; i<14; i++)
  447.                     for (j=4; j<24; j++)
  448.                         if (sit[i][j]) stein(i,j,sit[i][j]);
  449.                         else leer(i,j);
  450.             }
  451.             wind_get(wi_handle,WF_NEXTXYWH,&x,&y,&w,&h);
  452.         }
  453.         pxyarr[0]=xdesk; pxyarr[1]=ydesk;
  454.         pxyarr[2]=xdesk+wdesk-1; pxyarr[3]=ydesk+hdesk-1;
  455.         vs_clip(handle,1,pxyarr);
  456.         graf_mouse(M_ON,0);
  457.     }
  458.     wind_update(END_UPDATE);
  459. }
  460.  
  461. int move_stone(void)
  462. /* versucht, Stein zu bewegen. */
  463. {    int b[18][28],i,j,down,pause,taste,msgbuf[8];
  464.  
  465.     /* Mache Backup von Stellung mit fallendem Stein */
  466.     for (i=4; i<14; i++)
  467.         for (j=4; j<24; j++)
  468.             b[i][j]=sit[i][j];
  469.     moved=0;
  470.     pause=0;
  471.     do
  472.     {    j=evnt_multi(MU_KEYBD|MU_MESAG|MU_TIMER,
  473.                 1,1,1,
  474.                 0,0,0,0,0,
  475.                 0,0,0,0,0,
  476.                 msgbuf,
  477.                 0,0,
  478.                 &i,&i,&i,&i,&taste,&i);
  479.         if (j & MU_MESAG)
  480.         {
  481.             switch(msgbuf[0])
  482.             { case AC_CLOSE : wi_handle=-1; ende=-1; break;
  483.               case MN_SELECTED : /* Menue angewaehlt */
  484.                     menu_tnormal(menu_tree,msgbuf[3],1);
  485.                     break;
  486.               case WM_REDRAW :
  487.                       do_moveredraw(msgbuf[3],msgbuf[4],msgbuf[5],
  488.                           msgbuf[6],msgbuf[7]); break;
  489.                       /* Fenster neu zu zeichnen */
  490.               case WM_TOPPED :
  491.                       wind_set(msgbuf[3],WF_TOP,msgbuf[3]);
  492.                       break;
  493.               case WM_MOVED  : move_window(msgbuf[3],
  494.                       msgbuf[4],msgbuf[5],msgbuf[6],msgbuf[7]);
  495.                       break;
  496.               case WM_FULLED : stein_size(msgbuf[3]); break;
  497.             }
  498.         }
  499.         wind_get(0,WF_TOP,&i);
  500.         if (! ((i == wi_handle) || (wi_handle <= 0)))
  501.         {    if (! pause)
  502.             {    pause=1;
  503.                 if (wi_handle>0)
  504.                 {    wind_set(wi_handle,WF_INFO," ..."); }
  505.             }
  506.         }
  507.         else
  508.         {    if (pause)
  509.             {    pause=0;
  510.                 if (wi_handle>0)
  511.                 {    wind_set(wi_handle,WF_INFO,wi_info);
  512.                     timer=clock(); }
  513.             }
  514.         }
  515.     } while (pause);
  516.     if (ende<0) return 0;
  517.     if (j & MU_KEYBD)
  518.     {    switch (taste>>8)
  519.         {    case 0x4d : taste='6'; break;
  520.             case 0x4b : taste='4' ; break;
  521.             case 0x50 : taste='5' ; break;
  522.             case 0x48 : taste='2' ; break;
  523.         }
  524.         switch (taste&0xFF)
  525.         {    case '6' : js++; down=try_stone(); js--;
  526.                 is++; if (!try_stone()) is--;
  527.                     else moved=1;
  528.                 if (!down) goto nofall;
  529.                 break;
  530.             case '4' : js++; down=try_stone(); js--;
  531.                 is--; if (!try_stone()) is++;
  532.                     else moved=1; 
  533.                 if (!down) goto nofall;
  534.                 break;
  535.             case '5' : turn_stone(); 
  536.                 if (!try_stone()) turn_back();
  537.                     else moved=1; 
  538.                 break;
  539.             case ' ' :
  540.             case '2' :
  541.                 do { js++; punkte=lmin(punkte+2,MAXPUNKTE); }
  542.                     while (try_stone()) ;
  543.                 js--; punkte-=2; break;
  544.             case 27 :
  545.                 wind_update(BEG_UPDATE);
  546.                 ende|=(form_alert(2, rs_frstr[PAUSE])==2);
  547.                 wind_update(END_UPDATE);
  548.                 break;
  549.         }
  550.         /* Tastenpuffer löschen */
  551.         kbufclr();
  552.     }
  553.     /* Versuche Fall */
  554.     if (clock()>timer+delay)
  555.     {    js++; 
  556.         if (!try_stone()) js--; 
  557.         else {    moved=1;
  558.                 punkte=lmin(punkte+1,MAXPUNKTE);
  559.                 timer=clock(); }
  560.     }
  561.     else moved=1;
  562. nofall:
  563.     /* Enferne fallenden Stein */
  564.     for (i=0; i<18; i++)
  565.         for (j=0; j<28; j++)
  566.             sit[i][j]=back[i][j];
  567.     /* Setze ihn an neue Position */
  568.     for (i=0; i<4; i++)
  569.         for (j=0; j<4; j++)
  570.             if (st[i][j]) sit[is+i][js+j]=st[i][j];
  571.     
  572.     /* Zeichne geaenderte Felder */
  573.     wind_update(BEG_UPDATE);
  574.     wind_get(0,WF_TOP,&i);
  575.     if ((i==wi_handle) && (wi_handle>0))
  576.     {    graf_mouse(M_OFF,NULL);
  577.         for (i=4; i<14; i++)
  578.             for (j=4; j<24; j++)
  579.                 if (b[i][j]!=sit[i][j])
  580.                 {
  581.                     if (sit[i][j])
  582.                         stein(i,j,sit[i][j]);
  583.                     else
  584.                         leer(i,j);
  585.                 }
  586.         graf_mouse(M_ON,NULL);
  587.     }
  588.     else
  589.     {    /* Fenster nicht TOP */
  590.         do_moveredraw(wi_handle,xdesk,ydesk,wdesk,hdesk);
  591.     }
  592.     wind_update(END_UPDATE);
  593.     return moved;
  594. }
  595.  
  596. void empty_board(void)
  597. {    int i,j;
  598.     for (i=0; i<18; i++)
  599.         for (j=0; j<28; j++)
  600.             back[i][j]=((i<4)||(i>=14)||(j>=24));
  601. }
  602.  
  603. void wait(void)
  604. {    long t=clock();
  605.     while (clock()<(t+delay)) ;
  606. }
  607.  
  608. long remove_voll(void)
  609. /* Entfernt volle Reihen */
  610. {    int i,j,k,voll,voll1=0;
  611.     long erg;
  612.     erg=0L;
  613.     for (j=4; j<24; j++)
  614.     {    voll=1;
  615.         for (i=4; i<14; i++)
  616.             if (!back[i][j]) { voll=0; break; }
  617.         if (voll)
  618.         {    for (k=j; k>=4; k--)
  619.                 for (i=4; i<14; i++) back[i][k]=back[i][k-1];
  620.             voll1=1; erg++;
  621.             wait();
  622.         }
  623.     }
  624.     if (voll1) top_redraw();
  625.     return(erg);
  626. }
  627.  
  628. void best(void)
  629. {    OBJECT *o;
  630.     int i,j;
  631.     static STRING name="???";
  632.     static STRING sc[10];
  633.     if (rsrc_gaddr(R_TREE,BESTF,&o)==0) return;
  634.     o[BNAME].ob_spec.tedinfo->te_ptext=name;
  635.     o[BNAME].ob_spec.tedinfo->te_txtlen=16;
  636.     if (speed)
  637.     {    o[BQUICK].ob_flags&= ~HIDETREE; o[BSLOW].ob_flags|= HIDETREE; }
  638.     else
  639.     {    o[BSLOW].ob_flags&= ~HIDETREE; o[BQUICK].ob_flags|= HIDETREE; }
  640.     /* Setze Highscores ein */
  641.     for (i=0; i<10; i++)
  642.     {    o[B1+i].ob_spec.tedinfo->te_ptext=namen[speed][i];
  643.         o[B1+i].ob_spec.tedinfo->te_txtlen=16;
  644.         ltoa(score[speed][i],sc[i],10);
  645.         o[S1+i].ob_spec.tedinfo->te_ptext=sc[i];
  646.         o[S1+i].ob_spec.tedinfo->te_txtlen=8;
  647.     }
  648.     dialog(BESTF,0);
  649.     i=0; while ((i<10)&&(score[speed][i]>=punkte)) i++;
  650.     if (i<10)
  651.     {    for (j=9; j>i; j--) 
  652.         {    score[speed][j]=score[speed][j-1];
  653.             memcpy(namen[speed][j],namen[speed][j-1],32);
  654.         }
  655.         score[speed][i]=punkte;
  656.         memcpy(namen[speed][i],name,32);
  657.     }
  658. }
  659.  
  660. void play(void)
  661. {    int i,j;
  662.     wind_get(0,WF_TOP,&i);
  663.     if ((i != wi_handle) || (wi_handle <= 0)) return;
  664.     empty_board();
  665.     delay=maxdelay; punkte=0L; reihen=0L;
  666.     keyclr();
  667.     top_redraw();
  668.     draw_punkte();
  669.     ende=0;
  670.     while (1)
  671.     {    select_stone();
  672.         timer=clock();
  673.         if (!try_stone()) break;
  674.         if (ende) break;
  675.         punkte=lmin(punkte+5,MAXPUNKTE);
  676.         while ((move_stone())&&(!ende)) ;
  677.         for (i=4; i<14; i++)
  678.             for (j=0; j<24; j++)
  679.                 back[i][j]=sit[i][j];
  680.         reihen=lmin(reihen+remove_voll(),MAXREIHEN);
  681.         draw_punkte();
  682.         wait();
  683.         delay=lmin(lmax(mindelay,
  684.                 (maxdelay>50)?(100-punkte/200):(maxdelay-reihen/6)),
  685.                     maxdelay);
  686.     }
  687.     if (ende>=0)
  688.         best();
  689. }
  690.  
  691. void setdelay(void)
  692. {    OBJECT *info;
  693.     if (rsrc_gaddr(R_TREE,INFOF,&info)==0) return;
  694.     if (maxdelay>40)
  695.     {    maxdelay=40; menu_icheck(menu_tree,MENQUICK,1);
  696.         info[FQUICK].ob_state|= CHECKED; speed=1;
  697.         strcpy(wi_name,wi_qname);
  698.         if (wi_handle>0) wind_set(wi_handle,WF_NAME,wi_name); }
  699.     else
  700.     {    maxdelay=100; menu_icheck(menu_tree,MENQUICK,0);
  701.         info[FQUICK].ob_state&= ~CHECKED; speed=0;
  702.         strcpy(wi_name,wi_sname);
  703.         if (wi_handle>0) wind_set(wi_handle,WF_NAME,wi_name); }
  704. }
  705.  
  706. void load_score(void)
  707. {    FILE *sco;
  708.     int i,sp;
  709.     if ((sco=fopen("gemtris.sco","r"))>0)
  710.     {    fscanf(sco,"%d %d\n",&wi_x,&wi_y);
  711.         fscanf(sco,"%d\n",&steinsize);
  712.         for (sp=0; sp<2; sp++)
  713.             for (i=0; i<10; i++)
  714.                 fscanf(sco,"%s %ld\n",namen[sp][i],&score[sp][i]);
  715.         fclose(sco);
  716.     }
  717.     if (wi_x<0) wi_x=0;
  718.     if (wi_y<0) wi_y=0;
  719.     if (steinsize<8) steinsize=8;
  720. }
  721.  
  722. void save_score(void)
  723. {    FILE *sco;
  724.     int i,sp;
  725.     wind_update(BEG_UPDATE);
  726.     graf_mouse(HOURGLASS,NULL);
  727.     if ((sco=fopen("gemtris.sco","w"))>0)
  728.     {    fprintf(sco,"%d %d\n",wi_x,wi_y);
  729.         fprintf(sco,"%d\n",steinsize);
  730.         for (sp=0; sp<2; sp++)
  731.             for (i=0; i<10; i++)
  732.             {    if (namen[sp][i][0]<'1') 
  733.                     memcpy(namen[sp][i],"???",32);
  734.                 fprintf(sco,"%s %ld\n",namen[sp][i],score[sp][i]); 
  735.             }
  736.         fclose(sco);
  737.     }
  738.     graf_mouse(ARROW,NULL);
  739.     wind_update(END_UPDATE);
  740. }
  741.  
  742. void init(void)
  743. {    int i;
  744.     empty_board();
  745.     /* Highscore=0 */
  746.     for (i=0; i<10; i++)
  747.     {    memcpy(namen[0][i],"???",32); 
  748.         memcpy(namen[1][i],"???",32); 
  749.         score[0][i]=0; score[1][i]=0; }
  750.     load_score();
  751.     wi_handle=-1;
  752. }
  753.  
  754. void reinit(void)
  755. {    save_score();
  756. }    
  757.  
  758. int main_loop(void)
  759. /* Der Ereignisverwalter. Reagiert auf verschiedene Ereignisse */
  760. {    int ende=0,dirty,msg,evmask;
  761.     int msgbuf[8];
  762.     int mx,my,mb,state,key,clicks,evt;
  763.  
  764.     wind_update(BEG_UPDATE);
  765.     init();
  766.     if (_app)
  767.     {    if (rsrc_gaddr(R_TREE,MENMENU,&menu_tree)==0) ende=1;
  768.         menu_bar(menu_tree,1);
  769.         if (open_window()) ende=1;
  770.     }
  771.     setdelay();
  772.     wind_update(END_UPDATE);
  773.     if (ende) return 1;
  774.     dirty=0;
  775.     do
  776.     {    evmask=MU_KEYBD|MU_MESAG;
  777.         if (dirty) evmask|=MU_TIMER;
  778.         evt=evnt_multi(evmask,
  779.             1,1,1,
  780.             0,0,0,0,0,
  781.             0,0,0,0,0,
  782.             msgbuf,
  783.             0,0,
  784.             &mx,&my,&mb,&state,&key,&clicks);
  785.         if (evt & MU_MESAG) /* Message eingetroffen? */
  786.         {    msg=msgbuf[0];
  787.             switch(msg)
  788.             {    case AC_CLOSE:
  789.                     wi_handle=-1;
  790.                     dirty=0; break;
  791.                 case WM_REDRAW:
  792.                     do_redraw(msgbuf[3],msgbuf[4],msgbuf[5],msgbuf[6],msgbuf[7]);
  793.                     break;
  794.             }
  795.             if (dirty==0)
  796.             {    switch(msgbuf[0])
  797.                 {    case AC_OPEN:
  798.                         open_window(); show_info();
  799.                         dirty=1; break;
  800.                     case MN_SELECTED:
  801.                         switch(msgbuf[4])
  802.                         {    case MENQUIT: ende=1; break; 
  803.                               case MENINFO: show_info();
  804.                                   dirty=1; break;
  805.                               case MENQUICK: setdelay(); break;
  806.                               case MENGO:
  807.                                 menu_tnormal(menu_tree,msgbuf[3],1);
  808.                                   play();
  809.                                   dirty=1; break;
  810.                               case MENSCORE: save_score(); break;
  811.                               case MENLOOK: punkte=0; best();
  812.                                   dirty=1; break;
  813.                         }
  814.                         menu_tnormal(menu_tree,msgbuf[3],1);
  815.                         break;
  816.                      case WM_TOPPED:
  817.                         wind_set(msgbuf[3],WF_TOP,msgbuf[3]);
  818.                         dirty=1;
  819.                         break;
  820.                     case WM_MOVED:
  821.                         move_window(msgbuf[3],msgbuf[4],msgbuf[5],msgbuf[6],msgbuf[7]);
  822.                         dirty=1;
  823.                         break;
  824.                     case WM_FULLED:
  825.                         stein_size(msgbuf[3]); dirty=1; break;
  826.                 }
  827.             }
  828.         }
  829.         if ((evt & MU_KEYBD)&&(dirty==0))
  830.         { if (key==CNTRL_C) ende=1;
  831.           switch (key)
  832.           { case F1 : play(); dirty=1; break; 
  833.             case F2 : punkte=0; best(); dirty=1; break;
  834.             case F3 : save_score(); break;
  835.             case F10: setdelay(); break;
  836.             case HELP : show_info(); dirty=1; break;
  837.           }
  838.           keyclr();
  839.         }
  840.         
  841.         if (evt==MU_TIMER) dirty=0;
  842.         
  843.         if (ende)
  844.         {
  845.             if (_app)
  846.             {    wind_update(BEG_UPDATE);
  847.                 ende=form_alert(1, rs_frstr[QUIT]);
  848.                 wind_update(END_UPDATE);
  849.             }
  850.             else
  851.             {    ende=0;
  852.                 close_window();
  853.             }
  854.         }
  855.     } while (!ende);
  856.     wind_update(BEG_UPDATE);
  857.     close_window(); /* Schliesse Fenster */
  858.     if (_app)    menu_bar(menu_tree,0); /* Loesche Menue */
  859.     reinit();
  860.     wind_update(END_UPDATE);
  861.     return 0;
  862. }
  863.  
  864. main()
  865. /* Hauptprogramm */
  866. {
  867.         /* NUR BEI INTERNER RSC-FILE */
  868.     rsc_init();
  869.  
  870.     wind_update(BEG_UPDATE);
  871.  
  872.     if(open_vwork())         /* Arbeitstation aufmachen */
  873.         {
  874.         if (! _app)    
  875.             menu_register(gl_apid, "  GEMtris ");
  876.         else 
  877.             graf_mouse(ARROW, NULL);
  878.         
  879.         /*    NUR BEI EXTERNER RSC-FILE
  880.         if (rsrc_load("gemtris.rsc")==0)
  881.             {    
  882.             form_alert(1,"[3][  GEMtris: |  GEMTRIS.RSC ? ][ABORT]");
  883.             close_vwork();
  884.             goto exit;
  885.             }
  886.         */
  887.         
  888.         wind_update(END_UPDATE);
  889.  
  890.         main_loop(); /* Hauptschleife */
  891.  
  892.         wind_update(BEG_UPDATE);
  893.         
  894.         /*    NUR BEI EXTERNER RSC-FILE
  895.         rsrc_free();
  896.         */
  897.         
  898.         close_vwork(); /* Arbeitsstation schliessen */
  899.  
  900.         /* NUR BEI INTERNER RSC-FILE */
  901.         rsc_exit();
  902.  
  903.         }
  904.     else 
  905.         form_alert(1,"[3][  GEMtris: |  Init-Error ][ABORT]");
  906.  
  907. exit:
  908.     wind_update(END_UPDATE);
  909.     if (! _app)
  910.         while (1) evnt_timer(0xffff,0xffff);
  911.     
  912.     wind_update(BEG_UPDATE);
  913.     
  914.     graf_mouse(HOURGLASS,0);
  915.     
  916.     keyclr();
  917.     
  918.     wind_update(END_UPDATE);
  919.     
  920.     return 0; /* Alles klar */
  921. }
  922.