home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 7 Games / 07-Games.zip / pmlife10.zip / PMLIFE10.PAS < prev    next >
Pascal/Delphi Source File  |  1996-10-19  |  65KB  |  1,890 lines

  1. Program PMLife;
  2. {$PMTYPE PM}
  3. {$X+ }
  4. (* A test program for high-speed life game defined by Conway.
  5.    Definition :
  6.  
  7.     For cell A, the neighbouring cells are cells 1..8
  8.  
  9.         1 2 3
  10.         4 A 5
  11.         6 7 8
  12.  
  13.     If A is alive, it remains alive in case of total number of living cells
  14.     in its neighbourhood is 2 or 3 else A shall be dead in the next stage.
  15.     If A is branc (a dead cell is thought as a blanc one) and 3 neighbouring
  16.     cell are alive, then A become alive in the next stage.
  17.  
  18.     This program employ invented algorythm basically introduced in
  19.       'Programming Seminor' by K. Kakei et. al. 1985.
  20.  
  21.     vers 0.1 : 10, Dec., 1990   life.pas
  22.                 Original
  23.     vers 0.2 : 12, Dec., 1990   life2.pas
  24.                 Life Editor
  25.     vers 0.21: 14, Dec., 1990   life21.pas
  26.                 Preperation for colour version.
  27.                 * Cell status bit assignment is changed.
  28.                 * Display status is stored as colour code (bit 6-4)
  29.                 * Current registration status is set at bit 7 as negative
  30.                         logic (1-not registered in current stage )
  31.     vers 0.22: 19, Dec., 1990   life22.pas
  32.                 Run Faster.  faster than vers 0.2x
  33.                 * Linear access for cell field.
  34.                 * Field size/assignments are changed.
  35.     vers 0.23: , Dec., 1990   life23.pas
  36.                 Faster than vers 0.22.
  37.                 Colour change.
  38.                 Cell pattern can be stroed in a text file.
  39.          0.231  TP6, no colour
  40.          0.232  mouse
  41.          0.233  13, Feb., 1993 LIFE0233.PAS
  42.                 Editor Store/Recall
  43.          0.240  LIFE0240.PAS
  44.                 Two Tribe
  45.          0.241  LIFE0241.PAS
  46.                 bug fix (X, Y display)
  47.          0.242  LIFE0242.PAS
  48.                 zooming
  49.     versions above are for PC9801
  50.     followings are for OS/2 PM
  51.  
  52.     vers 0.3 :  Ported to OS/2 PM
  53.                   PMLIFE00, 01, 02, and 03    March..April, 1995
  54.     vers 0.4
  55.     vers 0.5
  56.     vers 0.6 :  Revised for Virtual Pascal for OS/2
  57.     vers 0.7 :  Planer 32bit!
  58.     vers 0.8 :  Large field
  59.     vers 0.9 :  Small, Medium, Large field
  60.     vers 1.0 :  Field size dialogue
  61.  
  62. *)
  63.  
  64. uses DOS, os2def, os2base, os2PMApi, strings, PMLCONST;
  65. {$R PMLIFE10}
  66. {$R-,S-,I-}
  67. const
  68. (* for game itself *)
  69. (*  +----------------------+ 0   *)
  70. (*  |                      |     *)
  71. (*  ~   vers 0.22          ~     *)
  72. (*  |                      |     *)
  73. (*  +----------------------+ col_size+1 *)
  74.   MaxXIndex       = 1023;
  75.   MaxXIndexMinus1 = MaxXIndex - 1;
  76.   MaxXIndexPlus1  = MaxXIndex + 1;
  77.   MaxXIndexPlus2  = MaxXIndex + 2;
  78.   MaxYIndex       = 1023;
  79.   MaxYIndexMinus1 = MaxYIndex - 1;
  80.   MaxYIndexPlus1  = MaxYIndex + 1;
  81.   MaxYIndexPlus2  = MaxYIndex + 2;
  82.   MaxLindex       = MaxXIndexPlus1 * MaxYIndexPlus1 - 1;
  83.   MaxXIndexMedium       = 511;
  84.   MaxXIndexMinus1Medium = MaxXIndexMedium - 1;
  85.   MaxXIndexPlus1Medium  = MaxXIndexMedium + 1;
  86.   MaxXIndexPlus2Medium  = MaxXIndexMedium + 2;
  87.   MaxYIndexMedium       = 511;
  88.   MaxYIndexMinus1Medium = MaxYIndexMedium - 1;
  89.   MaxYIndexPlus1Medium  = MaxYIndexMedium + 1;
  90.   MaxYIndexPlus2Medium  = MaxYIndexMedium + 2;
  91.   MaxLindexMedium       = MaxXIndexPlus1Medium * MaxYIndexPlus1Medium - 1;
  92.   MaxXIndexSmall       = 255;
  93.   MaxXIndexMinus1Small = MaxXIndexSmall - 1;
  94.   MaxXIndexPlus1Small  = MaxXIndexSmall + 1;
  95.   MaxXIndexPlus2Small  = MaxXIndexSmall + 2;
  96.   MaxYIndexSmall       = 255;
  97.   MaxYIndexMinus1Small = MaxYIndexSmall - 1;
  98.   MaxYIndexPlus1Small  = MaxYIndexSmall + 1;
  99.   MaxYIndexPlus2Small  = MaxYIndexSmall + 2;
  100.   MaxLindexSmall       = MaxXIndexPlus1Small * MaxYIndexPlus1Small - 1;
  101.   MaxAlive      =10000;
  102.   LiveMask      =   7;
  103.   toLive        =   3;
  104.   Colour1       = $80;
  105.   ColourMask    = $80;
  106.   notRegistered =   8;
  107.   MaxAlive2     = MaxAlive div 2;
  108.   EditFieldSize =  40;
  109.   EditFieldSizePlus1 = EditFieldSize + 1;
  110.   EditMaxAlive  =1000;
  111.   CharHeight    = 24;
  112.   MaxZoom       = 3;
  113.   VersNum       = 'PMLIFE 1.0';
  114.   ClassName     = 'LIFE';
  115.   InfoName      = 'INFO';
  116.   ININame       = 'PMLIFE.INI';
  117.  
  118. (* for PM control *)
  119.  
  120. (* For calculation thread *)
  121.   StackSize    = 8192;
  122.   WM_USER1     = WM_USER + 1;
  123.   WM_USER2     = WM_USER + 2;
  124.   WM_USER3     = WM_USER + 3;
  125.   WM_USER4     = WM_USER + 4;
  126.  
  127.   fSwp         = SWP_ACTIVATE + SWP_SIZE + SWP_MOVE + SWP_SHOW;
  128.  
  129. type
  130.   CellStatus   = byte;          (* bits |7654|3210|
  131.                                         |    |    +----+
  132.                                         |    |for count|
  133.                                         |    ||
  134.                                         |    |registered in current stage
  135.                                         |    |
  136.                                         |    +-----------+
  137.                                         |for tribe count |
  138.                                          |
  139.                                          displayed
  140.                                 bit 3 is overrided safely, because the
  141.                                 count is always 1 to 8. bit 3 has no in-
  142.                                 formation.
  143.                                 This assignment is employed in vers 0.21
  144.                                 changed in vers 0.24 *)
  145.   ColNum        = 1..MaxXIndex;      (* vers 0.22 *)
  146.   ColNumPlus1   = 0..MaxXIndexPlus1; (* vers 0.22 *)
  147.   RowNum        = 1..MaxYIndex;      (* vers 0.22 *)
  148.   RowNumPlus1   = 0..MaxYIndexPlus1; (* vers 0.22 *)
  149.   Xindex        = 0..MaxXindex;
  150.   Yindex        = 0..MaxYindex;
  151.   Lindex        = 0..MaxLindex;
  152.   BioRow        = array[Xindex] of CellStatus;   (* vers 0.22 *)
  153.   BioField      = array[Yindex] of BioRow;       (* vers 0.22 *)
  154.   BioFieldLinear= array[Lindex] of CellStatus;   (* vers 0.22 *)
  155.   ColNumMedium        = 1..MaxXIndexMedium;      (* vers 0.9 *)
  156.   ColNumPlus1Medium   = 0..MaxXIndexPlus1Medium; (* vers 0.9 *)
  157.   RowNumMedium        = 1..MaxYIndexMedium;      (* vers 0.9 *)
  158.   RowNumPlus1Medium   = 0..MaxYIndexPlus1Medium; (* vers 0.9 *)
  159.   XindexMedium        = 0..MaxXindexMedium;
  160.   YindexMedium        = 0..MaxYindexMedium;
  161.   LindexMedium        = 0..MaxLindexMedium;
  162.   BioRowMedium        = array[XindexMedium] of CellStatus;   (* vers 0.22 *)
  163.   BioFieldMedium      = array[YindexMedium] of BioRowMedium; (* vers 0.22 *)
  164.   BioFieldLinearMedium= array[LindexMedium] of CellStatus;   (* vers 0.22 *)
  165.   ColNumSmall        = 1..MaxXIndexSmall;      (* vers 0.9 *)
  166.   ColNumPlus1Small   = 0..MaxXIndexPlus1Small; (* vers 0.9 *)
  167.   RowNumSmall        = 1..MaxYIndexSmall;      (* vers 0.9 *)
  168.   RowNumPlus1Small   = 0..MaxYIndexPlus1Small; (* vers 0.9 *)
  169.   XindexSmall        = 0..MaxXindexSmall;
  170.   YindexSmall        = 0..MaxYindexSmall;
  171.   LindexSmall        = 0..MaxLindexSmall;
  172.   BioRowSmall        = array[XindexSmall] of CellStatus;   (* vers 0.22 *)
  173.   BioFieldSmall      = array[YindexSmall] of BioRowSmall; (* vers 0.22 *)
  174.   BioFieldLinearSmall= array[LindexSmall] of CellStatus;   (* vers 0.22 *)
  175.   BioFieldCmp   = record                                (* vers 0.22 *)
  176.     case integer of
  177.       0 : (linear  : BioFieldLinear);
  178.       1 : (matrix  : BioField);
  179.       2 : (linearm : BioFieldLinearMedium);
  180.       3 : (matrixm : BioFieldMedium);
  181.       4 : (linears : BioFieldLinearSmall);
  182.       5 : (matrixs : BioFieldSmall)
  183.     end;
  184.   pBioFieldCmp  = ^BioFieldCmp;
  185.   RunningModes  = (LargeField,  LargeFieldWrap,
  186.                    MediumField, MediumFieldWrap,
  187.                    SmallField,  SmallFieldWrap);
  188.   coordinate    = record
  189.     column      : ColNumPlus1;                  (* x *)
  190.     row         : RowNumPlus1                   (* y *)
  191.   end;
  192.   BioNumber     = 1..MaxAlive;
  193.   BioNumberPlus1= 0..MaxAlive+1;
  194.   AliveArray    = array[BioNumber] of coordinate;
  195.   BioStatus     = record
  196.     alive       : AliveArray;
  197.     CellNumber1,                    (* forward scan *)
  198.     CellNumber2 : BioNumberPlus1;   (* reverse scan *)
  199.     generation  : word
  200.   end;
  201.   tribes        = (none, Tribe1, Tribe2);
  202.   BioNumber2    = 1..MaxAlive2;
  203.   BioNumber2Plus1 = 0..MaxAlive2+1;
  204.   AliveArray2   = array[BioNumber2] of coordinate;
  205.   BioStatus2    = record
  206.     alive1,                         (* Tribe1 *)
  207.     alive2      : AliveArray2;      (* Tribe2 *)
  208.     CellNumber11,                   (* Tribe1 forward scan *)
  209.     CellNumber21,                   (* Tribe1 reverse scan *)
  210.     CellNumber12,                   (* Tribe2 forward scan *)
  211.     CellNumber22 : BioNumberPlus1;  (* Tribe2 reverse scan *)
  212.     generation : word
  213.   end;
  214.   BioStat       = record
  215.     case boolean of
  216.       false     : (for1 : BioStatus);
  217.       true      : (for2 : BioStatus2)
  218.     end;
  219.   EditAlive     = array [1..EditMaxAlive] of coordinate;
  220.   EditCells     = record
  221.     Ealive      : EditAlive;
  222.     CellNumber  : integer;
  223.     initColumn,
  224.     initRow     : word;
  225.     n           : byte
  226.   end;
  227.   pEditCells    = ^EditCells;
  228.  
  229.   dialogdata    = record
  230.     cb          : word; (* size of dialogdata *)
  231.     posx0, posy0,
  232.     posx1, posy1: integer;
  233.     delayval    : word;
  234.     prtyidle    : boolean;
  235.     RunMode     : RunningModes;
  236.     forecolour,
  237.     backcolour  : byte
  238.   end;
  239.   pdialogdata   = ^dialogdata;
  240.   char13        = array [0..13] of char;
  241.   char255       = array [0..255] of char;
  242.   pchar255      = ^char255;
  243.   str13         = string[13];
  244.   str30         = string[30];
  245.   lifeFile      = record
  246.     fname       : str13;
  247.     comment     : str30;
  248.     initx, inity: word
  249.   end;
  250.   lifeFileAry   = array [1..100] of lifeFile;
  251.   filedlgdt     = record
  252.     cb          : word;
  253.     filenm      : pchar255;
  254.     hmirror,
  255.     vmirror     : boolean;
  256.     rot         : byte;
  257.     ofsx, ofsy  : word
  258.   end;
  259.   pfiledlgdt    = ^filedlgdt;
  260.  
  261. var
  262.   status        : BioStat;             (* globally defined bio field status *)
  263.  
  264.   flst          : lifeFileAry;
  265.   fnum          : integer;
  266.  
  267. (* PM control *)
  268.   myhab         : HAB;
  269.   myhmq         : HMQ;
  270.   hwndFrame,                           (* Frame window HWND *)
  271.   hwndClient,                          (* Client window HWND *)
  272.   hwndHscroll,                         (* Horiz Scrollbar HWND *)
  273.   hwndVscroll,                         (* Vert Scrollbar HWND *)
  274.   hwndInfo      : HWND;                (* Sub HWND for Cell Number *)
  275.   myqmsg        : QMSG;
  276.   hpsInit       : HPS;                 (* Main - Life Field *)
  277.   idThread      : TID;                 (* Calculation Thread ID *)
  278.   UsePS         : HMTX;
  279.   ctlData       : ULONG;
  280.   ScrnCleared,                         (* Cells must be redraw *)
  281.   continue,                            (* running game *)
  282.   runcalc,
  283.   inited        : boolean;             (* Initial pattern loaded *)
  284.   MaxX          : XIndex;
  285.   MaxY          : YIndex;
  286.   Xscrn, Yscrn,                        (* Logical screen size *)
  287.   Xsize, Ysize  : word;                (* Phisical screen size *)
  288.   Xmove, Ymove  : integer;             (* size of hidden area *)
  289.   dx, dy        : integer;             (* display offset *)
  290.   ForeColour,
  291.   BackColour    : ULONG;
  292.   colour        : array [IDD_FOREBLACK - IDD_COLOUR ..
  293.                          IDD_BACKGREY - IDD_COLOUR] of ULONG;
  294.   zoom          : byte;                (* Zoom factor *)
  295.   dlgorg        : dialogdata;
  296.  
  297. function LoUShort(w : ULONG) : UShort; inline;
  298. begin
  299.   LoUShort := SmallWord( w )
  300. end;
  301.  
  302. function HiUShort(w : ULONG) : UShort; inline;
  303. begin
  304.   HiUShort := SmallWord( w shr 16 )
  305. end;
  306.  
  307. procedure ReadCellFromText(SourceName : string; var cells : EditCells);
  308. (* read cell pattern from a text file.
  309.   -- text file format --         example
  310. [pattern 1st line]              |-aaa---aaa---
  311. [pattern 2nd line]              |a---a-a---a--
  312. [pattern 3rd line]              |-aaa---aaa---
  313.         ...                     |---aaa---aaa-
  314. In <pattern>, the following     |--a---a-a---a
  315. charactors are available.       |---aaa---aaa-
  316.  cell     exists : <a>
  317.  cell not exist  : <space> or <-> or <_>
  318.  any other charactor is neglected and skipped.
  319. Every line must be terminated by EOLN charactor (CR-LF) and cannot
  320. exceed 249 charactors.
  321. Number of pattern must be less than 200 lines.
  322. Number of cells must be less than 4000.
  323. *)
  324. const
  325.   cExist     = 'a';
  326. var
  327.   source     : text;
  328.   SourceLine : string;
  329.   xp         : ColNum;
  330.   yp         : RowNum;
  331.   i          : integer;
  332. begin
  333.   if SourceName <> '' then
  334.     with cells do begin
  335.       assign(source, SourceName);
  336.       reset(source);
  337.       readln(source, SourceLine);
  338.       readln(source, SourceLine);
  339.       n  := 0;
  340.       yp := 1;
  341.       CellNumber := 0;
  342.       SourceLine := '';
  343.       while not eof(source) and (SourceLine<>'BEGIN') do
  344.         readln(source, SourceLine);
  345.       while not eof(source) do begin
  346.         readln(source, SourceLine);
  347.         xp := 1;
  348.         for i := 1 to length(SourceLine) do
  349.           case SourceLine[i] of
  350.             cExist :
  351.                 with cells do begin
  352.                   inc(CellNumber);
  353.                   with Ealive[CellNumber] do begin
  354.                     column := xp;
  355.                     row    := yp;
  356.                     inc(xp)
  357.                   end
  358.                 end;
  359.             ' ', '-', '_' : inc(xp)
  360.           end;
  361.         if n < length(SourceLine) then n := length(SourceLine);
  362.         inc(yp)
  363.       end;
  364.       close(source);
  365.       dec(yp);
  366.       if n < yp then n := yp
  367.     end
  368. end;
  369.  
  370. procedure RotateField(var ecl : EditCells; r : integer);
  371. var i, j, c : word;
  372. begin
  373.   with ecl do
  374.     for i := 1 to r do
  375.       for j := 1 to CellNumber do
  376.         with Ealive[j] do begin
  377.           c      := column;
  378.           column := row;
  379.           row    := succ(n - c)
  380.         end
  381. end;
  382.  
  383. procedure ReverseFieldH(var ecl : EditCells);
  384. var i : word;
  385. begin
  386.   with ecl do
  387.     for i := 1 to CellNumber do
  388.       with Ealive[i] do column := succ(n - column)
  389. end;
  390.  
  391. procedure ReverseFieldV(var ecl : EditCells);
  392. var i : word;
  393. begin
  394.   with ecl do
  395.     for i := 1 to CellNumber do
  396.       with Ealive[i] do row := succ(n - row)
  397. end;
  398.  
  399. procedure SetViewParam(magx, magy, ofsx, ofsy : integer);
  400. var mat : MATRIXLF;
  401. begin
  402.   fillchar(mat, sizeof(mat), 0);
  403.   with mat do begin
  404.     fxM11 := MAKEFIXED(magx, 0);
  405.     fxM22 := MAKEFIXED(magy, 0);
  406.     lM31  := ofsx;
  407.     lM32  := ofsy + CharHeight;
  408.     lM33  := 1
  409.   end;
  410.   GpiSetDefaultViewMatrix(hpsInit, 9, mat, TRANSFORM_REPLACE)
  411. end;
  412.  
  413. procedure DrawCell(ix : ColNumPlus1; iy : RowNumPlus1; c : integer);
  414. var ptl : POINTL;
  415. begin
  416.   with ptl do begin
  417.     x := ix;
  418.     y := iy;
  419.     GpiSetColor(hpsInit, c);
  420.     GpiSetPel(hpsInit, ptl)
  421.   end
  422. end;
  423.  
  424. procedure DispField;
  425. var i : BioNumberPlus1;
  426. begin
  427.   with status.for1 do
  428.     if odd(generation) then begin
  429.       WinPostMsg(hwndClient, WM_USER3,
  430.                  succ(MaxAlive - CellNumber2), generation);
  431.       for i := CellNumber2 to MaxAlive do
  432.         with alive[i] do DrawCell(column, row, ForeColour)
  433.     end else begin
  434.       WinPostMsg(hwndClient, WM_USER3, CellNumber1, generation);
  435.       for i := CellNumber1 downto 1 do
  436.         with alive[i] do DrawCell(column, row, ForeColour)
  437.     end;
  438.   ScrnCleared := false
  439. end;
  440.  
  441. procedure InitLifeField(var cell : EditCells; init : boolean);
  442. var i : integer;
  443.     mx,
  444.     my: word;
  445. begin
  446.   mx := pred(MaxX);
  447.   my := pred(MaxY);
  448.   with status.for1, cell do begin
  449.     if init then begin
  450.       CellNumber1 := 0;
  451.       generation := 0
  452.     end;
  453.     for i := 1 to CellNumber do begin (* generation is even *)
  454.       inc(CellNumber1);
  455.       with alive[CellNumber1] do begin
  456.         column := (Ealive[i].column + initColumn + MaxX) and mx;
  457.         row    := (initRow - Ealive[i].row + MaxY * 2)   and my
  458.       end
  459.     end
  460.   end
  461. end;
  462.  
  463. procedure LimitLifeField;
  464. var i      : BioNumberPlus1;
  465.     ii     : integer;
  466.     mx, my,
  467.     x,  y  : word;
  468. begin
  469.   mx := pred(MaxX);
  470.   my := pred(MaxY);
  471.   ii := 0;
  472.   with status.for1 do begin
  473.     for i := 1 to CellNumber1 do begin
  474.       x := alive[i].column;
  475.       y := alive[i].row;
  476.       if odd(ord(dlgorg.RunMode)) then begin
  477.         inc(ii);
  478.         alive[ii].column := x and mx;
  479.         alive[ii].row    := y and my
  480.       end else if (x <= mx) and (y <= my) then begin
  481.         inc(ii);
  482.         alive[ii].column := x;
  483.         alive[ii].row    := y
  484.       end
  485.     end;
  486.     CellNumber1 := ii
  487.   end
  488. end;
  489.  
  490. procedure SetMaxXY;
  491. begin
  492.   MaxX := MaxXIndexPlus1 shr (ord(dlgorg.RunMode) div 2);
  493.   MaxY := MaxYIndexPlus1 shr (ord(dlgorg.RunMode) div 2)
  494. end;
  495.  
  496. procedure MakeFileList(s : string;
  497.                        var flist : lifeFileAry; var n : integer);
  498. var sr : SearchRec;
  499.     f  : text;
  500. begin
  501.   n  := 0;
  502.   FindFirst(s, ReadOnly + Archive, sr);
  503.   while DOS.DosError = 0 do begin
  504.     inc(n);
  505.     with flist[n] do begin
  506.       fname := sr.Name;
  507.       assign(f, fname);
  508.       reset(f);
  509.       readln(f, comment);
  510.       readln(f, initx, inity);
  511.       close(f)
  512.     end;
  513.     FindNext(sr)
  514.   end;
  515.   FindClose(sr)
  516. end;
  517.  
  518. procedure MyMessage(h : HWND; title, mes : string);
  519. begin
  520.   title := title + chr(0);
  521.   mes   := mes + chr(0);
  522.   WinMessageBox(HWND_DESKTOP, h, @mes[1], @title[1], 0, MB_OK)
  523. end;
  524.  
  525. procedure MyNumMessage(h : HWND; n : integer);
  526. var ss: string[20];
  527. begin
  528.   str(n, ss);
  529.   MyMessage(h, 'Num Message', ss)
  530. end;
  531.  
  532. procedure LoadSettings(h : HWND; fn : string);
  533. type
  534.     rm = record
  535.       case boolean of
  536.         false : (n : byte);
  537.         true  : (m : RunningModes)
  538.       end;
  539. var t : text;
  540.     x0, y0, x1, y1, d, d2, f, b, z : integer;
  541.     r : rm;
  542. begin
  543.   if fn<>'' then begin
  544.     assign(t, fn);
  545.     reset(t);
  546.     if IOResult<>0 then begin
  547.       if h<>NULLHANDLE then MyMessage(h, '', 'File Not Found')
  548.     end else begin
  549.       readln(t, x0, y0, x1, y1);  (* Window Position *)
  550.       readln(t, d, d2);           (* d - 1 : idol, 0 : normal, delay *)
  551.       readln(t, r.n);             (* ord(RunMode) *)
  552.       readln(t, f, b);            (* forecolour, backcolour *)
  553.       readln(t, z);
  554.       if IOResult = 0 then begin
  555.         with dlgorg do begin
  556.           posx0 := x0;
  557.           posy0 := y0;
  558.           posx1 := x1;
  559.           posy1 := y1;
  560.           prtyidle := d > 0;
  561.           delayval := d2;
  562.           RunMode  := r.m;
  563.           forecolour := f;
  564.           backcolour := b
  565.         end;
  566.         ForeColour := colour[dlgorg.forecolour];
  567.         BackColour := colour[dlgorg.backcolour];
  568.         zoom       := z
  569.       end;
  570.       close(t)
  571.     end
  572.   end
  573. end;
  574.  
  575. procedure SaveSettings(h : HWND; fn : string);
  576. var t     : text;
  577.     myswp : SWP;
  578. begin
  579.   WinQueryWindowPos(h, myswp);
  580.   if fn<>'' then begin
  581.     assign(t, fn);
  582.     rewrite(t);
  583.     with dlgorg, myswp do begin
  584.       writeln(t, x, ' ', y, ' ', cx, ' ', cy);
  585.       writeln(t, ord(prtyidle), ' ', delayval);
  586.       writeln(t, ord(RunMode));
  587.       writeln(t, forecolour, ' ', backcolour);
  588.       writeln(t, zoom)
  589.     end;
  590.     close(t)
  591.   end
  592. end;
  593.  
  594. procedure InitVar;
  595. var i : integer;
  596. begin
  597.   ctlData := FCF_TITLEBAR + FCF_SYSMENU    + FCF_SIZEBORDER +
  598.              FCF_MINMAX   + FCF_HORZSCROLL + FCF_VERTSCROLL +
  599.              FCF_TASKLIST + FCF_MENU       + FCF_ACCELTABLE +
  600.              FCF_ICON;
  601.   with dlgorg do begin
  602.     cb       := sizeof(dlgorg);
  603.     posx0 := 0;
  604.     posy0 := 0;
  605.     posx1 := 550;
  606.     posy1 := 450;
  607.     delayval := 20;
  608.     prtyidle := true;
  609.     RunMode  := SmallFieldWrap;
  610.     forecolour := IDD_FOREWHITE - IDD_COLOUR;
  611.     backcolour := IDD_BACKBLACK - IDD_COLOUR
  612.   end;
  613.   colour[IDD_FOREBLACK  - IDD_COLOUR] := CLR_BLACK;
  614.   colour[IDD_FOREYELLOW - IDD_COLOUR] := CLR_YELLOW;
  615.   colour[IDD_FORECYAN   - IDD_COLOUR] := CLR_CYAN;
  616.   colour[IDD_FORERED    - IDD_COLOUR] := CLR_RED;
  617.   colour[IDD_FOREWHITE  - IDD_COLOUR] := CLR_WHITE;
  618.   colour[IDD_FOREGREY   - IDD_COLOUR] := CLR_PALEGRAY;
  619.   colour[IDD_BACKBLACK  - IDD_COLOUR] := CLR_BLACK;
  620.   colour[IDD_BACKYELLOW - IDD_COLOUR] := CLR_YELLOW;
  621.   colour[IDD_BACKBLUE   - IDD_COLOUR] := CLR_BLUE;
  622.   colour[IDD_BACKMAGENTA- IDD_COLOUR] := CLR_DARKPINK;
  623.   colour[IDD_BACKWHITE  - IDD_COLOUR] := CLR_WHITE;
  624.   colour[IDD_BACKGREY   - IDD_COLOUR] := CLR_DARKGRAY;
  625.   ForeColour    := CLR_WHITE;
  626.   BackColour    := CLR_BLACK;
  627.   zoom          := 1;
  628.   LoadSettings(NULLHANDLE, ININame);
  629.   SetMaxXY;
  630.   ScrnCleared   := true;
  631.   dx            := 0;
  632.   dy            := 0
  633. end;
  634.  
  635.  
  636. procedure InitialisePS(h : HWND; var hp : HPS);
  637. var s  : SIZEL;
  638.     hd : HDC;
  639. begin
  640.   hd := WinOpenWindowDC(h);
  641.   s.cx := 0;
  642.   s.cy := 0;
  643.   hp := GpiCreatePS(myhab, hd, s,
  644.                     PU_PELS + GPIF_DEFAULT + GPIT_MICRO + GPIA_ASSOC)
  645. end;
  646.  
  647. procedure SetEntryBoxVal(h : HWND; id : word; d : integer);
  648. (* set numeric value of entry box.
  649.     h : HWND of the Dialog Box
  650.     id: id of the Entry Field
  651.     d : number to set
  652. *)
  653. var s : string[4];
  654.     rc: boolean;
  655. begin
  656.   str(d, s);
  657.   s := s + chr(0);
  658.   rc := WinSetDlgItemText(h, id, @s[1])
  659. end;
  660.  
  661. (* Procedures / Functions for running LIFE GAME *)
  662.  
  663. function CalcMain(dummy : pointer) : longint;
  664. (* Main Routine for High-Speed calculation *)
  665. const
  666.   Inited    = colour1 or notRegistered or 1;
  667. var
  668.   localHAB : HAB;
  669.   field    : pBioFieldCmp;
  670.   memsz    : ULONG;
  671.   delayval : word;
  672.   RunMode  : RunningModes;
  673.  
  674.   procedure InitField; (* called only in the case of generation is even *)
  675.   var i : BioNumberPlus1;
  676.   begin
  677.     with status.for1, field^ do begin
  678.       case RunMode of
  679.         LargeField, LargeFieldWrap : begin
  680.             fillchar(field^, sizeof(BioField), 0);
  681.             for i := 1 to CellNumber1 do
  682.               with alive[i] do matrix[row, column] := colour1
  683.                                                   (* displayed and set now *)
  684.           end;
  685.         MediumField, MediumFieldWrap : begin
  686.             fillchar(field^, sizeof(BioFieldMedium), 0);
  687.             for i := 1 to CellNumber1 do
  688.               with alive[i] do matrixm[row, column] := colour1
  689.                                                   (* displayed and set now *)
  690.           end;
  691.         SmallField, SmallFieldWrap : begin
  692.             fillchar(field^, sizeof(BioFieldSmall), 0);
  693.             for i := 1 to CellNumber1 do
  694.               with alive[i] do matrixs[row, column] := colour1
  695.                                                   (* displayed and set now *)
  696.           end
  697.       end
  698.     end
  699.   end;  { of InitField }
  700.  
  701.   procedure SetSentinel;
  702.   var ii : Yindex;
  703.   begin
  704.     with field^ do begin
  705.       fillchar(matrix[0], sizeof(BioRow), notRegistered);
  706.       for ii := 1 to MaxYIndexMinus1 do begin
  707.         matrix[ii, 0]         := notRegistered;
  708.         matrix[ii, MaxXIndex] := notRegistered
  709.       end;
  710.       fillchar(matrix[MaxYIndex], sizeof(BioRow), notRegistered)
  711.     end
  712.   end;
  713.  
  714.   procedure SetSentinelMedium;
  715.   var ii : Yindex;
  716.   begin
  717.     with field^ do begin
  718.       fillchar(matrixm[0], sizeof(BioRowMedium), notRegistered);
  719.       for ii := 1 to MaxYIndexMinus1Medium do begin
  720.         matrixm[ii, 0]         := notRegistered;
  721.         matrixm[ii, MaxXIndexMedium] := notRegistered
  722.       end;
  723.       fillchar(matrixm[MaxYIndexMedium], sizeof(BioRowMedium), notRegistered)
  724.     end
  725.   end;
  726.  
  727.   procedure SetSentinelSmall;
  728.   var ii : Yindex;
  729.   begin
  730.     with field^ do begin
  731.       fillchar(matrixs[0], sizeof(BioRowSmall), notRegistered);
  732.       for ii := 1 to MaxYIndexMinus1Small do begin
  733.         matrixs[ii, 0]         := notRegistered;
  734.         matrixs[ii, MaxXIndexSmall] := notRegistered
  735.       end;
  736.       fillchar(matrixs[MaxYIndexSmall], sizeof(BioRowSmall), notRegistered)
  737.     end
  738.   end;
  739.  
  740.   procedure SeedField(var f : BioFieldLinear; p : Lindex);
  741.   begin
  742.     inc(f[p - MaxXIndexPlus2 ]); (* [pred(row), pred(column)] *)
  743.     inc(f[p - MaxXIndexPlus1 ]); (* [pred(row), column      ] *)
  744.     inc(f[p - MaxXIndex      ]); (* [pred(row), succ(column)] *)
  745.     inc(f[pred(p)]);             (* [row  , pred(column)] *)
  746.     inc(f[succ(p)]);             (* [row  , succ(column)] *)
  747.     inc(f[p + MaxXIndex      ]); (* [succ(row), pred(column)] *)
  748.     inc(f[p + MaxXIndexPlus1 ]); (* [succ(row), column      ] *)
  749.     inc(f[p + MaxXIndexPlus2 ])  (* [succ(row), succ(column)] *)
  750.   end;
  751.  
  752.   procedure SeedFieldWrap(var f : BioField; x : XIndex; y : YIndex);
  753.   var x0, x1, y0, y1 : word;
  754.   begin
  755.     x0 := (x + MaxXIndex)       and MaxXIndex;
  756.     x1 := (x + MaxXIndexPlus2)  and MaxXIndex;
  757.     y0 := (y + MaxYIndex)       and MaxYIndex;
  758.     y1 := (y + MaxYIndexPlus2)  and MaxYIndex;
  759.     inc(f[y0, x0]); (* [pred(row), pred(column)] *)
  760.     inc(f[y0, x ]); (* [pred(row), column      ] *)
  761.     inc(f[y0, x1]); (* [pred(row), succ(column)] *)
  762.     inc(f[y,  x0]); (* [row  , pred(column)] *)
  763.     inc(f[y,  x1]); (* [row  , succ(column)] *)
  764.     inc(f[y1, x0]); (* [succ(row), pred(column)] *)
  765.     inc(f[y1, x ]); (* [succ(row), column      ] *)
  766.     inc(f[y1, x1])  (* [succ(row), succ(column)] *)
  767.   end;
  768.  
  769.   procedure SeedFieldMedium(var f : BioFieldLinearMedium; p : Lindex);
  770.   begin
  771.     inc(f[p - MaxXIndexPlus2Medium ]); (* [pred(row), pred(column)] *)
  772.     inc(f[p - MaxXIndexPlus1Medium ]); (* [pred(row), column      ] *)
  773.     inc(f[p - MaxXIndexMedium      ]); (* [pred(row), succ(column)] *)
  774.     inc(f[pred(p)]);                   (* [row  , pred(column)] *)
  775.     inc(f[succ(p)]);                   (* [row  , succ(column)] *)
  776.     inc(f[p + MaxXIndexMedium      ]); (* [succ(row), pred(column)] *)
  777.     inc(f[p + MaxXIndexPlus1Medium ]); (* [succ(row), column      ] *)
  778.     inc(f[p + MaxXIndexPlus2Medium ])  (* [succ(row), succ(column)] *)
  779.   end;
  780.  
  781.   procedure SeedFieldWrapMedium(var f : BioFieldMedium;
  782.                                 x : XIndex; y : YIndex);
  783.   var x0, x1, y0, y1 : word;
  784.   begin
  785.     x0 := (x + MaxXIndexMedium)       and MaxXIndexMedium;
  786.     x1 := (x + MaxXIndexPlus2Medium)  and MaxXIndexMedium;
  787.     y0 := (y + MaxYIndexMedium)       and MaxYIndexMedium;
  788.     y1 := (y + MaxYIndexPlus2Medium)  and MaxYIndexMedium;
  789.     inc(f[y0, x0]); (* [pred(row), pred(column)] *)
  790.     inc(f[y0, x ]); (* [pred(row), column      ] *)
  791.     inc(f[y0, x1]); (* [pred(row), succ(column)] *)
  792.     inc(f[y , x0]); (* [row  , pred(column)] *)
  793.     inc(f[y,  x1]); (* [row  , succ(column)] *)
  794.     inc(f[y1, x0]); (* [succ(row), pred(column)] *)
  795.     inc(f[y1, x ]); (* [succ(row), column      ] *)
  796.     inc(f[y1, x1])  (* [succ(row), succ(column)] *)
  797.   end;
  798.  
  799.   procedure SeedFieldSmall(var f : BioFieldLinearSmall; p : Lindex);
  800.   begin
  801.     inc(f[p - MaxXIndexPlus2Small ]); (* [pred(row), pred(column)] *)
  802.     inc(f[p - MaxXIndexPlus1Small ]); (* [pred(row), column      ] *)
  803.     inc(f[p - MaxXIndexSmall      ]); (* [pred(row), succ(column)] *)
  804.     inc(f[pred(p)]);                  (* [row  , pred(column)] *)
  805.     inc(f[succ(p)]);                  (* [row  , succ(column)] *)
  806.     inc(f[p + MaxXIndexSmall      ]); (* [succ(row), pred(column)] *)
  807.     inc(f[p + MaxXIndexPlus1Small ]); (* [succ(row), column      ] *)
  808.     inc(f[p + MaxXIndexPlus2Small ])  (* [succ(row), succ(column)] *)
  809.   end;
  810.  
  811.   procedure SeedFieldWrapSmall(var f : BioFieldSmall;
  812.                                x : XIndex; y : YIndex);
  813.   var x0, x1, y0, y1 : word;
  814.   begin
  815.     x0 := (x + MaxXIndexSmall)       and MaxXIndexSmall;
  816.     x1 := (x + MaxXIndexPlus2Small)  and MaxXIndexSmall;
  817.     y0 := (y + MaxYIndexSmall)       and MaxYIndexSmall;
  818.     y1 := (y + MaxYIndexPlus2Small)  and MaxYIndexSmall;
  819.     inc(f[y0, x0]); (* [pred(row), pred(column)] *)
  820.     inc(f[y0, x ]); (* [pred(row), column      ] *)
  821.     inc(f[y0, x1]); (* [pred(row), succ(column)] *)
  822.     inc(f[y , x0]); (* [row  , pred(column)] *)
  823.     inc(f[y,  x1]);             (* [row  , succ(column)] *)
  824.     inc(f[y1, x0]); (* [succ(row), pred(column)] *)
  825.     inc(f[y1, x ]); (* [succ(row), column      ] *)
  826.     inc(f[y1, x1])  (* [succ(row), succ(column)] *)
  827.   end;
  828.  
  829.   procedure ScanStatus;
  830.    (* scans alive array and seeds on field *)
  831.   var
  832.     i : BioNumber;
  833.     istart, iend : BioNumberPlus1;
  834.  
  835.   begin
  836.     with status.for1 do begin
  837.       if odd(generation) then begin
  838.         istart := CellNumber2;
  839.         iend   := MaxAlive
  840.       end else begin
  841.         istart := 1;
  842.         iend   := CellNumber1
  843.       end;
  844.       with field^ do
  845.         case RunMode of
  846.           LargeField : begin
  847.               for i := istart to iend do
  848.                 with alive[i] do
  849.                   SeedField(linear, row * MaxXIndexPlus1 + column);
  850.               for i := istart to iend do
  851.                 with alive[i] do
  852.                   matrix[row, column] :=
  853.                     (matrix[row, column] and LiveMask ) or inited
  854.                                                 (* vers 0.24 *)
  855.             end;
  856.           LargeFieldWrap : begin
  857.               for i := istart to iend do
  858.                 with alive[i] do
  859.                   SeedFieldWrap(matrix, column, row);
  860.               for i := istart to iend do
  861.                 with alive[i] do
  862.                   matrix[row, column] :=
  863.                     (matrix[row, column] and LiveMask ) or inited
  864.                                                 (* vers 0.24 *)
  865.             end;
  866.           MediumField : begin
  867.               for i := istart to iend do
  868.                 with alive[i] do
  869.                   SeedFieldMedium(linearm,
  870.                                   row * MaxXIndexPlus1Medium + column);
  871.               for i := istart to iend do
  872.                 with alive[i] do
  873.                   matrixm[row, column] :=
  874.                     (matrixm[row, column] and LiveMask ) or inited
  875.                                                 (* vers 0.24 *)
  876.             end;
  877.           MediumFieldWrap : begin
  878.               for i := istart to iend do
  879.                 with alive[i] do
  880.                   SeedFieldWrapMedium(matrixm, column, row);
  881.               for i := istart to iend do
  882.                 with alive[i] do
  883.                   matrixm[row, column] :=
  884.                     (matrixm[row, column] and LiveMask ) or inited
  885.                                                 (* vers 0.24 *)
  886.             end;
  887.           SmallField : begin
  888.               for i := istart to iend do
  889.                 with alive[i] do
  890.                   SeedFieldSmall(linears,
  891.                                  row * MaxXIndexPlus1Small + column);
  892.               for i := istart to iend do
  893.                 with alive[i] do
  894.                   matrixs[row, column] :=
  895.                     (matrixs[row, column] and LiveMask ) or inited
  896.                                                 (* vers 0.24 *)
  897.             end;
  898.           SmallFieldWrap : begin
  899.               for i := istart to iend do
  900.                 with alive[i] do
  901.                   SeedFieldWrapSmall(matrixs, column, row);
  902.               for i := istart to iend do
  903.                 with alive[i] do
  904.                   matrixs[row, column] :=
  905.                     (matrixs[row, column] and LiveMask ) or inited
  906.                                                 (* vers 0.24 *)
  907.             end  { SmallFieldWrap }
  908.         end  { case }
  909.     end  { with }
  910.   end;  { of CalcMain.ScanStatus }
  911.  
  912.   procedure CheckField;
  913.   var
  914.     i         : BioNumberPlus1;
  915.     CurrentCell, AddFactor : integer;
  916.  
  917.     procedure SetCell(var cell : CellStatus;
  918.                       ix : ColNumPlus1; iy : RowNumPlus1);
  919.       (* check cell at [p] (linear) or [iy, ix] (matrix)
  920.                 and set new generation. vers 0.23 *)
  921.     const
  922.       ClearMask = ColourMask or notRegistered;
  923.       toClear   = colour1 or notRegistered; (* displayed and not registered *)
  924.     var c : CellStatus;
  925.     begin
  926.       c := cell;
  927.       if           (c and LiveMask) = toLive then begin
  928.                         (* 0000 0111    3 - will be alive *)
  929.         inc(CurrentCell, AddFactor); (* progress cell number *)
  930.         if (CurrentCell < 0) or (CurrentCell > MaxAlive) then begin
  931.           WinPostMsg(hwndClient, WM_USER2, 0, 0);
  932.           status.for1.CellNumber1 := 0;
  933.           status.for1.CellNumber2 := MaxAlive
  934.         end else begin
  935.           with status.for1.alive[CurrentCell] do begin
  936.             column := ix;       (* regist it *)
  937.             row    := iy
  938.           end;
  939.           if (c and ColourMask) = 0 then (* 1000 0000   0 - not displayed *)
  940.             DrawCell(ix, iy, ForeColour);
  941.           cell := colour1               (* 1000 0000 displayed and registered *)
  942.         end
  943.       end else if (c and ClearMask) = toClear then begin
  944.                         (* 1000 1000    1000 1000 - will be dead *)
  945.         DrawCell(ix, iy, BackColour);
  946.         cell := notRegistered           (* 0000 1000    - not registered *)
  947.       end else
  948.         cell := c and ClearMask         (* 1000 1000    - clear seed count *)
  949.     end;  { of CheckField.SetCell }
  950.  
  951.     procedure SetCells(var f : BioFieldLinear;
  952.                        x : ColNumPlus1; y : RowNumPlus1);
  953.     var p : Lindex;
  954.     begin
  955.       p := y * MaxXIndexPlus1 + x;
  956.       SetCell(f[p - MaxXIndexPlus2 ], pred(x), pred(y));
  957.       SetCell(f[p - MaxXIndexPlus1 ], x,       pred(y));
  958.       SetCell(f[p - MaxXIndex      ], succ(x), pred(y));
  959.       SetCell(f[pred(p)],             pred(x), y      );
  960.       SetCell(f[p],                   x,       y      );        (* itself *)
  961.       SetCell(f[succ(p)],             succ(x), y      );
  962.       SetCell(f[p + MaxXIndex      ], pred(x), succ(y));
  963.       SetCell(f[p + MaxXIndexPlus1 ], x,       succ(y));
  964.       SetCell(f[p + MaxXIndexPlus2 ], succ(x), succ(y))
  965.     end;
  966.  
  967.     procedure SetCellsWrap(var f : BioField;
  968.                            x : ColNumPlus1; y : RowNumPlus1);
  969.     var x0, x1, y0, y1 : word;
  970.     begin
  971.       x0 := (x + MaxXIndex)       and MaxXIndex;
  972.       x1 := (x + MaxXIndexPlus2)  and MaxXIndex;
  973.       y0 := (y + MaxYIndex)       and MaxYIndex;
  974.       y1 := (y + MaxYIndexPlus2)  and MaxYIndex;
  975.       SetCell(f[y0, x0 ], x0, y0);
  976.       SetCell(f[y0, x  ], x,  y0);
  977.       SetCell(f[y0, x1 ], x1, y0);
  978.       SetCell(f[y,  x0 ], x0, y );
  979.       SetCell(f[y,  x  ], x,  y );        (* itself *)
  980.       SetCell(f[y,  x1 ], x1, y );
  981.       SetCell(f[y1, x0 ], x0, y1);
  982.       SetCell(f[y1, x  ], x,  y1);
  983.       SetCell(f[y1, x1 ], x1, y1)
  984.     end;
  985.  
  986.     procedure SetCellsMedium(var f : BioFieldLinearMedium;
  987.                              x : ColNumPlus1; y : RowNumPlus1);
  988.     var p : Lindex;
  989.     begin
  990.       p := y * MaxXIndexPlus1Medium + x;
  991.       SetCell(f[p - MaxXIndexPlus2Medium ], pred(x), pred(y));
  992.       SetCell(f[p - MaxXIndexPlus1Medium ], x,       pred(y));
  993.       SetCell(f[p - MaxXIndexMedium      ], succ(x), pred(y));
  994.       SetCell(f[pred(p)],                   pred(x), y      );
  995.       SetCell(f[p],                         x,       y      ); (* itself *)
  996.       SetCell(f[succ(p)],                   succ(x), y      );
  997.       SetCell(f[p + MaxXIndexMedium      ], pred(x), succ(y));
  998.       SetCell(f[p + MaxXIndexPlus1Medium ], x,       succ(y));
  999.       SetCell(f[p + MaxXIndexPlus2Medium ], succ(x), succ(y))
  1000.     end;
  1001.  
  1002.     procedure SetCellsWrapMedium(var f : BioFieldMedium;
  1003.                                  x : ColNumPlus1; y : RowNumPlus1);
  1004.     var x0, x1, y0, y1 : word;
  1005.     begin
  1006.       x0 := (x + MaxXIndexMedium)       and MaxXIndexMedium;
  1007.       x1 := (x + MaxXIndexPlus2Medium)  and MaxXIndexMedium;
  1008.       y0 := (y + MaxYIndexMedium)       and MaxYIndexMedium;
  1009.       y1 := (y + MaxYIndexPlus2Medium)  and MaxYIndexMedium;
  1010.       SetCell(f[y0, x0 ], x0, y0);
  1011.       SetCell(f[y0, x  ], x,  y0);
  1012.       SetCell(f[y0, x1 ], x1, y0);
  1013.       SetCell(f[y,  x0 ], x0, y );
  1014.       SetCell(f[y,  x  ], x,  y );        (* itself *)
  1015.       SetCell(f[y,  x1 ], x1, y );
  1016.       SetCell(f[y1, x0 ], x0, y1);
  1017.       SetCell(f[y1, x  ], x,  y1);
  1018.       SetCell(f[y1, x1 ], x1, y1)
  1019.     end;
  1020.  
  1021.     procedure SetCellsSmall(var f : BioFieldLinearSmall;
  1022.                             x : ColNumPlus1; y : RowNumPlus1);
  1023.     var p : Lindex;
  1024.     begin
  1025.       p := y * MaxXIndexPlus1Small + x;
  1026.       SetCell(f[p - MaxXIndexPlus2Small ], pred(x), pred(y));
  1027.       SetCell(f[p - MaxXIndexPlus1Small ], x,       pred(y));
  1028.       SetCell(f[p - MaxXIndexSmall      ], succ(x), pred(y));
  1029.       SetCell(f[pred(p)],                  pred(x), y      );
  1030.       SetCell(f[p],                        x,       y      ); (* itself *)
  1031.       SetCell(f[succ(p)],                  succ(x), y      );
  1032.       SetCell(f[p + MaxXIndexSmall      ], pred(x), succ(y));
  1033.       SetCell(f[p + MaxXIndexPlus1Small ], x,       succ(y));
  1034.       SetCell(f[p + MaxXIndexPlus2Small ], succ(x), succ(y))
  1035.     end;
  1036.  
  1037.     procedure SetCellsWrapSmall(var f : BioFieldSmall;
  1038.                                 x : ColNumPlus1; y : RowNumPlus1);
  1039.     var x0, x1, y0, y1 : word;
  1040.     begin
  1041.       x0 := (x + MaxXIndexSmall)       and MaxXIndexSmall;
  1042.       x1 := (x + MaxXIndexPlus2Small)  and MaxXIndexSmall;
  1043.       y0 := (y + MaxYIndexSmall)       and MaxYIndexSmall;
  1044.       y1 := (y + MaxYIndexPlus2Small)  and MaxYIndexSmall;
  1045.       SetCell(f[y0, x0 ], x0, y0);
  1046.       SetCell(f[y0, x  ], x,  y0);
  1047.       SetCell(f[y0, x1 ], x1, y0);
  1048.       SetCell(f[y,  x0 ], x0, y );
  1049.       SetCell(f[y,  x  ], x,  y );        (* itself *)
  1050.       SetCell(f[y,  x1 ], x1, y );
  1051.       SetCell(f[y1, x0 ], x0, y1);
  1052.       SetCell(f[y1, x  ], x,  y1);
  1053.       SetCell(f[y1, x1 ], x1, y1)
  1054.     end;
  1055.  
  1056.   begin { of CalcMain.CheckField }
  1057.     with field^ do
  1058.       case RunMode of
  1059.         LargeField : begin
  1060.             SetSentinel;
  1061.             with status.for1 do begin
  1062.               if odd(generation) then begin
  1063.                 CurrentCell := 0;
  1064.                 AddFactor   := 1;
  1065.                 for i := CellNumber2 to MaxAlive do
  1066.                   with status.for1.alive[i] do SetCells(linear, column, row);
  1067.                 CellNumber1 := CurrentCell
  1068.               end else begin
  1069.                 CurrentCell := succ(MaxAlive);
  1070.                 AddFactor   :=-1;
  1071.                 for i := CellNumber1 downto 1 do
  1072.                   with status.for1.alive[i] do SetCells(linear, column, row);
  1073.                 CellNumber2 := CurrentCell
  1074.               end
  1075.             end
  1076.           end;
  1077.         LargeFieldWrap :
  1078.             with status.for1 do begin
  1079.               if odd(generation) then begin
  1080.                 CurrentCell := 0;
  1081.                 AddFactor   := 1;
  1082.                 for i := CellNumber2 to MaxAlive do
  1083.                   with status.for1.alive[i] do
  1084.                     SetCellsWrap(matrix, column, row);
  1085.                 CellNumber1 := CurrentCell
  1086.               end else begin
  1087.                 CurrentCell := succ(MaxAlive);
  1088.                 AddFactor   :=-1;
  1089.                 for i := CellNumber1 downto 1 do
  1090.                   with status.for1.alive[i] do
  1091.                     SetCellsWrap(matrix, column, row);
  1092.                 CellNumber2 := CurrentCell
  1093.               end
  1094.             end;
  1095.         MediumField : begin
  1096.             SetSentinelMedium;
  1097.             with status.for1 do begin
  1098.               if odd(generation) then begin
  1099.                 CurrentCell := 0;
  1100.                 AddFactor   := 1;
  1101.                 for i := CellNumber2 to MaxAlive do
  1102.                   with status.for1.alive[i] do
  1103.                     SetCellsMedium(linearm, column, row);
  1104.                 CellNumber1 := CurrentCell
  1105.               end else begin
  1106.                 CurrentCell := succ(MaxAlive);
  1107.                 AddFactor   :=-1;
  1108.                 for i := CellNumber1 downto 1 do
  1109.                   with status.for1.alive[i] do
  1110.                     SetCellsMedium(linearm, column, row);
  1111.                 CellNumber2 := CurrentCell
  1112.               end
  1113.             end
  1114.           end;
  1115.         MediumFieldWrap :
  1116.             with status.for1 do begin
  1117.               if odd(generation) then begin
  1118.                 CurrentCell := 0;
  1119.                 AddFactor   := 1;
  1120.                 for i := CellNumber2 to MaxAlive do
  1121.                   with status.for1.alive[i] do
  1122.                     SetCellsWrapMedium(matrixm, column, row);
  1123.                 CellNumber1 := CurrentCell
  1124.               end else begin
  1125.                 CurrentCell := succ(MaxAlive);
  1126.                 AddFactor   :=-1;
  1127.                 for i := CellNumber1 downto 1 do
  1128.                   with status.for1.alive[i] do
  1129.                     SetCellsWrapMedium(matrixm, column, row);
  1130.                 CellNumber2 := CurrentCell
  1131.               end { else }
  1132.             end; { with }
  1133.         SmallField : begin
  1134.             SetSentinelSmall;
  1135.             with status.for1 do begin
  1136.               if odd(generation) then begin
  1137.                 CurrentCell := 0;
  1138.                 AddFactor   := 1;
  1139.                 for i := CellNumber2 to MaxAlive do
  1140.                   with status.for1.alive[i] do
  1141.                     SetCellsSmall(linears, column, row);
  1142.                 CellNumber1 := CurrentCell
  1143.               end else begin
  1144.                 CurrentCell := succ(MaxAlive);
  1145.                 AddFactor   :=-1;
  1146.                 for i := CellNumber1 downto 1 do
  1147.                   with status.for1.alive[i] do
  1148.                     SetCellsSmall(linears, column, row);
  1149.                 CellNumber2 := CurrentCell
  1150.               end
  1151.             end
  1152.           end;
  1153.         SmallFieldWrap :
  1154.             with status.for1 do begin
  1155.               if odd(generation) then begin
  1156.                 CurrentCell := 0;
  1157.                 AddFactor   := 1;
  1158.                 for i := CellNumber2 to MaxAlive do
  1159.                   with status.for1.alive[i] do
  1160.                     SetCellsWrapSmall(matrixs, column, row);
  1161.                 CellNumber1 := CurrentCell
  1162.               end else begin
  1163.                 CurrentCell := succ(MaxAlive);
  1164.                 AddFactor   :=-1;
  1165.                 for i := CellNumber1 downto 1 do
  1166.                   with status.for1.alive[i] do
  1167.                     SetCellsWrapSmall(matrixs, column, row);
  1168.                 CellNumber2 := CurrentCell
  1169.               end { else }
  1170.             end  { with }
  1171.       end  { case }
  1172.   end;  { of CalcMain.CheckField }
  1173.  
  1174. begin   { of CalcMain }
  1175.   localHAB := WinInitialize(0);
  1176.  
  1177.   delayval := dlgorg.delayval;
  1178.   RunMode  := dlgorg.RunMode;
  1179.   case RunMode of
  1180.     LargeField, LargeFieldWrap   : memsz := sizeof(BioField);
  1181.     MediumField, MediumFieldWrap : memsz := sizeof(BioFieldMedium);
  1182.     SmallField, SmallFieldWrap   : memsz := sizeof(BioFieldSmall)
  1183.   end;
  1184.   DosAllocMem(pointer(field), memsz, PAG_COMMIT + PAG_WRITE + PAG_READ);
  1185.   InitField;
  1186.   with status.for1 do
  1187.     repeat
  1188.       if ScrnCleared then begin
  1189.         DosRequestMutexSem(UsePS, SEM_INDEFINITE_WAIT);
  1190.         DispField;
  1191.         ScrnCleared := false;
  1192.         DosReleaseMutexSem(UsePS)
  1193.       end;
  1194.       if (generation and 7) = 0 then
  1195.         WinPostMsg(hwndClient, WM_USER3, CellNumber1, generation);
  1196.       ScanStatus;
  1197.       DosRequestMutexSem(UsePS, SEM_INDEFINITE_WAIT);
  1198.       CheckField;
  1199.       DosReleaseMutexSem(UsePS);
  1200.       inc(generation);
  1201.       if delayval <> 0 then DosSleep(delayval-10)
  1202.     until not continue and not odd(generation);
  1203.   DosFreeMem(pointer(field));
  1204.   with status.for1 do
  1205.     WinPostMsg(hwndClient, WM_USER3, CellNumber1, generation);
  1206.  
  1207.   WinTerminate(localHAB);
  1208.   runcalc := false;
  1209.   DosExit(EXIT_THREAD, 0)
  1210. end;    { of CalcMain }
  1211.  
  1212. (* Dialog box procedures *)
  1213.  
  1214. function AboutDlgBoxProc (h : HWND;
  1215.                           w : ULONG;
  1216.                           m1: MPARAM;
  1217.                           m2: MPARAM) : MRESULT; CDECL;
  1218. begin
  1219.   AboutDlgBoxProc := WinDefDlgProc(h, w, m1, m2)
  1220. end;
  1221.  
  1222.  
  1223. function FileDlgBoxProc  (h : HWND;
  1224.                           w : ULONG;
  1225.                           m1: MPARAM;
  1226.                           m2: MPARAM) : MRESULT; CDECL;
  1227. var dlgdt : pfiledlgdt;
  1228.     i : integer;
  1229.     id: word;
  1230.     s : string;
  1231.  
  1232.   procedure SetInitPos(var dt : filedlgdt);
  1233.   var sel : ULONG;
  1234.   begin
  1235.     sel := WinSendDlgItemMsg(h, IDD_LISTBOX, LM_QUERYSELECTION, LIT_FIRST, 0);
  1236.     if sel <> LIT_NONE then
  1237.       with flst[succ(sel)], dt do begin
  1238.         SetEntryBoxVal(h, IDD_INITCOLUMN, initx);
  1239.         ofsx := initx;
  1240.         SetEntryBoxVal(h, IDD_INITROW,    inity);
  1241.         ofsy := inity
  1242.       end
  1243.   end;
  1244.  
  1245.   procedure GetFileName(var dt : filedlgdt);
  1246.   type
  1247.     str4 = string[4];
  1248.   var
  1249.     s   : str4;
  1250.     sel : ULONG;
  1251.     b1, b2 : boolean;
  1252.  
  1253.     procedure SetInt(var n : word; s : str4; var b : boolean);
  1254.     var n1 : word;
  1255.         i  : longint;
  1256.     begin
  1257.       if s <> '' then begin
  1258.         val(s, n1, i);
  1259.         if i = 0 then n := n1
  1260.       end else
  1261.         i := 1;
  1262.       b := i = 0
  1263.     end;
  1264.  
  1265.   begin
  1266.     sel := WinSendDlgItemMsg(h, IDD_LISTBOX, LM_QUERYSELECTION, LIT_FIRST, 0);
  1267.     if sel <> LIT_NONE then
  1268.       with dt do begin
  1269.         WinSendDlgItemMsg(h, IDD_LISTBOX, LM_QUERYITEMTEXT,
  1270.                            MAKELONG(sel, sizeof(filenm^)),
  1271.                            MPARAM(filenm));
  1272.         s[0] := chr(WinQueryDlgItemText(h, IDD_INITCOLUMN, 4, @s[1]));
  1273.         SetInt(ofsx, s, b1);
  1274.         s[0] := chr(WinQueryDlgItemText(h, IDD_INITROW,    4, @s[1]));
  1275.         SetInt(ofsy, s, b2);
  1276.         if b1 and b2 then WinDismissDlg(h, 1)
  1277.                      else MyMessage(h, '', 'Error in Numerical Format.')
  1278.       end
  1279.   end;
  1280.  
  1281. begin
  1282.   FileDlgBoxProc := 0;
  1283.   case w of
  1284.     WM_INITDLG : begin
  1285.         dlgdt := pfiledlgdt(m2);
  1286.         WinSetWindowPtr(h, QWL_USER, dlgdt);
  1287.         for i := 1 to fnum do
  1288.           with flst[i] do begin
  1289.             s := fname + ' ' + comment + chr(0);
  1290.             WinSendDlgItemMsg(h, IDD_LISTBOX, LM_INSERTITEM,
  1291.                               LIT_END, MPARAM(@s[1]))
  1292.           end
  1293.       end;
  1294.     WM_CONTROL : begin
  1295.         dlgdt := WinQueryWindowPtr(h, QWL_USER);
  1296.         id := LoUShort(m1);
  1297.         with dlgdt^ do
  1298.           case id of
  1299.             IDD_ROTATE0,
  1300.             IDD_ROTATE90,
  1301.             IDD_ROTATE180,
  1302.             IDD_ROTATE270 : rot := id - IDD_ROTATE0;
  1303.             IDD_MIRRORH,
  1304.             IDD_MIRRORV   :
  1305.                 if HiUShort(m1) = BN_CLICKED then
  1306.                   if id = IDD_MIRRORH then hmirror := not hmirror
  1307.                                       else vmirror := not vmirror;
  1308.             IDD_LISTBOX   :
  1309.                 case HiUShort(m1) of
  1310.                   LN_SELECT : SetInitPos(dlgdt^);
  1311.                   LN_ENTER  : GetFileName(dlgdt^)
  1312.                 end;
  1313.           else
  1314.             FileDlgBoxProc := WinDefDlgProc(h, w, m1, m2)
  1315.           end
  1316.       end;
  1317.     WM_COMMAND :
  1318.         case LoUShort(m1) of
  1319.           DID_OK     : begin
  1320.               dlgdt := WinQueryWindowPtr(h, QWL_USER);
  1321.               GetFileName(dlgdt^)
  1322.             end;
  1323.           DID_CANCEL : WinDismissDlg(h, 0)
  1324.         end;
  1325.   else
  1326.     FileDlgBoxProc := WinDefDlgProc(h, w, m1, m2)
  1327.   end
  1328. end;
  1329.  
  1330. function DelayDlgBoxProc (h : HWND;
  1331.                           w : ULONG;
  1332.                           m1: MPARAM;
  1333.                           m2: MPARAM) : MRESULT; CDECL;
  1334. var dlgdt : pdialogdata;
  1335.     d : ULONG;
  1336.     m : word;
  1337. begin
  1338.   DelayDlgBoxProc := 0;
  1339.   case w of
  1340.     WM_INITDLG : begin
  1341.         dlgdt := pdialogdata(m2);
  1342.         WinSetWindowPtr(h, QWL_USER, dlgdt);
  1343.         with dlgdt^ do begin
  1344.           WinSendDlgItemMsg(h, IDD_SCROLLBAR,
  1345.                             SLM_SETSLIDERINFO,
  1346.                             MAKEULONG(SMA_SLIDERARMPOSITION,
  1347.                                       SMA_INCREMENTVALUE),
  1348.                                       delayval div 10);
  1349.           SetEntryBoxVal(h, IDD_ENTRYBOX, delayval);
  1350.           WinSendDlgItemMsg(h, IDD_SETPRTY, BM_SETCHECK,
  1351.                             ord(prtyidle), 0)
  1352.         end
  1353.       end;
  1354.     WM_CONTROL : begin
  1355.         dlgdt := WinQueryWindowPtr(h, QWL_USER);
  1356.         m     := HiUShort(m1);
  1357.         case LoUShort(m1) of
  1358.           IDD_SETPRTY :
  1359.               if m = BN_CLICKED then
  1360.                 with dlgdt^ do begin
  1361.                   prtyidle := not prtyidle;
  1362.                   WinSendDlgItemMsg(h, IDD_SETPRTY, BM_SETCHECK,
  1363.                                     ord(prtyidle), 0)
  1364.                 end;
  1365.           IDD_SCROLLBAR :
  1366.               if m = SLN_CHANGE then begin
  1367.                 d := WinSendDlgItemMsg(h, IDD_SCROLLBAR,
  1368.                                        SLM_QUERYSLIDERINFO,
  1369.                                        MAKEULONG(SMA_SLIDERARMPOSITION,
  1370.                                                  SMA_INCREMENTVALUE),
  1371.                                        0);
  1372.                 d := d * 10;
  1373.                 with dlgdt^ do
  1374.                   if d<>delayval then begin
  1375.                     delayval := d;
  1376.                     SetEntryBoxVal(h, IDD_ENTRYBOX, d)
  1377.                   end
  1378.               end
  1379.         end
  1380.       end;
  1381.     WM_COMMAND :
  1382.         case LoUShort(m1) of
  1383.           DID_OK     : WinDismissDlg(h, 1);
  1384.           DID_CANCEL : WinDismissDlg(h, 0)
  1385.         end;
  1386.   else
  1387.     DelayDlgBoxProc := WinDefDlgProc(h, w, m1, m2)
  1388.   end
  1389. end;
  1390.  
  1391. function FieldDlgBoxProc (h : HWND;
  1392.                           w : ULONG;
  1393.                           m1: MPARAM;
  1394.                           m2: MPARAM) : MRESULT; CDECL;
  1395. var dlgdt : pdialogdata;
  1396.     d : ULONG;
  1397.     md: RunningModes;
  1398. begin
  1399.   FieldDlgBoxProc := 0;
  1400.   case w of
  1401.     WM_INITDLG : begin
  1402.         dlgdt := pdialogdata(m2);
  1403.         WinSetWindowPtr(h, QWL_USER, dlgdt);
  1404.         with dlgdt^ do begin
  1405.           WinSendDlgItemMsg(h, IDD_LARGEFIELD + ord(RunMode) div 2,
  1406.                             BM_SETCHECK, 1, 0);
  1407.           WinSendDlgItemMsg(h, IDD_FIELDWRAP, BM_SETCHECK,
  1408.                             ord(odd(ord(RunMode))), 0)
  1409.         end
  1410.       end;
  1411.     WM_COMMAND :
  1412.         case LoUShort(m1) of
  1413.           DID_OK     : begin
  1414.               dlgdt := WinQueryWindowPtr(h, QWL_USER);
  1415.               with dlgdt^ do begin
  1416.                 d := WinSendDlgItemMsg(h, IDD_LARGEFIELD,
  1417.                                        BM_QUERYCHECKINDEX, 0, 0);
  1418.                 if d in [0..2] then begin
  1419.                   case d of
  1420.                     0 : md := LargeField;
  1421.                     1 : md := MediumField;
  1422.                     2 : md := SmallField
  1423.                   end;
  1424.                   d := WinSendDlgItemMsg(h, IDD_FIELDWRAP,
  1425.                                          BM_QUERYCHECK, 0, 0);
  1426.                   if d = 1 then inc(md);
  1427.                   RunMode := md;
  1428.                   WinDismissDlg(h, 1)
  1429.                 end
  1430.               end
  1431.             end;
  1432.           DID_CANCEL : WinDismissDlg(h, 0)
  1433.         end;
  1434.   else
  1435.     FieldDlgBoxProc := WinDefDlgProc(h, w, m1, m2)
  1436.   end
  1437. end;
  1438.  
  1439.  
  1440. function ColourDlgBoxProc (h : HWND;
  1441.                            w : ULONG;
  1442.                            m1: MPARAM;
  1443.                            m2: MPARAM) : MRESULT; CDECL;
  1444. var id : word;
  1445.     dlgdt : pdialogdata;
  1446. begin
  1447.   case w of
  1448.     WM_INITDLG : begin
  1449.         dlgdt := pdialogdata(m2);
  1450.         WinSetWindowPtr(h, QWL_USER, dlgdt);
  1451.         with dlgdt^ do begin
  1452.           WinSendDlgItemMsg(h, forecolour + IDD_COLOUR, BM_SETCHECK, 1, 0);
  1453.           WinSendDlgItemMsg(h, backcolour + IDD_COLOUR, BM_SETCHECK, 1, 0)
  1454.         end;
  1455.         ColourDlgBoxProc := 0
  1456.       end;
  1457.     WM_CONTROL : begin
  1458.         dlgdt := WinQueryWindowPtr(h, QWL_USER);
  1459.         id := LoUShort(m1);
  1460.         ColourDlgBoxProc := 0;
  1461.         case id of
  1462.           IDD_FOREBLACK..IDD_FOREGREY : dlgdt^.forecolour := id - IDD_COLOUR;
  1463.           IDD_BACKBLACK..IDD_BACKGREY : dlgdt^.backcolour := id - IDD_COLOUR
  1464.         else
  1465.           ColourDlgBoxProc := WinDefDlgProc(h, w, m1, m2)
  1466.         end
  1467.       end;
  1468.     WM_COMMAND : begin
  1469.         case LoUShort(m1) of
  1470.           DID_OK      : WinDismissDlg(h, 1);
  1471.           DID_CANCEL  : WinDismissDlg(h, 0)
  1472.         end
  1473.       end;
  1474.   else
  1475.     ColourDlgBoxProc := WinDefDlgProc(h, w, m1, m2)
  1476.   end
  1477. end;
  1478.  
  1479. function InfoWndProc(   h : HWND;
  1480.                         w : ULONG;
  1481.                         m1: MPARAM;
  1482.                         m2: MPARAM) : MRESULT; CDECL;
  1483. type
  1484.   cellinfo = record
  1485.     cb  : word;
  1486.     num : word;
  1487.     gen : integer
  1488.   end;
  1489. var r : RECTL;
  1490.     hp: HPS;
  1491.     cinf : ^cellinfo;
  1492.     s : string[39];
  1493.     ss: string[5];
  1494. begin
  1495.   InfoWndProc := 0;
  1496.   case w of
  1497.     WM_CREATE: begin
  1498.         new(cinf);
  1499.         with cinf^ do begin
  1500.           cb := sizeof(cinf^);
  1501.           num:= 0;
  1502.           gen:= 0
  1503.         end;
  1504.         WinSetWindowPtr(h, QWL_USER, cinf)
  1505.       end;
  1506.     WM_PAINT : with status.for1 do begin
  1507.         cinf := WinQueryWindowPtr(h, QWL_USER);
  1508.         s := 'CELL :       TIME :       ' + VersNum;
  1509.         with cinf^ do begin
  1510.           str(num, ss);
  1511.           move(ss[1], s[8], length(ss));
  1512.           str(gen, ss);
  1513.           move(ss[1], s[21], length(ss))
  1514.         end;
  1515.         hp := WinBeginPaint(h, NULLHANDLE, @r);
  1516.         WinDrawText(hp, length(s), @s[1], r,
  1517.                     CLR_BLUE, 0, DT_LEFT + DT_ERASERECT);
  1518.         WinEndPaint(hp)
  1519.       end;
  1520.     WM_USER4 : begin
  1521.         cinf := WinQueryWindowPtr(h, QWL_USER);
  1522.         with cinf^ do begin
  1523.           num := m1;
  1524.           gen := m2
  1525.         end
  1526.       end;
  1527.     WM_ERASEBACKGROUND :
  1528.         InfoWndProc := 1;
  1529.     WM_CLOSE : begin
  1530.         cinf := WinQueryWindowPtr(h, QWL_USER);
  1531.         dispose(cinf);
  1532.         InfoWndProc := WinDefWindowProc(h, w, m1, m2)
  1533.       end
  1534.   else
  1535.     InfoWndProc := WinDefWindowProc(h, w, m1, m2)
  1536.   end
  1537. end;
  1538.  
  1539.  
  1540. function AppWndProc(    h : HWND;
  1541.                         w : ULONG;
  1542.                         m1: MPARAM;
  1543.                         m2: MPARAM) : MRESULT; CDECL;
  1544. (* Main Window Procedure *)
  1545. var
  1546.   myhps : HPS;
  1547.   rcl   : RECTL;
  1548.   currentpoint,
  1549.   waitpoint : HPOINTER;
  1550.  
  1551.   procedure EnableMenuItem(h : HWND; id : word; enable : boolean);
  1552.   begin
  1553.     WinSendMsg(h, MM_SETITEMATTR,
  1554.                MAKEULONG(id, 1),
  1555.                MAKEULONG(MIA_DISABLED, MIA_DISABLED * ord(not enable)))
  1556.   end;  { AppWndProc.EnableMenuItem }
  1557.  
  1558.   function hwndParent : HWND;
  1559.   begin
  1560.     hwndParent := WinQueryWindow(h, QW_PARENT)
  1561.   end;  { AppWndProc.hwndParent }
  1562.  
  1563.   procedure SetScrollParam;
  1564.   begin
  1565.     Xscrn := MaxX * zoom;
  1566.     Xmove := Xscrn - Xsize;
  1567.     if Xmove < 0 then Xmove := 0;
  1568.     Yscrn := MaxY * zoom;
  1569.     Ymove := Yscrn - Ysize;
  1570.     if Ymove < 0 then Ymove := 0;
  1571.     WinSendMsg(hwndHscroll, SBM_SETSCROLLBAR, 0, MAKELONG(0, Xmove));
  1572.     WinSendMsg(hwndHscroll, SBM_SETPOS, dx, 0);
  1573.     WinSendMsg(hwndVscroll, SBM_SETSCROLLBAR, 0, MAKELONG(0, Ymove));
  1574.     WinSendMsg(hwndVscroll, SBM_SETPOS, Ymove - dy, 0)
  1575.   end;  { AppWndProc.SetScrollParam }
  1576.  
  1577.   procedure ZoomInOut(zoomin : boolean);
  1578.   begin
  1579.     inc(zoom, pred(ord(zoomin) * 2));
  1580.     SetScrollParam;
  1581.     SetViewParam(zoom, zoom, -dx, -dy);
  1582.     WinInvalidateRect(h, nil, false)
  1583.   end;  { AppWndProc.ZoomInOut }
  1584.  
  1585.   procedure InitWin;
  1586.   begin
  1587.     continue  := false;
  1588.     runcalc   := false;
  1589.     inited    := false;
  1590.     InitialisePS(h, hpsInit);
  1591.     DosCreateMutexSem(nil, UsePS, 0, true);
  1592.     SetViewParam(1, 1, 0, 0);
  1593.     GpiSetBackColor(hpsInit, CLR_BLACK);
  1594.     DosReleaseMutexSem(UsePS);
  1595.     WinRegisterClass(myhab, InfoName, InfoWndProc, CS_SIZEREDRAW, 16);
  1596.     hwndInfo := WinCreateWindow(h, InfoName, nil, WS_VISIBLE,
  1597.                                 0, 0, MaxXIndex, CharHeight,
  1598.                                 h, HWND_TOP, 1, nil, nil);
  1599.     hwndHscroll := WinWindowFromID(hwndParent, FID_HORZSCROLL);
  1600.     hwndVscroll := WinWindowFromID(hwndParent, FID_VERTSCROLL);
  1601.     WinSendMsg(hwndVscroll, SBM_SETPOS, dy, 0)
  1602.   end;  { AppWndProc.InitWin }
  1603.  
  1604.   procedure InitMenu(cmd : word; mhwnd : HWND);
  1605.   begin
  1606.     case cmd of
  1607.       IDM_LIFE : begin
  1608.           EnableMenuItem(mhwnd, IDM_INIT,  not runcalc);
  1609.           EnableMenuItem(mhwnd, IDM_ADD,   inited > runcalc);
  1610.           EnableMenuItem(mhwnd, IDM_START, inited)
  1611.         end;
  1612.       IDM_OPTION : begin
  1613.           EnableMenuItem(mhwnd, IDM_ENLARGE,   zoom < MaxZoom);
  1614.           EnableMenuItem(mhwnd, IDM_SHRINK,    zoom > 1);
  1615.           EnableMenuItem(mhwnd, IDM_FIELDSIZE, not runcalc)
  1616.         end
  1617.     end
  1618.   end;  { AppWndProc.InitMenu }
  1619.  
  1620.   procedure CommandProcs(cmd : word);
  1621.   var dlgdata : pdialogdata;
  1622.       fdlg    : pfiledlgdt;
  1623.       changed : ULONG;
  1624.       s       : string;
  1625.  
  1626.     procedure ReadCellDataFile;
  1627.     var fname   : string;
  1628.         ecl     : pEditCells;
  1629.         i       : integer;
  1630.     begin
  1631.       currentpoint := WinQueryPointer(HWND_DESKTOP);
  1632.       waitpoint    := WinQuerySysPointer(HWND_DESKTOP, SPTR_WAIT, false);
  1633.       WinSetPointer(HWND_DESKTOP, waitpoint);
  1634.       new(ecl);
  1635.       with ecl^, fdlg^ do begin
  1636.         fname := StrPas(filenm^);
  1637.         i := pos(' ', fname);
  1638.         fname := copy(fname, 1, pred(i));
  1639.         ReadCellFromText(fname, ecl^);
  1640.         if ofsx = 0 then initColumn := MaxX div 2
  1641.                     else initColumn := ofsx;
  1642.         if ofsy = 0 then initRow    := MaxY div 2
  1643.                     else initRow    := ofsy;
  1644.         RotateField(ecl^, rot);
  1645.         if hmirror then ReverseFieldH(ecl^);
  1646.         if vmirror then ReverseFieldV(ecl^)
  1647.       end;
  1648.       InitLifeField(ecl^, cmd = IDM_INIT);
  1649.       dispose(ecl);
  1650.       WinSetPointer(HWND_DESKTOP, currentpoint)
  1651.     end;
  1652.  
  1653.     procedure SetPriority;
  1654.     var u : ULONG;
  1655.     begin
  1656.       if dlgorg.prtyidle then u := PRTYC_IDLETIME
  1657.                          else u := PRTYC_REGULAR;
  1658.       DosSetPriority(PRTYS_THREAD, u, 0, idThread)
  1659.     end;
  1660.  
  1661.     function GetFileName(title, extention : string; save : boolean) : string;
  1662.     var fdlg  : FILEDLG;
  1663.         cTitle: string;
  1664.         i     : integer;
  1665.         s     : string;
  1666.     begin
  1667.       cTitle     := title + ' File' + chr(0);
  1668.       fillchar(fdlg, sizeof(fdlg), 0);
  1669.       with fdlg do begin
  1670.         cbsize     := sizeof(fdlg);
  1671.         fl         := FDS_HELPBUTTON + FDS_CENTER;
  1672.         if save then inc(fl, FDS_SAVEAS_DIALOG)
  1673.                 else inc(fl, FDS_OPEN_DIALOG);
  1674.         pszTitle   := @cTitle[1];
  1675.         s          := '';
  1676.         i := WinFileDlg(HWND_DESKTOP, h, fdlg);
  1677.         if (i<>0) and (lReturn = DID_OK) then begin
  1678.           if papszFQFilename<>nil then begin
  1679.             s := StrPas(papszFQFilename^[0]);
  1680.             WinFreeFileDlgList(papszFQFilename)
  1681.           end else
  1682.             s := StrPas(szFullFile)
  1683.         end
  1684.       end;
  1685.       GetFileName := s
  1686.     end;
  1687.  
  1688.   begin
  1689.     case cmd of
  1690.       IDM_INIT, IDM_ADD    : begin
  1691.           currentpoint := WinQueryPointer(HWND_DESKTOP);
  1692.           waitpoint    := WinQuerySysPointer(HWND_DESKTOP, SPTR_WAIT, false);
  1693.           WinSetPointer(HWND_DESKTOP, waitpoint);
  1694.           MakeFileList('*.lif', flst, fnum);
  1695.           WinSetPointer(HWND_DESKTOP, currentpoint);
  1696.           new(fdlg);
  1697.           fillchar(fdlg^, sizeof(fdlg^), 0);
  1698.           with fdlg^ do begin
  1699.             cb := sizeof(fdlg^);
  1700.             new(filenm);
  1701.             fillchar(filenm^, sizeof(filenm^), 0)
  1702.           end;
  1703.           changed := WinDlgBox(HWND_DESKTOP, h, FileDlgBoxProc,
  1704.                                NULLHANDLE, IDD_FILELIST, fdlg);
  1705.           if changed <> 0 then begin
  1706.             ReadCellDataFile;
  1707.             inited := true;
  1708.             WinInvalidateRect(h, nil, false)
  1709.           end;
  1710.           dispose(fdlg^.filenm);
  1711.           dispose(fdlg)
  1712.         end;
  1713.       IDM_START   :
  1714.           if not runcalc then begin
  1715.             runcalc := true;
  1716.             continue:= true;
  1717.             BeginThread(nil, StackSize, CalcMain,
  1718.                         nil, CREATE_READY, idThread);
  1719.             SetPriority
  1720.           end;
  1721.       IDM_END     :
  1722.           continue := false;
  1723.       IDM_ENLARGE,
  1724.       IDM_SHRINK  :
  1725.           ZoomInOut(cmd = IDM_ENLARGE);
  1726.       IDM_SETDELAY: begin
  1727.           new(dlgdata);
  1728.           dlgdata^ := dlgorg;
  1729.           changed  := WinDlgBox(HWND_DESKTOP, h, DelayDlgBoxProc,
  1730.                                 NULLHANDLE, IDD_SETDELAY, dlgdata);
  1731.           if changed <> 0 then begin
  1732.             dlgorg := dlgdata^;
  1733.             if runcalc then SetPriority
  1734.           end;
  1735.           dispose(dlgdata)
  1736.         end;
  1737.       IDM_SETCOLOUR : begin
  1738.           new(dlgdata);
  1739.           dlgdata^ := dlgorg;
  1740.           changed  := WinDlgBox(HWND_DESKTOP, h, ColourDlgBoxProc,
  1741.                                 NULLHANDLE, IDD_COLOUR, dlgdata);
  1742.           if changed <> 0 then begin
  1743.             dlgorg := dlgdata^;
  1744.             ForeColour := colour[dlgorg.forecolour];
  1745.             BackColour := colour[dlgorg.backcolour];
  1746.             WinInvalidateRect(h, nil, false)
  1747.           end;
  1748.           dispose(dlgdata)
  1749.         end;
  1750.       IDM_FIELDSIZE : begin
  1751.           new(dlgdata);
  1752.           dlgdata^ := dlgorg;
  1753.           changed  := WinDlgBox(HWND_DESKTOP, h, FieldDlgBoxProc,
  1754.                                NULLHANDLE, IDD_FIELDSIZE, dlgdata);
  1755.           if changed <> 0 then begin
  1756.             dlgorg := dlgdata^;
  1757.             SetMaxXY;
  1758.             LimitLifeField;
  1759.             WinInvalidateRect(h, nil, false)
  1760.           end;
  1761.           dispose(dlgdata)
  1762.         end;
  1763.       IDM_LOADSETTINGS : begin
  1764.           s := GetFileName('Loading Setting', '*.ini', false);
  1765.           LoadSettings(h, s);
  1766.           SetMaxXY;
  1767.           LimitLifeField;
  1768.           WinInvalidateRect(h, nil, false)
  1769.         end;
  1770.       IDM_SAVESETTINGS : begin
  1771.           s := GetFileName('Saving Setting', '*.ini', false);
  1772.           SaveSettings(hwndFrame, s)
  1773.         end;
  1774.       IDM_SAVEDEFSETTINGS :
  1775.           SaveSettings(hwndFrame, ININame);
  1776.       IDM_ABOUT   :
  1777.           WinDlgBox(HWND_DESKTOP, h, AboutDlgBoxProc,
  1778.                     NULLHANDLE, IDD_ABOUT, nil)
  1779.     end
  1780.   end;  { AppWndProc.CommandProc }
  1781.  
  1782.   procedure HScrollProc(cmd : word);
  1783.   begin
  1784.     case cmd of
  1785.       SB_LINELEFT : dec(dx, zoom);
  1786.       SB_LINERIGHT: inc(dx, zoom);
  1787.       SB_PAGELEFT : dec(dx, zoom * 10);
  1788.       SB_PAGERIGHT: inc(dx, zoom * 10);
  1789.       SB_SLIDERPOSITION : dx := LoUShort(m2)
  1790.     end;
  1791.     if      dx < 0     then dx := 0
  1792.     else if dx > Xmove then dx := Xmove;
  1793.     WinSendMsg(hwndHscroll,  SBM_SETPOS, dx, 0);
  1794.     SetViewParam(zoom, zoom, -dx, -dy);
  1795.     WinInvalidateRect(h, nil, false)
  1796.   end;  { AppWndProc.HScrollProc }
  1797.  
  1798.   procedure VScrollProc(cmd : word);
  1799.   begin
  1800.     case cmd of
  1801.       SB_LINEUP  : inc(dy, zoom);
  1802.       SB_LINEDOWN: dec(dy, zoom);
  1803.       SB_PAGEUP  : inc(dy, zoom * 10);
  1804.       SB_PAGEDOWN: dec(dy, zoom * 10);
  1805.       SB_SLIDERPOSITION : dy := Ymove - LoUShort(m2)
  1806.     end;
  1807.     if      dy < 0     then dy := 0
  1808.     else if dy > Ymove then dy := Ymove;
  1809.     WinSendMsg(hwndVscroll, SBM_SETPOS, Ymove - dy, 0);
  1810.     SetViewParam(zoom, zoom, -dx, -dy);
  1811.     WinInvalidateRect(h, nil, false)
  1812.   end;  { AppWndProc.VScrollProc }
  1813.  
  1814. begin   { AppWndProc }
  1815.   AppWndProc := 0;
  1816.   case w of
  1817.     WM_CREATE :
  1818.         InitWin;
  1819.     WM_SIZE  : begin
  1820.         Xsize := LoUShort(m2);
  1821.         Ysize := HiUShort(m2);
  1822.         SetScrollParam;
  1823.         WinSetWindowPos(hwndInfo, HWND_TOP, 0, 0, Xsize, CharHeight, fSwp);
  1824.         WinInvalidateRect(h, nil, false)
  1825.       end;
  1826.     WM_PAINT : begin
  1827.         DosRequestMutexSem(UsePS, 500);
  1828.         WinBeginPaint(h, hpsInit, @rcl);
  1829.         WinFillRect(hpsInit, rcl, BackColour);
  1830.         if not continue then DispField;
  1831.         WinEndPaint(hpsInit);
  1832.         DosReleaseMutexSem(UsePS);
  1833.         ScrnCleared := true
  1834.       end;
  1835.     WM_USER2       : begin                (* Cell number overflow *)
  1836.         continue := false;
  1837.         MyMessage(h, '', 'Too Many Cells. Program Stopped.')
  1838.       end;
  1839.     WM_USER3       : begin
  1840.         WinSendMsg(hwndInfo, WM_USER4, m1, m2);
  1841.         WinInvalidateRect(hwndInfo, nil, false)
  1842.       end;
  1843.     WM_INITMENU :
  1844.         InitMenu(CommandMsgMP1(m1).cmd, HWND(m2));
  1845.     WM_COMMAND :
  1846.         CommandProcs(CommandMsgMP1(m1).cmd);
  1847.     WM_HSCROLL :
  1848.         HScrollProc(HiUShort(m2));
  1849.     WM_VSCROLL :
  1850.         VScrollProc(HiUShort(m2));
  1851.     WM_ERASEBACKGROUND :
  1852.         AppWndProc := 1;
  1853.     WM_CLOSE : begin
  1854.         WinReleasePS(hpsInit);
  1855.         AppWndProc := WinDefWindowProc(h, w, m1, m2)
  1856.       end
  1857.   else
  1858.     AppWndProc := WinDefWindowProc(h, w, m1, m2)
  1859.   end
  1860. end;   { AppWndProc }
  1861.  
  1862. begin  { Main }
  1863.   InitVar;
  1864.  
  1865.   myhab := WinInitialize(0);
  1866.   myhmq := WinCreateMsgQueue(myhab, 0);
  1867.  
  1868.   WinRegisterClass(myhab, ClassName, AppWndProc, CS_SIZEREDRAW, 0);
  1869.  
  1870.   hwndFrame := WinCreateStdWindow(HWND_DESKTOP,
  1871.                                   WS_VISIBLE + WS_CLIPCHILDREN,
  1872.                                   ctlData, ClassName, VersNum, 0,
  1873.                                   NULLHANDLE, ID_RESOURCE, @hwndClient);
  1874.  
  1875.   with dlgorg do
  1876.     WinSetWindowPos(hwndFrame, HWND_TOP, posx0, posy0, posx1, posy1, fSwp);
  1877.  
  1878.   while WinGetMsg(myhab, myqmsg, NULLHANDLE, 0, 0) do
  1879.     WinDispatchMsg(myhab, myqmsg);
  1880.  
  1881.   if continue then begin
  1882.     DosResumeThread(idThread);
  1883.     DosKillThread(idThread)
  1884.   end;
  1885.  
  1886.   WinDestroyMsgQueue(myhmq);
  1887.   WinTerminate(myhab)
  1888. end.
  1889.  
  1890.