home *** CD-ROM | disk | FTP | other *** search
/ Crawly Crypt Collection 1 / crawlyvol1.bin / games / vierfrei / vierfrei.c < prev    next >
C/C++ Source or Header  |  1993-12-21  |  100KB  |  3,463 lines

  1. /**************************************************************************/
  2. /*                                                                          */
  3. /*                            VIERFREI.C                                      */
  4. /*                                                                          */
  5. /*                        Version vom 21.12.93                              */
  6. /*                                                                          */
  7. /**************************************************************************/
  8.  
  9.  
  10. /*------------------------------------------------------------------------*/
  11. /*                                                                          */
  12. /*        Liste der zu '#include'nden Files                                  */
  13. /*                                                                          */
  14. /*------------------------------------------------------------------------*/
  15.  
  16.  
  17. #include <stdio.h>
  18. #include <stdlib.h>
  19. #include <aes.h>
  20. #include <vdi.h>
  21. #include <tos.h>
  22. #include <math.h>
  23. #include <string.h>
  24. #include <ctype.h>
  25. #include "VIERFREI.H"                /* Headerfile für Resource              */
  26.  
  27.  
  28. /*------------------------------------------------------------------------*/
  29. /*                                                                          */
  30. /*        einige '#define's                                                  */
  31. /*                                                                          */
  32. /*------------------------------------------------------------------------*/
  33.  
  34.  
  35. #define    N            52                /* Anzahl der Karten                  */
  36. #define NUM_COLUMNS    8                /* Anzahl der Reihen                  */
  37.  
  38. #define CARD_WIDTH    64                /* Breite einer Karte (in Pixeln)      */
  39. #define    CARD_LENGTH    93                /* Länge einer Karte (in Pixeln)      */
  40.  
  41. #define CARD_SIZE    186L            /* für Bild einer Karte benötigter      */
  42.                                     /* Speicher (in Byte)                  */
  43. #define    CARD_X_SPAC    10                /* horizontaler Abstand der Karten      */
  44. #define    CARD_Y_SPAC    15                /* vertikaler Abstand der Karten      */
  45.  
  46. #define    TOP_ROW        102                /* y-Position der Reihen (relativ zur */
  47.                                     /* Arbeitsfläche des Fensters)          */
  48. #define    NO_CARD        -1                /* 'Kartennummer' für Stellen, wo      */
  49.                                     /* keine (!) Karte liegt              */
  50. #define    HIST_LEN    250L            /* Anzahl der Züge, für die jeweils      */
  51.                                     /* Speicher alloziert wird (zwecks      */
  52.                                     /* Rücknahme ...)                      */
  53. #define    ON            1
  54. #define    OFF            0
  55.  
  56. #define    BLACK        1
  57. #define    WHITE        0
  58.  
  59. #define    NORM        1
  60. #define    INVERS        0
  61.  
  62. #define    F1            59                /* Scancodes verschiedener Tasten      */
  63. #define    F2            60
  64. #define    F3            61
  65. #define F4            62
  66. #define    F10            68
  67. #define    UNDO        97
  68. #define    DELETE        83
  69.  
  70. #define ESC            0x1B            /* ASCII-Codes der Zeichen              */
  71. #define BACKSPACE    0x08
  72. #define RETURN        0x0D            /* <RETURN> und <ENTER>                  */
  73.  
  74. #define S_TEXT    ob_spec.tedinfo->te_ptext        /* für Text-Objekte          */
  75.  
  76. #define MIN(x,y)    (((x) < (y)) ? (x) : (y))    /* Minimum zweier Zahlen  */
  77. #define MAX(x,y)    (((x) > (y)) ? (x) : (y))    /* Maximum zweier Zahlen  */
  78.  
  79. #define    _hz_200        0x04BAL            /* Adresse des Zähler des 200 Hz -      */
  80.                                     /* Interrupts                          */
  81.  
  82.  
  83. /*------------------------------------------------------------------------*/
  84. /*                                                                          */
  85. /*        Funktionsdeklarationen                                              */
  86. /*                                                                          */
  87. /*------------------------------------------------------------------------*/
  88.  
  89.  
  90. int init_history(void);
  91. int extend_history(void);
  92. int shorten_history(void);
  93. void take_move_back(void);
  94. void save_move(int source, int dest);
  95. int show_box(int ob_no);
  96. int on_mouse_event(int mox, int moy, int mbutton);
  97. int find_card(int x, int y);
  98. int is_touch_possible(int card_no);
  99. int get_move_length(int card_no);
  100. int find_where_to(int x, int y);
  101. int is_enough_room(int cards_to_move, int dest);
  102. int get_max_no(int place, int temp);
  103. int is_move_possible(int source, int dest);
  104. void wait_for_left_release(void);
  105. void move_card(int source, int dest, int mbox_flag);
  106. void take_away(int source);
  107. void move_multi_cards(int source, int dest);
  108. void move_temp_to_column(int *free_temp, int *act_temp, int max_temp,
  109.                                                                   int dest);
  110. int move_single_card(int source_column, int final_card, int *free_place,
  111.                                                         int act_free_place);
  112. int move_column_to_temp(int source_column, int final_card, int *free_temp,
  113.                                                         int *act_free_temp);
  114. void move_multi_to_temp(int card_no);
  115. void show_card(int card_no, int clip_flag);
  116. void shuffle(void);
  117. double make_seed(void);
  118. double random_generator(void);
  119. void show_all(int all_flag);
  120. void show_column(int col_no, int card_x, int clip_flag);
  121. int automatic_remove(void);
  122. void set_wind_header(char *title);
  123. void paint_background(void);
  124. void clear_column(int col, int clip_flag);
  125. int gem_init(char *title);
  126. void gem_exit(void);
  127. int make_cards(void);
  128. void reverse_card(long *source, long *dest);
  129. int select_game(char *title);
  130. void wind_redraw(int *rr, OBJECT *wind);
  131. int intersect(int *rr, int *ar);
  132. void move_window(int x, int y, OBJECT *wind);
  133. int resize_window(char *title);
  134. void i_to_a(char *s, long number, int n);
  135.  
  136.  
  137. /*------------------------------------------------------------------------*/
  138. /*                                                                          */
  139. /*        Deklaration einiger struct's                                      */
  140. /*                                                                          */
  141. /*------------------------------------------------------------------------*/
  142.  
  143.  
  144. struct Card                                /* Struktur für Karten (und auch  */
  145. {                                        /* für End- und Zwischenablage)      */
  146.     int x;                                /* x- und y- Position der Karte      */
  147.     int y;
  148.     int h;                                /* sichtbare Höhe der Karte          */
  149.     int column;                            /* Spalte oder Ablage, auf der      */
  150.                                         /* die Karte liegt                  */
  151.     int prev_card;                        /* Nummer der vorhergehenden und  */
  152.     int next_card;                        /* der nächsten Karte              */
  153. };                                        
  154.  
  155. /* Achtung : Bei den Card-Strukturen für End- und Zwischenablage enthält  */
  156. /*              prev_card die Nummer der darauf liegenden (obersten) Karte ! */
  157.  
  158. struct Column                            /* Struktur für Reihen              */
  159. {
  160.     int first_card;                        /* Nummer der obersten Karte      */
  161.     int x;                                /* x-Position der Reihe              */
  162.     int h;                                /* Länge der Reihe (in Pixeln)      */
  163.     int    del_y;                            /* Länge der gezeigten Teils von  */
  164. };                                        /* Karten, die überlagert sind      */
  165.         
  166.  
  167. /*------------------------------------------------------------------------*/
  168. /*                                                                          */
  169. /*        globale Variable                                                  */
  170. /*                                                                          */
  171. /*------------------------------------------------------------------------*/
  172.  
  173.  
  174. int ap_id;                            /* ID der eigenen Applikation          */
  175. int wkst_handle;                    /* Handle der Workstation              */
  176. int wind_handle;                    /* Handle des Fensters                  */
  177. int nplanes;                        /* Anzahl der Bitplanes                  */
  178. int wox, woy, wow, woh,                /* Außen- und Innenmaße des Fensters  */
  179.     wwx, wwy, www, wwh;
  180. OBJECT *menu;                        /* Adresse des Menues                  */
  181. long *pic;                            /* Adresse der Bilder der Karten      */
  182. double seed;                        /* akt. Seed des Zufallgenerators      */
  183. double old_seed;                    /* Startseed des Zufallgenerators      */
  184. struct Card card[N + 8];            /* Strukturen für Karten sowie End-      */
  185.                                     /* und Zwischenablage (Endablage ab      */
  186.                                     /* N bis (N + 3), Zwischenablage ab      */
  187.                                     /* (N + 4) bis (N + 7)                  */
  188. struct Column column[NUM_COLUMNS];    /* Strukturen für die Reihen          */
  189. char *history;                        /* Pointer auf Array für Speicherung  */
  190.                                     /* der bisherigen Züge                  */
  191. int no_history = OFF;                /* gesetzt, wenn nicht die Züge nicht */
  192.                                     /* gepeichert werden können              */
  193. long move_no;                        /* Anzahl der bisherigen Züge          */
  194. int remaining_cards;                /* Anzahl der restlichen Karten          */
  195. int scr_x, scr_y;                    /* maximale Bildschirmgröße              */
  196. int clip_array[4];                    /* Array für Cliping                  */
  197.  
  198.  
  199. /*------------------------------------------------------------------------*/
  200. /*                                                                          */
  201. /*        Hier fängt das eigentliche Programm (endlich) an ...              */
  202. /*                                                                          */
  203. /*------------------------------------------------------------------------*/
  204.  
  205.  
  206. main()
  207. {
  208.     int mwhich,                        /* Variablen für evnt_multi()          */
  209.         mbuf[8],
  210.         mox, moy,
  211.         mbutton, mokstate,
  212.         mkreturn, mbreturn;
  213.     int top_window;                    /* Handle des obersten Fensters          */
  214.     char wind_name[] = " VIERFREI #       ";    /* Titel des Fensters      */
  215.     int quit_flag = OFF;            /* Flag, bei Programmende gesetzt      */
  216.     
  217.     
  218.     /* Applikation anmelden, Workstation anmelden und Fenster öffnen      */
  219.  
  220.     if (!gem_init(wind_name))
  221.         return(0);
  222.     
  223.     /* Resource-File einlesen und Objektadressen bestimmen                  */
  224.  
  225.     if (!rsrc_load("VIERFREI.RSC"))
  226.     {
  227.         wind_delete(wind_handle);
  228.         gem_exit();
  229.         return(0);
  230.     }
  231.  
  232.     rsrc_gaddr(R_TREE, MENU, &menu);
  233.  
  234.     /* Menue-Zeile anzeigen                                                  */
  235.  
  236.     menu_bar(menu, ON);
  237.  
  238.     /* Bilder der Karten vorbereiten                                      */
  239.  
  240.     if (!make_cards())
  241.     {
  242.         menu_bar(menu, OFF);
  243.         rsrc_free();
  244.         wind_delete(wind_handle);
  245.         gem_exit();
  246.         return(0);
  247.     }
  248.  
  249.     /* Erstes Spiel vorbereiten                                              */
  250.  
  251.     if (!init_history())
  252.         menu_ienable(menu, T1E4, OFF);
  253.     old_seed = seed = make_seed();
  254.     set_wind_header(wind_name);
  255.     shuffle();
  256.  
  257.     graf_mouse(ARROW, 0);
  258.  
  259.     /* In einer Loop auf Tastatur-, Maus- oder Message-Ereignisse warten  */
  260.     /* und diesen entsprechend verzweigen ...                              */
  261.  
  262.     do
  263.     {
  264.         mwhich = evnt_multi(MU_KEYBD | MU_BUTTON | MU_MESAG,
  265.                             1, 1, 1,
  266.                             0, 0, 0, 0, 0,
  267.                             0, 0, 0, 0, 0,
  268.                             mbuf, 0, 0, &mox, &moy, &mbutton,
  269.                             &mokstate, &mkreturn, &mbreturn);
  270.  
  271.     /* Reaktion auf Messages ...                                          */
  272.  
  273.         if (mwhich & MU_MESAG)
  274.         {
  275.             switch (mbuf[0])
  276.             {
  277.                 case WM_CLOSED :                  /* Close-Box angeklickt */
  278.                     quit_flag = ON;
  279.                     break;
  280.  
  281.                 case WM_REDRAW :                   /* REDRAW-Aufforderung */
  282.                     wind_redraw(mbuf + 4, (OBJECT *) 0L);
  283.                     break;
  284.  
  285.                 case WM_TOPPED :        /* Fenster wurde oberstes Fenster */
  286.                     wind_set(wind_handle, WF_TOP);
  287.                     break;
  288.  
  289.                 case WM_MOVED :                  /* Fenster wurde verschoben */
  290.                     move_window(mbuf[4], mbuf[5], (OBJECT *) 0L);
  291.                     break;
  292.  
  293.                 case WM_FULLED :                   /* FULL-Box angeklickt */
  294.                     if (resize_window(wind_name))
  295.                         quit_flag = ON;
  296.                     break;
  297.             }
  298.         }
  299.  
  300.     /* Bei Tastatureingabe Anklicken von Menueeinträgen simulieren ...      */
  301.  
  302.         if (mwhich & MU_KEYBD)
  303.         {
  304.             switch(mkreturn >> 8)
  305.             {
  306.                 case F1 :                      /* neues (zufälliges) Spiel */
  307.                     mwhich |= MU_MESAG;
  308.                     mbuf[0] = MN_SELECTED;
  309.                     mbuf[3] = T1;
  310.                     mbuf[4] = T1E0;
  311.                     menu_tnormal(menu, T1, INVERS);
  312.                     break;
  313.  
  314.                 case F2 :               /* neues Spiel (entsprechend Zahl) */
  315.                     if (menu[T1E1].ob_state & DISABLED)
  316.                         break;
  317.                     mwhich |= MU_MESAG;
  318.                     mbuf[0] = MN_SELECTED;
  319.                     mbuf[3] = T1;
  320.                     mbuf[4] = T1E1;
  321.                     menu_tnormal(menu, T1, INVERS);
  322.                     break;
  323.  
  324.                 case F3 :                       /* altes Spiel wiederholen */
  325.                     mwhich |= MU_MESAG;
  326.                     mbuf[0] = MN_SELECTED;
  327.                     mbuf[3] = T1;
  328.                     mbuf[4] = T1E2;
  329.                     menu_tnormal(menu, T1, INVERS);
  330.                     break;
  331.  
  332.                 case F4 :                                 /* Über VIERFREI */
  333.                     mwhich |= MU_MESAG;
  334.                     mbuf[0] = MN_SELECTED;
  335.                     mbuf[3] = T0;
  336.                     mbuf[4] = T0E0;
  337.                     menu_tnormal(menu, T0, INVERS);
  338.                     break;
  339.  
  340.                 case F10 :                                 /* Spiel beenden */
  341.                     mwhich |= MU_MESAG;
  342.                     mbuf[0] = MN_SELECTED;
  343.                     mbuf[3] = T1;
  344.                     mbuf[4] = T1E5;
  345.                     menu_tnormal(menu, T1, INVERS);
  346.                     break;
  347.  
  348.                 case DELETE :                   /* automatisches Entfernen */
  349.                     mwhich |= MU_MESAG;
  350.                     mbuf[0] = MN_SELECTED;
  351.                     mbuf[3] = T1;
  352.                     mbuf[4] = T1E3;
  353.                     menu_tnormal(menu, T1, INVERS);
  354.                     break;
  355.  
  356.                 case UNDO :                      /* letzten Zug zurücknehmen */
  357.                     if (no_history)
  358.                         break;
  359.                     mwhich |= MU_MESAG;
  360.                     mbuf[0] = MN_SELECTED;
  361.                     mbuf[3] = T1;
  362.                     mbuf[4] = T1E4;
  363.                     menu_tnormal(menu, T1, INVERS);
  364.                     break;
  365.             }
  366.         }
  367.  
  368.     /* Handle des derzeitig obersten Fensters bestimmen - ist es nicht      */
  369.     /* das eigene wird auf die folgenden Events *nicht* reagiert          */
  370.  
  371.         wind_get(wind_handle, WF_TOP, &top_window);
  372.  
  373.         if (wind_handle != top_window)
  374.         {
  375.             if ((mwhich & MU_MESAG) && (mbuf[0] == MN_SELECTED))
  376.                 menu_tnormal(menu, mbuf[3], NORM);
  377.             continue;
  378.         }
  379.  
  380.     /* Reaktion auf Anklicken eines Menu-Eintrags                          */
  381.  
  382.         if ((mwhich & MU_MESAG) && (mbuf[0] == MN_SELECTED))
  383.         {
  384.             switch (mbuf[4])
  385.             {
  386.                 case T0E0 :                             /* Über VIERFREI ... */
  387.                     if (show_box(ABOUT))
  388.                         quit_flag = ON;
  389.                     break;
  390.  
  391.                 case T1E0 :                      /* neues (zufälliges) Spiel */
  392.                     old_seed = seed;
  393.                     set_wind_header(wind_name);
  394.                     shuffle();
  395.                     show_all(ON);
  396.                     break;
  397.  
  398.                 case T1E1 :               /* neues Spiel (entsprechend Zahl) */
  399.                     if (!select_game(wind_name))
  400.                         break;
  401.                     shuffle();
  402.                     show_all(ON);
  403.                     break;
  404.  
  405.                 case T1E2 :                       /* altes Spiel wiederholen */
  406.                     seed = old_seed;
  407.                     shuffle();
  408.                     show_all(ON);
  409.                     break;
  410.  
  411.                 case T1E3 :                       /* automatisches Entfernen */
  412.                     if (automatic_remove())
  413.                     {
  414.                         if (show_box(GRAT))
  415.                             quit_flag = ON;
  416.                     }
  417.                     break;
  418.  
  419.                 case T1E4 :                      /* letzten Zug zurücknehmem */
  420.                     take_move_back();
  421.                     break;
  422.  
  423.                 case T1E5 :                                 /* Spiel beenden */
  424.                     quit_flag = ON;
  425.                     break;
  426.             }
  427.  
  428.             menu_tnormal(menu, mbuf[3], NORM);
  429.         }
  430.  
  431.     /* Reaktion auf Drücken der linken Maustaste                          */
  432.  
  433.         if (mwhich & MU_BUTTON)
  434.         {
  435.             if (on_mouse_event(mox, moy, mbutton))
  436.             {
  437.                 if (show_box(GRAT))
  438.                     quit_flag = ON;
  439.             }
  440.         }
  441.  
  442.     } while (!quit_flag);
  443.  
  444.     /* Speicherplatz für Speicherung der Züge und die Bilder der Karten      */
  445.     /* freigeben                                                          */
  446.  
  447.     if (history)
  448.     {
  449.         while (!shorten_history())
  450.             ;
  451.         Mfree(history);
  452.     }
  453.  
  454.     Mfree(pic);
  455.  
  456.     /* Menue-Zeile entfernen und Speicher für Resource freigeben          */
  457.  
  458.     menu_bar(menu, OFF);
  459.     rsrc_free();
  460.  
  461.     /* Fenster und Workstation schließen                                  */
  462.  
  463.     wind_delete(wind_handle);
  464.     gem_exit();
  465.  
  466.     /* das war's ...                                                      */
  467.  
  468.     return(0);
  469. }
  470.  
  471.  
  472. /*------------------------------------------------------------------------*/
  473. /* init_history()                                                          */
  474. /*    Alloziert Speicher für Speicherung der Züge                              */
  475. /* <-  1 = alles ok, 0 : kein Speicher frei                                  */
  476. /*------------------------------------------------------------------------*/
  477.  
  478.  
  479. int init_history(void)
  480. {
  481.     char **ptr;
  482.  
  483.  
  484.     /* Platz für Speichern der Züge allozieren - gespeichert wird jeweils */
  485.     /* nur die Nummer der Ausgangs- und Zielreihe (bzw. des End- oder      */
  486.     /* Zwischenablageplatzes). Die letzten Byte in 'history' dienen zur      */
  487.     /* möglichen Erweiterung des Speicherplatzes, wenn mehr als HIST_LEN  */
  488.     /* Spielzüge stattgefunden haben - sie werden zunächst auf NULL ge-      */
  489.     /* setzt, so daß klar ist, daß noch kein weiterer Speicher alloziert  */
  490.     /* ist.                                                                  */
  491.  
  492.     if ((history = (char *) Malloc(2L * HIST_LEN * sizeof(char) + 
  493.                                                    sizeof(char *))) == NULL)
  494.     {
  495.         menu_ienable(menu, T1E4, OFF);
  496.         no_history = ON;
  497.         return(0);
  498.     }
  499.  
  500.     ptr = (char **) (history + 2L * HIST_LEN);
  501.     *ptr = (char *) 0L;
  502.  
  503.     return(1);
  504. }
  505.  
  506.  
  507. /*------------------------------------------------------------------------*/
  508. /* extend_history()                                                          */
  509. /*    Alloziert zusätzlichen Speicher für Speicherung der Züge                  */
  510. /* <-  1 = alles ok, 0 = kein weiterer Speicher mehr frei                  */
  511. /*------------------------------------------------------------------------*/
  512.  
  513.  
  514. int extend_history(void)
  515. {
  516.     char *ptr, **old_ptr;
  517.  
  518.  
  519.     /* Zur Erweiterung des Platzes für die Speicherung der bisherigen      */
  520.     /* Spielzüge wird weiterer Speicherplatz alloziert, dessen Adresse      */
  521.     /* in die letzten Byte des vorher allozierten Speicherplatzes ge-      */
  522.     /* schrieben wird - die letzten Byte des neu allozierten Speichers      */
  523.     /* werden zunächst auf NULL gesetzt, so daß klar ist, daß dies der      */
  524.     /* zuletzt allozierte Speicherplatz ist.                              */
  525.     
  526.     old_ptr = (char **) (history + 2L * HIST_LEN);
  527.     ptr = (char *) *old_ptr;
  528.  
  529.     while (ptr != (char *) 0L)
  530.     {
  531.         old_ptr = (char **) (ptr + 2L * HIST_LEN);
  532.         ptr = (char *) *old_ptr;
  533.     };
  534.  
  535.     if ((*old_ptr = (char *) Malloc(2L * HIST_LEN *
  536.                                     sizeof(char) + sizeof(char *))) == NULL)
  537.     {
  538.         menu_ienable(menu, T1E4, OFF);
  539.         no_history = ON;
  540.         while (!shorten_history())
  541.             ;
  542.         return(0);
  543.     }
  544.     else
  545.     {
  546.         old_ptr = (char **) ((char *) *old_ptr + 2L * HIST_LEN);
  547.         *old_ptr = (char *) 0L;
  548.         return(1);
  549.     }
  550. }
  551.  
  552.  
  553. /*------------------------------------------------------------------------*/
  554. /* shorten_history()                                                      */
  555. /*    Gibt das letzte zusätzlich für die Speicherung der Züge allozierte      */
  556. /*    Speicherstück wieder frei.                                              */
  557. /* <-  1 = aller zusätzlicher Speicher ist bereits freigegeben, 0 = es      */
  558. /*       gibt noch weitere allozierte Speicherbereiche                      */
  559. /*------------------------------------------------------------------------*/
  560.  
  561.  
  562. int shorten_history(void)
  563. {
  564.     char *ptr, *temp, **old_ptr;
  565.  
  566.  
  567.     temp =  history;
  568.     ptr = *((char **) (history + 2L * HIST_LEN));
  569.  
  570.     /* Falls die letzten Byte des zu Anfang allozierten Speicherbereichs  */
  571.     /* NULL sind gibt es keine weiteren freizugebenden Speicherbereiche      */
  572.  
  573.     if (ptr == (char *) 0L)
  574.         return(1);
  575.  
  576.     /* Sonst muß man sich bis zum am letzten allozierten Speicherbereich  */
  577.     /* durchhangeln (daran erkennbar, daß seine letzten Byte NULL sind)      */
  578.  
  579.     do
  580.     {
  581.         old_ptr = (char **) (temp + 2L * HIST_LEN);
  582.         temp = ptr;
  583.         ptr = *((char **) (ptr + 2L * HIST_LEN));
  584.     } while (ptr != (char *) 0L);
  585.  
  586.     /* Diesen Bereich freigeben und die letzten Byte des zuvor allozier-  */
  587.     /* ten Speicherbereich auf NULL setzen                                  */
  588.  
  589.     Mfree(temp);
  590.  
  591.     *old_ptr = (char *) 0L;
  592.  
  593.     return(0);
  594. }
  595.  
  596.  
  597. /*------------------------------------------------------------------------*/
  598. /* save_move()                                                              */
  599. /*    Speichert einen Zug ab                                                  */
  600. /* ->  Nummer der Ausgangs- und der Zielreihe                              */
  601. /*------------------------------------------------------------------------*/
  602.  
  603.  
  604. void save_move(int source, int dest)
  605. {
  606.     char *ptr;
  607.     long temp_move_no;
  608.  
  609.  
  610.     if (no_history)
  611.         return;
  612.  
  613.     /* Zuerst einmal durch die History durchhangeln (s.o.) ...              */
  614.  
  615.     temp_move_no = move_no;
  616.  
  617.     ptr = history;
  618.  
  619.     while (temp_move_no >= HIST_LEN)
  620.     {
  621.         ptr = *((char **) (ptr + 2L * HIST_LEN));
  622.         temp_move_no -= HIST_LEN;
  623.     }
  624.  
  625.     /* Nun die Züge abspeichern ...                                          */
  626.  
  627.     *(ptr + 2L * temp_move_no) = (char) source;
  628.     *(ptr + 2L * temp_move_no + 1) = (char) dest;
  629.  
  630.     move_no++;
  631.  
  632.     /* Wenn die History voll ist neuen Speicher allozieren ...              */
  633.  
  634.     if ((move_no % HIST_LEN) == 0)
  635.         extend_history();
  636. }
  637.  
  638.  
  639. /*------------------------------------------------------------------------*/
  640. /* take_move_back()                                                          */
  641. /*    Nimmt den letzten Zug zurück                                          */
  642. /*------------------------------------------------------------------------*/
  643.  
  644.  
  645. void take_move_back(void)
  646. {
  647.     char *ptr;
  648.     long temp_move_no;
  649.     int source_col, source, dest_col, dest;
  650.     int dest_x, dest_y;
  651.  
  652.  
  653.     /* Sind keine Züge gespeichert oder ist man beim ersten Zug angelangt */
  654.     /* gehts natürlich nicht weiter zurück ...                              */
  655.  
  656.     if ((no_history) || (move_no == 0))
  657.     {
  658.         Cconout('\a');
  659.         return;
  660.     }
  661.  
  662.     move_no--;
  663.  
  664.     /* Sonst zuerst einmal durch die History durchhangeln (s.o.) ...      */
  665.  
  666.     temp_move_no = move_no;
  667.  
  668.     ptr = history;
  669.  
  670.     while (temp_move_no >= HIST_LEN)
  671.     {
  672.         ptr = *((char **) (ptr + 2L * HIST_LEN));
  673.         temp_move_no -= HIST_LEN;
  674.     }
  675.  
  676.     /* ... die gespeicherten Zug holen ...                                  */
  677.  
  678.     dest_col = (int) *(ptr + 2L * temp_move_no);
  679.     source_col = (int) *(ptr + 2L * temp_move_no + 1);
  680.  
  681.     /* ... und die Karte erst entfernen und dann wieder an der alte Posi- */
  682.     /* tion zeichnen :                                                      */
  683.  
  684.     /* Dazu die unterste Karte der Reihe bestimmen, von der die Karte      */
  685.     /* wieder entfernt werden muß ...                                      */
  686.  
  687.     if (source_col >= N)
  688.         source = card[source_col].prev_card;
  689.     else
  690.     {
  691.         source = column[source_col].first_card;
  692.         while (card[source].next_card != NO_CARD)
  693.             source = card[source].next_card;
  694.     }
  695.  
  696.     /* ... und das selbe für die Zielreihe                                  */
  697.  
  698.     if (dest_col >= N)
  699.     {
  700.         dest = card[dest_col].prev_card;
  701.  
  702.         dest_x = card[dest_col].x;
  703.         dest_y = card[dest_col].y;
  704.     }
  705.     else
  706.     {
  707.         dest = column[dest_col].first_card;
  708.  
  709.         dest_x = column[dest_col].x;
  710.         dest_y = wwy + TOP_ROW;
  711.  
  712.         if (dest != NO_CARD)
  713.         {
  714.             while (card[dest].next_card != NO_CARD)
  715.                 dest = card[dest].next_card;
  716.             dest_y = card[dest].y;
  717.         }
  718.     }
  719.  
  720.     /* Karte von der alten Position löschen, eine sich von ihrer alten      */
  721.     /* zur neuen Position bewegende Box zeichnen und die Karte an die      */
  722.     /* Zielreihe anhängen                                                  */
  723.  
  724.     take_away(source);
  725.  
  726.     graf_mbox(CARD_WIDTH, CARD_LENGTH, card[source].x, card[source].y,
  727.                                                             dest_x, dest_y);
  728.  
  729.     if (dest_col >= N)
  730.     {
  731.         card[dest_col].prev_card = source;
  732.  
  733.         card[source].x = card[dest_col].x;
  734.         card[source].y = card[dest_col].y;
  735.         card[source].h = CARD_LENGTH;
  736.         card[source].column = dest_col;
  737.         card[source].prev_card = card[source].next_card = NO_CARD;
  738.  
  739.         show_card(source, ON);
  740.     }
  741.     else
  742.     {
  743.         if (dest != NO_CARD)
  744.         {
  745.             card[dest].next_card = source;
  746.             card[dest].h = column[dest_col].del_y;
  747.             card[source].prev_card = dest;
  748.             card[source].y = card[dest].y + column[dest_col].del_y;
  749.         }
  750.         else
  751.         {
  752.             card[source].prev_card = NO_CARD;
  753.             column[dest_col].first_card = source;
  754.             card[source].y = wwy + TOP_ROW;
  755.         }
  756.  
  757.         card[source].next_card = NO_CARD;
  758.         card[source].column = dest_col;
  759.         card[source].x = column[dest_col].x;
  760.         card[source].h = CARD_LENGTH;
  761.  
  762.         if ((card[source].y + CARD_LENGTH) < (wwy + wwh - 1))
  763.         {
  764.             show_card(source, ON);
  765.             if (column[dest_col].h == 0)
  766.                 column[dest_col].h = CARD_LENGTH;
  767.             else
  768.                 column[dest_col].h += column[dest_col].del_y;
  769.         }
  770.         else
  771.             show_column(dest_col, column[dest_col].x, ON);
  772.     }
  773.  
  774.     /* Wurde die Karte von der Endablage zurückgenommen, Anzahl der auf      */
  775.     /* der Spielfläche verbliebenen Karten inkrementieren                  */
  776.  
  777.     if ((source_col >= N) && (source_col < N + 4))
  778.         remaining_cards++;
  779.  
  780.     /* U. U. den Speicherplatz zur Speicherung der Züge verkleinern          */
  781.  
  782.     if ((move_no % HIST_LEN) == HIST_LEN - 1)
  783.         shorten_history();
  784. }
  785.  
  786.  
  787. /*------------------------------------------------------------------------*/
  788. /* show_box()                                                              */
  789. /*  Zeigt Gratulationsbox bei erfolgreicher Beendigung eines Spiels bzw.  */
  790. /*    Box mit Informationen über das Spiel.                                  */
  791. /* ->  Objektnummer der darzustellenden Box                                  */
  792. /* <-  1 = Spiel beenden, 0 = weitermachen                                  */
  793. /*------------------------------------------------------------------------*/
  794.  
  795.  
  796. int show_box(int ob_no)
  797. {
  798.     int mwhich,                            /* Variablen für evnt_multi()      */
  799.         mbuf[8],
  800.         mox, moy,
  801.         mbutton, mokstate,
  802.         mkreturn, mbreturn;
  803.     OBJECT *box;                        /* Pointer auf darzustellende Box */
  804.     int quit_flag = OFF;                /* gesetzt, wenn alles fertig ist */
  805.  
  806.  
  807.     /* Adresse der Box besorgen, Box vorbereiten und darstellen              */
  808.  
  809.     rsrc_gaddr(R_TREE, ob_no, &box);
  810.  
  811.     if ((scr_x - wwx < box->ob_width + 10) ||
  812.                                         (scr_y - wwy < box->ob_height + 10))
  813.         return(0);
  814.  
  815.     box->ob_x = MIN(wwx + (www - box->ob_width) / 2,
  816.                                          (scr_x + wwx - box->ob_width) / 2);
  817.     box->ob_y = MIN(wwy + (wwh - box->ob_height) / 2,
  818.                                         (scr_y + wwy - box->ob_height) / 2);
  819.  
  820.     /* Wenn es sich um die Gratulationsbox handelt, die Anzahl der benö-  */
  821.     /* tigten Züge eintragen                                              */
  822.  
  823.     if (ob_no == GRAT)
  824.         i_to_a(box[GNUMBER].S_TEXT, move_no, 5);
  825.  
  826.     objc_draw(box, R_TREE, 1, MAX(box->ob_x - 5, 0),
  827.                       MAX(box->ob_y - 5, 0), MIN(box->ob_width + 10, scr_x),
  828.                                            MIN(box->ob_height + 10, scr_y));
  829.  
  830.     /* MOVER und FULLER des Fensters ausschalten                          */
  831.  
  832.     wind_set(wind_handle, WF_KIND, CLOSER | NAME);
  833.  
  834.     /* Auf Messages, Anklicken von 'OK' oder Drücken der Return-Taste      */
  835.     /* warten                                                              */
  836.  
  837.     do
  838.     {
  839.         mwhich = evnt_multi(MU_BUTTON | MU_KEYBD | MU_MESAG,
  840.                             1, 1, 1,
  841.                             0, 0, 0, 0, 0,
  842.                             0, 0, 0, 0, 0,
  843.                             mbuf, 0, 0,
  844.                             &mox, &moy, &mbutton,
  845.                             &mokstate, &mkreturn, &mbreturn);
  846.  
  847.     /* Reaktion auf Messages ...                                          */
  848.  
  849.         if (mwhich & MU_MESAG)
  850.         {
  851.             switch (mbuf[0])           /* Nach Art der Message verzweigen */
  852.             {
  853.                 case WM_REDRAW :              /* REDRAW-Message empfangen */
  854.                     wind_redraw(mbuf + 4, (OBJECT *) 0L);
  855.                     wind_redraw(mbuf + 4, box);
  856.                     break;
  857.  
  858.                 case WM_TOPPED :        /* Fenster wurde oberstes Fenster */
  859.                     wind_set(wind_handle, WF_TOP);
  860.                     break;
  861.  
  862.                 case WM_CLOSED :                         /* Spiel beenden */
  863.                     return(1);
  864.  
  865.                 case MN_SELECTED :       /* nur auf Spiel beenden reagieren */
  866.                     menu_tnormal(menu, mbuf[3], NORM);
  867.                     if ((mbuf[3] == T1) && (mbuf[4] == T1E5))
  868.                         return(1);
  869.                     break;
  870.             }
  871.         }
  872.  
  873.     /* Abbrechen, wenn 'OK' angeklickt oder RETURN gedrückt wurde          */
  874.  
  875.         if (mwhich & MU_BUTTON)
  876.         {
  877.             if (((ob_no == GRAT) &&
  878.                         (GREADY == objc_find(box, 0, 1, mox, moy))) ||
  879.                 ((ob_no == ABOUT) &&
  880.                         (AREADY == objc_find(box, 0, 1, mox, moy))))
  881.             quit_flag = ON;
  882.         }
  883.  
  884.         if ((mwhich & MU_KEYBD) && ((mkreturn & 0xFF) == RETURN))
  885.             quit_flag = ON;
  886.  
  887.     } while (!quit_flag);
  888.  
  889.     /* Von der Box überdeckten Teil des Spielfeld neu zeichnen ...          */
  890.  
  891.     clip_array[0] = MAX(box->ob_x - 5, 0);
  892.     clip_array[1] = MAX(box->ob_y - 5, 0);
  893.     clip_array[2] = MIN(box->ob_x + box->ob_width + 4, scr_x);
  894.     clip_array[3] = MIN(box->ob_y + box->ob_height + 4, scr_y);
  895.     vs_clip(wkst_handle, ON, clip_array);
  896.  
  897.     show_all(OFF);
  898.  
  899.     /* ... und FULLER und MOVER des Fensters wieder anschalten              */
  900.  
  901.     wind_set(wind_handle, WF_KIND, CLOSER | NAME | FULLER | MOVER);
  902.  
  903.     return(0);
  904. }
  905.  
  906.  
  907. /*------------------------------------------------------------------------*/
  908. /* on_mouse_event()                                                          */
  909. /*    1. Testen, ob eine Karte angeklickt wurde                              */
  910. /*    2. Testen, ob die Karte überhaupt bewegt werden kann                  */
  911. /*    3. Box um die Karte mit der Maus verschieben lassen                      */
  912. /*    4. Zielkarte feststellen                                              */
  913. /*    5. bei mehreren zu verschiebenden Karten testen, ob genügend freie      */
  914. /*       Plätze für diese Aktion vorhanden sind                              */
  915. /*    6. Funktionen zum Verschieben der Karte(n) aufrufen                      */
  916. /*                                                                          */
  917. /* ->  x- und y-Position der Maus beim Drücken des Buttons sowie Zustand  */
  918. /*       der Mausbuttons                                                      */
  919. /* <-  1 = Spiel ist zu Ende, 0 = noch nicht alle Karten abgelegt          */
  920. /*------------------------------------------------------------------------*/
  921.  
  922.  
  923. int on_mouse_event(int mox, int moy, int mbutton)
  924. {
  925.     int del_x, del_y;
  926.     int touched_card, cards_to_move, where_to;
  927.  
  928.  
  929.     /* Herausfinden welche Karte angeklickt wurde                          */
  930.  
  931.     if ((touched_card = find_card(mox, moy)) == NO_CARD)
  932.     {
  933.         wait_for_left_release();
  934.         return(0);
  935.     }
  936.  
  937.     /* Untersuchen ob die angeklickte Karte überhaupt bewegt werden kann  */
  938.     /* und um wieviele es sich handelt (bei Zügen, bei denen beide Maus-  */
  939.     /* buttons gedrückt sind, also eine Reihe auf die Zwischenablage ge-  */
  940.     /* schoben werden soll, müssen die zu verschiebenden Karten *nicht*      */
  941.     /* aneinanderpassen)                                                  */
  942.  
  943.     if (((cards_to_move = is_touch_possible(touched_card)) == 0) &&
  944.                                                              (mbutton != 3))
  945.     {
  946.         wait_for_left_release();
  947.         return(0);
  948.     }
  949.  
  950.     /* Wenn beide Mausbuttons gedrückt sind, versuchen, die Karte(n) in      */
  951.     /* die Zwischenablage zu verschieben                                  */
  952.  
  953.     if (mbutton & 2)
  954.     {
  955.         move_multi_to_temp(touched_card);
  956.         return(0);
  957.     }
  958.  
  959.     /* Sonst die Karte(n) in Form von Dragbox (mit Größe entsprechend der */
  960.     /* Maße der zu verschiebenden Karte(n)) verschieben lassen, Maus      */
  961.     /* dabei als Hand darstellen                                          */
  962.  
  963.     graf_mouse(FLAT_HAND, 0);
  964.  
  965.     del_x = mox - card[touched_card].x - 2;
  966.     del_y = moy - card[touched_card].y;
  967.  
  968.     graf_dragbox(CARD_WIDTH - 4, get_move_length(touched_card),
  969.                              card[touched_card].x + 2, card[touched_card].y,
  970.                                             wwx, wwy, www, wwh, &mox, &moy);
  971.     graf_mouse(ARROW, 0);
  972.  
  973.     mox += del_x;
  974.     moy += del_y;
  975.  
  976.     /* Ziel des Verschiebens feststellen                                  */
  977.  
  978.     if ((where_to = find_where_to(mox, moy)) == NO_CARD)
  979.         return(0);
  980.  
  981.     /* Untersuchen ob zu verschiebende Karte überhaupt an das Ziel paßt      */
  982.  
  983.     if (!is_move_possible(touched_card, where_to))
  984.     {
  985.         if (card[touched_card].column != where_to)
  986.             Cconout('\a');
  987.         return(0);
  988.     }
  989.  
  990.     /* Bei mehr als einer zu verschiebenden Karte untersuchen ob genügend */
  991.     /* freie Plätze zur Verfügung stehen                                  */
  992.  
  993.     if ((cards_to_move > 1) && !is_enough_room(cards_to_move, where_to))
  994.     {
  995.         Cconout('\a');
  996.         return(0);
  997.     }
  998.  
  999.     /* Wenn alle Bedingungen erfüllt sind kann endlich verschoben werden  */
  1000.  
  1001.     if (cards_to_move == 1)
  1002.         move_card(touched_card, where_to, OFF);
  1003.     else
  1004.         move_multi_cards(touched_card, where_to);
  1005.  
  1006.     if (remaining_cards == 0)
  1007.         return(1);
  1008.     else
  1009.         return(0);
  1010. }
  1011.  
  1012.  
  1013. /*------------------------------------------------------------------------*/
  1014. /* find_card()                                                              */
  1015. /*    Stellt die Nummer der Karte an der Mausposition fest.                  */
  1016. /* ->  x- und y-Position der Maus                                          */
  1017. /* <-  Nummer der angeklickten Karte (bzw. NO_CARD, wenn sich an der ent- */
  1018. /*       sprechenden Stelle gar keine Karte befindet)                          */
  1019. /*------------------------------------------------------------------------*/
  1020.  
  1021.  
  1022. int find_card(int x, int y)
  1023. {
  1024.     int i;
  1025.  
  1026.     /* Positionen aller Karten mit der angeklickten Stelle vergleichen      */
  1027.  
  1028.     for (i = 0; i < N; i++)
  1029.     {
  1030.         if ((x >= card[i].x) && (x < card[i].x + CARD_WIDTH) &&
  1031.                             (y >= card[i].y) && (y < card[i].y + card[i].h))
  1032.             return(i);
  1033.     }
  1034.  
  1035.     return(NO_CARD);
  1036. }
  1037.  
  1038.  
  1039. /*------------------------------------------------------------------------*/
  1040. /* is_touch_possible()                                                      */
  1041. /*    Testet, ob die angeklickte Karte überhaupt den Regeln entsprechend      */
  1042. /*    bewegt werden kann.                                                      */
  1043. /* ->  Nummer der zu bewegenden Karte                                      */
  1044. /* <-  1 = alles ok, 0 = Karte kann nicht bewegt werden                      */
  1045. /*------------------------------------------------------------------------*/
  1046.  
  1047.  
  1048. int is_touch_possible(int card_no)
  1049. {
  1050.     int i, count;
  1051.  
  1052.  
  1053.     /* Zug von der Zwischenablage aus ist immer möglich                      */
  1054.  
  1055.     if (card[card_no].column >= N + 4)
  1056.         return(1);
  1057.  
  1058.     /* Rücknahme eines Karte von der Endablage ist verboten !              */
  1059.  
  1060.     if (card[card_no].column >= N)
  1061.         return(0);
  1062.  
  1063.     /* Zug mit der letzten Karte einer Reihe ist im Prinzip immer möglich */
  1064.  
  1065.     if ((i = card[card_no].next_card) == NO_CARD)
  1066.         return(1);
  1067.  
  1068.     /* Sonst muß überprüft werden ob die folgenden Karten in geordneter      */
  1069.     /* Form vorliegen und dabei gleichzeitig zählen, wieviele Karten zu      */
  1070.     /* verschieben sind                                                      */
  1071.  
  1072.     count = 1;
  1073.     do
  1074.     {
  1075.  
  1076.     /* (card_no & 1) ergibt die Farbe einer Karte (nämlich 0 für schwarz  */
  1077.     /* und 1 für rot), während mit (card_no >> 2) ihr Wert bestimmt wird  */
  1078.  
  1079.         if (((card_no & 1) ^ (i & 1)) && ((card_no >> 2) - 1 == (i >> 2)))
  1080.         {
  1081.             card_no = i;
  1082.             i = card[i].next_card;
  1083.             count++;
  1084.         }
  1085.         else
  1086.             return(0);
  1087.     } while (i != NO_CARD);
  1088.  
  1089.     return(count);
  1090. }
  1091.  
  1092.  
  1093. /*------------------------------------------------------------------------*/
  1094. /* get_move_length()                                                      */
  1095. /*    Stellt fest, wie lang (in Pixeln) die zu bewegende Reihe von Karten      */
  1096. /*    ist.                                                                  */
  1097. /* ->  Nummer der obersten zu bewegenden Karte                              */
  1098. /* <-  Länge (in Pixeln) der zu verschiebenden Reihe                      */
  1099. /*------------------------------------------------------------------------*/
  1100.  
  1101.  
  1102. int get_move_length(int card_no)
  1103. {
  1104.     if (card[card_no].column < N)
  1105.         return(column[card[card_no].column].h + TOP_ROW + wwy -
  1106.                                                            card[card_no].y);
  1107.     else
  1108.         return(CARD_LENGTH);
  1109. }
  1110.  
  1111.  
  1112. /*------------------------------------------------------------------------*/
  1113. /* find_where_to()                                                          */
  1114. /*    Stellt die Nummer der Reihe fest, an die die zu bewegende(n) Karte(n) */
  1115. /*    angelegt werden soll(en).                                              */
  1116. /* ->  x- und y-Position der Zielkarte                                      */
  1117. /* <-  Nummer der Zielreihe (bzw. NO_CARD wenn keine vorhanden)              */
  1118. /*------------------------------------------------------------------------*/
  1119.  
  1120.  
  1121. int find_where_to(int x, int y)
  1122. {
  1123.     int i;
  1124.  
  1125.  
  1126.     /* Nach passender Reihe suchen ...                                      */
  1127.  
  1128.     if (y >= wwy + TOP_ROW)
  1129.     {
  1130.         for (i = 0; i < NUM_COLUMNS; i++)
  1131.             if ((x >= column[i].x) && (x < column[i].x + CARD_WIDTH))
  1132.                 return(i);
  1133.         return(NO_CARD);
  1134.     }
  1135.  
  1136.     /* ... sonst mit Positionen der End- und Zwischenablage vergleichen      */
  1137.  
  1138.     for (i = N; i < N + 8; i++)
  1139.     {
  1140.         if ((x >= card[i].x) && (x < card[i].x + CARD_WIDTH) &&
  1141.                             (y >= card[i].y) && (y < card[i].y + card[i].h))
  1142.             return(i);
  1143.     }
  1144.  
  1145.     return(NO_CARD);
  1146. }
  1147.  
  1148.  
  1149. /*------------------------------------------------------------------------*/
  1150. /* is_enough_room()                                                          */
  1151. /*    Testet, ob genügend freie Plätze in der Zwischenablage sowie leere      */
  1152. /*    Reihen vorhanden sind, um die geplante Verschiebung durchzuführen.      */
  1153. /* ->  Zahl der zu verschiebenden Karten und Nummer der Zielreihe          */
  1154. /* <-  1 = alles ok, 0 = nicht genügend freie Plätze                      */
  1155. /*------------------------------------------------------------------------*/
  1156.  
  1157.  
  1158. int is_enough_room(int no, int dest)
  1159. {
  1160.     int free_temp = 0, free_place = 0;
  1161.     int i;
  1162.  
  1163.  
  1164.     /* Ein Mehrfachzug auf die End- oder Zwischenablage ist nicht möglich */
  1165.  
  1166.     if (dest >= NUM_COLUMNS)
  1167.         return(0);
  1168.  
  1169.     /* Jetzt feststellen wieviele freie Reihen und leere Zwischenablage-  */
  1170.     /* plätze es gibt                                                      */
  1171.  
  1172.     for (i = 0; i < NUM_COLUMNS; i++)
  1173.         if (column[i].first_card == NO_CARD)
  1174.             free_place++;
  1175.  
  1176.     for (i = N + 4; i < N + 8; i++)
  1177.         if (card[i].prev_card == NO_CARD)
  1178.             free_temp++;
  1179.  
  1180.     /* Falls die Zielposition einer der freien Plätze ist, so kann er      */
  1181.     /* nicht als Zwischenlagerplatz genutzt werden                          */
  1182.  
  1183.     if (column[dest].first_card == NO_CARD)
  1184.         free_place--;
  1185.  
  1186.     /* Nun berechnen wieviele Karten maximal bewegt werden können          */
  1187.  
  1188.     if (get_max_no(free_place, free_temp) >= no)
  1189.         return(1);
  1190.     else
  1191.         return(0);
  1192. }
  1193.  
  1194.  
  1195. /*------------------------------------------------------------------------*/
  1196. /* get_max_no()                                                              */
  1197. /*    Berechnet, wieviele Karten bei gegebener Anzahl von freien Reihen und */
  1198. /*    freien Plätzen in der Zwischenablage verschoben werden können          */
  1199. /* ->  Anzahl der freien Reihen und Zwischenablageplätze                  */
  1200. /* <-  Anzahl der maximal zu verschiebenden Karten                          */
  1201. /*------------------------------------------------------------------------*/
  1202.  
  1203.  
  1204. int get_max_no(int place, int temp)
  1205. {
  1206.     int max_no = 0;
  1207.  
  1208.  
  1209.     /* Bei bester Ausnutzung der Plätze passen auf die erste freie Reihe  */
  1210.     /* (temp + 1) Karten (temp ist die Anzahl der freien Zwischenablage-  */
  1211.     /* plätze), auf die zweite 2 * (temp + 1) usw., und zum Schluß kön-      */
  1212.     /* nen noch temp Karten in die Zwischenablage gelegt werden und eine  */
  1213.     /* weitere Karte verschoben werden.                                      */
  1214.  
  1215.     while (place > 0)
  1216.         max_no += place-- * (temp + 1);
  1217.  
  1218.     return(max_no + temp + 1);
  1219. }
  1220.  
  1221.  
  1222.  
  1223. /*------------------------------------------------------------------------*/
  1224. /* is_move_possible()                                                      */
  1225. /*    Untersucht, ob ein Verschieben (den Spielregeln entsprechend) möglich */
  1226. /*    ist.                                                                  */
  1227. /* ->  Nummer der (obersten) zu bewegenden Karte und Nummer der Zielreihe */
  1228. /* <-  1 = alles ok, 0 = Zug ist nicht möglich                              */
  1229. /*------------------------------------------------------------------------*/
  1230.  
  1231.  
  1232. int is_move_possible(int source, int dest)
  1233. {
  1234.     int j;
  1235.  
  1236.  
  1237.     /* Rücknahme von der Endablage ist nicht erlaubt !                      */
  1238.  
  1239.     if ((card[source].column >= N) && (card[source].column < N + 4))
  1240.         return(0);
  1241.  
  1242.     /* Bei Reihe als Ziel auf Kompatibilität mit dem Wert der letzten      */
  1243.     /* Karte in der Reihe untersuchen                                      */
  1244.  
  1245.     if (dest <= NUM_COLUMNS)
  1246.     {
  1247.         if ((j = column[dest].first_card) == NO_CARD)
  1248.             return(1);
  1249.         while (card[j].next_card != NO_CARD)
  1250.             j = card[j].next_card;
  1251.  
  1252.         return(((source & 1) ^ (j & 1)) &&
  1253.                                          ((j >> 2) == ((source >> 2) + 1)));
  1254.     }
  1255.  
  1256.     /* Bei Ablage auf der Endablage untersuchen, ob die Karte paßt          */
  1257.  
  1258.     if (dest < N + 4)
  1259.     {
  1260.         if (card[dest].prev_card == NO_CARD)
  1261.         {
  1262.             if (dest - N != source)
  1263.                 return(0);
  1264.             else
  1265.                 return(1);
  1266.         }
  1267.  
  1268.         if (((card[dest].prev_card & 3) == (source & 3)) &&
  1269.                          ((card[dest].prev_card >> 2) + 1 == (source >> 2)))
  1270.             return(1);
  1271.         else
  1272.             return(0);
  1273.     }
  1274.  
  1275.     /* Bei Zwischenablage als Ziel untersuchen, ob die Position frei ist  */
  1276.  
  1277.     if ((dest < (N + 8)) && (card[dest].prev_card == NO_CARD))
  1278.         return(1);
  1279.     else
  1280.         return(0);
  1281. }
  1282.  
  1283.  
  1284. /*------------------------------------------------------------------------*/
  1285. /* wait_for_left_release()                                                  */
  1286. /*    Wartet auf Loslassen der linken Maustaste.                              */
  1287. /*------------------------------------------------------------------------*/
  1288.  
  1289.  
  1290. void wait_for_left_release(void)
  1291. {
  1292.     int dummy;
  1293.  
  1294.     evnt_button(0, 1, 0, &dummy, &dummy, &dummy, &dummy);
  1295. }
  1296.  
  1297.  
  1298. /*------------------------------------------------------------------------*/
  1299. /* move_card()                                                              */
  1300. /*    Verschiebt einzelne Karte.                                              */
  1301. /* ->  Nummer der zu verschiebenden Karte, Nummer der Zielreihe (bzw.      */
  1302. /*       End- oder Zwischenablage) sowie Flag, das anzeigt, ob MBOX beim      */
  1303. /*       Verschieben gezeigt werden soll                                      */
  1304. /*------------------------------------------------------------------------*/
  1305.  
  1306.  
  1307. void move_card(int source, int dest, int mbox_flag)
  1308. {
  1309.     int j, dest_x, dest_y;
  1310.  
  1311.  
  1312.     /* AES an Aktionen auf dem Bildschirm hindern                          */
  1313.  
  1314.     wind_update(BEG_UPDATE);
  1315.  
  1316.     /* Falls erwünscht, MBOX von der Ausgangskarte zur Zielkarte anzeigen */
  1317.  
  1318.     if (mbox_flag)
  1319.     {
  1320.         if (dest >= N)                /* Karte auf End- oder Zwischenablage */
  1321.         {
  1322.             graf_mbox(CARD_WIDTH, CARD_LENGTH, card[source].x,
  1323.                                 card[source].y, card[dest].x, card[dest].y);
  1324.         }
  1325.         else                                     /* Anlegen an eien Reihe */
  1326.         {
  1327.             j = column[dest].first_card;
  1328.             if (j != NO_CARD)                      /* Zielreihe nicht leer */
  1329.             {
  1330.                 while (card[j].next_card != NO_CARD)
  1331.                     j = card[j].next_card;
  1332.  
  1333.                 dest_x = card[j].x;
  1334.                 dest_y = card[j].y;
  1335.             }
  1336.             else                                   /* Zielreihe noch leer */
  1337.             {
  1338.                 dest_x = column[dest].x;
  1339.                 dest_y = wwy + TOP_ROW;
  1340.             }
  1341.  
  1342.             graf_mbox(CARD_WIDTH, CARD_LENGTH, card[source].x,
  1343.                                            card[source].y, dest_x , dest_y);
  1344.         }
  1345.     }
  1346.  
  1347.     /* Zug abspeichern ...                                                  */
  1348.  
  1349.     if (!(menu[T1E4].ob_state & DISABLED))
  1350.         save_move(card[source].column, dest);
  1351.  
  1352.     /* Karte von ihrer alten Position entfernen                              */
  1353.  
  1354.     take_away(source);
  1355.  
  1356.     /* bei Ablage auf End- oder Zwischenablage :                          */
  1357.  
  1358.     if (dest >= N)
  1359.     {
  1360.         card[source].x = card[dest].x;
  1361.         card[source].y = card[dest].y;
  1362.         card[source].h = CARD_LENGTH;
  1363.         card[source].column = dest;
  1364.         card[source].prev_card = card[source].next_card = NO_CARD;
  1365.         card[dest].prev_card = source;
  1366.         show_card(source, ON);
  1367.  
  1368.     /* Bei Ablage auf Endablage Restkartenzahl dekrementieren              */
  1369.  
  1370.         if ((dest >= N) && (dest < N +4))
  1371.             remaining_cards--;
  1372.  
  1373.     /* AES-Aktionen auf dem Bildschirm wieder zulassen und fertig          */
  1374.  
  1375.         wind_update(END_UPDATE);
  1376.         return;
  1377.     }
  1378.     
  1379.     /* bei Ablage am Ende einer Reihe                                      */
  1380.  
  1381.     j = column[dest].first_card;
  1382.     if (j != NO_CARD)                      /* Reihe enthält schon Karte(n) */
  1383.     {
  1384.         while (card[j].next_card != NO_CARD)
  1385.             j = card[j].next_card;
  1386.         card[source].x = card[j].x;
  1387.         card[source].y = card[j].y + column[card[j].column].del_y;
  1388.         card[source].h = CARD_LENGTH;
  1389.         card[source].column = card[j].column;
  1390.         card[j].next_card = source; 
  1391.         card[source].prev_card = j;
  1392.         card[source].next_card = NO_CARD;
  1393.         card[j].h = column[dest].del_y;
  1394.     }
  1395.     else                  /* sonst bildet die neue Karte eine neue Reihe  */
  1396.     {
  1397.         card[source].x = column[dest].x;
  1398.         card[source].y = wwy + TOP_ROW;
  1399.         card[source].h = CARD_LENGTH;
  1400.         card[source].column = dest;
  1401.         card[source].prev_card = card[source].next_card = NO_CARD;
  1402.         column[dest].first_card = source;
  1403.     }
  1404.  
  1405.     /* Wenn die Reihe durch die neue Karte zu lang wird, um noch in das      */
  1406.     /* Fenster zu passen, muß die ganze Reihe neu gezeichnet werden,      */
  1407.     /* sonst nur die neue Karte ans Ende der Reihe zeichnen                  */
  1408.  
  1409.     if ((card[source].y + CARD_LENGTH) < (wwy + wwh - 1))
  1410.     {
  1411.         show_card(source, ON);
  1412.         if (column[card[source].column].h == 0)
  1413.             column[dest].h = CARD_LENGTH;
  1414.         else
  1415.             column[card[source].column].h +=
  1416.                                           column[card[source].column].del_y;
  1417.     }
  1418.     else
  1419.         show_column(card[source].column, column[card[source].column].x, ON);
  1420.  
  1421.     /* AES-Aktionen auf dem Bildschirm wieder zulassen                      */
  1422.  
  1423.     wind_update(END_UPDATE);
  1424. }
  1425.  
  1426.  
  1427. /*------------------------------------------------------------------------*/
  1428. /* take_away()                                                              */
  1429. /*    Entfernt Karte von ihrer augenblicklichen Position.                      */
  1430. /* ->  Nummer der zu entfernenden Karte                                      */
  1431. /*------------------------------------------------------------------------*/
  1432.  
  1433.  
  1434. void take_away(int card_no)
  1435. {
  1436.     int i;
  1437.  
  1438.  
  1439.     /* Clipping auf Bereich der Karte einstellen                          */
  1440.  
  1441.     clip_array[0] = MAX(card[card_no].x, 0);
  1442.     clip_array[1] = MAX(card[card_no].y, 0);
  1443.     clip_array[2] = MIN(card[card_no].x + CARD_WIDTH - 1, scr_x);
  1444.     clip_array[3] = MIN(card[card_no].y + CARD_LENGTH - 1, scr_y);
  1445.  
  1446.     vs_clip(wkst_handle, ON, clip_array);
  1447.  
  1448.     /* Wenn die Karte in einer Reihe liegt muß sie mit dem Muster des      */
  1449.     /* Hintergrunds übermalt werden und die darüberliegenden Karten z. T. */
  1450.     /* neu gemalt werden, u. U. muß bei gestauchten Reihen auch die ganze */
  1451.     /* Reihe neu gezeichnet werden                                          */
  1452.  
  1453.     if (card[card_no].column < NUM_COLUMNS)
  1454.     {
  1455.         paint_background();
  1456.  
  1457.         i = card[card_no].prev_card;
  1458.         if (i != NO_CARD)
  1459.         {
  1460.             card[i].h = CARD_LENGTH;
  1461.             card[i].next_card = NO_CARD;
  1462.             if (column[card[card_no].column].del_y == CARD_Y_SPAC)
  1463.             {
  1464.                 show_card(i, ON);
  1465.                 column[card[card_no].column].h -= CARD_Y_SPAC;
  1466.             }
  1467.             else
  1468.                 show_column(card[card_no].column,
  1469.                                         column[card[card_no].column].x, ON);
  1470.         }
  1471.  
  1472.     /* Bei der Zwischenablage muß nur diese neu (leer) gezeichnet werden, */
  1473.     /* bei der Endablage u. U. die darunterliegende Karte                  */
  1474.  
  1475.         else
  1476.         {
  1477.             column[card[card_no].column].first_card = NO_CARD;
  1478.             column[card[card_no].column].h = 0;
  1479.         }
  1480.     }
  1481.     else
  1482.     {
  1483.         if (card[card_no].column >= N + 4)
  1484.             card[card[card_no].column].prev_card = NO_CARD;
  1485.         else
  1486.         {
  1487.             if (card_no > 3)
  1488.                 card[card[card_no].column].prev_card -= 4;
  1489.             else
  1490.                 card[card[card_no].column].prev_card = NO_CARD;
  1491.         }
  1492.  
  1493.         if (card[card[card_no].column].prev_card == NO_CARD)
  1494.             show_card(card[card_no].column, ON);
  1495.         else
  1496.             show_card(card[card[card_no].column].prev_card, ON);
  1497.     }
  1498. }
  1499.  
  1500.  
  1501. /*------------------------------------------------------------------------*/
  1502. /* move_multi_cards()                                                      */
  1503. /*    Verschiebt eine ganze Reihe von Karten                                  */
  1504. /* ->  Nummer der obersten Karte der zu verschiebenden Reihe und Nummer      */
  1505. /*       der Zielreihe                                                      */
  1506. /*------------------------------------------------------------------------*/
  1507.  
  1508.  
  1509. void move_multi_cards(int source, int dest)
  1510. {
  1511.     int free_place[NUM_COLUMNS], max_place = 0, num_place;
  1512.     int free_temp[4], max_temp = 0, num_temp;
  1513.     int i, k, place_first = OFF;
  1514.  
  1515.  
  1516.     /* Zuerst die Lage der freien Reihen sowie ihre Anzahl bestimmen -      */
  1517.     /* eine leere Zielreihe darf aber nicht berücksichigt werden !          */
  1518.  
  1519.     for (i = 0; i < NUM_COLUMNS; i++)
  1520.     {
  1521.         if (i == dest)
  1522.             continue;
  1523.         if (column[i].first_card == NO_CARD)
  1524.             free_place[max_place++] = i;
  1525.     }
  1526.  
  1527.     /* Ebenso die Position und Anzahl der freien Zwischenablageplätze      */
  1528.  
  1529.     for (i = N + 4; i < N + 8; i++)
  1530.     {
  1531.         if (card[i].prev_card == NO_CARD)
  1532.             free_temp[max_temp++] = i;
  1533.     }
  1534.  
  1535.     /* Nun kommt die große Hin- und Herschieberei ...                      */
  1536.  
  1537.     free_place[max_place] = dest;
  1538.  
  1539.     num_temp = max_temp;
  1540.     num_place = max_place;
  1541.  
  1542.     /* Solange noch nicht alle freien Plätze belegt sind ...              */
  1543.  
  1544.     k = 0;
  1545.     while (k < max_place)
  1546.     {
  1547.         num_place = max_place;
  1548.  
  1549.     /* Alle freien Plätze über die Zwischenablage mit Karten belegen -      */
  1550.     /* wenn die letzte zu verschiebende Karte dabei erreicht wird ab-      */
  1551.     /* brechen                                                              */
  1552.  
  1553.         while (num_place > k)
  1554.         {
  1555.             if (move_column_to_temp(card[source].column, source, free_temp,
  1556.                                                                  &num_temp))
  1557.                 goto reverse_multi;
  1558.  
  1559.             if (move_single_card(card[source].column, source, free_place,
  1560.                                                              num_place - 1))
  1561.             {
  1562.                 place_first = ON;
  1563.                 goto reverse_multi;
  1564.             }
  1565.  
  1566.             move_temp_to_column(free_temp, &num_temp, max_temp,
  1567.                                              *(free_place + num_place - 1));
  1568.             num_place--;
  1569.         }
  1570.  
  1571.     /* Und diese auf die freien Plätze verteilten Karten wieder auf    den      */
  1572.     /* am weitesten links liegenden freien Plätze umschichten              */
  1573.  
  1574.         while (++num_place < max_place)
  1575.         {
  1576.             move_column_to_temp(*(free_place + num_place), NO_CARD,
  1577.                                                       free_temp, &num_temp);
  1578.             move_single_card(*(free_place + num_place), NO_CARD,
  1579.                                                              free_place, k);
  1580.             move_temp_to_column(free_temp, &num_temp, max_temp,
  1581.                                                          *(free_place + k));
  1582.         }
  1583.  
  1584.         k++;
  1585.     }
  1586.  
  1587.     /* Zum Schluß auch noch die wieder freien Zwischenablageplätze mit      */
  1588.     /* Karten füllen                                                      */
  1589.  
  1590.     move_column_to_temp(card[source].column, source, free_temp, &num_temp);
  1591.  
  1592. reverse_multi:
  1593.  
  1594.     /* Jetzt als erstes die letzte (oberste) Karte der zu verschiebenden  */
  1595.     /*  Reihe an die Zielreihe anlegen ...                                  */
  1596.  
  1597.     move_single_card(card[source].column, NO_CARD, free_place, max_place);
  1598.  
  1599.     /* ... und die Zwischenablage daran anlegen    (gegebenfalls vorher noch */
  1600.     /* die einzelne Karte vom freien Platz holen)                           */
  1601.  
  1602.     if (place_first)
  1603.         move_single_card(*(free_place + num_place - 1), NO_CARD, free_place,
  1604.                                                                  max_place);
  1605.  
  1606.     move_temp_to_column(free_temp, &num_temp, max_temp, dest);
  1607.  
  1608.     /* Zum Schluß die gesamten auf die freien Plätze umgeschichteten Kar- */
  1609.     /* ten anlegen. Zuerst die nicht vollständig umgelegten Haufen wieder */
  1610.     /* in richtiger Ordnung an die Zielreihe anlegen ...                  */
  1611.  
  1612.     k = num_place;
  1613.     while (k < max_place)
  1614.     {
  1615.         if (column[*(free_place + k)].first_card == NO_CARD)
  1616.             continue;
  1617.  
  1618.         move_column_to_temp(*(free_place + k), NO_CARD,
  1619.                                                       free_temp, &num_temp);
  1620.         move_single_card(*(free_place + k), NO_CARD, free_place, max_place);
  1621.         move_temp_to_column(free_temp, &num_temp, max_temp,
  1622.                                                  *(free_place + max_place));
  1623.         k++;
  1624.     }
  1625.  
  1626.     /* ... dann die restlichen Haufen auseinandernehmen und an die Ziel-  */
  1627.     /* reihe anlegen                                                      */
  1628.  
  1629.     while (num_place-- > 0)
  1630.     {
  1631.         /* Wenn keine Karte auf der Reihe liegt, nächste Reihe probieren  */
  1632.  
  1633.         if (column[*(free_place + num_place)].first_card == NO_CARD)
  1634.             continue;
  1635.  
  1636.         /* Reihe in Einzelteile zerlegen ...                              */
  1637.  
  1638.         k = max_place - 1;
  1639.         while (k > num_place)
  1640.         {
  1641.             move_column_to_temp(*(free_place + num_place), NO_CARD,
  1642.                                                       free_temp, &num_temp);
  1643.             move_single_card(*(free_place + num_place), NO_CARD, free_place,
  1644.                                                                          k);
  1645.             move_temp_to_column(free_temp, &num_temp, max_temp,
  1646.                                                          *(free_place + k));
  1647.             k--;
  1648.         }
  1649.  
  1650.         /* ... und nacheinander an der Zielreihe anlegen                  */
  1651.  
  1652.         k = num_place;
  1653.         while (k < max_place)
  1654.         {
  1655.             move_column_to_temp(*(free_place + k), NO_CARD,
  1656.                                                       free_temp, &num_temp);
  1657.             move_single_card(*(free_place + k), NO_CARD,
  1658.                                                      free_place, max_place);
  1659.             move_temp_to_column(free_temp, &num_temp, max_temp,
  1660.                                                  *(free_place + max_place));
  1661.             k++;
  1662.         }
  1663.     }
  1664. }
  1665.  
  1666.  
  1667. /*------------------------------------------------------------------------*/
  1668. /* move_temp_to_column()                                                  */
  1669. /*    Legt den Inhalt der Zwischenablage, der dort vorher mit der Funktion  */
  1670. /*    move_column_to_temp() abgelegt wurde in richtiger Reihenfolge wieder  */
  1671. /*    an einer Reihe an. (Diese Funktion wird nur von move_multi_cards()      */
  1672. /*    benötigt.)                                                              */
  1673. /* ->  Pointer auf Liste der von move_column_to_temp() verwendeten freien */
  1674. /*       Plätze in der Zwischenablage, Pointer auf Anzahl der zu verschie-  */
  1675. /*       benden Karten, maximale Anzahl der freien Plätze in der Zwischen-  */
  1676. /*       ablage sowie Nummer der Zielreihe                                  */
  1677. /*------------------------------------------------------------------------*/
  1678.  
  1679.  
  1680. void move_temp_to_column(int *free_temp, int *act_temp, int max_temp,
  1681.                                                                    int dest)
  1682. {
  1683.     int next;
  1684.  
  1685.  
  1686.     /* Zuerst die letzte Karte der Zielreihe bestimmen                      */
  1687.  
  1688.     next = column[dest].first_card;
  1689.     while (card[next].next_card != NO_CARD)
  1690.         next = card[next].next_card;
  1691.  
  1692.     /* Nun alle Karten von der Zwischenablage auf die Reihe schieben      */
  1693.  
  1694.     while (++(*act_temp) < max_temp)
  1695.         move_card(card[*(free_temp + *act_temp)].prev_card, dest, ON);
  1696. }
  1697.  
  1698.  
  1699. /*------------------------------------------------------------------------*/
  1700. /* move_single_card()                                                      */
  1701. /*    Verschiebt eine einzelne Karte von einer Reihe zu einer anderen.      */
  1702. /*    (Diese Funktion wird nur von move_multi_cards() benötigt.)              */
  1703. /* ->  Nummer der Ausgangsreihe, Nummer der obersten Karte der insgesamt  */
  1704. /*       zu bewegenden Reihe, Liste der leeren Reihen sowie Anzahl der      */
  1705. /*       freien Reihen                                                      */
  1706. /* <-  1 = Karte über der bewegten Karte ist die oberste Karte der insge- */
  1707. /*       samt zu bewegenden Reihe, 0 = sonst                                  */
  1708. /*------------------------------------------------------------------------*/
  1709.  
  1710.  
  1711. int move_single_card(int source_column, int final_card, int *free_place,
  1712.                                                          int act_free_place)
  1713. {
  1714.     int next, inter;
  1715.  
  1716.     /* Wenn gar keine Karte da ist sofort abbrechen                          */
  1717.  
  1718.     if ((next = column[source_column].first_card) == NO_CARD)
  1719.         return(0);
  1720.  
  1721.     /* Sonst die zu verschiebende Karte bestimmen ...                      */
  1722.     
  1723.     while (card[next].next_card != NO_CARD)
  1724.         next = card[next].next_card;
  1725.  
  1726.     inter = card[next].prev_card;
  1727.  
  1728.     /* ... und verschieben                                                  */
  1729.  
  1730.     move_card(next, *(free_place + act_free_place), ON);
  1731.  
  1732.     if (inter == final_card)
  1733.         return(1);
  1734.     else
  1735.         return(0);
  1736. }
  1737.  
  1738.  
  1739. /*------------------------------------------------------------------------*/
  1740. /* move_column_to_temp()                                                  */
  1741. /*    Verschiebt die Karten aus einer Reihe in die Zwischenablage, bis die- */
  1742. /*    gefüllt ist oder aber die nächste zu verschiedene Karte die oberste      */
  1743. /*    Karte der zu verschiebenden Reihe ist. (Diese Funktion wird nur von      */
  1744. /*    move_multi_cards() benötigt.)                                          */
  1745. /* ->  Nummer der Ausgangsreihe, Nummer der letzten überhaupt zu ver-      */
  1746. /*       schiebenden Karte, Array mit Nummern der freien Zwischenablage-      */
  1747. /*       plätze sowie Pointer auf deren Anzahl                              */
  1748. /* <-  1 = Karte über der bewegten Karte ist die oberste Karte der insge- */
  1749. /*       samt zu bewegenden Reihe, 0 = sonst                                  */
  1750. /*------------------------------------------------------------------------*/
  1751.  
  1752.  
  1753. int move_column_to_temp(int source_column, int final_card, int *free_temp,
  1754.                                                          int *act_free_temp)
  1755. {
  1756.     int next, inter;
  1757.  
  1758.  
  1759.     /* Wenn gar keine Karte da ist sofort abbrechen                          */
  1760.  
  1761.     if ((next = column[source_column].first_card) == NO_CARD)
  1762.         return(0);
  1763.  
  1764.     /* Sonst erst einmal die unterste zu verschiebende Karte bestimmen      */
  1765.  
  1766.     while (card[next].next_card != NO_CARD)
  1767.         next = card[next].next_card;
  1768.  
  1769.     /* Nun soviele Karten in die Zwischenablage schieben, bis sie entwe-  */
  1770.     /* der voll ist oder die nächste zu verschiebende Karte die oberste      */
  1771.     /* der zu verschiebenden Reihe ist (oder die Reihe leer ist)          */
  1772.  
  1773.     (*act_free_temp)--;
  1774.     while (*act_free_temp >= 0)
  1775.     {
  1776.         inter = card[next].prev_card;
  1777.  
  1778.         move_card(next, *(free_temp + *act_free_temp), ON);
  1779.         (*act_free_temp)--;
  1780.  
  1781.         if (inter == NO_CARD)
  1782.             return(0);
  1783.  
  1784.         if (inter == final_card)
  1785.             return(1);
  1786.         else
  1787.             next = inter;
  1788.     }
  1789.  
  1790.     return(0);
  1791. }
  1792.  
  1793.  
  1794. /*------------------------------------------------------------------------*/
  1795. /* move_multi_to_temp()                                                      */
  1796. /*    Verschiebt mehrere Karten gleichzeitig in die Zwischenablage.          */
  1797. /* ->  Nummer der obersten Karte der zu verschiebenden Reihe              */
  1798. /*------------------------------------------------------------------------*/
  1799.  
  1800.  
  1801. void move_multi_to_temp(int card_no)
  1802. {
  1803.     int free_temp[4], num_temp = 0, i, no = 1, next;
  1804.  
  1805.  
  1806.     /* Zuerst Anzahl der freien Zwischenablageplätze bestimmen und Array  */
  1807.     /* mit ihren Nummern besetzen                                          */
  1808.  
  1809.     for (i = N + 4; i < N + 8; i++)
  1810.     {
  1811.         if (card[i].prev_card == NO_CARD)
  1812.             free_temp[num_temp++] = i;
  1813.     }
  1814.  
  1815.     /* Anzahl der auf Zwischenablage zu verschienenden Karten bestimmen      */
  1816.  
  1817.     next = card_no;
  1818.     while ((next = card[next].next_card) != NO_CARD)
  1819.         no++;
  1820.  
  1821.     /* Abbruch, wenn die Anzahl der freien Plätze nicht ausreicht          */
  1822.  
  1823.     if (no > num_temp)
  1824.     {
  1825.         Cconout('\a');
  1826.         wait_for_left_release();
  1827.         return;
  1828.     }
  1829.  
  1830.     /* Karten auf die Zwischenablage verschieben                          */
  1831.  
  1832.     move_column_to_temp(card[card_no].column, card[card_no].prev_card,
  1833.                                                      free_temp, & num_temp);
  1834.  
  1835.     /* Warten, bis der linke Mausbutton wieder losgelassen ist (anderen-  */
  1836.     /* falls befindet sich die Maus u. U. noch auf einer Karte und die      */
  1837.     /* gedrücken Mausbuttons würden als Befehlswiederholung interpretiert */
  1838.  
  1839.     wait_for_left_release();
  1840. }
  1841.  
  1842.  
  1843. /*------------------------------------------------------------------------*/
  1844. /* show_card()                                                              */
  1845. /*    Dient zur tatsächliche Darstellung einer Karte auf dem Bildschirm.      */
  1846. /* ->  Nummer der darzustellenden Karte sowie Flag, das anzeigt, ob Clip- */
  1847. /*       ping-Bereich gesetzt werden soll (bei Aufruf dieser Funktion durch */
  1848. /*       wind_redraw() ist Clipping bereits gesetzt)                          */
  1849. /*------------------------------------------------------------------------*/
  1850.  
  1851.  
  1852. void show_card(int card_no, int clip_flag)
  1853. {
  1854.     int copy_array[8];
  1855.     MFDB source, dest;
  1856.  
  1857.  
  1858.     /* MFDBs für Kopieren der Karten vorbereiten                          */
  1859.  
  1860.     source.fd_w = CARD_WIDTH;
  1861.     source.fd_h = CARD_LENGTH;
  1862.     source.fd_wdwidth = CARD_WIDTH / 16;
  1863.     source.fd_stand = 0;
  1864.     source.fd_nplanes = nplanes;
  1865.     
  1866.     dest.fd_addr = 0L;
  1867.  
  1868.     /* Array mit Positionen fürs Kopieren vorbereiten                      */
  1869.  
  1870.     copy_array[0] = copy_array[1] = 0;
  1871.     copy_array[2] = CARD_WIDTH - 1;
  1872.     copy_array[3] = CARD_LENGTH - 1;
  1873.  
  1874.     copy_array[4] = card[card_no].x;
  1875.     copy_array[5] = card[card_no].y;
  1876.     copy_array[6] = copy_array[4] + CARD_WIDTH - 1;
  1877.     copy_array[7] = copy_array[5] + CARD_LENGTH - 1;
  1878.  
  1879.     v_hide_c(wkst_handle);
  1880.  
  1881.     /* Wenn Clipping gesetzt werden soll, dies auf Bereich der Karte ein- */
  1882.     /* stellen                                                              */
  1883.  
  1884.     if (clip_flag)
  1885.     {
  1886.         clip_array[0] = MAX(copy_array[4], 0);
  1887.         clip_array[1] = MAX(copy_array[5], 0);
  1888.         clip_array[2] = MIN(copy_array[6], scr_x);
  1889.         clip_array[3] = MIN(copy_array[7], scr_y);
  1890.         vs_clip(wkst_handle, ON, copy_array + 4);
  1891.     }
  1892.  
  1893.     /* Maske auf neue Position (mit AND-Verknüpfung) kopieren              */
  1894.  
  1895.     source.fd_addr = (void *) (pic + 57 * CARD_SIZE * nplanes);
  1896.     vro_cpyfm(wkst_handle, S_AND_D, copy_array, &source, &dest);
  1897.  
  1898.     /* Karte (mit OR-Verknüpfung) auf neue Position kopieren                */
  1899.  
  1900.     source.fd_addr = (void *) (pic + MIN(card_no, N + 4) * CARD_SIZE *
  1901.                                                                    nplanes);
  1902.     vro_cpyfm(wkst_handle, S_OR_D, copy_array, &source, &dest);
  1903.  
  1904.     v_show_c(wkst_handle, 0);
  1905. }
  1906.  
  1907.  
  1908. /*------------------------------------------------------------------------*/
  1909. /* shuffle()                                                              */
  1910. /*    Dient zum Mischen der Karten sowie der anschließenden Verkettung der  */
  1911. /*    Karten zu Listen für die einzelnen Reihen.                              */
  1912. /*------------------------------------------------------------------------*/
  1913.  
  1914.  
  1915. void shuffle(void)
  1916. {
  1917.     int s_array[N];                    /* Array für Mischen der Karten          */
  1918.     int index, i, j, k;
  1919.     double f_index;
  1920.  
  1921.  
  1922.     /* Zähler für Anzahl der bereits erfolgten Züge auf Null setzen und      */
  1923.     /* den für Anzahl der Karten auf der Spielfläche auf N                  */
  1924.  
  1925.     move_no = 0;
  1926.     remaining_cards = N;
  1927.  
  1928.     /* Speicherbereiche für Speicherung der Züge des letzten Spiels frei- */
  1929.     /* geben                                                              */
  1930.  
  1931.     if (no_history)
  1932.     {
  1933.         if (history)
  1934.         {
  1935.             no_history = OFF;
  1936.             menu_ienable(menu, T1E4, ON);
  1937.         }
  1938.     }
  1939.     else
  1940.     {
  1941.         while (!shorten_history())
  1942.             ;
  1943.     }
  1944.  
  1945.     /* Array fürs Mischen (geordnet) vorbesetzen                          */
  1946.  
  1947.     for (i = 0; i < N; i++)
  1948.         *(s_array + i) = i;
  1949.  
  1950.     /* Mischen, indem zuerst die letzte Karte mit irgendeiner anderen      */
  1951.     /* vertauscht wird, dann die vorletzte, dann die vorvorletzte ...      */
  1952.  
  1953.     for (i = N - 1; i > 0; i--)
  1954.     {
  1955.         f_index = (double) i * random_generator();
  1956.         index = (int) (2.0 * f_index) - (int) f_index;
  1957.         k = *(s_array + i);
  1958.         *(s_array + i) = *(s_array + index);
  1959.         *(s_array + index) = k;
  1960.     }
  1961.  
  1962.     /* Liste der Karten verketten (erste Karte hat keinen Vorgänger, die  */
  1963.     /* letzte keinen Nachfolger)                                          */
  1964.  
  1965.     card[*s_array].prev_card = NO_CARD;
  1966.     card[*s_array].next_card = *(s_array + 1);
  1967.  
  1968.     for (i = 1; i < N - 1; i++)
  1969.     {
  1970.         card[*(s_array + i)].prev_card = *(s_array + i - 1);
  1971.         card[*(s_array + i)].next_card = *(s_array + i + 1);
  1972.     }
  1973.  
  1974.     card[*(s_array + N - 1)].prev_card = *(s_array + N - 2);
  1975.     card[*(s_array + N - 1)].next_card = NO_CARD;
  1976.  
  1977.     /* Liste in Teilketten für einzelne Reihen zerlegen (die erste Karte  */
  1978.     /* in einer Reihe hat keinen Vorgänger, die letzte keinen Nachfolger) */
  1979.  
  1980.     for (i = *s_array, j = 0; j < NUM_COLUMNS; j++)
  1981.     {
  1982.         column[j].first_card = i;
  1983.         card[i].prev_card = NO_CARD;
  1984.  
  1985.         for (k = 0; k < ((j < 4) ? 6 : 5); k++)
  1986.             i = card[i].next_card;
  1987.  
  1988.         k = card[i].next_card;
  1989.         card[i].next_card = NO_CARD;
  1990.         i = k;
  1991.     }
  1992.  
  1993.     /* Zeiger in den Strukturen für End- und Zwischenablage auf die dar-  */
  1994.     /* auf liegende Karte auf 'keine Karte' setzen                          */
  1995.  
  1996.     for (i = N; i < N + 8; i++)
  1997.         card[i].prev_card = NO_CARD;
  1998. }
  1999.  
  2000.  
  2001. /*------------------------------------------------------------------------*/
  2002. /* show_all()                                                              */
  2003. /*    Neudarstellung des gesamten Spielfeldes, also Zeichnen des Hinter-      */
  2004. /*    grundes, der Zwischen-und Endablage sowie der Karten. Außerdem werden */
  2005. /*    dabei diverse Einträge in den Strukturen für die Karten gesetzt.      */
  2006. /* ->  Flag, das anzeigt, ob die gesamte Spielfläche oder nur ein Aus-      */
  2007. /*       schnitt neu gezeichnet werden muß - im ersten Fall muß vorher      */
  2008. /*       der entsprechende Clipping-Bereich gesetzt sein                      */
  2009. /*------------------------------------------------------------------------*/
  2010.  
  2011.  
  2012. void show_all(int all_flag)
  2013. {
  2014.     int i, j, card_x;
  2015.  
  2016.  
  2017.     /* Hintergrund zeichnen                                                  */
  2018.  
  2019.     if (all_flag)
  2020.     {
  2021.         wind_update(BEG_UPDATE);
  2022.         clip_array[0] = MAX(wwx, 0);
  2023.         clip_array[1] = MAX(wwy, 0);
  2024.         clip_array[2] = MIN(wwx + www - 1, scr_x);
  2025.         clip_array[3] = MIN(wwy + wwh - 1, scr_y);
  2026.         vs_clip(wkst_handle, ON, clip_array);
  2027.     }
  2028.  
  2029.     paint_background();
  2030.  
  2031.     /* Plätze für die Zwischenablage zeichnen, vorher einige Einträge in  */
  2032.     /* den Strukturen (neu) setzen                                          */
  2033.  
  2034.     card_x = wwx + CARD_X_SPAC;
  2035.     for (i = N + 4; i < N + 8; i++, card_x += CARD_WIDTH + CARD_X_SPAC)
  2036.     {
  2037.         card[i].x = card_x;
  2038.         card[i].y = wwy + 3;
  2039.         card[i].h = CARD_LENGTH;
  2040.         if (card[i].prev_card == NO_CARD)
  2041.             show_card(i, all_flag);
  2042.         else
  2043.         {
  2044.             j = card[i].prev_card;
  2045.             card[j].x = card_x;
  2046.             card[j].y = wwy + 3;
  2047.             card[j].h = CARD_LENGTH;
  2048.             show_card(j, all_flag);
  2049.         }
  2050.     }
  2051.  
  2052.     /* Plätze für Endablage zeichnen, ebenfalls einige Einträge in den      */
  2053.     /* Strukuren (neu) setzen                                              */
  2054.  
  2055.     card_x = wwx + MAX((www - 4 * (CARD_WIDTH + CARD_X_SPAC)),
  2056.                               (www - 8 * CARD_WIDTH - 7 * CARD_X_SPAC) / 2);
  2057.     for (i = N; i < N + 4; i++, card_x += CARD_WIDTH + CARD_X_SPAC)
  2058.     {
  2059.         
  2060.         card[i].x = card_x;
  2061.         card[i].y = wwy + 3;
  2062.         card[i].h = CARD_LENGTH;
  2063.         if (card[i].prev_card == NO_CARD)
  2064.             show_card(i, all_flag);
  2065.         else
  2066.         {
  2067.             j = card[i].prev_card;
  2068.             while (j >= 0)
  2069.             {
  2070.                 card[j].x = card_x;
  2071.                 card[j].y = wwy + 3;
  2072.                 card[j].h = CARD_LENGTH;
  2073.                 j -= 4;
  2074.             }
  2075.             show_card(card[i].prev_card, all_flag);
  2076.         }
  2077.     }
  2078.  
  2079.     /* Karten auslegen indem alle Reihen gezeichnet werden                  */
  2080.  
  2081.     card_x = wwx + (www - NUM_COLUMNS * CARD_WIDTH - (NUM_COLUMNS - 1) *
  2082.                                                            CARD_X_SPAC) / 2;
  2083.     for (i = 0; i < NUM_COLUMNS; i++, card_x += CARD_WIDTH + CARD_X_SPAC)
  2084.         show_column(i, card_x, all_flag);
  2085.  
  2086.     /* AES-Aktionen auf dem Bildschirm wieder zulassen                      */
  2087.  
  2088.     if (all_flag)
  2089.         wind_update(END_UPDATE);
  2090. }
  2091.  
  2092.  
  2093. /*------------------------------------------------------------------------*/
  2094. /* show_column()                                                          */
  2095. /*    Darstellung einer ganzen Reihe inklusive der Berechnung der Über-      */
  2096. /*    lappungslänge der Karten.                                              */
  2097. /* ->  Nummer der Reihe, deren x-Position sowie Flag, das anzeigt, ob      */
  2098. /*       kein Clipping gesetzt wird (nur für Weitergabe an show_card()      */
  2099. /*       und clear_column() von Bedeutung)                                   */
  2100. /*------------------------------------------------------------------------*/
  2101.  
  2102.  
  2103. void show_column(int col_no, int card_x, int clip_flag)
  2104. {
  2105.     int j, k;
  2106.     int card_y, del_y;
  2107.  
  2108.  
  2109.     /* Paramter in Struktur für Reihe setzen                              */
  2110.  
  2111.     column[col_no].x = card_x;
  2112.     column[col_no].h = 0;
  2113.     column[col_no].del_y = CARD_Y_SPAC;
  2114.  
  2115.     /* Schon fertig, wenn die Reihe keine Karte enthält                      */
  2116.  
  2117.     if ((k = column[col_no].first_card) == NO_CARD)
  2118.         return;
  2119.  
  2120.     /* Sonst Anzahl der Karten in der Reihe bestimmen und daraus die      */
  2121.     /* Überlappungsbreite der Karten berechnen                              */
  2122.  
  2123.     j = 1;
  2124.     while ((k = card[k].next_card) != NO_CARD)
  2125.         j++;
  2126.  
  2127.     card_y = wwy + TOP_ROW;
  2128.     if (j > 1)
  2129.         del_y = MIN(CARD_Y_SPAC, (wwh - CARD_LENGTH - TOP_ROW) / (j - 1));
  2130.  
  2131.     column[col_no].del_y = del_y;
  2132.  
  2133.     /* Bereich der Reihe vollständig löschen ...                          */
  2134.  
  2135.     clear_column(col_no, clip_flag);
  2136.  
  2137.     /* ... und alle Karten der Reihe nach neu zeichnen                      */
  2138.  
  2139.     k = column[col_no].first_card;
  2140.     do
  2141.     {
  2142.         card[k].x = card_x;
  2143.         card[k].y = card_y;
  2144.         card[k].column = col_no;
  2145.         if (card[k].next_card != NO_CARD)
  2146.             card[k].h = del_y;
  2147.         else
  2148.             card[k].h = CARD_LENGTH;
  2149.  
  2150.         show_card(k, clip_flag);
  2151.  
  2152.         column[col_no].h += card[k].h;
  2153.         card_y += del_y;
  2154.         k = card[k].next_card;
  2155.     } while (k != NO_CARD);
  2156. }
  2157.  
  2158.  
  2159. /*------------------------------------------------------------------------*/
  2160. /* automatic_remove()                                                      */
  2161. /*    Entfernt alle Karten aus dem Spiel, für die dies möglich ist und die  */
  2162. /*    mit Sicherheit nicht mehr im Verlauf des Spiels gebraucht werden.      */
  2163. /* <-  1 = Spiel ist zu Ende, 0 = noch nicht alle Karten abgelegt          */
  2164. /*------------------------------------------------------------------------*/
  2165.  
  2166.  
  2167. int automatic_remove(void)
  2168. {
  2169.     int i, j;
  2170.     int value;
  2171.     int no_remove;
  2172.  
  2173.  
  2174.     /* Solange Karten entfernen, bis keine zu entfernende Karte mehr ge-  */
  2175.     /* funden wird                                                          */
  2176.  
  2177.     do
  2178.     {
  2179.         no_remove = ON;
  2180.  
  2181.         /* Zuerst mögliche Züge von der Zwischenablage aus untersuchen      */
  2182.  
  2183.         for (i = N + 4; i < N + 8; i++)
  2184.         {
  2185.  
  2186.         /* Nächsten Platz testen, wenn der aktuelle Zwischenablageplatz      */
  2187.         /* keine Karte enthält                                              */
  2188.  
  2189.             if (card[i].prev_card == NO_CARD)
  2190.                 continue;
  2191.  
  2192.         /* Ebenfalls, wenn Karte nicht auf entsprechende Endablage paßt      */
  2193.  
  2194.             value = card[i].prev_card >> 2;
  2195.             if (value - 1 !=
  2196.                          (card[(card[i].prev_card & 3) + N].prev_card >> 2))
  2197.                 continue;
  2198.  
  2199.         /* Oder auch, wenn niedrigere Karten der Gegenfarbe noch nicht      */
  2200.         /* abgelegt sind (außer bei As und 2)                              */
  2201.  
  2202.             if (value > 1)
  2203.             {
  2204.                 if (card[i].prev_card & 1)
  2205.                 {
  2206.                     if (((card[N].prev_card >> 2 ) < value - 1) ||
  2207.                                 ((card[N + 2].prev_card >> 2 ) < value - 1))
  2208.                         continue;
  2209.                 }
  2210.                 else
  2211.                 {
  2212.                     if (((card[N + 1].prev_card >> 2 ) < value - 1) ||
  2213.                                 ((card[N + 3].prev_card >> 2 ) < value - 1))
  2214.                         continue;
  2215.                 }
  2216.             }
  2217.  
  2218.         /* Sonst Karte auf Endablage legen und Flag zurücksetzen          */
  2219.  
  2220.             move_card(card[i].prev_card, N + (card[i].prev_card & 3), ON);
  2221.             no_remove = OFF;
  2222.         }
  2223.  
  2224.         /* Nun auch alle Reihen untersuchen                                  */
  2225.  
  2226.         for (i = 0; i < NUM_COLUMNS; i++)
  2227.         {
  2228.  
  2229.         /* Weiter mit nächster Reihe wenn die Reihe keine Karten enthält  */
  2230.  
  2231.             if ((j = column[i].first_card) == NO_CARD)
  2232.                 continue;
  2233.  
  2234.         /* Letzte Karte der Reihe bestimmen                                  */
  2235.  
  2236.             for ( ; card[j].next_card != NO_CARD; j = card[j].next_card)
  2237.                 ;
  2238.  
  2239.         /* Weiter mit nächster Reihe, wenn Karte nicht auf die entspre-      */
  2240.         /* chende Endablage paßt                                          */
  2241.  
  2242.             value = j >> 2;
  2243.             if (value - 1 != (card[(j & 3) + N].prev_card >> 2))
  2244.                 continue;
  2245.  
  2246.         /* Oder wenn niedrigere Karten der Gegenfarbe noch nicht abgelegt */
  2247.         /* sind (außer bei As und 2)                                      */
  2248.  
  2249.             if (value > 1)
  2250.             {
  2251.                 if (j & 1)
  2252.                 {
  2253.                     if (((card[N].prev_card >> 2 ) < value - 1) ||
  2254.                                 ((card[N + 2].prev_card >> 2 ) < value - 1))
  2255.                         continue;
  2256.                 }
  2257.                 else
  2258.                 {
  2259.                     if (((card[N + 1].prev_card >> 2 ) < value - 1) ||
  2260.                                 ((card[N + 3].prev_card >> 2 ) < value - 1))
  2261.                         continue;
  2262.                 }
  2263.             }
  2264.  
  2265.         /* Sonst Karte auf Endablage legen und Flag zurücksetzen          */
  2266.  
  2267.             move_card(j, N + (j & 3), ON);
  2268.             no_remove = OFF;
  2269.         }
  2270.     } while (!no_remove);
  2271.  
  2272.     if (remaining_cards == 0)
  2273.         return(1);
  2274.     else
  2275.         return(0);
  2276. }
  2277.  
  2278.  
  2279. /*------------------------------------------------------------------------*/
  2280. /* make_seed()                                                              */
  2281. /*    Berechnet (aus Zähler des 200-Hz-Timer-Interrupts und dem Datum) eine */
  2282. /*    sechsstellige Pseudozufallszahl (0 <= x < 1), die als Ausgangszahl      */
  2283. /*    für den Zufallsgenerators für das Mischen verwendet wird.              */
  2284. /* <-  Pseudozufallszahl                                                  */
  2285. /*------------------------------------------------------------------------*/
  2286.  
  2287.  
  2288. double make_seed(void)
  2289. {
  2290.     long old_stack, temp;
  2291.  
  2292.  
  2293.     /* Als Startwert des Zufallsgenerators die Summe aus Zahl der Timer-  */
  2294.     /* Interrupts und Datum (mod 1,000,000) verwenden                      */
  2295.  
  2296.     old_stack = Super(NULL);
  2297.     temp = *(long *) _hz_200;
  2298.     Super((void *) old_stack);
  2299.  
  2300.     temp += Gettime();
  2301.  
  2302.     return((double) (temp % 1000000L) * 1.E-6);
  2303. }
  2304.  
  2305.  
  2306. /*------------------------------------------------------------------------*/
  2307. /* random_generator()                                                      */
  2308. /*    Pseudozufallsgenerator für Zahlen 0 <= x < 1                          */
  2309. /* <- neue Pseudozufallszahl                                              */
  2310. /*------------------------------------------------------------------------*/
  2311.  
  2312.  
  2313. double random_generator(void)
  2314. {
  2315.     /* Zufallsgenerator aus dem Handbuch zum HP-41 (liefert    1,000,000      */
  2316.     /* verschiedene Zahlen zwischen 0 und 0.999999), dabei sicherstellen, */
  2317.     /* daß nicht durch Rundungsfehler mehr als 6 Stellen auftreten          */
  2318.  
  2319.     seed = fmod(9821.0 * seed + 0.211327, 1.0);
  2320.     seed = (floor(seed * 2.E6) - floor(seed * 1.E6)) * 1.E-6;
  2321.     return(seed);
  2322. }
  2323.  
  2324.  
  2325.  
  2326. /*------------------------------------------------------------------------*/
  2327. /* set_window_header()                                                      */
  2328. /*    Setzt die Startzufallszahl für das aktuelle Spiel in die Titelzeile      */
  2329. /*    des Fensters des Spiels (Wert der Zahl zwischen 0 und 999999).          */
  2330. /* ->  Pointer auf String mit Titelzeile                                  */
  2331. /*------------------------------------------------------------------------*/
  2332.  
  2333.  
  2334. void set_wind_header(char *title)
  2335. {
  2336.     ltoa((long) (old_seed * 1.E6), title + 11, 10);
  2337.     strcat(title, " ");
  2338.     wind_set(wind_handle, WF_NAME, (int) ((long) title >> 16),
  2339.                                          (int) ((long) title & 0x0000FFFF));
  2340. }
  2341.  
  2342.  
  2343. /*------------------------------------------------------------------------*/
  2344. /* paint_background()                                                      */
  2345. /*    Zeichnen des Hintergrundes des Spielfeldes.                              */
  2346. /*------------------------------------------------------------------------*/
  2347.  
  2348.  
  2349. void paint_background(void)
  2350. {
  2351.     int clear_array[4];
  2352.  
  2353.  
  2354.     /* Array mit Maßen der sichtbaren Arbeitsfläche des Fensters besetzen */
  2355.  
  2356.     clear_array[0] = wwx;
  2357.     clear_array[1] = wwy;
  2358.     clear_array[2] = MIN(wwx + www - 1, scr_x);
  2359.     clear_array[3] = MIN(wwy + wwh - 1, scr_y);
  2360.  
  2361.     /* Maus ausschalten und mit Muster des Hintergrundes übermalen          */
  2362.  
  2363.     graf_mouse(M_OFF, 0);
  2364.     v_bar(wkst_handle, clear_array);
  2365.     graf_mouse(M_ON, 0);
  2366. }
  2367.  
  2368.  
  2369. /*------------------------------------------------------------------------*/
  2370. /* clear_column()                                                          */
  2371. /*    Löscht den Bereich einer Reihe durch Übermalen mit dem Muster des      */
  2372. /*    Spielfeldhintergrundes.                                                  */
  2373. /* ->  Nummer der zu löschenden Reihe und Flag, das anzeigt, ob Clipping- */
  2374. /*       Bereich auf den gesamten Bereich der Reihe gesetzt werden soll      */
  2375. /*       oder auf nur Schnitfläche mit bereits gesetzten Clipping-Bereich      */
  2376. /*------------------------------------------------------------------------*/
  2377.  
  2378.  
  2379. void clear_column(int col, int clip_flag)
  2380. {
  2381.     int old_clip[4], i;
  2382.  
  2383.  
  2384.     /* Wenn Flag nicht gesetzt, alten Clippingbereich zwischenspeichern      */
  2385.     /* und Clipping auf Schnittfläche mit der Reihe setzen                  */
  2386.  
  2387.     if (!clip_flag)
  2388.     {
  2389.         if ((column[col].x + CARD_WIDTH - 1 < clip_array[0]) ||
  2390.                 (column[col].x > clip_array[2]) ||
  2391.                     (wwy + wwh - 1 < clip_array[1]) ||
  2392.                         (wwy + TOP_ROW > clip_array[3]))
  2393.             return;
  2394.  
  2395.         for (i = 0; i < 4; i++)
  2396.             old_clip[i] = clip_array[i];
  2397.  
  2398.         clip_array[0] = MAX(MAX(column[col].x, clip_array[0]), 0);
  2399.         clip_array[1] = MAX(MAX(wwy + TOP_ROW, clip_array[1]), 0);
  2400.         clip_array[2] = MIN(MIN(column[col].x + CARD_WIDTH - 1,
  2401.                                                      clip_array[2]), scr_x);
  2402.         clip_array[3] = MIN(MIN(wwy + wwh - 1, clip_array[3]), scr_y);
  2403.     }
  2404.     else
  2405.     {
  2406.         clip_array[0] = MAX(column[col].x, 0);
  2407.         clip_array[1] = MAX(wwy + TOP_ROW, 0);
  2408.         clip_array[2] = MIN(column[col].x + CARD_WIDTH - 1, scr_x);
  2409.         clip_array[3] = MIN(wwy + wwh - 1, scr_y);
  2410.     }
  2411.  
  2412.     vs_clip(wkst_handle, ON, clip_array);
  2413.  
  2414.     /* Übermalen durch Hintergrundmuster                                  */
  2415.  
  2416.     paint_background();
  2417.  
  2418.     /* U. U. wieder alten Clippingbereich setzen                          */
  2419.  
  2420.     if (!clip_flag)
  2421.     {
  2422.         for (i = 0; i < 4; i++)
  2423.             clip_array[i] = old_clip[i];
  2424.         vs_clip(wkst_handle, ON, clip_array);
  2425.     }
  2426. }
  2427.  
  2428.  
  2429. /*------------------------------------------------------------------------*/
  2430. /* gem_init()                                                              */
  2431. /*    Meldet eine Applikation an, öffnet eine virtuelle Workstation (mit      */
  2432. /*    dem Handle 'wkst_handle') und erzeugt ein unterlegtes Fenster (mit      */
  2433. /*  dem Handle 'wind_handle').                                              */
  2434. /* ->  Pointer auf String mit Titel des Fensters                          */
  2435. /* <-  1 bei erfolgreichem Abschluß, 0 bei Fehler                          */
  2436. /*------------------------------------------------------------------------*/
  2437.  
  2438.  
  2439. int gem_init(char *title)
  2440. {
  2441.     int work_in[11],                  /* Eingabe- und Ausgabeparameter       */
  2442.         work_out[57];                  /* für Öffnen der Workstation          */
  2443.     int gl_hchar,                      /* Höhe und Breite eines Zeichens      */
  2444.         gl_wchar,                      /* aus dem Standardzeichensatz      */
  2445.         gl_hbox,                      /* und die einer Box, in die die    */
  2446.         gl_wbox;                      /* Zeichen hineinpassen              */
  2447.  
  2448.  
  2449.     if ((ap_id = appl_init()) == -1)            /* Applikation anmelden   */
  2450.         return(0);                                /* ... mißlungen          */
  2451.  
  2452.     wkst_handle = graf_handle(&gl_wchar, &gl_hchar,      /* Handle der Work- */
  2453.                               &gl_wbox, &gl_hbox);      /* station besorgen */
  2454.  
  2455.     work_in[0]  = wkst_handle;       /* verschiedene Parameter der zu öff-  */
  2456.                                    /* nenden Workstation festsetzen          */
  2457.     work_in[1]  = 1;               /* Linientyp = durchgezogen              */
  2458.     work_in[2]  = BLACK;           /* Linienfarbe = schwarz                  */
  2459.     work_in[3]  = 1;               /* Markertyp = Punkt                      */
  2460.     work_in[4]  = BLACK;           /* Markerfarbe = schwarz                  */
  2461.     work_in[5]  = 0;               /* Textstil = Normalschrift              */
  2462.     work_in[6]  = BLACK;           /* Textfarbe = schwarz                  */
  2463.     work_in[7]  = 2;               /* Fülltyp                              */
  2464.     work_in[8]  = 8;               /* Füllmuster-Index                      */
  2465.     work_in[9]  = WHITE;           /* Füllmuster-Farbe                      */
  2466.     work_in[10] = 2;               /* Rasterkoordinaten                      */
  2467.  
  2468.     v_opnvwk(work_in, &wkst_handle, work_out);     /* Workstation öffnen      */
  2469.  
  2470.     /* Anzahl der Bitplanes berechnen                                      */
  2471.  
  2472.     nplanes = 0;
  2473.     while (work_out[13] >>= 1)
  2474.         nplanes++;
  2475.  
  2476.     /* größte mögliche Bildschirmkoordinaten speichern                      */
  2477.  
  2478.     scr_x = work_out[0];
  2479.     scr_y = work_out[1];
  2480.  
  2481.     /* verschieden Attribute der Workstation setzen                          */
  2482.  
  2483.     vswr_mode(wkst_handle, MD_REPLACE);
  2484.     vsf_interior(wkst_handle, FIS_PATTERN);
  2485.     vsf_style(wkst_handle, 4);
  2486.     vsf_color(wkst_handle, BLACK);
  2487.     vsf_perimeter(wkst_handle, OFF);
  2488.     
  2489.     /* Fenster mit Mindestgrße des Arbeitsbereichs von 600 * 300 Punkten  */
  2490.     /* öffnen                                                              */    
  2491.  
  2492.     wind_get(0, WF_WORKXYWH, &wox, &woy, &wow, &woh);
  2493.     wind_calc(WC_WORK, NAME | CLOSER | FULLER | MOVER, wox, woy, wow, woh,
  2494.                                                     &wwx, &wwy, &www, &wwh);
  2495.  
  2496.     if ((www < 600) || (wwh < 300))
  2497.     {
  2498.         gem_exit();
  2499.         return(0);
  2500.     }
  2501.  
  2502.     /* Arbeitsfläche so setzen, daß das gesamte Fenster maximal den Bild- */
  2503.     /* schirm bei TT-Medium-Auflösung überdeckt - es wäre Blödsinn auch      */
  2504.     /* bei Großbildschirmen allen Platz zu okkupieren ...                  */
  2505.  
  2506.     www = MIN(www, 638);
  2507.     wwh = MIN(wwh, 442);
  2508.  
  2509.     wind_calc(WC_BORDER, NAME | CLOSER | FULLER | MOVER, wwx, wwy, www, wwh,
  2510.                                                     &wox, &woy, &wow, &woh);
  2511.  
  2512.     wind_handle = wind_create(NAME | CLOSER | FULLER | MOVER, wox, woy, wow,
  2513.                                                                        woh);
  2514.     if (wind_handle < 0)         /* kein Fenster mehr da ? -> Abbruch ... */
  2515.     {
  2516.         gem_exit();
  2517.         return(0);
  2518.     }
  2519.  
  2520.     wind_set(wind_handle, WF_NAME, (int) ((long) title >> 16),
  2521.                                          (int) ((long) title & 0x0000FFFF));
  2522.  
  2523.     if (!wind_open(wind_handle, wox, woy, wow, woh))
  2524.     {
  2525.         wind_delete(wind_handle);
  2526.         gem_exit();
  2527.         return(0);
  2528.     }
  2529.  
  2530.     return(1);
  2531. }
  2532.  
  2533.  
  2534. /*------------------------------------------------------------------------*/
  2535. /* gem_exit() schließt die virtuelle Workstation und meldet die Applika-  */
  2536. /* tion ab.                                                                  */
  2537. /*------------------------------------------------------------------------*/
  2538.  
  2539.  
  2540. void gem_exit()
  2541. {
  2542.     v_clsvwk(wkst_handle);                        /* Workstation schliessen */
  2543.     appl_exit();                                /* Applikation abmelden      */
  2544. }
  2545.  
  2546.  
  2547. /*------------------------------------------------------------------------*/
  2548. /* make_cards()                                                              */
  2549. /*    Dient zum Herstellen der Bilder der Karten - die Bilder sind zum Teil */
  2550. /*    im File 'VIERFREI.DAT' gespeichert, werden von dort in den vorher      */
  2551. /*    allozierten Speicherbereich eingelesen und nachbearbeitet.              */
  2552. /*    Ist eine ziemliche schweinische Bitfiddelei, deshalb auch nicht    son-  */
  2553. /*    derlich gut kommentiert - 'tschuldigung ...                              */
  2554. /*------------------------------------------------------------------------*/
  2555.  
  2556.  
  2557. int make_cards(void)
  2558. {
  2559.     int i, j, k;
  2560.     int value;
  2561.     long *act_pic;
  2562.     long card_pic[1316];
  2563.     int *from, *to;
  2564.     unsigned long kl_farbe[28];
  2565.     unsigned long gr_farbe[60];
  2566.     long act_card;
  2567.     FILE *fp;
  2568.  
  2569.  
  2570.     /* Speicherplatz für Bilder der Karten allozieren                      */
  2571.  
  2572.     if ((pic = (long *) Malloc(CARD_SIZE * (N + 6) * nplanes *
  2573.                                                      sizeof(long))) == NULL)
  2574.         return(0);
  2575.  
  2576.     /* File mit Daten für Bilder der Karten öffnen                          */
  2577.  
  2578.     if ((fp = fopen("VIERFREI.DAT", "rb")) == NULL)
  2579.     {
  2580.         Mfree(pic);
  2581.         return(0);
  2582.     }
  2583.  
  2584.     /* Halbbilder der Karten einlesen                                      */
  2585.  
  2586.     if (fread((void *) card_pic, sizeof(long), 1316, fp) != 1316)
  2587.     {
  2588.         Mfree(pic);
  2589.         return(0);
  2590.     }
  2591.  
  2592.     /* Muster für kleine Darstellung von Kreuz, Pik, Herz und Karo ein-      */
  2593.     /* lesen ...                                                          */
  2594.  
  2595.     if (fread((void *) kl_farbe, sizeof(long), 28, fp) != 28)
  2596.     {
  2597.         Mfree(pic);
  2598.         return(0);
  2599.     }
  2600.  
  2601.     /* ... und das selbe für die Muster für die große Darstellung          */
  2602.  
  2603.     if (fread((void *) gr_farbe, sizeof(long), 60, fp) != 60)
  2604.     {
  2605.         Mfree(pic);
  2606.         return(0);
  2607.     }
  2608.  
  2609.     fclose(fp);
  2610.  
  2611.     /* Bilder aller Karten aus den Daten erzeugen                          */
  2612.  
  2613.     act_pic = pic;
  2614.     for (k = 0; k < 52; k++, act_pic += CARD_SIZE)
  2615.     {
  2616.  
  2617.         value = k & 3;
  2618.         act_card = (k >> 2) * 94;
  2619.         for (i = 0; i < 94; i++)
  2620.             act_pic[i] = card_pic[act_card++];
  2621.  
  2622.         /* linke kleine Farbe nach act_pic                                  */
  2623.  
  2624.         switch (k >> 2)
  2625.         {
  2626.             case 0 : case 1 : case 2 : case 3 : case 4 :
  2627.             case 5 : case 6 : case 7 : case 8 :
  2628.                 for (i = 0; i < 7; i++)
  2629.                     act_pic[6 + 2 * i] |= kl_farbe[value * 7 + i] >> 13;
  2630.                 break;
  2631.  
  2632.             case 9 :
  2633.                 for (i = 0; i < 7; i++)
  2634.                     act_pic[6 + 2 * i] |= kl_farbe[value * 7 + i] >> 14;
  2635.                 break;
  2636.  
  2637.             case 10 : case 11 : case 12 :
  2638.                 for (i = 0; i < 7; i++)
  2639.                     act_pic[6 + 2 * i] |= kl_farbe[value * 7 + i] >> 12;
  2640.                 break;
  2641.         }
  2642.  
  2643.         /* rechte kleine Farbe nach act_pic                                  */
  2644.  
  2645.         switch (k >> 2)
  2646.         {
  2647.             case 0 : case 1 : case 2 : case 3 : case 4 :
  2648.             case 5 : case 6 : case 7 : case 8 :
  2649.                 for (i = 0; i < 7; i++)
  2650.                     act_pic[7 + 2 * i] |= kl_farbe[value * 7 + i] >> 12;
  2651.                 break;
  2652.  
  2653.             case 9 :
  2654.                 for (i = 0; i < 7; i++)
  2655.                     act_pic[7 + 2 * i] |= kl_farbe[value * 7 + i] >> 11;
  2656.                 break;
  2657.  
  2658.             case 10 : case 11 : case 12 :
  2659.                 for (i = 0; i < 7; i++)
  2660.                     act_pic[23 + 2 * i] |= kl_farbe[value * 7 + i] >> 20;
  2661.                 break;
  2662.         }
  2663.  
  2664.         /* große Farbe (teilweise) nach act_pic                              */
  2665.  
  2666.         switch (k >> 2)
  2667.         {
  2668.             case 1 :                                                 /* 2 */
  2669.                 for (i = 0; i < 15; i++)
  2670.                 {
  2671.                     act_pic[46 + 2 * i] |= gr_farbe[value * 15 + i] >> 25;
  2672.                     act_pic[47 + 2 * i] |= gr_farbe[value * 15 + i] << 7;
  2673.                 }
  2674.                 break;
  2675.  
  2676.             case 2 :                                                 /* 3 */
  2677.                 for (i = 0; i < 15; i++)
  2678.                 {
  2679.                     act_pic[40 + 2 * i] |= gr_farbe[value * 15 + i] >> 25;
  2680.                     act_pic[41 + 2 * i] |= gr_farbe[value * 15 + i] << 7;
  2681.                 }
  2682.                 break;
  2683.  
  2684.             case 3 :                                                 /* 4 */
  2685.                 for (i = 0; i < 15; i++)
  2686.                 {
  2687.                     act_pic[46 + 2 * i] |= gr_farbe[value * 15 + i] >> 13;
  2688.                     act_pic[47 + 2 * i] |= gr_farbe[value * 15 + i] >> 4;
  2689.                 }
  2690.                 break;
  2691.  
  2692.             case 4 :                                                 /* 5 */
  2693.                 for (i = 0; i < 15; i++)
  2694.                 {
  2695.                     act_pic[46 + 2 * i] |= gr_farbe[value * 15 + i] >> 13;
  2696.                     act_pic[47 + 2 * i] |= gr_farbe[value * 15 + i] >> 4;
  2697.                 }
  2698.                 break;
  2699.  
  2700.             case 5 :                                                 /* 6 */
  2701.                 for (i = 0; i < 15; i++)
  2702.                 {
  2703.                     act_pic[40 + 2 * i] |= gr_farbe[value * 15 + i] >> 13;
  2704.                     act_pic[41 + 2 * i] |= gr_farbe[value * 15 + i] >> 4;
  2705.                 }
  2706.                 break;
  2707.  
  2708.             case 6 :                                                 /* 7 */
  2709.                 for (i = 0; i < 15; i++)
  2710.                 {
  2711.                     act_pic[40 + 2 * i] |= gr_farbe[value * 15 + i] >> 14;
  2712.                     act_pic[41 + 2 * i] |= gr_farbe[value * 15 + i] >> 3;
  2713.                 }
  2714.                 break;
  2715.  
  2716.             case 7 :                                                 /* 8 */
  2717.                 for (i = 0; i < 15; i++)
  2718.                 {
  2719.                     act_pic[26 + 2 * i] |= gr_farbe[value * 15 + i] >> 14;
  2720.                     act_pic[27 + 2 * i] |= gr_farbe[value * 15 + i] >> 4;
  2721.                     act_pic[60 + 2 * i] |= gr_farbe[value * 15 + i] >> 14;
  2722.                     act_pic[61 + 2 * i] |= gr_farbe[value * 15 + i] >> 4;
  2723.                 }
  2724.                 break;
  2725.  
  2726.             case 8 :                                                 /* 9 */
  2727.                 for (i = 0; i < 15; i++)
  2728.                 {
  2729.                     act_pic[22 + 2 * i] |= gr_farbe[value * 15 + i] >> 13;
  2730.                     act_pic[23 + 2 * i] |= gr_farbe[value * 15 + i] >> 4;
  2731.                     act_pic[56 + 2 * i] |= gr_farbe[value * 15 + i] >> 13;
  2732.                     act_pic[57 + 2 * i] |= gr_farbe[value * 15 + i] >> 4;
  2733.                 }
  2734.                 break;
  2735.  
  2736.             case 9 :                                                /* 10 */
  2737.                 for (i = 0; i < 15; i++)
  2738.                 {
  2739.                     act_pic[22 + 2 * i] |= gr_farbe[value * 15 + i] >> 13;
  2740.                     act_pic[23 + 2 * i] |= gr_farbe[value * 15 + i] >> 4;
  2741.                     act_pic[62 + 2 * i] |= gr_farbe[value * 15 + i] >> 13;
  2742.                     act_pic[63 + 2 * i] |= gr_farbe[value * 15 + i] >> 4;
  2743.                     act_pic[42 + 2 * i] |= gr_farbe[value * 15 + i] >> 25;
  2744.                     act_pic[43 + 2 * i] |= gr_farbe[value * 15 + i] << 7;
  2745.                 }
  2746.                 break;
  2747.  
  2748.             case 10 :                                              /* Bube */
  2749.                 for (i = 0; i < 15; i++)
  2750.                     act_pic[20 + 2 * i] |= gr_farbe[value * 15 + i] >> 6;
  2751.                 break;
  2752.  
  2753.             case 11 :                                              /* Dame */
  2754.                 for (i = 0; i < 15; i++)
  2755.                     act_pic[18 + 2 * i] |= gr_farbe[value * 15 + i] >> 11;
  2756.                 break;
  2757.  
  2758.             case 12 :                                             /* König */
  2759.                 for (i = 0; i < 15; i++)
  2760.                     act_pic[20 + 2 * i] |= gr_farbe[value * 15 + i] >> 12;
  2761.                 break;
  2762.         }
  2763.  
  2764.         /* Karte punktspiegeln                                              */
  2765.  
  2766.         for (i = 94, j = i - 3; i < 186; j -= 2, i += 2)
  2767.             reverse_card(act_pic + j, act_pic + i);
  2768.  
  2769.         /* für einige Karten nochmal große Farbe nach act_pic              */
  2770.  
  2771.         switch (k >> 2)
  2772.         {
  2773.             case 0 : case 2 : case 4 : case 8 :               /* As, 3, 5, 9 */
  2774.                 for (i = 0; i < 15; i++)
  2775.                 {
  2776.                     act_pic[78 + 2 * i] |= gr_farbe[value * 15 + i] >> 25;
  2777.                     act_pic[79 + 2 * i] |= gr_farbe[value * 15 + i] << 7;
  2778.                 }
  2779.                 break;
  2780.  
  2781.             case 5 :                                                 /* 6 */
  2782.                 for (i = 0; i < 15; i++)
  2783.                 {
  2784.                     act_pic[78 + 2 * i] |= gr_farbe[value * 15 + i] >> 13;
  2785.                     act_pic[79 + 2 * i] |= gr_farbe[value * 15 + i] >> 4;
  2786.                 }
  2787.                 break;
  2788.  
  2789.             case 6 :                                                 /* 7 */
  2790.                 for (i = 0; i < 15; i++)
  2791.                 {
  2792.                     act_pic[78 + 2 * i] |= gr_farbe[value * 15 + i] >> 8;
  2793.                     act_pic[79 + 2 * i] |= gr_farbe[value * 15 + i] >> 10;
  2794.                     act_pic[78 + 2 * i] |= gr_farbe[value * 15 + i] >> 25;
  2795.                     act_pic[79 + 2 * i] |= gr_farbe[value * 15 + i] << 7;
  2796.                 }
  2797.                 break;
  2798.         }
  2799.     }
  2800.  
  2801.     /* Nun die Karten mit nur den Farbsymbolen (für die Endablage) sowie  */
  2802.     /* die leere Karte (für die Zwischenablagen) vorbereiten              */
  2803.  
  2804.     for (k = 0; k < 5; k++, act_pic += CARD_SIZE)
  2805.     {
  2806.         act_card = 1222L;
  2807.         for (i = 0; i < 94; i++)
  2808.             act_pic[i] = card_pic[act_card++];
  2809.         for (i = 94, j = i - 3; i < 186; j -= 2, i += 2)
  2810.             reverse_card(act_pic + j, act_pic + i);
  2811.  
  2812.         if (k == 4)
  2813.             continue;
  2814.         else
  2815.         {
  2816.             for (i = 0; i < 15; i++)
  2817.             {
  2818.                 act_pic[78 + 2 * i] |= gr_farbe[k * 15 + i] >> 25;
  2819.                 act_pic[79 + 2 * i] |= gr_farbe[k * 15 + i] << 7;
  2820.             }
  2821.         }
  2822.     }
  2823.  
  2824.     /* Maske für die Karten erzeugen - 'per Hand', da ich vergessen hatte */
  2825.     /* sie in den Datenfile einzubauen ...                                  */
  2826.  
  2827.     act_pic[0] = act_pic[184] = 0xFE000000L;
  2828.     act_pic[1] = act_pic[185] = 0x0000007FL;
  2829.     act_pic[2] = act_pic[182] = 0xF8000000L;
  2830.     act_pic[3] = act_pic[183] = 0x0000001FL;
  2831.     act_pic[4] = act_pic[180] = 0xF0000000L;
  2832.     act_pic[5] = act_pic[181] = 0x0000000FL;
  2833.     act_pic[6] = act_pic[8] = act_pic[176] = act_pic[178] = 0xE0000000L;
  2834.     act_pic[7] = act_pic[9] = act_pic[177] = act_pic[179] = 0x00000007L;
  2835.  
  2836.     for (i = 10; i < 176; )
  2837.     {
  2838.         act_pic[i++] = 0xC0000000L;
  2839.         act_pic[i++] = 0x00000003L;
  2840.     }
  2841.  
  2842.     if (nplanes == 1)
  2843.         return(1);
  2844.  
  2845.     /* Für Auflösungen mit mehr als einer Bitplane (z. B. TT-Medium) die  */
  2846.     /* Bilder der Karten für die Bitplanes im Speicher umkopieren          */
  2847.  
  2848.     from = (int *) (pic + CARD_SIZE * (N + 6));
  2849.     to = (int *) (pic + CARD_SIZE * (N + 6) * nplanes);
  2850.  
  2851.     while (from-- != (int *) pic)
  2852.     {
  2853.         to -= nplanes;
  2854.         for (i = 0; i < nplanes; i++)
  2855.             *(to + i) = *from;
  2856.     }
  2857.  
  2858.     return(1);
  2859. }
  2860.  
  2861.  
  2862. /*------------------------------------------------------------------------*/
  2863. /* reverse_card()                                                          */
  2864. /*    Dient zum Spiegeln einer Zeile einer Karte.                              */
  2865. /* ->  Pointer auf Ausgangszeile und Pointer auf Zielzeile                  */
  2866. /*------------------------------------------------------------------------*/
  2867.  
  2868.  
  2869. void reverse_card(long *source, long *dest)
  2870. {
  2871.     int k;
  2872.  
  2873.     *dest = *(dest + 1) = 0L;
  2874.     for (k = 0; k < 32; k++)
  2875.     {
  2876.         *dest <<= 1;
  2877.         *dest |= (*source >> k) & 1;
  2878.         *(dest + 1) <<= 1;
  2879.         *(dest + 1) |= (*(source - 1) >> k) & 1;
  2880.     }
  2881. }
  2882.  
  2883.  
  2884. /*------------------------------------------------------------------------*/
  2885. /* select_game()                                                          */
  2886. /*    Dient zur Auswahl eines Spiels entsprechend einer zu editierenden      */
  2887. /*    Zahl. Beim Editieren können BACKSPACE- und ESCAPE-Taste verwendet      */
  2888. /*    werden.                                                                  */
  2889. /* ->  Pointer auf String mit Title des Fensters                          */
  2890. /* <-  1 = neues Spiel starten, 0 = Abbruch des Editierens, nichts tun      */
  2891. /*------------------------------------------------------------------------*/
  2892.  
  2893.  
  2894. int select_game(char *title)
  2895. {
  2896.     int mwhich,                        /* Variablen für evnt_multi()          */
  2897.         mbuf[8],
  2898.         mox, moy,
  2899.         mbutton, mokstate,
  2900.         mkreturn, mbreturn;
  2901.     OBJECT *form;                    /* Pointre auf Auswahlbox              */
  2902.     long number;
  2903.     char *str,                        /* zwei Pointer auf (oder in) den      */
  2904.          *help_str;                    /* zu editierenden String              */
  2905.     int cur_pos = 0,                /* Position des Cursors im String      */
  2906.         max_len;                    /* maximale Länge des Strings          */
  2907.     int x, y, w, h;                    /* Koordinaten und Maße des Strings      */
  2908.     int cur_line[4];                /* Coordinaten des Cursors              */
  2909.     int cell_width,                    /* Breite eines Buchstabens              */
  2910.         dummy;                        /* Dummy-Variable                      */
  2911.     int top_window;
  2912.     int quit_flag = OFF;            /* gesetzt bei Ende des Editierens      */
  2913.  
  2914.  
  2915.  
  2916.     /* Adresse der Auswahlbox besorgen und ihre Position berechnen          */
  2917.  
  2918.     rsrc_gaddr(0, GETNUM, &form);
  2919.  
  2920.     form->ob_x = MIN((scr_x + wwx - form->ob_width) / 2,
  2921.                                           wwx + (www - form->ob_width) / 2);
  2922.     form->ob_y = MIN((scr_y  + wwy - form->ob_height) / 2,
  2923.                                          wwy + (wwh - form->ob_height) / 2);
  2924.  
  2925.     /* Neuen Seed in die Zahl eintragen                                      */
  2926.  
  2927.     number = (long) (seed * 1.E6);
  2928.     str = help_str = form[NUMBER].S_TEXT;
  2929.     ltoa(number, str, 10);
  2930.  
  2931.     /* Falls noch Stellen frei sind, diese mit '_'s auffüllen              */
  2932.  
  2933.     while (*help_str++ != '\0')
  2934.         cur_pos++;
  2935.  
  2936.     max_len = form[NUMBER].ob_spec.tedinfo->te_txtlen - 1;
  2937.     while (help_str < str + max_len)
  2938.         *help_str++ = '_';
  2939.  
  2940.     *--help_str = '\0';
  2941.  
  2942.     /* Auswahlbox zeichnen                                                  */
  2943.  
  2944.     objc_draw(form, 0, 1, MAX(form->ob_x - 5, 0), MAX(form->ob_y - 5, 0),
  2945.          MIN(form->ob_width + 10, scr_x), MIN(form->ob_height + 10, scr_y));
  2946.  
  2947.     str += cur_pos - 1;
  2948.  
  2949.     /* Koordinaten und Maße des Strings besorgen und Clipping setzen      */
  2950.  
  2951.     x = form->ob_x + form[NUMBER].ob_x;
  2952.     y = form->ob_y + form[NUMBER].ob_y;
  2953.     w = form[NUMBER].ob_width;
  2954.     h = form[NUMBER].ob_height;
  2955.  
  2956.     clip_array[0] = MAX(form->ob_x - 5, 0);
  2957.     clip_array[1] = MAX(form->ob_y - 5, 0);
  2958.     clip_array[2] = MIN(form->ob_x + form->ob_width + 4, scr_x);
  2959.     clip_array[3] = MIN(form->ob_y + form->ob_height + 4, scr_y);
  2960.  
  2961.     vs_clip(wkst_handle, ON, clip_array);
  2962.  
  2963.     /* Zum Schluß der Vorbereitungen den Cursor zeichnen                  */
  2964.  
  2965.     vqt_width(wkst_handle, ' ', &cell_width, &dummy, &dummy);
  2966.  
  2967.     cur_line[0] = cur_line[2] = x + cell_width * cur_pos;
  2968.     cur_line[1] = y;
  2969.     cur_line[3] = y + h - 1;
  2970.  
  2971.     v_hide_c(wkst_handle);
  2972.     v_pline(wkst_handle, 2, cur_line);
  2973.     v_show_c(wkst_handle, OFF);
  2974.  
  2975.     /* Tastaturbuffer leeren                                              */
  2976.  
  2977.     while (Cconis())
  2978.         Crawcin();
  2979.  
  2980.     /* Es folgt die Loop, in der der String editiert wird (als Reaktion      */
  2981.     /* entweder auf einen Mausklick oder einen Tastendruck), außerdem      */
  2982.     /* müssen Messages behandelt werden                                      */
  2983.  
  2984.     do
  2985.     {
  2986.         mwhich = evnt_multi(MU_KEYBD | MU_BUTTON | MU_MESAG,
  2987.                             1, 1, 1,
  2988.                             0, 0, 0, 0, 0,
  2989.                             0, 0, 0, 0, 0,
  2990.                             mbuf, 0, 0, &mox, &moy, &mbutton,
  2991.                             &mokstate, &mkreturn, &mbreturn);
  2992.  
  2993.     /* Messages auswerten ...                                              */
  2994.  
  2995.         if (mwhich & MU_MESAG)
  2996.         {
  2997.             switch (mbuf[0])
  2998.             {
  2999.  
  3000.     /* Bei REDRAW-Message müssen sowohl das Spielfeld mit Karten als auch */
  3001.     /* das darüberliegende Formular neu gezeichnet werden - wenn das ei-  */
  3002.     /* gene Fenster dabei das oberste wird, muß außerdem sicherheitshal-  */
  3003.     /* ber der Cursor neu gezeichnet werden                                  */
  3004.  
  3005.                 case WM_REDRAW :
  3006.                     wind_redraw(mbuf + 4, (OBJECT *) 0L);
  3007.                     wind_redraw(mbuf + 4, form);
  3008.  
  3009.                     wind_get(wind_handle, WF_TOP, &top_window);
  3010.                     if (wind_handle == top_window)
  3011.                     {
  3012.                         v_hide_c(wkst_handle);
  3013.                         v_pline(wkst_handle, 2, cur_line);
  3014.                         v_show_c(wkst_handle, OFF);
  3015.                     }
  3016.                     break;
  3017.  
  3018.     /* Bei TOPPED-Message muß das Fenster neu gesetzt werden, REDRAW ge-  */
  3019.     /* schieht daraufhin automatisch, weil das AES von sich aus eine      */
  3020.     /* REDRAW-Message schickt                                              */
  3021.  
  3022.                 case WM_TOPPED :        /* Fenster wurde oberstes Fenster */
  3023.                     wind_set(wind_handle, WF_TOP);
  3024.                     break;
  3025.  
  3026.     /* Bei Anklicken von Menueeinträgen nur den Menuetitel wieder normal  */
  3027.     /* darstellen, sonst nicht darauf reagieren                              */    
  3028.  
  3029.                 case MN_SELECTED :
  3030.                     menu_tnormal(menu, mbuf[3], NORM);
  3031.                     break;
  3032.             }
  3033.         }
  3034.  
  3035.     /* Reaktion auf Tastatur-Ereignisse ...                                  */
  3036.  
  3037.         if (mwhich & MU_KEYBD)
  3038.         {
  3039.             switch (mkreturn & 0xFF)
  3040.             {
  3041.  
  3042.     /* bei ESC den gesamten String löschen (d.h. alle Einträge durch '_'  */
  3043.     /* ersetzen und den Cursor an den Anfang malen                          */
  3044.  
  3045.                 case ESC :
  3046.                     str = form[NUMBER].S_TEXT;
  3047.                     while (*str)
  3048.                         *str++ = '_';
  3049.                     str = form[NUMBER].S_TEXT - 1;
  3050.                     objc_draw(form, NUMBER, 0, x, y, w, h);
  3051.  
  3052.                     v_hide_c(wkst_handle);
  3053.                     if (cur_pos == max_len)
  3054.                     {
  3055.                         vsl_color(wkst_handle, WHITE);
  3056.                         v_pline(wkst_handle, 2, cur_line);
  3057.                         vsl_color(wkst_handle, BLACK);
  3058.                     }
  3059.                     cur_pos = 0;
  3060.  
  3061.                     cur_line[0] = cur_line[2] = x;
  3062.                     v_pline(wkst_handle, 2, cur_line);
  3063.                     v_show_c(wkst_handle, OFF);
  3064.                     break;
  3065.  
  3066.     /* bei BACKSPACE das links vom Cursor stehende Zeichen löschen (d.h.  */
  3067.     /* durch '_' ersetzen) und den Cursor verschieben                      */
  3068.  
  3069.                 case BACKSPACE :
  3070.                     if (cur_pos == 0)              /* wenn String leer ist */
  3071.                         break;
  3072.  
  3073.                     v_hide_c(wkst_handle);
  3074.  
  3075.                     *str-- = '_';
  3076.                     objc_draw(form, NUMBER, 0, x, y, w, h);
  3077.  
  3078.                     if (cur_pos-- == max_len)
  3079.                     {
  3080.                         vsl_color(wkst_handle, WHITE);
  3081.                         v_pline(wkst_handle, 2, cur_line);
  3082.                         vsl_color(wkst_handle, BLACK);
  3083.                     }
  3084.  
  3085.                     cur_line[0] = cur_line[2] -= cell_width;
  3086.                     v_pline(wkst_handle, 2, cur_line);
  3087.                     v_show_c(wkst_handle, OFF);
  3088.                     break;
  3089.  
  3090.     /* Bei RETURN oder ENTER beenden des Editierens indem das Anklicken      */
  3091.     /* von 'Fertig' simuliert wird                                          */
  3092.  
  3093.                 case RETURN :
  3094.                     mwhich |= MU_BUTTON;
  3095.                     objc_offset(form, NREADY, &mox, &moy);
  3096.                     break;
  3097.  
  3098.     /* Neue Zeichen werden nur akzeptiert, wenn es sich um Zahlen handelt */
  3099.     /* und der String nicht bereits voll ist                              */
  3100.  
  3101.                 default :
  3102.                     if (!isdigit(mkreturn & 0xFF) || (cur_pos == max_len))
  3103.                         break;
  3104.  
  3105.                     *++str = mkreturn & 0xFF;
  3106.                     objc_draw(form, NUMBER, 0, x, y, w, h);
  3107.  
  3108.                     cur_pos++;
  3109.                     cur_line[0] = cur_line[2] += cell_width;
  3110.                     v_pline(wkst_handle, 2, cur_line);
  3111.                     v_show_c(wkst_handle, OFF);
  3112.                     break;
  3113.             }
  3114.         }
  3115.  
  3116.     /* Reaktion auf Mausklicks                                              */
  3117.  
  3118.         if (mwhich & MU_BUTTON)
  3119.         {
  3120.             /* Testen, welcher Button angeklickt wurde und entsprechend      */
  3121.             /* verzweigen                                                  */
  3122.  
  3123.             switch (objc_find(form, 0, 1, mox, moy))
  3124.             {
  3125.                 case NREADY :                                    /* Fertig */
  3126.                     quit_flag = 1;
  3127.                     break;
  3128.  
  3129.                 case QUIT :                                       /* Abbruch */
  3130.                     quit_flag = -1;
  3131.                     break;
  3132.             }
  3133.         }
  3134.  
  3135.     } while (!quit_flag);
  3136.  
  3137.     /* Cursor löschen                                                      */
  3138.  
  3139.     if (cur_pos == max_len)
  3140.     {
  3141.         v_hide_c(wkst_handle);
  3142.         vsl_color(wkst_handle, WHITE);
  3143.         v_pline(wkst_handle, 2, cur_line);
  3144.         vsl_color(wkst_handle, BLACK);
  3145.         v_show_c(wkst_handle, OFF);
  3146.     }
  3147.  
  3148.     /* Bei Abbruch Auswahlbox löschen und fertig                          */
  3149.  
  3150.     if (quit_flag == -1)
  3151.     {
  3152.         show_all(OFF);
  3153.         return(0);
  3154.     }
  3155.  
  3156.     /* Sonst editierte Zahl auswerten und Seed entsprechend setzen          */
  3157.  
  3158.     help_str = form[NUMBER].S_TEXT;
  3159.     while (isdigit(*help_str))
  3160.         help_str++;
  3161.  
  3162.     *help_str = '\0';
  3163.  
  3164.     old_seed = seed = ((double) atol(form[NUMBER].S_TEXT) * 1.E-6);
  3165.     set_wind_header(title);
  3166.  
  3167.     return(1);
  3168. }
  3169.  
  3170.  
  3171. /*------------------------------------------------------------------------*/
  3172. /* wind_redraw()                                                          */
  3173. /*    Dient sowohl zur Wiederherstellung des Fensterinhaltes als auch von      */
  3174. /*    Objekten, wenn eine REDRAW-Message eingegangen ist.                      */
  3175. /* ->  Pointer auf Array mit Maßen des wiederherzustellenden Rechtecks      */
  3176. /*       sowie Pointer auf wiederherzustellendes Objekt (wenn dieser NULL      */
  3177. /*       ist, muß ein Fenster neu gezeichnet werden, sonst ein Objekt)      */
  3178. /*------------------------------------------------------------------------*/
  3179.  
  3180.  
  3181. void wind_redraw(int *rr, OBJECT *wind)
  3182. {
  3183.     int ar[4];            /* Maße des aktuell neu zu zeichnenden Rechtecks  */
  3184.  
  3185.  
  3186.     /* AES-Aktionen auf dem Bildschirm unterbinden                          */
  3187.  
  3188.     wind_update(BEG_UPDATE);
  3189.  
  3190.     /* Maße des ersten neu zu zeichnenden Rechtecks aus der Rechteckliste */
  3191.     /* besorgen                                                              */
  3192.  
  3193.     wind_get(wind_handle, WF_FIRSTXYWH, ar, ar + 1, ar + 2, ar + 3);
  3194.  
  3195.     /* Neu zeichnen, solange wiederholen bis Höhe oder Breite des näch-      */
  3196.     /* sten wiederherzustellenden Rechtecks ungleich Null ist              */    
  3197.  
  3198.     while (ar[2] || ar[3])
  3199.     {
  3200.  
  3201.     /* Wenn das aktuelle Rechteck sich mit dem gesamten wiederherzustel-  */
  3202.     /* lenden Rechteck überschneidet, dieses neu zeichenen                  */
  3203.  
  3204.         if (intersect(rr, ar))
  3205.         {
  3206.             clip_array[0] = MAX(ar[0], 0);
  3207.             clip_array[1] = MAX(ar[1], 0);
  3208.             clip_array[2] = MIN(ar[0] + ar[2] - 1, scr_x);
  3209.             clip_array[3] = MIN(ar[1] + ar[3] - 1, scr_y);
  3210.             vs_clip(wkst_handle, ON, clip_array);
  3211.  
  3212.     /* Je nach Wert des Objektpointers Fenster oder Formular neu zeichnen */
  3213.  
  3214.             if (wind == (OBJECT *) 0L)
  3215.                 show_all(OFF);
  3216.             else
  3217.                 objc_draw(wind, R_TREE, 1, ar[0], ar[1], ar[2], ar[3]);
  3218.         }
  3219.  
  3220.     /* Und Maße des nächsten neu zu zeichnenden Rechtecks holen              */
  3221.  
  3222.         wind_get(wind_handle, WF_NEXTXYWH, ar, ar + 1, ar + 2, ar + 3);
  3223.     }
  3224.  
  3225.     /* AES-Aktionen auf dem Bildschirm wieder zulassen                      */
  3226.  
  3227.     wind_update(END_UPDATE);
  3228. }
  3229.  
  3230.  
  3231. /*------------------------------------------------------------------------*/
  3232. /* intersect()                                                              */
  3233. /*    Stellt fest, ob sich zwei Rechtecke überschneiden und gibt die Maße      */
  3234. /*    des Überschneidungsbereich im zweiten übergebenen Array zurück.          */
  3235. /*    (Entsprechend 'ATARI Profibuch' von Jankowski/Rabich/Reschke)          */
  3236. /* ->  Pointer auf Array's mit den Maßen zweier Rechtecke                  */
  3237. /* <-  1 = Rechtecke überschneiden sich, 0 = sie überschneiden sich nicht */
  3238. /*------------------------------------------------------------------------*/
  3239.  
  3240.  
  3241. int intersect(int *rr, int *ar)
  3242. {
  3243.     int ix, iy, iw, ih;
  3244.  
  3245.  
  3246.     /* Positionen des linken oberen und rechten unteren Punktes der          */
  3247.     /* Schnittfläche bestimmen                                              */
  3248.  
  3249.     ix = MAX(rr[0], ar[0]);
  3250.     iy = MAX(rr[1], ar[1]);
  3251.     iw = MIN(rr[0] + rr[2], ar[0] + ar[2]);
  3252.     ih = MIN(rr[1] + rr[3], ar[1] + ar[3]);
  3253.  
  3254.     /* Daraus Position und Maße der Schittfläche berechnen (und in den      */
  3255.     /* zweiten übergebenen Array eintragen)                                  */
  3256.  
  3257.     ar[0] = ix;
  3258.     ar[1] = iy;
  3259.     ar[2] = iw - ix;
  3260.     ar[3] = ih - iy;
  3261.  
  3262.     return((iw > ix) && (ih > iy));
  3263. }
  3264.  
  3265.  
  3266. /*------------------------------------------------------------------------*/
  3267. /* move_window()                                                          */
  3268. /*    Dient zur Ausführung aller notwendigen Aktionen beim Verschieben des  */
  3269. /*    Fensters. Der zusätzliche übergebene Objektpointer ist nur beim Ver-  */
  3270. /*    schieben des auf kleinste Maße geschrumpften Fensters von Bedeutung,  */
  3271. /*    da dessen Inhalt durch ein Objekt gegeben ist.                          */
  3272. /* ->  neue x- und y-Position des Fensters sowie Objekt-Pointer              */
  3273. /*------------------------------------------------------------------------*/
  3274.  
  3275.  
  3276. void move_window(int x, int y, OBJECT *wind)
  3277. {
  3278.     int del_x, del_y;
  3279.     OBJECT *ob;
  3280.  
  3281.  
  3282.     /* Größe der Verschiebung berechnen                                      */
  3283.  
  3284.     del_x = x - wox;
  3285.     del_y = y - woy;
  3286.  
  3287.     /* Neue Position der linken oberen Ecke des Fensterinneren bestimmen  */
  3288.  
  3289.     wwx += del_x;
  3290.     wwy += del_y;
  3291.  
  3292.     /* Neue x- und y-Position des Fensteräußeren setzen                      */
  3293.  
  3294.     wox = x;
  3295.     woy = y;
  3296.  
  3297.     wind_set(wind_handle, WF_CURRXYWH, wox, woy, wow, woh);
  3298.  
  3299.     /* Objekt für Fensterinneres bei kleinstmöglichem Fenster setzen      */
  3300.  
  3301.     if (wind != (OBJECT *) 0L)
  3302.     {
  3303.         wind->ob_x = wwx;
  3304.         wind->ob_y = wwy;
  3305.     }
  3306.  
  3307.     /* Wenn die Verschiebung nur zu größeren x- oder y-Werten erfolgt      */
  3308.     /* durch Neuzeichnen des Fensters die Positionen der Karten usw.      */
  3309.     /* neu berechnen (andernfalls erfolt dies bei der sonst automatisch      */
  3310.     /* folgenden REDRAW-Message)                                          */
  3311.  
  3312.     if (((del_x > 0) && (del_y >= 0)) || ((del_x >= 0) && (del_y > 0)))
  3313.     {
  3314.         if (wind == (OBJECT *) 0L)
  3315.             show_all(ON);
  3316.     }
  3317.  
  3318.     /* Nun noch bei nicht verkleinertem Fenster untersuchen ob die Boxen  */
  3319.     /* für Starten eines Spiels entsprechend einer einzugebenden Zahl      */
  3320.     /* bzw. mit Informationen über das Spiel noch in das verschobene Fen- */
  3321.     /* ster passen und die zugehörigen Menueeinträge entsprechend setzen  */
  3322.  
  3323.     if (wind != (OBJECT *) 0L)
  3324.         return;
  3325.  
  3326.     rsrc_gaddr(R_TREE, GETNUM, &ob);
  3327.     if ((ob->ob_width + 10 > scr_x - wwx) ||
  3328.                                          (ob->ob_height + 10 > scr_y - wwy))
  3329.         menu_ienable(menu, T1E1, OFF);
  3330.     else
  3331.         menu_ienable(menu, T1E1, ON);
  3332.  
  3333.     rsrc_gaddr(R_TREE, ABOUT, &ob);
  3334.     if ((ob->ob_width + 10 > scr_x - wwx) ||
  3335.                                          (ob->ob_height + 10 > scr_y - wwy))
  3336.         menu_ienable(menu, T0E0, OFF);
  3337.     else
  3338.         menu_ienable(menu, T0E0, ON);
  3339. }
  3340.  
  3341.  
  3342. /*------------------------------------------------------------------------*/
  3343. /* resize_window()                                                          */
  3344. /*    Dient zum Verkleinern des Fensters und aller nachfolgenden Aktionen,  */
  3345. /*    bis das Fenster schließlich wieder auf die ursprüngliche Größe ge-      */
  3346. /*    bracht wird.                                                          */
  3347. /* ->  Pointer auf normalen String mit Fenstertitel                          */
  3348. /* <-  1 = Spiel sofort beenden, 0 = Spiel normal fortsetzen              */
  3349. /*------------------------------------------------------------------------*/
  3350.  
  3351.  
  3352. int resize_window(char *title)
  3353. {
  3354.     OBJECT *wind;                    /* Pointer auf Objekt mit Inhalt des  */
  3355.                                     /* verkleinerten Fensters              */
  3356.     int owow, owoh;                    /* ursprüngliche Maße des Fensters      */
  3357.     char *new_title = "";            /* Titel des verleinerten Fensters      */
  3358.     int mbuf[8];                    /* Buffer für Messages                  */
  3359.  
  3360.  
  3361.     /* Adresse des Objekts mit Inhalt des verkleinerten Fensters besorgen */
  3362.  
  3363.     rsrc_gaddr(R_TREE, WIND, &wind);
  3364.  
  3365.     /* Neue Maße des Fensters berechnen und Fenster entsprechend setzen      */
  3366.  
  3367.     owow = wow;
  3368.     owoh = woh;
  3369.     wind_calc(WC_BORDER, CLOSER | FULLER | MOVER, wwx, wwy,
  3370.                    wind->ob_width, wind->ob_height, &wox, &woy, &wow, &woh);
  3371.     wind_set(wind_handle, WF_NAME, (int) ((long) new_title >> 16),
  3372.                                      (int) ((long) new_title & 0x0000FFFF));
  3373.     wind_set(wind_handle, WF_KIND, CLOSER | FULLER | MOVER);
  3374.     wind_set(wind_handle, WF_CURRXYWH, wox, woy, wow, woh);
  3375.  
  3376.     /* Objekt mit Inhalt des verkleinerten Fensters zeichnen              */
  3377.  
  3378.     wind->ob_x = wwx;
  3379.     wind->ob_y = wwy;
  3380.     objc_draw(wind, R_TREE, 1, wwx, wwy, wind->ob_width, wind->ob_height);
  3381.  
  3382.     /* Verschieden Menueeinträge disablen                                  */
  3383.  
  3384.     menu_ienable(menu, T0E0, OFF);
  3385.     menu_ienable(menu, T1E0, OFF);
  3386.     menu_ienable(menu, T1E1, OFF);
  3387.     menu_ienable(menu, T1E2, OFF);
  3388.     menu_ienable(menu, T1E3, OFF);
  3389.     menu_ienable(menu, T1E4, OFF);
  3390.  
  3391.     /* Nun auf Messages warten, bis das Fenster wieder vergrößert wird      */
  3392.  
  3393.     do
  3394.     {
  3395.         evnt_mesag(mbuf);
  3396.  
  3397.         switch (mbuf[0])
  3398.         {
  3399.             case WM_REDRAW :                  /* Redraw-Message empfangen */
  3400.                 wind_redraw(mbuf + 4, wind);
  3401.                 break;
  3402.  
  3403.             case WM_MOVED :                      /* Fenster wurde verschoben */
  3404.                 move_window(mbuf[4], mbuf[5], wind);
  3405.                 break;
  3406.  
  3407.             case WM_TOPPED :            /* Fenster wurde oberstes Fenster */
  3408.                 wind_set(wind_handle, WF_TOP);
  3409.                 break;
  3410.  
  3411.             case WM_CLOSED :                /* CLOSE-Box wurde angeklickt */
  3412.                 return(1);
  3413.  
  3414.             case MN_SELECTED :                   /* Menueeintrag angeklickt */
  3415.                 if ((mbuf[3] == T1) && (mbuf[4] == T1E5))
  3416.                     return(1);                             /* Spiel beenden */
  3417.                 else
  3418.                     menu_tnormal(menu, mbuf[3], NORM);
  3419.                 break;
  3420.         }
  3421.  
  3422.     } while (mbuf[0] != WM_FULLED);
  3423.  
  3424.     /* Disablete Menueeinträge wieder enablen                              */
  3425.  
  3426.     menu_ienable(menu, T0E0, ON);
  3427.     menu_ienable(menu, T1E0, ON);
  3428.     menu_ienable(menu, T1E1, ON);
  3429.     menu_ienable(menu, T1E2, ON);
  3430.     menu_ienable(menu, T1E3, ON);
  3431.     menu_ienable(menu, T1E4, ON);
  3432.  
  3433.     /* Fenster wieder auf ursprüngliche Größe bringen                      */
  3434.  
  3435.     wow = owow;
  3436.     woh = owoh;
  3437.     wind_set(wind_handle, WF_NAME, (int) ((long) title >> 16),
  3438.                                          (int) ((long) title & 0x0000FFFF));
  3439.     wind_set(wind_handle, WF_KIND, NAME | CLOSER | FULLER | MOVER);
  3440.     wind_set(wind_handle, WF_CURRXYWH, wox, woy, wow, woh);
  3441.  
  3442.     return(0);
  3443. }
  3444.  
  3445.  
  3446. /*------------------------------------------------------------------------*/
  3447. /* i_to_a()                                                                  */
  3448. /*    Wandelt eine positive Integerzahl rechtsbündig in einen String mit      */
  3449. /*    festgelegter Länge ein.                                                  */
  3450. /* ->  Pointer auf String für die Zahl, zu wandelnde Zahl sowie Länge des */
  3451. /*       Strings                                                              */
  3452. /*------------------------------------------------------------------------*/
  3453.  
  3454.  
  3455. void i_to_a(char *s, long number, int n)
  3456. {
  3457.     *(s + n--) = '\0';                     /* Nullbyte ans Ende des Strings */
  3458.     
  3459.     for ( ; n >= 0; number /= 10)                  /* String von hinten mit */
  3460.         *(s + n--) = number % 10 + '0';                    /* Ziffern füllen */
  3461.     while (*s == '0')                             /* führende Nullen durch */
  3462.         *s++ = ' ';                                   /* Leerzechen ersetzen */
  3463. }