home *** CD-ROM | disk | FTP | other *** search
/ Aztec Shareware Collection / AZ_096.ISO / yahwho / yahwho.pas < prev    next >
Pascal/Delphi Source File  |  1993-06-27  |  67KB  |  2,662 lines

  1. {$B-,V-,X+} {These MUST be set!}
  2. Program YahWho;
  3.  
  4. { Developed in Borland Pascal 7.0 & Turbo Vision 2.0.
  5.  
  6.   Program Author: Keith Greer
  7.                   68 Tamworth Rd.
  8.                   Troy, OH 45373-1551
  9.  
  10.   Thanks to Tom & Guy Hunter for original logic & algorithms.
  11.  
  12. }
  13. uses YahWho1,YahHelp,GpFrame,App,Dos,Objects,Drivers,Memory,Validate,
  14.      Views,Menus,Dialogs,StdDlg,MsgBox,HelpFile,ColorSel;
  15.  
  16. type
  17.  
  18.   Scorestring = string[20];
  19.   TDice       = array[1..5] of byte;
  20.   ScoreType   = (Upper,Lower);
  21.   TScore      = record
  22.      TValue    : ScoreType;
  23.      Value     : word;
  24.   end;
  25.  
  26.   {TMyStatusLine}
  27.   PMyStatusLine = ^TMyStatusLine;
  28.   TMyStatusLine = object(TStatusLine)
  29.     function Hint(AHelpCtx: Word): String; virtual;
  30.   end;
  31.  
  32.   {TMyColorDialog}
  33.  
  34.   PMyColorDialog = ^TMyColorDialog;
  35.   TMyColorDialog = object(TColorDialog)
  36.     DPal : TPalette;
  37.     constructor Init(APalette: TPalette;
  38.                      DPalette: TPalette; AGroups: PColorGroup);
  39.     procedure HandleEvent(var Event: TEvent); virtual;
  40.   end;
  41.  
  42.   PTopScore = ^TTopScore;
  43.   TTopScore = object(TObject)
  44.     Score : integer;
  45.     Name,
  46.     Date  : string[10];
  47.     constructor Init(NewScore : integer; const NewName, NewDate : String);
  48.     constructor Load(var S : TStream);
  49.     procedure Store(var S : TStream); virtual;
  50.   end;
  51.  
  52.   PScoreList = ^TScoreList;
  53.   TScoreList = object(TSortedCollection)
  54.     constructor Init(ALimit, ADelta: Integer);
  55.     function Compare(Key1, Key2: Pointer): Integer; virtual;
  56.     function KeyOf(Item: Pointer): Pointer; virtual;
  57.   end;
  58.  
  59.   PTopScoreList = ^TTopScoreList;
  60.   TTopScoreList = object(TScoreList)
  61.     MinScore : integer;
  62.     constructor Init(ALimit, ADelta: Integer);
  63.     constructor Load(var S : TStream);
  64.     procedure Store(var S : TStream); virtual;
  65.     procedure Insert(Item: Pointer); virtual;
  66.   end;
  67.  
  68.   PScoreListBox = ^TScoreListBox;
  69.   TScoreListBox = object(TListBox)
  70.     function GetText(Item: Integer; MaxLen: Integer): String; virtual;
  71.   end;
  72.  
  73.   PYahWho = ^TYahWho;
  74.   TYahWho = object(TApplication)
  75.     constructor Init;
  76.     destructor Done; virtual;
  77.     constructor Load(var S : TStream);
  78.     procedure About;
  79.     procedure LoadDesktop(var S: TStream);
  80.     procedure StoreDesktop(var S: TStream);
  81.     procedure GetEvent(var Event: TEvent); virtual;
  82.     function GetPalette: PPalette; virtual;
  83.     function Valid(Command: Word): Boolean; virtual;
  84.     procedure HandleEvent(var Event: TEvent); virtual;
  85.     procedure Idle; virtual;
  86.     procedure InitMenuBar; virtual;
  87.     procedure InitStatusLine; virtual;
  88.     procedure OutOfMemory; virtual;
  89.     procedure Awaken; virtual;
  90.   end;
  91.  
  92.   PScoreItem = ^TScoreItem;
  93.   TScoreItem = object(TView)
  94.     constructor Init(Bounds : TRect; HKey : char; const Name : Scorestring);
  95.     destructor Done; virtual;
  96.     constructor Load(var S : TStream);
  97.     procedure Store(var S : TStream); virtual;
  98.     procedure HandleEvent(var Event: TEvent); virtual;
  99.     function GetPalette: PPalette; virtual;
  100.     procedure Draw; virtual;
  101.     function ValidScore(const D : TDice) : boolean; virtual;
  102.   private
  103.     HotKey    : char;
  104.     ScoreName : PString;
  105.     Score     : word;
  106.     Lite      : boolean;
  107.     Yahtzee,
  108.     Scored     : boolean;
  109.     TempScore  : word;
  110.   end;
  111.  
  112.   PScoreBoard = ^TScoreBoard;
  113.   TScoreBoard = object(TGroup)
  114.     constructor Init(Bounds : TRect);
  115.     procedure SizeLimits(var Min, Max: TPoint); virtual;
  116.   end;
  117.  
  118.   PDiceSet = ^TDiceSet;
  119.   TDiceSet = object(TGroup)
  120.     constructor Init(Bounds : TRect);
  121.     procedure SizeLimits(var Min, Max: TPoint); virtual;
  122.   end;
  123.  
  124.   PDiceFrame = ^TDiceFrame;
  125.   TDiceFrame = object(TGroupFrame)
  126.     procedure HandleEvent(var Event: TEvent); virtual;
  127.   end;
  128.  
  129.   PScoreFrame = ^TScoreFrame;
  130.   TScoreFrame = object(TGroupFrame)
  131.     procedure Draw; virtual;
  132.   end;
  133.  
  134.   PDie = ^TDie;
  135.   TDie = object(TView)
  136.     Value : byte;
  137.     constructor Init(Bounds : TRect; HKey : char);
  138.     constructor Load(var S : TStream);
  139.     procedure Store(var S : TStream); virtual;
  140.     function GetPalette : PPalette; virtual;
  141.     procedure Draw; virtual;
  142.     procedure HandleEvent(var Event: TEvent); virtual;
  143.   private
  144.     HotKey : char;
  145.     Selected   : boolean;
  146.   end;
  147.  
  148.   PGameWindow = ^TGameWindow;
  149.   TGameWindow = object(TWindow)
  150.     Total     : word;
  151.     RollCount : byte;
  152.     Dice      : TDice;
  153.     PlayerDone : boolean;
  154.     constructor Init(Bounds :TRect; const Player : string);
  155.     constructor Load(var S : TStream);
  156.     procedure Store(var S : TStream); virtual;
  157.     procedure HandleEvent(var Event: TEvent); virtual;
  158.     function Valid(Command: Word): Boolean; virtual;
  159.     function RollOk : boolean;
  160.   private
  161.     ScoreBoard : PScoreBoard;
  162.     DiceSet    : PDiceSet;
  163.   end;
  164.  
  165.   PRollCounter = ^TRollCounter;
  166.   TRollCounter = object(TView)
  167.     constructor Init(Bounds : TRect);
  168.     procedure Draw; virtual;
  169.     procedure HandleEvent(var Event: TEvent); virtual;
  170.     constructor Load(var S : TStream);
  171.     procedure Store(var S : TStream); virtual;
  172.   private
  173.     Count : byte;
  174.   end;
  175.  
  176.   POnes = ^TOnes;
  177.   TOnes = object(TScoreItem)
  178.     function ValidScore(const D : TDice) : boolean; virtual;
  179.   end;
  180.  
  181.   PTwos = ^TTwos;
  182.   TTwos = object(TScoreItem)
  183.     function ValidScore(const D : TDice) : boolean; virtual;
  184.   end;
  185.  
  186.   PThrees = ^TThrees;
  187.   TThrees = object(TScoreItem)
  188.     function ValidScore(const D : TDice) : boolean; virtual;
  189.   end;
  190.  
  191.   PFours = ^TFours;
  192.   TFours = object(TScoreItem)
  193.     function ValidScore(const D : TDice) : boolean; virtual;
  194.   end;
  195.  
  196.   PFives = ^TFives;
  197.   TFives = object(TScoreItem)
  198.     function ValidScore(const D : TDice) : boolean; virtual;
  199.   end;
  200.  
  201.   PSixes = ^TSixes;
  202.   TSixes = object(TScoreItem)
  203.     function ValidScore(const D : TDice) : boolean; virtual;
  204.   end;
  205.  
  206.   P3Kind = ^T3Kind;
  207.   T3Kind = object(TScoreItem)
  208.     function ValidScore(const D : TDice) : boolean; virtual;
  209.   end;
  210.  
  211.   P4Kind = ^T4Kind;
  212.   T4Kind = object(TScoreItem)
  213.     function ValidScore(const D : TDice) : boolean; virtual;
  214.   end;
  215.  
  216.   PFullHouse = ^TFullHouse;
  217.   TFullHouse = object(TScoreItem)
  218.     function ValidScore(const D : TDice) : boolean; virtual;
  219.   end;
  220.  
  221.   PSmStraight = ^TSmStraight;
  222.   TSmStraight = object(TScoreItem)
  223.     function ValidScore(const D : TDice) : boolean; virtual;
  224.   end;
  225.  
  226.   PLgStraight = ^TLgStraight;
  227.   TLgStraight = object(TScoreItem)
  228.     function ValidScore(const D : TDice) : boolean; virtual;
  229.   end;
  230.  
  231.   PYahtzee = ^TYahtzee;
  232.   TYahtzee = object(TScoreItem)
  233.     procedure HandleEvent(var Event: TEvent); virtual;
  234.     function ValidScore(const D : TDice) : boolean; virtual;
  235.   end;
  236.  
  237.   PChance = ^TChance;
  238.   TChance = object(TScoreItem)
  239.     function ValidScore(const D : TDice) : boolean; virtual;
  240.   end;
  241.  
  242.   PUpperTotal = ^TUpperTotal;
  243.   TUpperTotal = object(TView)
  244.     constructor Init(Bounds : TRect; const Name : Scorestring);
  245.     destructor Done; virtual;
  246.     constructor Load(var S : TStream);
  247.     procedure Store(var S : TStream); virtual;
  248.     procedure HandleEvent(var Event: TEvent); virtual;
  249.     function GetPalette: PPalette; virtual;
  250.     procedure Draw; virtual;
  251.   private
  252.     ScoreName : PString;
  253.     Total     : word;
  254.     Bonus     : boolean;
  255.   end;
  256.  
  257.   PUpperBonus = ^TUpperBonus;
  258.   TUpperBonus = object(TView)
  259.     constructor Init(Bounds : TRect; const Name : Scorestring);
  260.     destructor Done; virtual;
  261.     constructor Load(var S : TStream);
  262.     procedure Store(var S : TStream); virtual;
  263.     procedure HandleEvent(var Event: TEvent); virtual;
  264.     function GetPalette: PPalette; virtual;
  265.     procedure Draw; virtual;
  266.   private
  267.     ScoreName : PString;
  268.   end;
  269.  
  270.   PTotal = ^TTotal;
  271.   TTotal = object(TView)
  272.     constructor Init(Bounds : TRect; const Name : Scorestring);
  273.     destructor Done; virtual;
  274.     constructor Load(var S : TStream);
  275.     procedure Store(var S : TStream); virtual;
  276.     procedure HandleEvent(var Event: TEvent); virtual;
  277.     function GetPalette: PPalette; virtual;
  278.     procedure Draw; virtual;
  279.   private
  280.     ScoreName : PString;
  281.     TopScore,BottomScore,
  282.     Total  : word;
  283.   end;
  284.  
  285. const
  286.  
  287. RTopScore : TStreamRec = (
  288.   ObjType: 2500;
  289.   VmtLink: Ofs(TypeOf(TTopScore)^);
  290.   Load: @TTopScore.Load;
  291.   Store: @TTopScore.Store);
  292.  
  293. RScoreList : TStreamRec = (
  294.   ObjType: 2501;
  295.   VmtLink: Ofs(TypeOf(TScoreList)^);
  296.   Load: @TScoreList.Load;
  297.   Store: @TScoreList.Store);
  298.  
  299. RTopScoreList : TStreamRec = (
  300.   ObjType: 2502;
  301.   VmtLink: Ofs(TypeOf(TTopScoreList)^);
  302.   Load: @TTopScoreList.Load;
  303.   Store: @TTopScoreList.Store);
  304.  
  305. RYahWho : TStreamRec = (
  306.   ObjType: 2503;
  307.   VmtLink: Ofs(TypeOf(TYahWho)^);
  308.   Load: @TYahWho.Load;
  309.   Store: @TYahWho.Store);
  310.  
  311. RScoreItem : TStreamRec = (
  312.   ObjType: 2504;
  313.   VmtLink: Ofs(TypeOf(TScoreItem)^);
  314.   Load: @TScoreItem.Load;
  315.   Store: @TScoreItem.Store);
  316.  
  317. RScoreBoard : TStreamRec = (
  318.   ObjType: 2505;
  319.   VmtLink: Ofs(TypeOf(TScoreBoard)^);
  320.   Load: @TScoreBoard.Load;
  321.   Store: @TScoreBoard.Store);
  322.  
  323. RDiceSet : TStreamRec = (
  324.   ObjType: 2506;
  325.   VmtLink: Ofs(TypeOf(TDiceSet)^);
  326.   Load: @TDiceSet.Load;
  327.   Store: @TDiceSet.Store);
  328.  
  329. RDiceFrame : TStreamRec = (
  330.   ObjType: 2507;
  331.   VmtLink: Ofs(TypeOf(TDiceFrame)^);
  332.   Load: @TDiceFrame.Load;
  333.   Store: @TDiceFrame.Store);
  334.  
  335. RDie : TStreamRec = (
  336.   ObjType: 2508;
  337.   VmtLink: Ofs(TypeOf(TDie)^);
  338.   Load: @TDie.Load;
  339.   Store: @TDie.Store);
  340.  
  341. RGameWindow : TStreamRec = (
  342.   ObjType: 2509;
  343.   VmtLink: Ofs(TypeOf(TGameWindow)^);
  344.   Load: @TGameWindow.Load;
  345.   Store: @TGameWindow.Store);
  346.  
  347. RUpperBonus : TStreamRec = (
  348.   ObjType: 2510;
  349.   VmtLink: Ofs(TypeOf(TUpperBonus)^);
  350.   Load: @TUpperBonus.Load;
  351.   Store: @TUpperBonus.Store);
  352.  
  353. RTotal : TStreamRec = (
  354.   ObjType: 2511;
  355.   VmtLink: Ofs(TypeOf(TTotal)^);
  356.   Load: @TTotal.Load;
  357.   Store: @TTotal.Store);
  358.  
  359. RScoreFrame : TStreamRec = (
  360.   ObjType: 2512;
  361.   VmtLink: Ofs(TypeOf(TScoreFrame)^);
  362.   Load: @TScoreFrame.Load;
  363.   Store: @TScoreFrame.Store);
  364.  
  365. ROnes : TStreamRec = (
  366.   ObjType: 2513;
  367.   VmtLink: Ofs(TypeOf(TOnes)^);
  368.   Load: @TOnes.Load;
  369.   Store: @TOnes.Store);
  370.  
  371. RTwos : TStreamRec = (
  372.   ObjType: 2514;
  373.   VmtLink: Ofs(TypeOf(TTwos)^);
  374.   Load: @TTwos.Load;
  375.   Store: @TTwos.Store);
  376.  
  377. RThrees : TStreamRec = (
  378.   ObjType: 2515;
  379.   VmtLink: Ofs(TypeOf(TThrees)^);
  380.   Load: @TThrees.Load;
  381.   Store: @TThrees.Store);
  382.  
  383. RFours : TStreamRec = (
  384.   ObjType: 2516;
  385.   VmtLink: Ofs(TypeOf(TFours)^);
  386.   Load: @TFours.Load;
  387.   Store: @TFours.Store);
  388.  
  389. RFives : TStreamRec = (
  390.   ObjType: 2517;
  391.   VmtLink: Ofs(TypeOf(TFives)^);
  392.   Load: @TFives.Load;
  393.   Store: @TFives.Store);
  394.  
  395. RSixes : TStreamRec = (
  396.   ObjType: 2518;
  397.   VmtLink: Ofs(TypeOf(TSixes)^);
  398.   Load: @TSixes.Load;
  399.   Store: @TSixes.Store);
  400.  
  401. R3Kind : TStreamRec = (
  402.   ObjType: 2519;
  403.   VmtLink: Ofs(TypeOf(T3Kind)^);
  404.   Load: @T3Kind.Load;
  405.   Store: @T3Kind.Store);
  406.  
  407. R4Kind : TStreamRec = (
  408.   ObjType: 2520;
  409.   VmtLink: Ofs(TypeOf(T4Kind)^);
  410.   Load: @T4Kind.Load;
  411.   Store: @T4Kind.Store);
  412.  
  413. RFullHouse : TStreamRec = (
  414.   ObjType: 2521;
  415.   VmtLink: Ofs(TypeOf(TFullHouse)^);
  416.   Load: @TFullHouse.Load;
  417.   Store: @TFullHouse.Store);
  418.  
  419. RSmStraight : TStreamRec = (
  420.   ObjType: 2522;
  421.   VmtLink: Ofs(TypeOf(TSmStraight)^);
  422.   Load: @TSmStraight.Load;
  423.   Store: @TSmStraight.Store);
  424.  
  425. RLgStraight : TStreamRec = (
  426.   ObjType: 2523;
  427.   VmtLink: Ofs(TypeOf(TLgStraight)^);
  428.   Load: @TLgStraight.Load;
  429.   Store: @TLgStraight.Store);
  430.  
  431. RYahtzee : TStreamRec = (
  432.   ObjType: 2524;
  433.   VmtLink: Ofs(TypeOf(TYahtzee)^);
  434.   Load: @TYahtzee.Load;
  435.   Store: @TYahtzee.Store);
  436.  
  437. RChance : TStreamRec = (
  438.   ObjType: 2525;
  439.   VmtLink: Ofs(TypeOf(TChance)^);
  440.   Load: @TChance.Load;
  441.   Store: @TChance.Store);
  442.  
  443. RUpperTotal : TStreamRec = (
  444.   ObjType: 2526;
  445.   VmtLink: Ofs(TypeOf(TUpperTotal)^);
  446.   Load: @TUpperTotal.Load;
  447.   Store: @TUpperTotal.Store);
  448.  
  449. RRollCounter : TStreamRec = (
  450.   ObjType: 2527;
  451.   VmtLink: Ofs(TypeOf(TRollCounter)^);
  452.   Load: @TRollCounter.Load;
  453.   Store: @TRollCounter.Store);
  454.  
  455. procedure RegisterGame;
  456. begin
  457.   RegisterType(RTopScore);
  458.   RegisterType(RScoreList);
  459.   RegisterType(RTopScoreList);
  460.   RegisterType(RYahWho);
  461.   RegisterType(RScoreItem);
  462.   RegisterType(RScoreBoard);
  463.   RegisterType(RDiceSet);
  464.   RegisterType(RDiceFrame);
  465.   RegisterType(RDie);
  466.   RegisterType(RGameWindow);
  467.   RegisterType(RUpperBonus);
  468.   RegisterType(RTotal);
  469.   RegisterType(RScoreFrame);
  470.   RegisterType(ROnes);
  471.   RegisterType(RTwos);
  472.   RegisterType(RThrees);
  473.   RegisterType(RFours);
  474.   RegisterType(RFives);
  475.   RegisterType(RSixes);
  476.   RegisterType(R3Kind);
  477.   RegisterType(R4Kind);
  478.   RegisterType(RFullHouse);
  479.   RegisterType(RSmStraight);
  480.   RegisterType(RLgStraight);
  481.   RegisterType(RYahtzee);
  482.   RegisterType(RChance);
  483.   RegisterType(RUpperTotal);
  484.   RegisterType(RRollCounter);
  485. end;
  486.  
  487. { ************************** Method definitions ************************* }
  488.  
  489. {***** TMyColorDialog *****}
  490.  
  491. constructor TMyColorDialog.Init;
  492. var
  493.   R : TRect;
  494. begin
  495.   TColorDialog.Init(APalette, AGroups);
  496.   DPal := DPalette;
  497.   R.Assign(25, 15, 34, 17);
  498.   Insert(New(PButton, Init(R, '~R~eset', cmRstColors, bfNormal)));
  499. end;
  500.  
  501. procedure TMyColorDialog.HandleEvent;
  502. begin
  503.   if (Event.What = evCommand) and (Event.Command = cmRstColors) then
  504.   begin
  505.     SetData(DPal);
  506.     ClearEvent(Event);
  507.   end else
  508.   TColorDialog.HandleEvent(Event);
  509. end;
  510.  
  511. { ********** TScoreListBox ********** }
  512.  
  513. {This function governs the text in the Hall of Fame list box}
  514.  
  515. function TScoreListBox.GetText(Item: Integer; MaxLen: Integer): String;
  516. var
  517.   S : string[3];
  518.   N : string[11];
  519.   R : string;
  520. begin
  521.   if List=nil then GetText:='' else
  522.   begin
  523.     with PTopScore(List^.At(Item))^ do
  524.     begin
  525.       Str(Score:3,S);
  526.       N := Name;
  527.       while Length(N) < 11 do N := N+' ';
  528.       R := Date+' '+N+S;
  529.       if Length(R) > MaxLen then R[0]:= Chr(MaxLen);
  530.       GetText := R;
  531.     end;
  532.   end;
  533. end;
  534.  
  535. { ********** TScoreList ********** }
  536.  
  537.  
  538. constructor TScoreList.Init;
  539. begin
  540.   Inherited Init(ALimit, ADelta);
  541.   Duplicates := True;
  542. end;
  543.  
  544. function TScoreList.Compare; {Decending score order}
  545. begin
  546.   if integer(Key1^) > integer(Key2^) then Compare := -1 else
  547.   if integer(Key1^) = integer(Key2^) then Compare :=  0 else
  548.   Compare :=  1;
  549. end;
  550.  
  551. function TScoreList.KeyOf;
  552. begin
  553.   KeyOf := @PTopScore(Item)^.Score;
  554. end;
  555.  
  556. { ********** TTopScore ********** }
  557.  
  558. constructor TTopScore.Init;
  559. begin
  560.   Inherited Init;
  561.   Score := NewScore;
  562.   Name := NewName;
  563.   Date := NewDate;
  564. end;
  565.  
  566. constructor TTopScore.Load;
  567. begin
  568.   with S do
  569.   begin
  570.     Read(Score, SizeOf(Score));
  571.     Read(Name, SizeOf(Name));
  572.     Read(Date, SizeOf(Date));
  573.   end;
  574. end;
  575.  
  576. procedure TTopScore.Store;
  577. begin
  578.   with S do
  579.   begin
  580.     Write(Score, SizeOf(Score));
  581.     Write(Name, SizeOf(Name));
  582.     Write(Date, SizeOf(Date));
  583.   end;
  584. end;
  585.  
  586. { **********  TTopScoreList ********** }
  587.  
  588. constructor TTopScoreList.Init;
  589. begin
  590.   Inherited Init(ALimit,ADelta);
  591.   MinScore := 0;
  592. end;
  593.  
  594. constructor TTopScoreList.Load;
  595. begin
  596.   Inherited Load(S);
  597.   S.Read(MinScore, SizeOf(MinScore));
  598. end;
  599.  
  600. procedure TTopScoreList.Store;
  601. begin
  602.   Inherited Store(S);
  603.   S.Write(MinScore, SizeOf(MinScore));
  604. end;
  605.  
  606. procedure TTopScoreList.Insert;
  607. begin
  608.   with PTopScore(Item)^ do if Score > MinScore then
  609.   begin
  610.     if Count=10 then AtDelete(9);
  611.     Inherited Insert(Item);
  612.     if Count > 0 then MinScore := PTopScore(At(Count-1))^.Score
  613.     else MinScore := 0;
  614.   end;
  615. end;
  616.  
  617. { **********  TScoreBoard ********** }
  618.  
  619. constructor TScoreBoard.Init;
  620. var
  621.   R : TRect;
  622. begin
  623.   Inherited Init(Bounds);
  624.   Options := Options or (ofSelectable + ofFirstClick);
  625.   HelpCtx := hcScore;
  626.   GetExtent(R);
  627.   Insert(New(PScoreFrame, Init(R)));
  628.   R.Assign(2,1,25,2);
  629.   Insert(New(POnes, Init(R,'1','Ones .........')));
  630.   R.Move(0,1);
  631.   Insert(New(PTwos, Init(R,'2','Twos .........')));
  632.   R.Move(0,1);
  633.   Insert(New(PThrees, Init(R,'3','Threes .......')));
  634.   R.Move(0,1);
  635.   Insert(New(PFours, Init(R,'4','Fours ........')));
  636.   R.Move(0,1);
  637.   Insert(New(PFives, Init(R,'5','Fives ........')));
  638.   R.Move(0,1);
  639.   Insert(New(PSixes, Init(R,'6','Sixes ........')));
  640.   R.Move(0,1);
  641.   Insert(New(PUpperBonus, Init(R,'Upper Bonus ....    35')));
  642.   R.Move(0,1);
  643.   Insert(New(PUpperTotal, Init(R,'Upper Total ....')));
  644.   R.Move(0,2);
  645.   Insert(New(P3Kind, Init(R,'A','3 of a Kind ..')));
  646.   R.Move(0,1);
  647.   Insert(New(P4Kind, Init(R,'B','4 of a Kind ..')));
  648.   R.Move(0,1);
  649.   Insert(New(PFullHouse, Init(R,'C','Full House ...')));
  650.   R.Move(0,1);
  651.   Insert(New(PSmStraight, Init(R,'D','Sm Straight ..')));
  652.   R.Move(0,1);
  653.   Insert(New(PLgStraight, Init(R,'E','Lg Straight ..')));
  654.   R.Move(0,1);
  655.   Insert(New(PYahtzee, Init(R,'F','YAHTZEE ......')));
  656.   R.Move(0,1);
  657.   Insert(New(PChance, Init(R,'G','Chance .......')));
  658.   R.Move(0,2);
  659.   Insert(New(PTotal, Init(R,'Total ....')));
  660.   SetState(sfDisabled,True);
  661. end;
  662.  
  663. procedure TScoreBoard.SizeLimits(var Min, Max: TPoint);
  664. begin
  665.   Min := ScoreBoardSize;
  666.   Max := Min;
  667. end;
  668.  
  669. { **********  TDiceFrame ********** }
  670.  
  671. procedure TDiceFrame.HandleEvent;
  672. var
  673.   MouseHere : TPoint;
  674. begin
  675.   {A double click on the dice frame selects them all. A single click
  676.    deselects them.}
  677.  
  678.   if (Event.What=evMouseDown) then
  679.   begin
  680.     MakeLocal(Event.Where,MouseHere);
  681.     with MouseHere do if (X in [0,Size.X-1]) or (Y in [0,Size.Y-1]) then
  682.     begin
  683.       if Event.Double then Message(Owner,evCommand,cmSelectAll,nil)
  684.       else Message(Owner,evCommand,cmDeSelectAll,nil);
  685.     end;
  686.     ClearEvent(Event);
  687.   end else Inherited HandleEvent(Event);
  688. end;
  689.  
  690.  
  691. { **********  TScoreFrame ********** }
  692.  
  693. procedure TScoreFrame.Draw;
  694. begin
  695.   Inherited Draw;
  696.   WriteStr(19,17,'────── ',4);   {Underscore the Total}
  697. end;
  698.  
  699. { **********  TScoreItem ********** }
  700.  
  701. constructor TScoreItem.Init;
  702. begin
  703.   Inherited Init(Bounds);
  704.   Options := Options or
  705.     (ofScore + ofPreprocess + ofSelectable + ofFirstClick);
  706.   EventMask := EventMask or evBroadcast;
  707.   HotKey := HKey;
  708.   ScoreName := NewStr(Name);
  709.   Score := 0;
  710.   Lite := False;
  711.   Scored := False;
  712.   Yahtzee := False;
  713. end;
  714.  
  715. destructor TScoreItem.Done;
  716. begin
  717.   DisposeStr(ScoreName);
  718.   Inherited Done;
  719. end;
  720.  
  721. constructor TScoreItem.Load;
  722. begin
  723.   Inherited Load(S);
  724.   with S do
  725.   begin
  726.     Read(HotKey, SizeOf(HotKey));
  727.     ScoreName := ReadStr;
  728.     Read(Score, SizeOf(Score));
  729.     Read(Lite, SizeOf(Lite));
  730.     Read(Yahtzee, SizeOf(Yahtzee));
  731.     Read(Scored, SizeOf(Scored));
  732.     Read(TempScore, SizeOf(TempScore));
  733.   end;
  734. end;
  735.  
  736. procedure TScoreItem.Store;
  737. begin
  738.   Inherited Store(S);
  739.   with S do
  740.   begin
  741.     Write(HotKey, SizeOf(HotKey));
  742.     WriteStr(ScoreName);
  743.     Write(Score, SizeOf(Score));
  744.     Write(Lite, SizeOf(Lite));
  745.     Write(Yahtzee, SizeOf(Yahtzee));
  746.     Write(Scored, SizeOf(Scored));
  747.     Write(TempScore, SizeOf(TempScore));
  748.   end;
  749. end;
  750.  
  751. procedure TScoreItem.HandleEvent(var Event : TEvent);
  752. var
  753.   N : TScore;
  754.  
  755. begin
  756.   Inherited HandleEvent(Event);
  757.   if (Event.What=evBroadcast) then
  758.   case Event.Command of
  759.     cmRollDone:
  760.       begin
  761.         Lite := (ValidScore(TDice(Event.InfoPtr^))) and not Scored;
  762.         DrawView;
  763.       end;
  764.     cmScored:
  765.       begin
  766.         Lite := False;
  767.         DrawView;
  768.       end;
  769.   end {case}
  770.   else if ((Event.What=evMouseDown) or
  771.       ((Event.What=evKeyDown) and (Upcase(Event.CharCode)=HotKey))) then
  772.   begin
  773.     if not Scored then
  774.     begin
  775.       if (TempScore=0) and (MessageBox(^C'Take a zero?', nil,
  776.           mfConfirmation+mfYesButton+mfNoButton) = cmNo) then exit;
  777.       Scored :=True;
  778.       Score := TempScore;
  779.       N.Value := Score;
  780.       if HotKey in ['1'..'6'] then N.TValue:=Upper else N.TValue:=Lower;
  781.       DrawView;
  782.       Tune(Bleep);
  783.       if Yahtzee then Message(Desktop,evBroadcast,cmYahtzee,@Self);
  784.       Message(Desktop,evBroadcast,cmScored,@N);
  785.     end else Tune(Bells);
  786.     ClearEvent(Event);
  787.   end;
  788. end;
  789.  
  790. function TScoreItem.GetPalette : PPalette;
  791. const
  792.   C = #4#5;
  793.   P : string[Length(C)] = C;
  794. begin
  795.   GetPalette := @P;
  796. end;
  797.  
  798. procedure TScoreItem.Draw;
  799. var
  800.   S : string[3];
  801.   C : integer;
  802.  
  803. begin
  804.   if Lite then C := 2 else C := 1;
  805.   WriteChar(0,0,' ',C,23);
  806.   WriteChar(1,0,HotKey,2,1);
  807.   WriteStr(3,0,ScoreName^,C);
  808.   if not Scored then WriteStr(21,0,'-',C) else
  809.   begin
  810.     Str(Score:3, S);
  811.     WriteStr(20,0,S,C);
  812.   end;
  813.   if Lite and ShowMarkers then WriteChar(0,0,#175,1 ,1);
  814. end;
  815.  
  816. function TScoreItem.ValidScore(const D : TDice) : boolean;
  817. begin
  818.   Abstract;
  819. end;
  820.  
  821. function TOnes.ValidScore(const D : TDice) : boolean;
  822. var
  823.   i : byte;
  824. begin
  825.   TempScore := 0;
  826.   for i:=1 to 5 do if D[i]=1 then Inc(TempScore);
  827.   Yahtzee := TempScore=5;
  828.   ValidScore := TempScore>0;
  829. end;
  830.  
  831. function TTwos.ValidScore(const D : TDice) : boolean;
  832. var
  833.   i : byte;
  834. begin
  835.   TempScore := 0;
  836.   for i:=1 to 5 do if D[i]=2 then Inc(TempScore,2);
  837.   Yahtzee := TempScore=10;
  838.   ValidScore := TempScore>0;
  839. end;
  840.  
  841.  
  842. function TThrees.ValidScore(const D : TDice) : boolean;
  843. var
  844.   i : byte;
  845. begin
  846.   TempScore := 0;
  847.   for i:=1 to 5 do if D[i]=3 then Inc(TempScore,3);
  848.   Yahtzee := TempScore=15;
  849.   ValidScore := TempScore>0;
  850. end;
  851.  
  852.  
  853. function TFours.ValidScore(const D : TDice) : boolean;
  854. var
  855.   i : byte;
  856. begin
  857.   TempScore := 0;
  858.   for i:=1 to 5 do if D[i]=4 then Inc(TempScore,4);
  859.   Yahtzee := TempScore=20;
  860.   ValidScore := TempScore>0;
  861. end;
  862.  
  863.  
  864. function TFives.ValidScore(const D : TDice) : boolean;
  865. var
  866.   i : byte;
  867. begin
  868.   TempScore := 0;
  869.   for i:=1 to 5 do if D[i]=5 then Inc(TempScore,5);
  870.   Yahtzee := TempScore=25;
  871.   ValidScore := TempScore>0;
  872. end;
  873.  
  874.  
  875. function TSixes.ValidScore(const D : TDice) : boolean;
  876. var
  877.   i : byte;
  878. begin
  879.   TempScore := 0;
  880.   for i:=1 to 5 do if D[i]=6 then Inc(TempScore,6);
  881.   Yahtzee := TempScore=30;
  882.   ValidScore := TempScore>0;
  883. end;
  884.  
  885.  
  886. function T3Kind.ValidScore(const D : TDice) : boolean;
  887. var
  888.   i,j : byte;
  889.   n : array[1..6] of byte;
  890. begin
  891.   FillChar(n,SizeOf(n),0);
  892.   for i:=1 to 6 do
  893.     for j:=1 to 5 do if D[j]=i then Inc(n[i]);
  894.   j:=0; TempScore := 0;
  895.   for i:=1 to 6 do if n[i]>j then j:=n[i];
  896.   Yahtzee := j=5;
  897.   if j>=3 then
  898.   begin
  899.     ValidScore := True;
  900.     for i:=1 to 5 do Inc(TempScore,D[i]);
  901.   end
  902.   else ValidScore := False;
  903. end;
  904.  
  905. function T4Kind.ValidScore(const D : TDice) : boolean;
  906. var
  907.   i,j : byte;
  908.   n : array[1..6] of byte;
  909. begin
  910.   FillChar(n,SizeOf(n),0);
  911.   for i:=1 to 6 do
  912.     for j:=1 to 5 do if D[j]=i then Inc(n[i]);
  913.   j:=0; TempScore := 0;
  914.   for i:=1 to 6 do if n[i]>j then j:=n[i];
  915.   Yahtzee := j=5;
  916.   if j>=4 then
  917.   begin
  918.     ValidScore:=True;
  919.     for i:=1 to 5 do Inc(TempScore,D[i]);
  920.   end
  921.   else ValidScore:=False;
  922. end;
  923.  
  924. function TFullHouse.ValidScore(const D : TDice) : boolean;
  925. var
  926.   i,j : byte;
  927.   n : array[1..6] of byte;
  928.   Ok : boolean;
  929. begin
  930.   FillChar(n,SizeOf(n),0);
  931.   for i:=1 to 6 do
  932.     for j:=1 to 5 do if D[j]=i then Inc(n[i]);
  933.  
  934.   {n now contains the count of how many times each number (1..6) appears
  935.    in the dice roll. For example, if n[2]=3, then 2 appears on 3 dice.
  936.    In order to have a valid Full House, any given number must either
  937.    not appear at all, appear twice, or three times. This may be a brute
  938.    force approach. I'm sure there are more elegant ways, but this is
  939.    foolproof, and it doesn't take long.}
  940.  
  941.   Ok:=True; i:=1;
  942.   while Ok and (i<=6) do
  943.   begin
  944.     Ok := n[i] in [0,2,3]; Inc(i);
  945.   end;
  946.   if Ok then
  947.   begin
  948.     ValidScore := True; TempScore:=25;
  949.   end else
  950.   begin
  951.     ValidScore := False; TempScore:=0;
  952.   end;
  953. end;
  954.  
  955. function TSmStraight.ValidScore(const D : TDice) : boolean;
  956. var
  957.   i : byte;
  958.   M : set of 1..6;
  959.   Ok : boolean;
  960. begin
  961.  
  962.   {Sets are sweet! Too bad, C++}
  963.  
  964.   M:=[];
  965.   for i:=1 to 5 do Include(M,D[i]);
  966.   Ok := (M*[1..4]=[1..4]) or
  967.         (M*[2..5]=[2..5]) or
  968.         (M*[3..6]=[3..6]);
  969.   if Ok then
  970.   begin
  971.     ValidScore:=True; TempScore:=30;
  972.   end else
  973.   begin
  974.     ValidScore:=False; TempScore:=0;
  975.   end;
  976. end;
  977.  
  978. function TLgStraight.ValidScore(const D : TDice) : boolean;
  979. var
  980.   i,c : byte;
  981.   M : set of 1..6;
  982.   Ok : boolean;
  983. begin
  984.   M:=[];
  985.   for i:=1 to 5 do Include(M,D[i]);
  986.   Ok := (M=[1..5]) or (M=[2..6]);
  987.   if Ok then
  988.   begin
  989.     ValidScore:=True; TempScore:=40;
  990.   end else
  991.   begin
  992.     ValidScore:=False; TempScore:=0;
  993.   end;
  994. end;
  995.  
  996. procedure TYahtzee.HandleEvent(var Event: TEvent);
  997. var
  998.   N : TScore;
  999. begin
  1000.   Inherited HandleEvent(Event);
  1001.   with Event do
  1002.   if (What=evBroadcast) and (Command=cmYahtzee) and (InfoPtr<>@Self) then
  1003.     if Score > 0 then
  1004.     begin
  1005.       Inc(Score,100); DrawView; {Award Bonus Yahtzee }
  1006.       N.TValue := Lower; N.Value := 100;
  1007.       Message(Owner,evBroadcast,cmScored,@N);
  1008.     end else ClearEvent(Event);
  1009. end;
  1010.  
  1011.  
  1012. function TYahtzee.ValidScore(const D : TDice) : boolean;
  1013. var
  1014.   i : byte;
  1015. begin
  1016.   i:=1;
  1017.  
  1018.   while (i<5) and (D[i]=D[i+1]) do Inc(i);
  1019.  
  1020.   if i=5 then
  1021.   begin
  1022.     ValidScore:=True; TempScore:=50;
  1023.     Yahtzee := True;
  1024.   end else
  1025.   begin
  1026.     ValidScore:=False; TempScore:=0;
  1027.     Yahtzee:=False;
  1028.   end;
  1029. end;
  1030.  
  1031. function TChance.ValidScore(const D : TDice) : boolean;
  1032. var
  1033.   i : byte;
  1034. begin
  1035.   ValidScore := True;
  1036.   TempScore:=0;
  1037.   for i:=1 to 5 do Inc(TempScore,D[i]);
  1038.   i:=1;
  1039.   while (i<5) and (D[i]=D[i+1]) do Inc(i);
  1040.   Yahtzee:=i=5;
  1041. end;
  1042.  
  1043. { **********  TUpperBonus ********** }
  1044.  
  1045. constructor TUpperBonus.Init;
  1046. begin
  1047.   Inherited Init(Bounds);
  1048.   Options := Options or ofPreprocess;
  1049.   EventMask := EventMask or evBroadcast;
  1050.   ScoreName := NewStr(Name);
  1051.   Hide;
  1052. end;
  1053.  
  1054. destructor TUpperBonus.Done;
  1055. begin
  1056.   DisposeStr(ScoreName);
  1057.   Inherited Done;
  1058. end;
  1059.  
  1060. constructor TUpperBonus.Load;
  1061. begin
  1062.   Inherited Load(S);
  1063.   ScoreName := S.ReadStr;
  1064. end;
  1065.  
  1066. procedure TUpperBonus.Store;
  1067. begin
  1068.   Inherited Store(S);
  1069.   S.WriteStr(ScoreName);
  1070. end;
  1071.  
  1072.  
  1073. procedure TUpperBonus.HandleEvent(var Event : TEvent);
  1074. begin
  1075.   Inherited HandleEvent(Event);
  1076.   if (Event.What=evBroadcast) and (Event.Command=cmShowBonus) then
  1077.   begin
  1078.     Show;
  1079.     ClearEvent(Event);
  1080.   end;
  1081. end;
  1082.  
  1083. function TUpperBonus.GetPalette : PPalette;
  1084. const
  1085.   C = #4#5;
  1086.   P : string[Length(C)] = C;
  1087. begin
  1088.   GetPalette := @P;
  1089. end;
  1090.  
  1091. procedure TUpperBonus.Draw;
  1092.  
  1093. begin
  1094.   WriteChar(0,0,' ',1,23);
  1095.   WriteStr(1,0,ScoreName^,1);
  1096. end;
  1097.  
  1098. { **********  TUpperTotal ********** }
  1099.  
  1100. constructor TUpperTotal.Init;
  1101. begin
  1102.   Inherited Init(Bounds);
  1103.   Options := Options or ofPreprocess;
  1104.   EventMask := EventMask or evBroadcast;
  1105.   ScoreName := NewStr(Name);
  1106.   Total := 0;
  1107.   Bonus := False;
  1108. end;
  1109.  
  1110. destructor TUpperTotal.Done;
  1111. begin
  1112.   DisposeStr(ScoreName);
  1113.   Inherited Done;
  1114. end;
  1115.  
  1116. constructor TUpperTotal.Load;
  1117. begin
  1118.   Inherited Load(S);
  1119.   with S do
  1120.   begin
  1121.     ScoreName := ReadStr;
  1122.     Read(Total, SizeOf(Total));
  1123.     Read(Bonus, SizeOf(Bonus));
  1124.   end;
  1125. end;
  1126.  
  1127. procedure TUpperTotal.Store;
  1128. begin
  1129.   Inherited Store(S);
  1130.   with S do
  1131.   begin
  1132.     WriteStr(ScoreName);
  1133.     Write(Total, SizeOf(Total));
  1134.     Write(Bonus, SizeOf(Bonus));
  1135.   end;
  1136. end;
  1137.  
  1138.  
  1139. procedure TUpperTotal.HandleEvent(var Event : TEvent);
  1140. begin
  1141.   Inherited HandleEvent(Event);
  1142.   if (Event.What=evBroadcast) and (Event.Command=cmScored) then
  1143.   begin
  1144.     with TScore(Event.InfoPtr^) do
  1145.       if TValue=Upper then Inc(Total,Value);
  1146.     if (Total >= 63) and not Bonus then
  1147.     begin
  1148.       Bonus := True;
  1149.       Inc(Total,35);
  1150.       Message(Owner,evBroadcast,cmShowBonus,nil);
  1151.     end;
  1152.     DrawView;
  1153.   end;
  1154. end;
  1155.  
  1156. function TUpperTotal.GetPalette : PPalette;
  1157. const
  1158.   C = #4#5;
  1159.   P : string[Length(C)] = C;
  1160. begin
  1161.   GetPalette := @P;
  1162. end;
  1163.  
  1164. procedure TUpperTotal.Draw;
  1165. var
  1166.   S : string[3];
  1167.  
  1168. begin
  1169.   WriteChar(0,0,' ',1,23);
  1170.   WriteStr(1,0,ScoreName^,1);
  1171.   Str(Total:3, S);
  1172.   WriteStr(20,0,S,1);
  1173. end;
  1174.  
  1175. { **********  TTotal ********** }
  1176.  
  1177. constructor TTotal.Init;
  1178. begin
  1179.   Inherited Init(Bounds);
  1180.   Options := Options or ofPreprocess;
  1181.   EventMask := EventMask or evBroadcast;
  1182.   ScoreName := NewStr(Name);
  1183.   Total := 0; TopScore := 0; BottomScore := 0;
  1184. end;
  1185.  
  1186. destructor TTotal.Done;
  1187. begin
  1188.   DisposeStr(ScoreName);
  1189.   Inherited Done;
  1190. end;
  1191.  
  1192. constructor TTotal.Load;
  1193. begin
  1194.   Inherited Load(S);
  1195.   with S do
  1196.   begin
  1197.     ScoreName := ReadStr;
  1198.     Read(TopScore, SizeOf(TopScore));
  1199.     Read(BottomScore, SizeOf(BottomScore));
  1200.     Read(Total, SizeOf(Total));
  1201.   end;
  1202. end;
  1203.  
  1204. procedure TTotal.Store;
  1205. begin
  1206.   Inherited Store(S);
  1207.   with S do
  1208.   begin
  1209.     WriteStr(ScoreName);
  1210.     Write(TopScore, SizeOf(TopScore));
  1211.     Write(BottomScore, SizeOf(BottomScore));
  1212.     Write(Total, SizeOf(Total));
  1213.   end;
  1214. end;
  1215.  
  1216. procedure TTotal.HandleEvent(var Event : TEvent);
  1217. begin
  1218.   Inherited HandleEvent(Event);
  1219.   if (Event.What=evBroadcast) and (Event.Command=cmScored) then
  1220.   begin
  1221.     with TScore(Event.InfoPtr^) do
  1222.       if TValue=Upper then Inc(TopScore,Value) else Inc(BottomScore,Value);
  1223.     Total := TopScore + BottomScore;
  1224.     if TopScore > 63 then Inc(Total,35);
  1225.     DrawView;
  1226.     Message(Desktop,evBroadcast,cmNewTotal,@Total);
  1227.   end;
  1228. end;
  1229.  
  1230. function TTotal.GetPalette : PPalette;
  1231. const
  1232.   C = #4#5;
  1233.   P : string[Length(C)] = C;
  1234. begin
  1235.   GetPalette := @P;
  1236. end;
  1237.  
  1238. procedure TTotal.Draw;
  1239. var
  1240.   S : string[3];
  1241.  
  1242. begin
  1243.   WriteChar(0,0,' ',1,23);
  1244.   WriteStr(7,0,ScoreName^,1);
  1245.   Str(Total:3, S);
  1246.   WriteStr(20,0,S,1);
  1247. end;
  1248.  
  1249. { **********  TDiceSet ********** }
  1250.  
  1251. constructor TDiceSet.Init;
  1252. var
  1253.   R : TRect;
  1254. begin
  1255.   Inherited Init(Bounds);
  1256.   Options := Options or (ofSelectable + ofFirstClick);
  1257.   GrowMode := gfGrowLoX+gfGrowHiX;
  1258.   HelpCtx := hcRoll;
  1259.   GetExtent(R);
  1260.   Insert(New(PDiceFrame, Init(R)));
  1261.   R.Assign(3,0,11,1);
  1262.   Insert(New(PRollCounter, Init(R)));
  1263.   R.Assign(3,1,12,4);
  1264.   Insert(New(PDie, Init(R, '1')));
  1265.   R.Move(0,4);
  1266.   Insert(New(PDie, Init(R, '2')));
  1267.   R.Move(0,4);
  1268.   Insert(New(PDie, Init(R, '3')));
  1269.   R.Move(0,4);
  1270.   Insert(New(PDie, Init(R, '4')));
  1271.   R.Move(0,4);
  1272.   Insert(New(PDie, Init(R, '5')));
  1273. end;
  1274.  
  1275. procedure TDiceSet.SizeLimits(var Min, Max: TPoint);
  1276. begin
  1277.   Min := DiceSetSize;
  1278.   Max := Min;
  1279. end;
  1280.  
  1281. { **********  TDie ********** }
  1282.  
  1283. constructor TDie.Init;
  1284. begin
  1285.   Inherited Init(Bounds);
  1286.   EventMask := EventMask or evBroadcast;
  1287.   HotKey := HKey;
  1288.   Options := Options or (ofDie + ofPreProcess + ofSelectable + ofFirstClick);
  1289.   Value := 1 + Random(6);
  1290.   Selected := False;
  1291.   Hide;
  1292. end;
  1293.  
  1294. constructor TDie.Load;
  1295. begin
  1296.   Inherited Load(S);
  1297.   with S do
  1298.   begin
  1299.     Read(Value, SizeOf(Value));
  1300.     Read(HotKey, SizeOf(HotKey));
  1301.     Read(Selected, SizeOf(Selected));
  1302.   end;
  1303. end;
  1304.  
  1305. procedure TDie.Store;
  1306. begin
  1307.   Inherited Store(S);
  1308.   with S do
  1309.   begin
  1310.     Write(Value, SizeOf(Value));
  1311.     Write(HotKey, SizeOf(HotKey));
  1312.     Write(Selected, SizeOf(Selected));
  1313.   end;
  1314. end;
  1315.  
  1316. procedure TDie.HandleEvent(var Event: TEvent);
  1317. begin
  1318.   Inherited HandleEvent(Event);
  1319.  
  1320.   if Event.What = evCommand then
  1321.   case Event.Command of
  1322.     cmRollDie     : if Selected then
  1323.                     begin
  1324.                       Selected := False;
  1325.                       Value := Random(6) + 1;
  1326.                       DrawView;
  1327.                     end;
  1328.     cmSelectAll   : begin
  1329.                       Selected := True; DrawView;
  1330.                     end;
  1331.     cmDeSelectAll : begin
  1332.                       Selected := False; DrawView;
  1333.                     end;
  1334.   end {case}
  1335.   else if ((Event.What = evMouseDown) or
  1336.             ((Event.What=evKeyDown) and (Event.CharCode=HotKey))) then
  1337.   begin
  1338.     Selected := not Selected;
  1339.     DrawView;
  1340.     ClearEvent(Event);
  1341.   end
  1342.   else if (Event.What = evBroadcast) and
  1343.     (Event.Command = cmScored) then  Hide;
  1344. end;
  1345.  
  1346. function TDie.GetPalette : PPalette;
  1347. const
  1348.   CDie = #6#7#5#4;
  1349.   P : string[Length(CDie)] = CDie;
  1350. begin
  1351.   GetPalette := @P;
  1352. end;
  1353.  
  1354. procedure TDie.Draw;
  1355. const
  1356.   Dot =#254;
  1357. var
  1358.   C : byte;
  1359.  
  1360. procedure Draw1;
  1361. begin
  1362.   WriteStr(0,0,'       ',C);
  1363.   WriteStr(0,1,'   '+Dot+'   ',C);  {Concatenate to save code, speed}
  1364.   WriteStr(0,2,'       ',C);
  1365. end;
  1366.  
  1367. procedure Draw2;
  1368. begin
  1369.   WriteStr(0,0,' '+Dot+'     ',C);
  1370.   WriteStr(0,1,'       ',C);
  1371.   WriteStr(0,2,'     '+Dot+' ',C);
  1372. end;
  1373.  
  1374. procedure Draw3;
  1375. begin
  1376.   WriteStr(0,0,' '+Dot+'     ',C);
  1377.   WriteStr(0,1,'   '+Dot+'   ',C);
  1378.   WriteStr(0,2,'     '+Dot+' ',C);
  1379. end;
  1380.  
  1381. procedure Draw4;
  1382. begin
  1383.   WriteStr(0,0,' '+Dot+'   '+Dot+' ',C);
  1384.   WriteStr(0,1,'       ',C);
  1385.   WriteStr(0,2,' '+Dot+'   '+Dot+' ',C);
  1386. end;
  1387.  
  1388. procedure Draw5;
  1389. begin
  1390.   WriteStr(0,0,' '+Dot+'   '+Dot+' ',C);
  1391.   WriteStr(0,1,'   '+Dot+'   ',C);
  1392.   WriteStr(0,2,' '+Dot+'   '+Dot+' ',C);
  1393. end;
  1394.  
  1395. procedure Draw6;
  1396. begin
  1397.   WriteStr(0,0,' '+Dot+' '+Dot+' '+Dot+' ',C);
  1398.   WriteStr(0,1,'       ',C);
  1399.   WriteStr(0,2,' '+Dot+' '+Dot+' '+Dot+' ',C);
  1400. end;
  1401.  
  1402. var
  1403.   B : TDrawBuffer;
  1404.  
  1405. begin
  1406.   if Selected then C := 2 else C := 1;
  1407.   MoveStr(B, '         ', GetColor(4 ));
  1408.   WriteLine(0, 0, Size.X, Size.Y, B);
  1409.  
  1410.   case Value of
  1411.     1 : Draw1;
  1412.     2 : Draw2;
  1413.     3 : Draw3;
  1414.     4 : Draw4;
  1415.     5 : Draw5;
  1416.     6 : Draw6;
  1417.   end; {case}
  1418.   WriteChar(8,0,HotKey,3,1);
  1419.   if Selected and ShowMarkers then WriteChar(8,1,#174,4,1);
  1420. end;
  1421.  
  1422. { ********** TRollCounter ********** }
  1423.  
  1424. constructor TRollCounter.Init;
  1425. begin
  1426.   Inherited Init(Bounds);
  1427.   EventMask := EventMask or evBroadcast;
  1428.   Count:=1;
  1429.   Hide;
  1430. end;
  1431.  
  1432. constructor TRollCounter.Load;
  1433. begin
  1434.   Inherited Load(S);
  1435.   S.Read(Count, SizeOf(Count));
  1436. end;
  1437.  
  1438. procedure TRollCounter.Store;
  1439. begin
  1440.   Inherited Store(S);
  1441.   S.Write(Count,SizeOf(Count));
  1442. end;
  1443.  
  1444. procedure TRollCounter.Draw;
  1445. begin
  1446.   if Owner^.GetState(sfFocused) then
  1447.     WriteStr(0,0,' Roll '+Chr(Count+48)+' ',2)
  1448.   else WriteStr(0,0,' Roll '+Chr(Count+48)+' ',1);
  1449. end;
  1450.  
  1451. procedure TRollCounter.HandleEvent(var Event: TEvent);
  1452. begin
  1453.   Inherited HandleEvent(Event);
  1454.   if Event.What = evBroadcast then
  1455.   case Event.Command of
  1456.     cmRollDone:
  1457.       begin
  1458.         Count := byte(Event.InfoPtr^);
  1459.         DrawView;
  1460.         ClearEvent(Event);
  1461.       end;
  1462.     cmReceivedFocus,cmReleasedFocus: DrawView;
  1463.     cmScored:
  1464.       begin
  1465.         Hide;
  1466.         Count := 1;
  1467.       end;
  1468.   end;
  1469. end;
  1470.  
  1471.  
  1472. { **********  TGameWindow ********** }
  1473.  
  1474. constructor TGameWindow.Init;
  1475. const
  1476.   ScoreBoardX = 5;
  1477.   ScoreBoardY = 1;
  1478.   DiceSetX = 60;
  1479.   DiceSetY = 1;
  1480. var
  1481.   R :TRect;
  1482. begin
  1483.   Randomize;
  1484.   Inherited Init(Bounds,Player,WinNumber);
  1485.   Options := Options or (ofTileable+ofGameWindow);
  1486.   EventMask := EventMask or evBroadcast;
  1487.  
  1488.   R.Assign(ScoreBoardX,ScoreBoardY,
  1489.            ScoreBoardX+ScoreBoardSize.X,
  1490.            ScoreBoardY+ScoreBoardSize.Y);
  1491.   ScoreBoard := New(PScoreBoard, Init(R));
  1492.   Insert(ScoreBoard);
  1493.  
  1494.   R.Assign(DiceSetX,DiceSetY,
  1495.            DiceSetX+DiceSetSize.X,
  1496.            DiceSetY+DiceSetSize.Y);
  1497.   DiceSet := New(PDiceSet, Init(R));
  1498.   Insert(DiceSet);
  1499.   RollCount := 0;
  1500.   PlayerDone := False;
  1501. end;
  1502.  
  1503. constructor TGameWindow.Load;
  1504. begin
  1505.   Inherited Load(S);
  1506.   with S do
  1507.   begin
  1508.     Read(Total, SizeOf(Total));
  1509.     Read(RollCount, SizeOf(RollCount));
  1510.     Read(Dice, SizeOf(Dice));
  1511.     Read(PlayerDone, SizeOf(PlayerDone));
  1512.     GetSubViewPtr(S, ScoreBoard);
  1513.     GetSubViewPtr(S, DiceSet);
  1514.   end;
  1515. end;
  1516.  
  1517. procedure TGameWindow.Store;
  1518. begin
  1519.   Inherited Store(S);
  1520.   with S do
  1521.   begin
  1522.     Write(Total, SizeOf(Total));
  1523.     Write(RollCount, SizeOf(RollCount));
  1524.     Write(Dice, SizeOf(Dice));
  1525.     Write(PlayerDone, SizeOf(PlayerDone));
  1526.     PutSubViewPtr(S, ScoreBoard);
  1527.     PutSubViewPtr(S, DiceSet);
  1528.   end;
  1529. end;
  1530.  
  1531. function TGameWindow.Valid(Command: Word): Boolean;
  1532. begin
  1533.   if (Command in [cmClose,cmQuit]) and not PlayerDone then
  1534.       Valid := MessageBox(^C'Are you sure you want to quit?', nil ,
  1535.                mfConfirmation+mfYesButton+mfNoButton)=cmYes
  1536.     else Valid:=True;
  1537. end;
  1538.  
  1539. procedure TGameWindow.HandleEvent(var Event: TEvent);
  1540. const
  1541.   Msg = 'Y  A  H  T  Z  E  E  !!!';
  1542.  
  1543. var
  1544.   i : byte;
  1545.   D : PDialog;
  1546.   R : TRect;
  1547.   B : PView;
  1548.  
  1549.   procedure GetDice(D : PDie); far;
  1550.   begin
  1551.     with D^ do if Options and ofDie <> 0 then Dice[i] := Value;
  1552.     Inc(i);
  1553.   end;
  1554.  
  1555.   procedure ShowDice(D : PView); far;
  1556.   begin
  1557.     with D^ do
  1558.     begin
  1559.       Show;
  1560.       if Options and ofDie <> 0 then PDie(D)^.Selected := True;
  1561.     end;
  1562.   end;
  1563.  
  1564.   function Unscored(S : PScoreItem) : boolean; far;
  1565.   begin
  1566.     with S^ do
  1567.       Unscored := (Options and ofScore <> 0) and not Scored;
  1568.   end;
  1569.  
  1570. begin
  1571.  
  1572.   if (Event.What=evCommand) and (Event.Command=cmRollDie)
  1573.         and (RollCount=0) then
  1574.   begin
  1575.     DiceSet^.Select;
  1576.     DiceSet^.ForEach(@ShowDice);
  1577.   end;
  1578.  
  1579.   Inherited HandleEvent(Event);
  1580.  
  1581.   if (Event.What=evCommand) and (Event.Command=cmRollDie) then
  1582.   begin
  1583.     Tune(DiceRoll);
  1584.     ScoreBoard^.SetState(sfDisabled,False);
  1585.     Inc(RollCount);
  1586.     i:=1;
  1587.     DiceSet^.ForEach(@GetDice);
  1588.     Message(ScoreBoard,evBroadcast,cmRollDone,@Dice);
  1589.     Message(DiceSet,evBroadcast,cmRollDone,@RollCount);
  1590.     if RollCount=3 then
  1591.     begin
  1592.       DiceSet^.SetState(sfDisabled,True);
  1593.       ScoreBoard^.Select;
  1594.     end;
  1595.     ClearEvent(Event);
  1596.   end else
  1597.   if (Event.What=evBroadcast) then
  1598.   case Event.Command of
  1599.     cmYahtzee:
  1600.       begin
  1601.         R.Assign(0,0,35,8);
  1602.         Tune(Yahtzee);
  1603.  
  1604.         D := New(PDialog, Init(R, 'Congratulations!'));
  1605.         with D^ do
  1606.         begin
  1607.           Options := Options or ofCentered;
  1608.           R.Assign(0,0,Length(Msg),1);
  1609.           B := New(PStaticText, Init(R,Msg));
  1610.           with B^ do Options := Options or ofCentered;
  1611.           Insert(B);
  1612.  
  1613.           GetExtent(R);
  1614.           R.Assign(0,R.B.Y-3,8,R.B.Y-1);
  1615.           B := New(PButton, Init(R, 'O~K~', cmOk, bfDefault));
  1616.           with B^ do Options := Options or ofCenterX;
  1617.           Insert(B);
  1618.  
  1619.           Application^.ExecuteDialog(D,nil);
  1620.         end;
  1621.  
  1622.         ClearEvent(Event);
  1623.       end;
  1624.     cmNewTotal:
  1625.       begin
  1626.         Total:=word(Event.InfoPtr^);
  1627.         ClearEvent(Event);
  1628.       end;
  1629.     cmScored:
  1630.       begin
  1631.         RollCount := 0;
  1632.         PlayerDone := (Scoreboard^.FirstThat(@Unscored) = nil);
  1633.         ScoreBoard^.SetState(sfDisabled,True);
  1634.         DiceSet^.SetState(sfDisabled,False);
  1635.  
  1636.         Application^.Idle; {Ensure GameOver gets updated}
  1637.         if GameOver then
  1638.         begin
  1639.           Event.What:=evCommand;
  1640.           Event.Command:=cmShowWinner;
  1641.           Application^.HandleEvent(Event);
  1642.         end;
  1643.         ClearEvent(Event);
  1644.       end;
  1645.   end; {case}
  1646. end;
  1647.  
  1648. function TGameWindow.RollOk;
  1649.  
  1650.   function DieSelected(D : PDie): boolean; far;
  1651.   begin
  1652.       DieSelected := (D^.Options and ofDie <> 0) and D^.Selected;
  1653.   end;
  1654.  
  1655. begin
  1656.   if RollCount in [1,2] then EnableCommands([cmSelectAll,cmDeSelectAll])
  1657.   else DisableCommands([cmSelectAll,cmDeSelectAll]);
  1658.  
  1659.   if GetState(sfFocused) and not GetState(sfDragging) and not PlayerDone then
  1660.   RollOk := ((DiceSet^.FirstThat(@DieSelected) <> nil) or (RollCount=0))
  1661.   else RollOk := False;
  1662. end;
  1663.  
  1664. { **********  TYahWho ********** }
  1665.  
  1666. constructor TYahWho.Init;
  1667. var
  1668.   S : TDosStream;
  1669.   Snow : boolean;
  1670. begin
  1671.   ActivePal := DefaultPal;
  1672.   LCD := False;
  1673.   Snow := False;
  1674.   SoundOn := True;
  1675.   Awaken;
  1676.   with S do
  1677.   begin
  1678.     Init(OrigDir+ConfigName, stOpenRead);
  1679.     if Status = stOk then
  1680.     begin
  1681.       Read(ActivePal, SizeOf(ActivePal));
  1682.       Read(ScreenMode, SizeOf(ScreenMode));
  1683.       Read(Snow, SizeOf(Snow));
  1684.       Read(LCD, SizeOf(LCD));
  1685.       Read(SoundOn, SizeOf(SoundOn));
  1686.     end;
  1687.     Done;
  1688.   end;
  1689.  
  1690.   Inherited Init;
  1691.  
  1692.   CheckSnow := Snow;
  1693.   RegisterObjects;
  1694.   RegisterViews;
  1695.   RegisterMenus;
  1696.   RegisterDialogs;
  1697.   RegisterApp;
  1698.   RegisterGame;
  1699.   RegisterColorSel;
  1700.   RegisterHelpFile;
  1701.   ShowMarkers := (ScreenMode <> smCO80);
  1702.   About;
  1703. end;
  1704.  
  1705. constructor TYahWho.Load;
  1706. begin
  1707.   Inherited Load(S);
  1708.   Awaken;
  1709. end;
  1710.  
  1711. procedure TYahWho.Awaken;
  1712. { This procedure is called from application constructors to initialize
  1713. the OrigDir variable to the home directory. Note that OrigDir must be a
  1714. global static variable. If it is a field within the TYahWho object, it
  1715. will be obliterated in the Inherited Init call.}
  1716. var
  1717.   Orig           : PathStr;
  1718.   OrigName       : NameStr;
  1719.   OrigExt        : ExtStr;
  1720. begin
  1721.   Inherited Awaken;
  1722.   if Lo(DosVersion) >= 3
  1723.       then Orig:=ParamStr(0) {DOS 3.x, can locate our origin}
  1724.   else Orig := FSearch('YAHWHO.EXE',GetEnv('PATH')); {DOS 2.x approach}
  1725.   FSplit(Orig,OrigDir,OrigName,OrigExt);
  1726. end;
  1727.  
  1728. destructor TYahWho.Done;
  1729. begin
  1730.   Inherited Done;
  1731.   WriteLn('Thanks for playing YahWho!');
  1732. end;
  1733.  
  1734. procedure TYahWho.About;
  1735. var
  1736.   D: PDialog;
  1737.   Control: PView;
  1738.   R: TRect;
  1739.   Mem : string[10];
  1740. begin
  1741.   Str(MemAvail div 1024,Mem); Mem := Mem+'K';
  1742.   R.Assign(0, 0, 40, 13);
  1743.   D := New(PDialog, Init(R, 'About'));
  1744.   with D^ do
  1745.   begin
  1746.     Options := Options or ofCentered;
  1747.     Palette := dpBlueDialog;
  1748.     R.Grow(-1, -1);
  1749.     Dec(R.B.Y, 3);
  1750.     Insert(New(PStaticText, Init(R,
  1751.       #13 +
  1752.       ^C'YahWho!'#13 +
  1753.       ^C'Version 1.0d'#13 +
  1754.       #13 +
  1755.       ^C'by Keith Greer'#13#13 +
  1756.       ^C'Memory Available: '+Mem)));
  1757.  
  1758.     R.Assign(15, 10, 25, 12);
  1759.     Insert(New(PButton, Init(R, 'O~K', cmOk, bfDefault)));
  1760.   end;
  1761.   ExecuteDialog(D,nil);
  1762. end;
  1763.  
  1764. procedure TYahWho.LoadDesktop(var S: TStream);
  1765. var
  1766.   P: PView;
  1767.  
  1768. procedure CloseView(P: PView); far;
  1769. begin
  1770.   if P^.Options and ofGameWindow <> 0 then PGameWindow(P)^.PlayerDone:=True;
  1771.   Message(P, evCommand, cmClose, nil);
  1772. end;
  1773.  
  1774. begin
  1775.   Lock;
  1776.   Desktop^.ForEach(@CloseView); { Clear the desktop }
  1777.   Unlock;
  1778.   repeat
  1779.     P := PView(S.Get);
  1780.     Desktop^.InsertBefore(ValidView(P), Desktop^.Last);
  1781.   until P = nil;
  1782. end;
  1783.  
  1784. procedure TYahWho.StoreDesktop(var S: TStream);
  1785.  
  1786. procedure WriteView(P: PView); far;
  1787. begin
  1788.   if P <> Desktop^.Last then S.Put(P);
  1789. end;
  1790.  
  1791. begin
  1792.   Desktop^.ForEach(@WriteView);
  1793.   S.Put(nil);
  1794. end;
  1795.  
  1796. function TYahWho.Valid(Command: Word): Boolean;
  1797. { Check to see if any unfinished game windows are open.
  1798.   If so, ask if user wants to abort them before proceeding.}
  1799.  
  1800.   function NotDone(P : PView) : boolean; far;
  1801.   begin
  1802.     NotDone := (P^.Options and ofGameWindow <> 0) and
  1803.                 (not PGameWindow(P)^.PlayerDone);
  1804.   end;
  1805.  
  1806.   procedure PlayersDone(P: PView); far;
  1807.   begin
  1808.     if P^.Options and ofGameWindow <> 0 then PGameWindow(P)^.PlayerDone:=True;
  1809.   end;
  1810.  
  1811. begin
  1812.   if (Command=cmQuit) and  (Desktop^.FirstThat(@NotDone) <> nil) then
  1813.   begin
  1814.     if (MessageBox(^C'Quit all players'' games?',nil,
  1815.         mfWarning+mfYesButton+mfNoButton) = cmYes) then
  1816.     begin
  1817.       Desktop^.ForEach(@PlayersDone); { Make all players done }
  1818.       Valid := Inherited Valid(Command);
  1819.     end else Valid := False;
  1820.   end else Valid :=Inherited Valid(Command);
  1821. end; {TYahWho.Valid}
  1822.  
  1823.  
  1824. procedure TYahWho.HandleEvent;
  1825.  
  1826. procedure CloseAll;
  1827.  
  1828. procedure CloseView(P: PView); far;
  1829. begin
  1830.   if P^.Options and ofGameWindow <> 0 then PGameWindow(P)^.PlayerDone:=True;
  1831.   Message(P, evCommand, cmClose, nil);
  1832. end;
  1833.  
  1834. begin
  1835.   with Desktop^ do
  1836.   begin
  1837.       Lock;
  1838.       ForEach(@CloseView); { Clear the desktop }
  1839.       Unlock;
  1840.       WinNumber := 0;
  1841.   end;
  1842. end;  {CloseAll}
  1843.  
  1844. procedure NewPlayer;
  1845. var
  1846.   R,Bounds : TRect;
  1847.   I : PInputLine;
  1848.   D : PDialog;
  1849.   Name : string[10];
  1850. begin
  1851.   Bounds.Assign(0,0,24,7);
  1852.   D := New(PDialog, Init(Bounds,'Player Name'));
  1853.   with D^ do
  1854.   begin
  1855.     Options := Options or ofCentered;
  1856.     Palette := dpCyanDialog;
  1857.     HelpCtx := hcDNewPlayer;
  1858.  
  1859.     R.Assign(2,4,10,6);
  1860.     Insert(New(PButton, Init(R, 'O~K', cmOk, bfDefault)));
  1861.  
  1862.     R.Assign(12,4,22,6);
  1863.     Insert(New(PButton, Init(R, '~C~ancel', cmCancel, bfNormal)));
  1864.  
  1865.     R.Assign(5,2,17,3);
  1866.     I := New(PInputLine, Init(R,10));
  1867.     {Make the first letter of each word in caps}
  1868.     I^.SetValidator(New(PPXPictureValidator, Init('*{&*?[ ]}',False)));
  1869.     Insert(I);
  1870.   end;
  1871.   Name := '';
  1872.  
  1873.   if (ExecuteDialog(D,@Name) = cmCancel) or (Name = '') then exit;
  1874.  
  1875.  
  1876.   Desktop^.GetExtent(Bounds);
  1877.   InsertWindow(New(PGameWindow,Init(Bounds,Name)));
  1878.  
  1879. end; {NewPlayer}
  1880.  
  1881. procedure NewGame;
  1882. var
  1883.   Players : TStringCollection;
  1884.   Bounds  : TRect;
  1885.  
  1886. { Check to see if any unfinished game windows are open.
  1887.   If so, ask if user wants to abort them before proceeding.}
  1888.  
  1889.   function NotDone(P : PView) : boolean; far;
  1890.   begin
  1891.     NotDone := (P^.Options and ofGameWindow <> 0) and
  1892.                 (not PGameWindow(P)^.PlayerDone);
  1893.   end;
  1894.  
  1895.   procedure GetPlayers(P : PGameWindow); far;
  1896.   begin
  1897.     if P^.Options and ofGameWindow <> 0 then
  1898.       Players.Insert(NewStr(P^.Title^));
  1899.   end;
  1900.  
  1901.   procedure Player(N : PString); far;
  1902.   begin
  1903.     if (N <> nil) and (N^ <> '') then
  1904.     begin
  1905.       Inc(WinNumber);
  1906.       InsertWindow(New(PGameWindow,Init(Bounds,N^)));
  1907.     end;
  1908.   end;
  1909.  
  1910.  
  1911. begin
  1912.   if (Desktop^.FirstThat(@NotDone) <> nil) and
  1913.      (MessageBox(^C'Quit current game?',nil,
  1914.       mfWarning+mfYesButton+mfNoButton) <> cmYes) then exit;
  1915.  
  1916.   if (CommandEnabled(cmClose)) and (MessageBox(^C'Same Players?', nil,
  1917.      mfConfirmation+mfYesButton+mfNoButton) = cmYes) then
  1918.   begin
  1919.     Players.Init(5,5);
  1920.     Players.Duplicates := True;
  1921.     Desktop^.ForEach(@GetPlayers);
  1922.     CloseAll;
  1923.     WinNumber := 0;  {Have to handle WinNumber manually because the
  1924.                       Idle routine can't catch up}
  1925.     Desktop^.GetExtent(Bounds);
  1926.     Players.ForEach(@Player);
  1927.     Players.Done;
  1928.   end else
  1929.   begin
  1930.     CloseAll;
  1931.     NewPlayer;
  1932.   end;
  1933. end; {NewGame}
  1934.  
  1935. procedure ShowWinner;
  1936. var
  1937.   S : word;
  1938.   N : PString;
  1939.   Msg : string;
  1940.   SStr : string[3];
  1941.   Hall : Text;
  1942.   i,j : integer;
  1943.   Event : TEvent;
  1944.   ScoreFile,
  1945.   HOFFile   : PDosStream;
  1946.   ScoreList : PTopScoreList;
  1947.   HOFList   : PScoreList;
  1948.   NewHigh   : boolean;
  1949.  
  1950.   procedure GetWinner(W : PGameWindow); far;
  1951.   begin
  1952.     with W^ do if (Options and ofGameWindow <> 0) and (Total > S) then
  1953.     begin
  1954.       S := Total; N := Title;
  1955.     end;
  1956.   end;
  1957.  
  1958.   procedure RecordHighs(W : PGameWindow); far;
  1959.   begin
  1960.     with W^ do if (Options and ofGameWindow <> 0) and (Title^ <> '') then
  1961.     begin
  1962.       if Total > ScoreList^.MinScore then
  1963.       begin
  1964.         NewHigh := True;
  1965.         ScoreList^.Insert(New(PTopScore, Init(Total, Title^, Today)));
  1966.       end;
  1967.  
  1968.       if Total > HOF_Threshold then {Enter the Hall of Fame}
  1969.         HOFList^.Insert(New(PTopScore, Init(Total, Title^, Today)));
  1970.     end;
  1971.   end;
  1972.  
  1973. begin {ShowWinner}
  1974.   S := 0; N := nil;
  1975.   DeskTop^.ForEach(@GetWinner);
  1976.   if N<>nil then
  1977.   begin
  1978.     Str(S,SStr);
  1979.     Msg := ^C'And the winner is...'^M^C +
  1980.            N^ + ' with a score of ' + SStr;
  1981.     MessageBox(Msg,nil, mfOkButton+mfInformation);
  1982.   end;
  1983.  
  1984.   ScoreFile := New(PDosStream, Init(OrigDir+Top10Name,stOpen));
  1985.   if ScoreFile^.Status <> stOk then {File not found. Create it.}
  1986.   begin
  1987.     Dispose(ScoreFile,Done);
  1988.     ScoreFile := New(PDosStream, Init(OrigDir+Top10Name,stCreate));
  1989.     ScoreList := New(PTopScoreList, Init(10,0));
  1990.   end else {File was found. Read in the scores}
  1991.   ScoreList := PTopScoreList(ScoreFile^.Get);
  1992.   if ScoreFile^.Status <> stOk then
  1993.     MessageBox(^C'Score file corrupted!', nil, mfError+mfOkButton);
  1994.  
  1995.   HOFFile := New(PDosStream, Init(OrigDir+HOFName,stOpen));
  1996.   if HOFFile^.Status <> stOk then {File not found. Create it.}
  1997.   begin
  1998.     Dispose(HOFFile,Done);
  1999.     HOFFile := New(PDosStream, Init(OrigDir+HOFName,stCreate));
  2000.     HOFList := New(PScoreList, Init(10,5));
  2001.   end else {File was found. Read in the scores}
  2002.   HOFList := PScoreList(HOFFile^.Get);
  2003.   if HOFFile^.Status <> stOk then
  2004.     MessageBox(^C'Hall of Fame file corrupted!', nil,
  2005.                   mfError+mfOkButton);
  2006.  
  2007.   NewHigh := False;
  2008.  
  2009.   DeskTop^.ForEach(@RecordHighs);
  2010.  
  2011.   ScoreFile^.Seek(0);
  2012.   ScoreFile^.Put(ScoreList);
  2013.   if ScoreFile^.Status <> stOk then
  2014.     MessageBox(^C'Could not write score file!', nil, mfError+mfOkButton);
  2015.  
  2016.   HOFFile^.Seek(0);
  2017.   HOFFile^.Put(HOFList);
  2018.   if HOFFile^.Status <> stOk then
  2019.     MessageBox(^C'Could not write Hall of Fame file!', nil,
  2020.                    mfError+mfOkButton);
  2021.  
  2022.   Dispose(ScoreFile,Done);
  2023.   Dispose(HOFFile,Done);
  2024.   Dispose(ScoreList,Done);
  2025.   Dispose(HOFList,Done);
  2026.  
  2027.   if NewHigh then
  2028.   begin
  2029.     Tune(Top10);
  2030.     Event.What:=evCommand; Event.Command:=cmShowTop10;
  2031.     HandleEvent(Event);
  2032.   end;
  2033.  
  2034. end;
  2035.  
  2036. procedure ShowTop10;
  2037. var
  2038.   i : integer;
  2039.   R : TRect;
  2040.   D : PDialog;
  2041.   S : string[3];
  2042.   B : PView;
  2043.   ScoreFile : PDosStream;
  2044.   ScoreList : PTopScoreList;
  2045.  
  2046.   procedure ShowScore(TopScore : PTopScore); far;
  2047.   var
  2048.     N : string[11];
  2049.   begin
  2050.     with TopScore^ do
  2051.     begin
  2052.       Str(Score:3,S);
  2053.       N := Name;
  2054.       while Length(N) < 11 do N := N+' ';
  2055.       B:=New(PStaticText, Init(R,Date+' '+N+S));
  2056.     end;
  2057.     with B^ do Options := Options or ofCenterX;
  2058.     D^.Insert(B);
  2059.     R.Move(0,1);
  2060.   end;
  2061.  
  2062. begin
  2063.   ScoreFile := New(PDosStream, Init(OrigDir+Top10Name, stOpenRead));
  2064.   if ScoreFile^.Status <> stOk then
  2065.   begin
  2066.     Dispose(ScoreFile,Done);
  2067.     MessageBox(^C'Could not open score file.', nil, mfError+mfOkButton);
  2068.     exit;
  2069.   end;
  2070.  
  2071.   ScoreList := PTopScoreList(ScoreFile^.Get);
  2072.   if ScoreFile^.Status <> stOk then
  2073.       MessageBox(^C'Score file corrupted!', nil, mfError+mfOkButton) else
  2074.   begin
  2075.     R.Assign(0,0,33,16);
  2076.     D := New(PDialog, Init(R, 'The Top 10 Scores'));
  2077.     with D^ do
  2078.     begin
  2079.       Options := Options or ofCentered;
  2080.       Palette := dpCyanDialog;
  2081.       HelpCtx := hcDTop10;
  2082.       R.Assign(0,2,23,3);
  2083.       ScoreList^.ForEach(@ShowScore);
  2084.       Dispose(ScoreList, Done);
  2085.  
  2086.       GetExtent(R); R.Grow(-1,-1);
  2087.       R.A.Y:=R.B.Y-2; R.B.X := R.A.X + 8;
  2088.       B := New(PButton, Init(R,'O~K~',cmOK,bfDefault));
  2089.       with B^ do Options := Options or ofCenterX;
  2090.       Insert(B);
  2091.     end;
  2092.     ExecuteDialog(D,nil);
  2093.   end;
  2094.   Dispose(ScoreFile,Done);
  2095. end;
  2096.  
  2097. procedure ShowHall;
  2098. var
  2099.   R    : TRect;
  2100.   D    : PDialog;
  2101.   B    : PView;
  2102.   HOFFile  : PDosStream;
  2103.   HallList : PScoreList;
  2104.   sbPtr    : PScrollbar;
  2105.  
  2106. begin
  2107.   HOFFile := New(PDosStream, Init(OrigDir+'YAHWHO.HOF', stOpenRead));
  2108.   if HOFFile^.Status <> stOk then
  2109.   begin
  2110.     Dispose(HOFFile,Done);
  2111.     MessageBox(^C'Could not open Hall of Fame file.', nil,
  2112.                     mfError+mfOkButton);
  2113.     exit;
  2114.   end;
  2115.  
  2116.   HallList := PScoreList(HOFFile^.Get);
  2117.   if HOFFile^.Status <> stOk then
  2118.       MessageBox(^C'Hall of Fame file corrupted!', nil,
  2119.                    mfError+mfOkButton) else
  2120.   begin
  2121.     R.Assign(0,0,34,14);
  2122.     D := New(PDialog, Init(R,'The Hall of Fame'));
  2123.     with D^ do
  2124.     begin
  2125.       Options := Options or ofCentered;
  2126.       Palette := dpCyanDialog;
  2127.       HelpCtx := hcDHall;
  2128.  
  2129.       GetExtent(R); R.Grow(-1,-1);
  2130.       R.A.Y:=R.B.Y-2; R.B.X := R.A.X + 8;
  2131.       B := New(PButton, Init(R,'O~K~',cmOK,bfDefault));
  2132.       with B^ do Options := Options or ofCenterX;
  2133.       Insert(B);
  2134.  
  2135.       sbPtr := StandardScrollBar(sbVertical);
  2136.       R.Assign(4,2,29,10);
  2137.       with sbPtr^ do
  2138.       begin
  2139.         Origin.X:=29; Origin.Y:=2;
  2140.         Size.Y := 8;
  2141.       end;
  2142.       B := New(PScoreListBox, Init(R, 1, sbPtr));
  2143.       PScoreListBox(B)^.NewList(HallList);
  2144.       Insert(B);
  2145.     end;
  2146.     ExecuteDialog(D,nil);
  2147.   end;
  2148.   Dispose(HOFFile,Done);
  2149. end;
  2150.  
  2151. procedure ResetScores;
  2152. var
  2153.   Scores : file;
  2154. begin
  2155.   if MessageBox(^C'Are you sure you want to'^M +
  2156.                 ^C'erase the scores?', nil,
  2157.                 mfWarning+mfYesButton+mfNoButton) = cmYes then
  2158.   begin
  2159.     Assign(Scores,OrigDir+Top10Name); {$I-} Erase(Scores); {$I+}
  2160.     if IOresult<>0 then MessageBox(^C'Could not erase the score file.', nil,
  2161.            mfError+mfOkButton);
  2162.   end;
  2163. end;
  2164.  
  2165. procedure SaveDesktop;
  2166.  
  2167. const
  2168.   Wildcard = '*.DKG';
  2169.  
  2170. var
  2171.   FileName: FNameStr;
  2172.   D : PFileDialog;
  2173.   W : PView;
  2174.   S : PStream;
  2175.   F : File;
  2176.   Action : word;
  2177.  
  2178. begin
  2179.   FileName := Wildcard;
  2180.   D := New(PFileDialog, Init(WildCard, 'Save a Game File',
  2181.        '~N~ame', fdOkButton + fdClearButton + fdHelpButton, 100));
  2182.   if D <> nil then D^.HelpCtx := hcFOFileOpenDBox;
  2183.  
  2184.   case ExecuteDialog(D, @FileName) of
  2185.   cmFileOpen,cmOk :
  2186.   begin
  2187.     if Exists(FileName) and (MessageBox(^C'Overwrite '+FileName+'?', nil,
  2188.        mfWarning+mfYesButton+mfNoButton) = cmNo) then exit;
  2189.     S := New(PBufStream, Init(FileName, stCreate, 1024));
  2190.     if not LowMemory and (S^.Status = stOk) then
  2191.     begin
  2192.       StoreDesktop(S^);
  2193.       if S^.Status <> stOk then
  2194.       begin
  2195.         MessageBox('Could not create '+FileName, nil, mfOkButton + mfError);
  2196.         {$I-}
  2197.         Dispose(S, Done);
  2198.         Assign(F, FileName);
  2199.         Erase(F);
  2200.         Exit;
  2201.       end;
  2202.     end;
  2203.     Dispose(S, Done);
  2204.   end;
  2205.  
  2206.   cmFileClear : if MessageBox(^C'Delete '+FileName+'?', nil,
  2207.                     mfYesButton+mfNoButton+mfWarning) = cmYes then
  2208.     begin
  2209.       {$I-}
  2210.       Assign(F, FileName);
  2211.       Erase(F);
  2212.     end;
  2213.   end; {case}
  2214. end;
  2215.  
  2216. procedure RestoreDesktop;
  2217. const
  2218.   Wildcard = '*.DKG';
  2219.  
  2220. var
  2221.   FileName: FNameStr;
  2222.   D : PFileDialog;
  2223.   W : PView;
  2224.   S : PStream;
  2225.   F : File;
  2226.  
  2227.   function NotDone(P : PView) : boolean; far;
  2228.   begin
  2229.     NotDone := (P^.Options and ofGameWindow <> 0) and
  2230.                 (not PGameWindow(P)^.PlayerDone);
  2231.   end;
  2232.  
  2233. begin
  2234.   if (Desktop^.FirstThat(@NotDone) <> nil) and
  2235.      (MessageBox(^C'Quit current game?',nil,
  2236.       mfWarning+mfYesButton+mfNoButton) <> cmYes) then exit;
  2237.  
  2238.   CloseAll;
  2239.   FileName := Wildcard;
  2240.   D := New(PFileDialog, Init(WildCard, 'Load a Game File',
  2241.        '~N~ame', fdOpenButton + fdClearButton + fdHelpButton, 100));
  2242.   if D <> nil then D^.HelpCtx := hcFOFileOpenDBox;
  2243.  
  2244.   case ExecuteDialog(D, @FileName) of
  2245.   cmFileOpen,cmOk :
  2246.   begin
  2247.     S := New(PBufStream, Init(FileName, stOpenRead, 1024));
  2248.     if LowMemory then OutOfMemory
  2249.     else if S^.Status <> stOk then
  2250.       MessageBox(^C'Could not open '+FileName, nil, mfOkButton + mfError)
  2251.     else
  2252.     begin
  2253.       LoadDesktop(S^);
  2254.       if S^.Status <> stOk then
  2255.         MessageBox(^C'Invalid game file format', nil, mfOkButton + mfError);
  2256.     end;
  2257.     Dispose(S, Done);
  2258.   end;
  2259.   
  2260.   cmFileClear : if MessageBox(^C'Delete '+FileName+'?', nil,
  2261.                     mfYesButton+mfNoButton+mfWarning) = cmYes then
  2262.     begin
  2263.       {$I-}
  2264.       Assign(F, FileName);
  2265.       Erase(F);
  2266.     end;
  2267.   end; {case}
  2268. end;
  2269.  
  2270. procedure Colors;
  2271. var
  2272.   D: PMyColorDialog;
  2273. begin
  2274.   D := New(PMyColorDialog, Init('', DefaultPal[AppPalette],
  2275.     ColorGroup('Desktop',       DesktopColorItems(nil),
  2276.     ColorGroup('Menus',         MenuColorItems(nil),
  2277.     ColorGroup('Std Dialogs',  DialogColorItems(dpGrayDialog, nil),
  2278.     ColorGroup('Top 10/Hall',  DialogColorItems(dpCyanDialog, nil),
  2279.     ColorGroup('About Box',    DialogColorItems(dpBlueDialog, nil),
  2280.     ColorGroup('Game Window',
  2281.       ColorItem('Frame passive',      8,
  2282.       ColorItem('Frame active',       9,
  2283.       ColorItem('Frame icons',       10,
  2284.       ColorItem('Normal Score',      11,
  2285.       ColorItem('HiLite Score',      12,
  2286.       ColorItem('Normal Dice',       13,
  2287.       ColorItem('HiLite Dice',       14, nil))))))),
  2288.     ColorGroup('Help System',
  2289.       ColorItem('Frame passive',    128,
  2290.       ColorItem('Frame active',     129,
  2291.       ColorItem('Frame icons',      130,
  2292.       ColorItem('Scroll bar page',  131,
  2293.       ColorItem('Normal Text',      133,
  2294.       ColorItem('Keyword',          134,
  2295.       ColorItem('Selected Keyword', 135, nil))))))), nil)))))))));
  2296.  
  2297.     D^.HelpCtx := hcOCColorsDBox;
  2298.     if ExecuteDialog(D, Application^.GetPalette) <> cmCancel then
  2299.     begin
  2300.       DoneMemory;  { Dispose all group buffers }
  2301.       ReDraw;      { Redraw application with new palette }
  2302.     end;
  2303. end;
  2304.  
  2305. procedure SaveConfig;
  2306. var
  2307.   S : TDosStream;
  2308. begin
  2309.   S.Init(OrigDir+ConfigName,stCreate);
  2310.   with S do
  2311.   begin
  2312.     if Status = stOk then
  2313.     begin
  2314.       Write(ActivePal, SizeOf(ActivePal));
  2315.       Write(ScreenMode, SizeOf(ScreenMode));
  2316.       Write(CheckSnow, SizeOf(CheckSnow));
  2317.       Write(LCD, SizeOf(LCD));
  2318.       Write(SoundOn, SizeOf(SoundOn));
  2319.     end;
  2320.     Done;
  2321.   end;
  2322. end;
  2323.  
  2324. procedure Prefs;
  2325. var
  2326.   D : PDialog;
  2327.   B : PView;
  2328.   Bounds, R : TRect;
  2329.   DlgData : record
  2330.     SnwChk   : word;
  2331.     Noises   : word;
  2332.     DMode    : word;
  2333.   end;
  2334.   OldDMode, Mode : word;
  2335.  
  2336. begin
  2337.   if ScreenMode<>smMono then
  2338.   begin
  2339.     Bounds.Assign(0,0,23,15);
  2340.     D := New(PDialog, Init(Bounds, 'Preferences'));
  2341.     with D^ do
  2342.     begin
  2343.       Options := Options or ofCentered;
  2344.       HelpCtx := hcOPrefs;
  2345.  
  2346.       R.Assign(2,8,21,9);
  2347.       B:=New(PCheckBoxes, Init(R,
  2348.         NewSItem('~S~now Checking',
  2349.         nil)));
  2350.       if HiResScreen then PCheckBoxes(B)^.Hide; {Snow checking only on CGA}
  2351.       Insert(B);
  2352.  
  2353.       R.Assign(2,10,21,11);
  2354.       B:=New(PCheckBoxes, Init(R,
  2355.         NewSItem('S~o~unds',
  2356.         nil)));
  2357.       Insert(B);
  2358.  
  2359.       R.Assign(2,12,10,14);
  2360.       Insert(New(PButton, Init(R, 'O~K', cmOk, bfDefault)));
  2361.  
  2362.       R.Assign(11,12,21,14);
  2363.       Insert(New(PButton, Init(R, '~C~ancel', cmCancel, bfNormal)));
  2364.  
  2365.       R.Assign(4,3,14,6);
  2366.       B:=New(PRadioButtons, Init(R,
  2367.         NewSItem('~C~O80',
  2368.         NewSItem('~B~W80',
  2369.         NewSItem('~L~CD',
  2370.         nil)))));
  2371.  
  2372.       Insert(B);
  2373.       R.Assign(3,2,19,3);
  2374.       Insert(New(PLabel, Init(R,'Screen ~M~ode',B)));
  2375.     end;
  2376.  
  2377.     with DlgData do
  2378.     begin
  2379.       case ScreenMode of
  2380.         smCO80 : DMode := 0;
  2381.         smBW80 : if LCD then DMode := 2 else DMode := 1;
  2382.         else DlgData.DMode := 0;
  2383.       end;
  2384.       if CheckSnow then SnwChk := 1 else SnwChk := 0;
  2385.       if SoundOn then Noises:=1 else Noises:=0;
  2386.     end;
  2387.  
  2388.     OldDmode := DlgData.DMode;
  2389.  
  2390.     if ExecuteDialog(D,@DlgData) <> cmCancel then
  2391.     begin
  2392.       CheckSnow := DlgData.SnwChk=1;
  2393.       SoundOn := DlgData.Noises=1;
  2394.  
  2395.       case DlgData.DMode of
  2396.         0   : Mode := smCO80;
  2397.         1,2 : Mode := smBW80;
  2398.       end;
  2399.       LCD := DlgData.Dmode = 2;
  2400.     end;
  2401.  
  2402.     if DlgData.DMode <> OldDMode then
  2403.     begin
  2404.       Desktop^.Lock;
  2405.       SetScreenMode(Mode);
  2406.       CheckSnow := DlgData.SnwChk=1;
  2407.       ShowMarkers := (ScreenMode<>smCO80);
  2408.       DoneMemory;
  2409.       Redraw;
  2410.       Desktop^.UnLock;
  2411.     end;
  2412.   end else {Running on a Mono machine}
  2413.   begin
  2414.     Bounds.Assign(0,0,23,8);
  2415.     D := New(PDialog, Init(Bounds, 'Preferences'));
  2416.     with D^ do
  2417.     begin
  2418.       Options := Options or ofCentered;
  2419.       HelpCtx := hcOPrefs;
  2420.  
  2421.       R.Assign(2,2,21,3);
  2422.       B:=New(PCheckBoxes, Init(R,
  2423.         NewSItem('S~o~unds',
  2424.         nil)));
  2425.       Insert(B);
  2426.  
  2427.       R.Assign(2,5,10,7);
  2428.       Insert(New(PButton, Init(R, 'O~K', cmOk, bfDefault)));
  2429.  
  2430.       R.Assign(11,5,21,7);
  2431.       Insert(New(PButton, Init(R, '~C~ancel', cmCancel, bfNormal)));
  2432.     end;
  2433.     if SoundOn then Mode := 1 else Mode := 0;
  2434.     if ExecuteDialog(D,@Mode) <> cmCancel then SoundOn := Mode=1;
  2435.   end;
  2436. end;
  2437.  
  2438. begin {TYahWho.HandleEvent}
  2439.   Inherited HandleEvent(Event);
  2440.   case Event.What of
  2441.     evCommand: begin
  2442.       case Event.Command of
  2443.         cmAbout      : About;
  2444.         cmNewGame    : NewGame;
  2445.         cmSaveGame   : SaveDeskTop;
  2446.         cmLoadGame   : RestoreDeskTop;
  2447.         cmNewPlayer  : NewPlayer;
  2448.         cmShowWinner : ShowWinner;
  2449.         cmShowTop10  : ShowTop10;
  2450.         cmShowHall   : ShowHall;
  2451.         cmReset      : ResetScores;
  2452.         cmColors     : Colors;
  2453.         cmSaveConfig : SaveConfig;
  2454.         cmPrefs      : Prefs;
  2455.         else Exit;
  2456.       end; {Case}
  2457.       ClearEvent(Event); {We took care of it}
  2458.     end;
  2459.   end;
  2460. end;
  2461.  
  2462. procedure TYahWho.GetEvent(var Event: TEvent);
  2463. var
  2464.   W: PWindow;
  2465.   HFile: PHelpFile;
  2466.   HelpStrm: PDosStream;
  2467. const
  2468.   HelpInUse: Boolean = False;
  2469. begin
  2470.   Inherited GetEvent(Event);
  2471.   case Event.What of
  2472.     evCommand:
  2473.       if (Event.Command = cmHelp) and not HelpInUse then
  2474.       begin
  2475.         HelpInUse := True;
  2476.         HelpStrm := New(PDosStream, Init(OrigDir+HelpName, stOpenRead));
  2477.         HFile := New(PHelpFile, Init(HelpStrm));
  2478.         if HelpStrm^.Status <> stOk then
  2479.         begin
  2480.           MessageBox(^C'Could not open '+OrigDir+HelpName, nil, mfError + mfOkButton);
  2481.           Dispose(HFile, Done);
  2482.         end
  2483.         else
  2484.         begin
  2485.           W := New(PHelpWindow,Init(HFile, GetHelpCtx));
  2486.           if ValidView(W) <> nil then
  2487.           begin
  2488.             ExecView(W);
  2489.             Dispose(W, Done);
  2490.           end;
  2491.           ClearEvent(Event);
  2492.         end;
  2493.         HelpInUse := False;
  2494.       end;
  2495.   end;
  2496. end;
  2497.  
  2498. function TYahWho.GetPalette: PPalette;
  2499. begin
  2500.   if (ScreenMode=smBW80) and LCD then AppPalette:=apMonochrome;
  2501.   GetPalette := @ActivePal[AppPalette];
  2502. end;
  2503.  
  2504. procedure TYahWho.Idle;
  2505. var
  2506.   NumPlayers : word;
  2507.  
  2508.   procedure SetWinNum(P:PGameWindow); far;
  2509.   begin
  2510.     with P^ do
  2511.       if (Options and ofGameWindow <> 0) then
  2512.       begin
  2513.         if Number > WinNumber then WinNumber := Number;
  2514.         Inc(NumPlayers);
  2515.       end;
  2516.   end;
  2517.  
  2518.   function GameInWork(W : PGameWindow) : boolean; far;
  2519.   begin
  2520.     with W^ do if Options and ofGameWindow <> 0 then
  2521.     GameInWork := not PlayerDone
  2522.     else GameInWork := False;
  2523.   end;
  2524.  
  2525.  
  2526. begin
  2527.   Inherited Idle;
  2528.  
  2529.   {Make WinNumber 1 higher than any open window number}
  2530.   WinNumber := 0; NumPlayers := 0;
  2531.   DeskTop^.ForEach(@SetWinNum);
  2532.   Inc(WinNumber);
  2533.   if NumPlayers > 1 then EnableCommands(GWinCmds) else
  2534.   DisableCommands(GWinCmds);
  2535.  
  2536.   if (DeskTop^.Current<>nil) and
  2537.      (DeskTop^.Current^.Options and ofGameWindow <> 0) then
  2538.   begin
  2539.     if PGameWindow(DeskTop^.Current)^.RollOk then EnableCommands([cmRollDie])
  2540.     else DisableCommands([cmRollDie]);
  2541.   end else
  2542.     DisableCommands([cmRollDie,cmSelectAll,cmDeSelectAll]);
  2543.  
  2544.   {Now look for an unfinished GameWindow on the Desktop to
  2545.   see if all players are done}
  2546.  
  2547.   GameOver := (Desktop^.FirstThat(@GameInWork)=nil);
  2548.   if GameOver then DisableCommands([cmNewPlayer]) else
  2549.   EnableCommands([cmNewPlayer]);
  2550. end;
  2551.  
  2552. procedure TYahWho.InitMenuBar;
  2553. var
  2554.   R: TRect;
  2555. begin
  2556.   GetExtent(R);
  2557.   R.B.Y := R.A.Y+1;
  2558.   MenuBar := New(PMenuBar, Init(R, NewMenu(
  2559.     NewSubMenu('~'#240'~', hcMAbout, NewMenu(
  2560.       NewItem('~A~bout', '', kbNoKey, cmAbout, hcMAbout, nil)),
  2561.     NewSubMenu('~G~ame', hcGame, NewMenu(
  2562.       NewItem('~N~ew Game','', kbNoKey, cmNewGame, hcGNewGame,
  2563.       NewItem('New ~P~layer','F2', kbF2, cmNewPlayer, hcGNewPlayer,
  2564.       NewItem('~S~ave','', kbNoKey, cmSaveGame, hcGSave,
  2565.       NewItem('~L~oad','', kbNoKey, cmLoadGame, hcGLoad,
  2566.       NewItem('E~x~it','Alt-X', kbAltX, cmQuit, hcGExit, nil)))))),
  2567.     NewSubMenu('~D~ice', hcDice, NewMenu(
  2568.       NewItem('~S~elect All', 'F4', kbF4, cmSelectAll, hcDiceSel,
  2569.       NewItem('~D~eSelect All', 'Shift-F4', kbShiftF4, cmDeSelectAll,
  2570.                  hcDiceDeSel, nil))),
  2571.     NewSubMenu('~S~cores', hcScores, NewMenu(
  2572.       NewItem('~T~op 10', '', kbNoKey, cmShowTop10, hcSTop10,
  2573.       NewItem('~H~all of Fame', '', kbNoKey, cmShowHall, hcSHall,
  2574.       NewItem('~R~eset Scores', '', kbNoKey, cmReset, hcSReset, nil)))),
  2575.     NewSubMenu('~O~ptions', hcOptions, NewMenu(
  2576.       NewItem('~C~olors', '', kbNoKey, cmColors, hcOColors,
  2577.       NewItem('~P~references', '', kbNoKey, cmPrefs, hcOPrefs,
  2578.       NewItem('~S~ave Config', '', kbNoKey, cmSaveConfig, hcOConfig, nil)))),
  2579.     NewSubMenu('~W~indows', hcWindows, NewMenu(
  2580.       NewItem('~T~ile', '', kbNoKey, cmTile, hcWTile,
  2581.       NewItem('Ca~s~cade', '', kbNoKey, cmCascade, hcWCascade,
  2582.       NewItem('~M~ove/Resize', 'Ctrl-F5', kbCtrlF5, cmResize, hcWResize,
  2583.       NewItem('~Z~oom', 'F5', kbF5, cmZoom, hcWZoom,
  2584.       NewItem('~N~ext', 'F3', kbF3, cmNext, hcWNext,
  2585.       NewItem('~P~revious', 'Shift-F3', kbShiftF3, cmPrev, hcWPrev,
  2586.       NewItem('~C~lose', 'Alt-F3', kbAltF3, cmClose, hcWClose, nil)))))))),
  2587.             nil)))))))));
  2588. end;
  2589.  
  2590. procedure TYahWho.InitStatusLine;
  2591. var
  2592.   R: TRect;
  2593. begin
  2594.   GetExtent(R);
  2595.   R.A.Y := R.B.Y - 1;
  2596.   StatusLine := New(PMyStatusLine, Init(R,
  2597.     NewStatusDef(0, $100-1,
  2598.       NewStatusKey('~F1~ Help', kbF1, cmHelp,
  2599.       NewStatusKey('~F2~ New Player', kbF2, cmNewPlayer,
  2600.       NewStatusKey('~F3~ Next Player', kbF3, cmNext,
  2601.       NewStatusKey('~F10~ Menu', kbF10, cmMenu,
  2602.       NewStatusKey('~Alt-X~ Exit', kbAltX, cmQuit,
  2603.       NewStatusKey(' ~'#17#217'~ Roll', kbEnter, cmRollDie,
  2604.       NewStatusKey('', kbF5, cmZoom,
  2605.       NewStatusKey('', kbCtrlF5, cmResize,
  2606.       NewStatusKey('', kbAltF3, cmClose, nil))))))))),
  2607.     NewStatusDef($100, $FFFF,
  2608.       NewStatusKey('~F1~ Help', kbF1, cmHelp, nil),
  2609.        nil))));
  2610. end;
  2611.  
  2612. function TMyStatusLine.Hint(AHelpCtx: Word): String;
  2613. begin
  2614.   case AHelpCtx of
  2615.     hcMAbout        : Hint := 'Display Program Information';
  2616.     hcGame          : Hint := 'Start New Game, Add Players...';
  2617.     hcGNewGame      : Hint := 'Begin a new game';
  2618.     hcGNewPlayer    : Hint := 'Add a new player';
  2619.     hcGSave         : Hint := 'Save game to disk';
  2620.     hcGLoad         : Hint := 'Retrieve game from disk';
  2621.     hcGExit         : Hint := 'Quit YahWho';
  2622.     hcDice          : Hint := 'Select/DeSelect All Dice';
  2623.     hcDiceSel       : Hint := 'Select all dice';
  2624.     hcDiceDeSel     : Hint := 'DeSelect all dice';
  2625.     hcScores        : Hint := 'High Scores/Hall of Fame';
  2626.     hcSTop10        : Hint := 'Display Top 10 Scores';
  2627.     hcSHall         : Hint := 'Display Hall of Fame';
  2628.     hcSReset        : Hint := 'Reset (erase) Top 10 Scores';
  2629.     hcOptions       : Hint := 'Set colors/preferences';
  2630.     hcOColors       : Hint := 'Set program colors';
  2631.     hcOPrefs        : Hint := 'Set program behaviors';
  2632.     hcOConfig       : Hint := 'Make program settings permanent';
  2633.     hcDNewPlayer    : Hint := 'Enter player name (10 chars max)';
  2634.     hcWindows       : Hint := 'Resize, move, tile, cascade windows';
  2635.     hcWTile         : Hint := 'Tile all open windows';
  2636.     hcWCascade      : Hint := 'Cascade all open windows';
  2637.     hcWResize       : Hint := 'Arrows move, Shift-arrows resize window';
  2638.     hcWZoom         : Hint := 'Toggle zoomed status';
  2639.     hcWNext         : Hint := 'Select next open window';
  2640.     hcWPrev         : Hint := 'Select previous open window';
  2641.     hcWClose        : Hint := 'Close selected window';
  2642.     hcFOFileOpenDBox : Hint := 'Specify game file to save/open';
  2643.     else Hint := '';
  2644.   end;
  2645. end;
  2646.  
  2647. procedure TYahWho.OutOfMemory;
  2648. begin
  2649.   MessageBox(^C'Not enough memory available to complete operation.',
  2650.     nil, mfError + mfOkButton);
  2651. end;
  2652.  
  2653. var
  2654.   Yah_Who : TYahWho;
  2655.  
  2656. begin {Main Program}
  2657.   Yah_Who.Init;
  2658.   Yah_Who.Run;
  2659.   Yah_Who.Done;
  2660. end.
  2661.  
  2662.