home *** CD-ROM | disk | FTP | other *** search
/ C Programming Starter Kit 2.0 / SamsPublishing-CProgrammingStarterKit-v2.0-Win31.iso / bc45 / ttt.pak / TTT.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1997-07-24  |  29.2 KB  |  1,211 lines

  1. //----------------------------------------------------------------------------
  2. // ObjectWindows - (C) Copyright 1992,1994 by Borland International
  3. //
  4. //   TicTacToe Demo Program
  5. //
  6. //   Plays a game of TicTacToe with the user.
  7. //
  8. //   TGameApp - Main TicTacToe application, derived from TApplication
  9. //   TGame -   Game document
  10. //   TGameOptionsBox - A TDialog box for setting TicTacToe options
  11. //   TGameView -   View window for the game, derived from TToolBox
  12. //   Square - Game squares (gadgets), derived from TButtonGadget
  13. //   TAboutBox - A TDialog box for info about TicTacToe
  14. //
  15. //----------------------------------------------------------------------------
  16. #include <owl/owlpch.h>
  17. #include <owl/applicat.h>
  18. #include <owl/framewin.h>
  19. #include <owl/decframe.h>
  20. #include <owl/dialog.h>
  21. #include <owl/dc.h>
  22. #include <owl/button.h>
  23. #include <owl/static.h>
  24. #include <owl/radiobut.h>
  25. #include <owl/groupbox.h>
  26. #include <owl/buttonga.h>
  27. #include <owl/toolbox.h>
  28. #include <owl/celarray.h>
  29. #include <owl/buttonga.h>
  30. #include <owl/ocfevent.h>
  31. #include <ocf/ocreg.h>
  32. #include <ocf/ocapp.h>
  33. #include <ocf/ocdoc.h>
  34. #include <ocf/ocremvie.h>
  35. #include <ocf/ocstorag.h>
  36. #include <owl/controlb.h>
  37. #include <owl/olefacto.h>
  38.  
  39. #include "ttt.h"
  40.  
  41. #define WM_GAMEVIEWSYNC WM_USER + 100
  42.  
  43. const char  GameStreamName[] = "TicTacToe";
  44. const int DllIdleTime = 200;    // time in MS for idle action polling
  45. const int TTT_DLLIDLE = 32000;  // Idle timer ID for DLL servers
  46.  
  47. // App dictionary & Ole registrar objects
  48. //
  49. DEFINE_APP_DICTIONARY(AppDictionary);
  50. static TPointer<TOcRegistrar> Registrar;
  51.  
  52. REGISTRATION_FORMAT_BUFFER(100)
  53.  
  54. BEGIN_REGISTRATION(AppReg)
  55. #if defined(BI_APP_DLL)
  56.  REGDATA(clsid,      "{5E4BD420-8ABC-101B-A23B-CE4E85D07ED2}")
  57. // REGDATA(progid,     "TicTacToe.DllServer")
  58. #else
  59.  REGDATA(clsid,      "{5E4BD425-8ABC-101B-A23B-CE4E85D07ED2}")
  60. // REGDATA(progid,     "TicTacToe.Application")
  61. #endif
  62.  REGDATA(description, "TicTacToe Application")
  63.  REGDATA(appname,     "TicTacToe")
  64. END_REGISTRATION
  65.  
  66. BEGIN_REGISTRATION(DocReg)
  67. #if defined(BI_APP_DLL)
  68.  REGDATA(progid,     "TicTacToeDll.Game.1")
  69.  REGDATA(description,"TicTacToeDll Game")
  70. // REGDATA(serverctx, "Inproc")
  71. #else
  72.  REGDATA(progid,     "TicTacToeExe.Game.1")
  73.  REGDATA(description,"TicTacToeExe Game")
  74. // REGDATA(debugger,   "tdw")
  75. #endif
  76.  REGDATA(menuname,   "Game")
  77.  REGDATA(insertable, "")
  78.  REGDATA(extension,  "ttt")
  79.  REGDATA(docfilter,  "*.ttt")
  80.  REGDATA(verb0,      "&Play")
  81.  REGFORMAT(0, ocrEmbedSource,  ocrContent, ocrIStorage, ocrGet)
  82.  REGFORMAT(1, ocrMetafilePict, ocrContent, ocrMfPict,   ocrGet)
  83. END_REGISTRATION
  84.  
  85. TRegLink* RegLinkHead;
  86. TRegLink  tttGameLink(::DocReg, ::RegLinkHead);
  87.  
  88. //----------------------------------------------------------------------------
  89.  
  90. class TGameApp : public TApplication, public TOcModule {
  91.   public:
  92.     TGameApp();
  93.    ~TGameApp();
  94.     TUnknown* CreateOleObject(uint32 options, TRegLink* link);
  95.  
  96.   private:
  97.     void   CmAbout();
  98.     void   InitMainWindow();
  99.  
  100.   DECLARE_RESPONSE_TABLE(TGameApp);
  101. };
  102. DEFINE_RESPONSE_TABLE1(TGameApp, TApplication)
  103.   EV_COMMAND(CM_ABOUT, CmAbout),
  104. END_RESPONSE_TABLE;
  105.  
  106. //----------------------------------------------------------------------------
  107.  
  108. static const int freeMasks[] = {
  109.   0x006, 0x005, 0x003, 0x030, 0x028, 0x018, 0x180, 0x140, 0x0C0, // row
  110.   0x048, 0x041, 0x009, 0x090, 0x082, 0x012, 0x120, 0x104, 0x024, // col
  111.   0x110, 0x101, 0x011, 0x050, 0x044, 0x014                       // diagonal
  112. };
  113.  
  114. static const int winningMasks[] = {
  115.   0x1C0, 0x038, 0x007, 0x124, 0x092, 0x049, 0x111, 0x054
  116. };
  117.  
  118. //
  119. //
  120. //
  121. static void
  122. freeSquare(int mask, int i, int& square)
  123. {
  124.   int mode = i/9; // row, col, or diag
  125.   if (mode == 0)
  126.     mask ^= 0x007 << (i/3)*3;
  127.   else if (mode == 1)
  128.     mask ^= 0x049 << (i%9)/3;
  129.   else if (((i%9)/3) == 0)
  130.     mask ^= 0x111;
  131.   else
  132.     mask ^= 0x054;
  133.   for (int j = 0, test = 1; test; test <<= 1, j++)
  134.     if (test & mask)
  135.       break;
  136.   square = j;
  137. }
  138.  
  139. //----------------------------------------------------------------------------
  140.  
  141. enum TSquareState {
  142.   SqsEmpty,
  143.   SqsX,
  144.   SqsO,
  145.   SqsCount
  146. };
  147.  
  148. class TGame {
  149.   public:
  150.     TGame(TGame* p = 0, int dim=3);
  151.  
  152.     void New();
  153.     void SetView(TWindow* view) {View = view;}
  154.  
  155.     int  GetDimension() const {return Dim;}  // Dim x Dim game
  156.     bool IsOver();// const;
  157.     bool IsWon();// const;
  158.     bool IsPlaying() const {return Playing;}
  159.     TSquareState GetState(int sq) const;
  160.  
  161.     void UserTurn(int sq);
  162.     void ComputerTurn();
  163.     void SetApplication(TGameApp* app) {App = app;}
  164.     TGameApp* GetApplication() {return App;}
  165.  
  166.   private:
  167.     int          Dim;
  168.     int          UserBoardMap;
  169.     int          ComputerBoardMap;
  170.     TSquareState UserSide;
  171.     TSquareState ComputerSide;
  172.     bool         ComputerGoesFirst;
  173.     bool         Playing;
  174.     TWindow*     View;
  175.     TGameApp*    App;
  176.  
  177.     friend class TGameOptionsBox; // sleazy
  178.  
  179.   private:
  180.     void SetState(int sq, TSquareState state);
  181.     void MakeAMark(int sq, TSquareState mark);
  182.     bool IsAWinner(int sq) const;
  183.  
  184.   friend class TGameView;
  185. };
  186.  
  187. TGame::TGame(TGame* /*not used*/, int dim)
  188. {
  189.   UserSide = SqsX;
  190.   ComputerSide = SqsO;
  191.   ComputerGoesFirst = false;
  192.   Playing = true;
  193.   UserBoardMap = ComputerBoardMap = 0;
  194.   Dim = dim;
  195. }
  196.  
  197. void
  198. TGame::New()
  199. {
  200.   Playing = true;
  201.   UserBoardMap = 0;
  202.   ComputerBoardMap = 0;
  203.   ComputerSide = UserSide==SqsX ? SqsO : SqsX;
  204.  
  205.   if (ComputerGoesFirst)
  206.     ComputerTurn();
  207.  
  208.   if (View)
  209.    View->PostMessage(WM_GAMEVIEWSYNC, 0xFFFF);
  210. }
  211.  
  212. //
  213. // Assign a square to user or computer and repaint the game board
  214. //
  215. void
  216. TGame::MakeAMark(int sq, TSquareState mark)
  217. {
  218.   SetState(sq, mark);
  219.   if (View)
  220.     View->PostMessage(WM_GAMEVIEWSYNC, sq);
  221. }
  222.  
  223. //
  224. // Check if the game is over, ie, no more blank squares
  225. //
  226. bool
  227. TGame::IsOver()
  228. {
  229.   if ((UserBoardMap|ComputerBoardMap) == 0x1FF)
  230.     Playing = false;
  231.   return !Playing;
  232. }
  233.  
  234. //
  235. // Check if the game is won by either user or computer
  236. //
  237. bool
  238. TGame::IsWon()
  239. {
  240.   for (int i = 0; i < 8; i++)
  241.     if ((UserBoardMap & winningMasks[i]) == winningMasks[i] ||
  242.         (ComputerBoardMap & winningMasks[i]) == winningMasks[i]) {
  243.       Playing = false;
  244.       return true;
  245.     }
  246.   return false;
  247. }
  248.  
  249. //
  250. // Check if a square belongs to user or computer
  251. //
  252. TSquareState
  253. TGame::GetState(int sq) const
  254. {
  255.   int mask = 1 << sq;
  256.  
  257.   if (ComputerBoardMap & mask)
  258.     return ComputerSide;
  259.   if (UserBoardMap & mask)
  260.     return UserSide;
  261.   return SqsEmpty;
  262. }
  263.  
  264. //
  265. // Assign a square to a user or computer or neither
  266. //
  267. void
  268. TGame::SetState(int sq, TSquareState state)
  269. {
  270.   int mask = 1 << sq;
  271.  
  272.   if (state == SqsEmpty) {
  273.     ComputerBoardMap &= ~mask;
  274.     UserBoardMap &= ~mask;
  275.  
  276.   } else if (state == UserSide) {
  277.     ComputerBoardMap &= ~mask;
  278.     UserBoardMap |= mask;
  279.  
  280.   } else {
  281.     ComputerBoardMap |= mask;
  282.     UserBoardMap &= ~mask;
  283.   }
  284. }
  285.  
  286. //
  287. // The computer tries to determine if there is a winning move
  288. //
  289. bool
  290. TGame::IsAWinner(int sq) const
  291. {
  292.   int map = ComputerBoardMap | (1 << sq);
  293.   for (int i = 0; i < 8; i++)
  294.     if ((map & winningMasks[i]) == winningMasks[i])
  295.       return true;
  296.   return false;
  297. }
  298.  
  299. //
  300. //
  301. //
  302. void
  303. TGame::UserTurn(int sq)
  304. {
  305.   if (GetState(sq) == SqsEmpty)
  306.     MakeAMark(sq, UserSide);
  307. }
  308.  
  309. //
  310. //
  311. //
  312. void
  313. TGame::ComputerTurn()
  314. {
  315.   bool madeMove = false;
  316.  
  317.   // Look for a winning move first.
  318.   //
  319.   {
  320.     for (int i = 0; i < Dim*Dim; i++) {
  321.       if (GetState(i) == SqsEmpty && IsAWinner(i)) {
  322.         MakeAMark(i, ComputerSide);
  323.         madeMove = true;
  324.         break;
  325.       }
  326.     }
  327.   }
  328.  
  329.   // Look for a blocking move. This is the key to not losing the game!
  330.   //
  331.   if (!madeMove) {
  332.     for (int i = 0; i < 24; i++)
  333.       if ((UserBoardMap & freeMasks[i]) == freeMasks[i]) {
  334.         int sq;
  335.       freeSquare(freeMasks[i], i, sq);
  336.         if (GetState(sq) == ComputerSide)
  337.           continue;
  338.         MakeAMark(sq, ComputerSide);
  339.         madeMove = true;
  340.         break;
  341.       }
  342.   }
  343.  
  344.   // Nothing to block, go to the middle if empty, else first open corner, else
  345.   // first open edge
  346.   // Game can be beaten if user knows how computer plays: try 5,7,8, & 2 to win
  347.   //
  348.   if (!madeMove) {
  349.     int mask = UserBoardMap|ComputerBoardMap;
  350.     if (!(mask & 0x010)) {
  351.       MakeAMark(4, ComputerSide);    // #4 is the middle of 3x3
  352.  
  353.     } else if ((mask & 0x145) != 0x145) {  // corner mask
  354.       int sq;
  355.       if (!(mask & 0x001))
  356.         sq = 0;
  357.       else if (!(mask & 0x004))
  358.         sq = 2;
  359.       else if (!(mask & 0x040))
  360.         sq = 6;
  361.     else  // 0x100
  362.         sq = 8;
  363.       MakeAMark(sq, ComputerSide);    // #4 is the middle of 3x3
  364.  
  365.     } else {
  366.       for (int i = 0; mask & 1; mask >>= 1)
  367.         i++;
  368.       MakeAMark(i, ComputerSide);
  369.     }
  370.   }
  371.  
  372.   // See if the game is over now.
  373.   //
  374.   if (IsWon() || IsOver())
  375.     Playing = false;
  376. }
  377.  
  378. //----------------------------------------------------------------------------
  379.  
  380. class TGameOptionsBox : public TDialog {
  381.   public:
  382.     TGameOptionsBox(TWindow* parent, TGame* game);
  383.  
  384.   private:
  385.     void SetupWindow();
  386.  
  387.    TGroupBox     *YouMeGroup, *XOGroup;
  388.     TRadioButton  *You, *Me, *X, *O;
  389.     TGame*         Game;
  390.  
  391.     void HandleYouMeGroupMsg(UINT);
  392.     void HandleXOGroupMsg(UINT);
  393.  
  394.   DECLARE_RESPONSE_TABLE(TGameOptionsBox);
  395. };
  396. DEFINE_RESPONSE_TABLE1(TGameOptionsBox, TDialog)
  397.   EV_CHILD_NOTIFY_ALL_CODES(IDYOUMEGROUP, HandleYouMeGroupMsg),
  398.   EV_CHILD_NOTIFY_ALL_CODES(IDXOGROUP, HandleXOGroupMsg),
  399. END_RESPONSE_TABLE;
  400.  
  401. TGameOptionsBox::TGameOptionsBox(TWindow* parent, TGame* game)
  402. :
  403.   TDialog(parent, IDD_OPTIONS),
  404.   Game(game)
  405. {
  406.   new TButton(this, IDOK, "Ok", 30, 240, 40, 40, true);
  407.   new TButton(this, IDCANCEL, "Cancel", 150, 240, 40, 40, true);
  408.   YouMeGroup = new TGroupBox(this, IDYOUMEGROUP, "Who goes first?", 15,
  409.                      30, 200, 20);
  410.   You = new TRadioButton(this, IDYOU, "You (Human)", 15, 55, 150, 20, YouMeGroup);
  411.   Me = new TRadioButton(this, IDME, "Me (Computer)", 15, 80, 150, 20, YouMeGroup);
  412.   XOGroup = new TGroupBox(this, IDXOGROUP, "I am playing", 15, 120, 200, 20);
  413.   X = new TRadioButton(this, IDX, "X\'s", 15, 145, 50, 20, XOGroup);
  414.   O = new TRadioButton(this, IDO, "O\'s", 15, 170, 50, 20, XOGroup);
  415. }
  416.  
  417. void
  418. TGameOptionsBox::SetupWindow()
  419. {
  420.   TDialog::SetupWindow();
  421.   if (Game->ComputerGoesFirst)
  422.     Me->Check();
  423.   else
  424.     You->Check();
  425.  
  426.   if (Game->UserSide == SqsX)
  427.     O->Check();
  428.   else
  429.     X->Check();
  430. }
  431.  
  432. void
  433. TGameOptionsBox::HandleYouMeGroupMsg(UINT)
  434. {
  435.   Game->ComputerGoesFirst = (You->GetCheck() == BF_CHECKED) ? false : true;
  436. }
  437.  
  438. void
  439. TGameOptionsBox::HandleXOGroupMsg(UINT)
  440. {
  441.   Game->UserSide = (X->GetCheck() == BF_CHECKED) ? SqsO : SqsX;
  442.   Game->Playing = false;
  443.   Parent->PostMessage(WM_COMMAND, CM_GAMENEW);
  444. }
  445.  
  446. //----------------------------------------------------------------------------
  447.  
  448. class TSquare : public TButtonGadget {
  449.   public:
  450.     TSquare(int id);
  451.    ~TSquare() {CelArray = 0;}
  452.  
  453.     void      SetGlyph(int g);
  454.     void      Paint(TDC& dc);
  455.  
  456.   protected:
  457.     void      Activate(TPoint& p);
  458.     int       Glyph;
  459.  
  460.   private:
  461.     static TCelArray*  StateCels[3];
  462.   friend class TGameView;
  463. };
  464. typedef TSquare* PTSquare;
  465.  
  466. TCelArray* TSquare::StateCels[SqsCount]; // entry for each state
  467. static TResId StateResId[SqsCount] = { IDB_EMPTY, IDB_X, IDB_O };
  468.  
  469. TSquare::TSquare(int id)
  470. :
  471.   TButtonGadget(IDB_EMPTY, id, NonExclusive, true, Up, false),
  472.   Glyph(0)
  473. {
  474. }
  475.  
  476. void
  477. TSquare::SetGlyph(int g)
  478. {
  479.   Glyph = g;
  480.   SetButtonState(Glyph ? Down : Up);
  481.   Invalidate();
  482. }
  483.  
  484. void
  485. TSquare::Paint(TDC& dc)
  486. {
  487.   // Fool button gadget into making our special state cel arrays
  488.   //
  489.   delete CelArray;   // delete any that might have been created
  490.   for (int i = 0; i < SqsCount; i++)
  491.     if (!StateCels[i]) {
  492.       ResId = StateResId[i];
  493.       CelArray = 0;     // leak?
  494.       BuildCelArray();
  495.       StateCels[i] = CelArray;
  496.     }
  497.  
  498.   // slip in the correct cel array just before painting
  499.   //
  500.   CelArray = StateCels[Glyph];
  501.   TButtonGadget::Paint(dc);
  502.   CelArray = 0;
  503. }
  504.  
  505. //
  506. // Modify activate behavior to make the buttons 'sticky'
  507. //
  508. void
  509. TSquare::Activate(TPoint& pt)
  510. {
  511.   if (!Glyph) {
  512.     TButtonGadget::Activate(pt);
  513.     Window->PostMessage(WM_COMMAND, GetId()); // post to owner view too
  514.   } else
  515.     CancelPressed(pt);
  516. }
  517.  
  518. //----------------------------------------------------------------------------
  519. class TGameView : public TToolBox {
  520.   public:
  521.     TGameView(TGame& game);
  522.    ~TGameView();
  523.     TUnknown* SetupView(bool isEmbeded);
  524.     TGame&    Game;
  525.  
  526.     static const char far* StaticName() {return "TGameView";}
  527.   private:
  528.     void      SetupWindow();
  529.     void      CleanupWindow();
  530.     LRESULT   EvCommand(UINT id, HWND hWndCtl, UINT notifyCode);
  531.     void      EvCommandEnable(TCommandEnabler& ce);
  532.     LRESULT   EvGameViewSync(WPARAM wParam, LPARAM lParam);
  533.  
  534.     LRESULT   EvOcEvent(WPARAM wParam, LPARAM lParam);
  535.  
  536.     const char far* EvOcViewTitle();
  537.     bool   EvOcPartInvalid(TOcPart far&){return false;}
  538.     bool   EvOcViewSavePart(TOcSaveLoad far& ocSave);
  539.     bool   EvOcViewLoadPart(TOcSaveLoad far& ocLoad);
  540.     bool   EvOcViewPaint(TOcViewPaint far&);
  541.     bool   EvOcViewInsMenus(TOcMenuDescr far&);
  542.     bool   EvOcViewShowTools(TOcToolBarInfo far&);
  543.     bool   EvOcViewGetPalette(LOGPALETTE far* far*);
  544.     bool   EvOcViewClipData(TOcFormatData far&);
  545.     bool   EvOcViewClose();
  546.     bool   EvOcViewAttachWindow(bool attach);
  547.  
  548.     void   CmGameNew();
  549.     void   CmGameOptions();
  550.  
  551.     bool   IdleAction(long idleCount);
  552.     
  553.     enum TEndReason { Scratch, UserWon, ComputerWon };
  554.     void      GameOver(TEndReason why);
  555.  
  556.     TSquare** Board;
  557.     int       Dim;
  558.     TControlBar* ToolBar;
  559.     char*     ContainerName;
  560.     bool      IsEmbedded;
  561.  
  562.   public:
  563.     TOcRemView*  RemView;
  564.     TOcDocument* Document;
  565.  
  566.   DECLARE_RESPONSE_TABLE(TGameView);
  567. };
  568.  
  569. DEFINE_RESPONSE_TABLE1(TGameView, TToolBox)
  570.   EV_MESSAGE(WM_GAMEVIEWSYNC, EvGameViewSync),
  571.   EV_MESSAGE(WM_OCEVENT, EvOcEvent),
  572.  
  573.   EV_OC_VIEWPAINT,
  574.   EV_OC_VIEWSAVEPART,
  575.   EV_OC_VIEWLOADPART,
  576.   EV_OC_VIEWINSMENUS,
  577.   EV_OC_VIEWSHOWTOOLS,
  578.   EV_OC_VIEWGETPALETTE,
  579.   EV_OC_VIEWCLIPDATA,
  580.   EV_OC_VIEWCLOSE,
  581.  
  582.   EV_OC_VIEWATTACHWINDOW, //!
  583.  
  584.   EV_COMMAND(CM_GAMENEW, CmGameNew),
  585.   EV_COMMAND(CM_GAMEOPTIONS, CmGameOptions),
  586. END_RESPONSE_TABLE;
  587.  
  588. TGameView::TGameView(TGame& game)
  589. :
  590.   Game(game),
  591.   TToolBox(0, game.GetDimension(), AS_MANY_AS_NEEDED, Horizontal, game.GetApplication()),
  592.   RemView(0)
  593. {
  594.   Dim = Game.GetDimension();
  595.   Board = new PTSquare[Dim*Dim];
  596.   ToolBar = 0;
  597.   ContainerName = new char[255];
  598.   IsEmbedded = false;
  599.  
  600.   TOcApp* ocApp = Game.GetApplication()->OcApp;
  601.   Document = new TOcDocument(*ocApp, 0, 0);  // temp file (deletes on close)
  602.  
  603.   for (int i = 0; i < Dim; i++)
  604.     for (int j = 0; j < Dim; j++) {
  605.       TSquare* sq = new TSquare(CM_SQUARE + i*Dim + j);
  606.       Board[i*Dim + j] = sq;
  607.       Insert(*sq);
  608.     }
  609.   Game.SetView(this);
  610.  
  611.   ocApp->AddRef();
  612. }
  613.  
  614. //
  615. // Called after the window is created to create & attach to the OcRemView
  616. //
  617. TUnknown*
  618. TGameView::SetupView(bool isEmbedded)
  619. {
  620.   IsEmbedded = isEmbedded;
  621.   RemView = new TOcRemView(*Document, &::DocReg);
  622.   RemView->SetupWindow(*this, isEmbedded);
  623.   return RemView;
  624. }
  625.  
  626. static TControlBar*
  627. BuildControlBar(TWindow* parent, TControlBar::TTileDirection direction)
  628. {
  629.   TControlBar* cb = new TControlBar(parent, direction, new TGadgetWindowFont);
  630.   cb->Insert(*new TButtonGadget(CM_GAMENEW, CM_GAMENEW));
  631.   cb->Insert(*new TButtonGadget(CM_GAMEOPTIONS, CM_GAMEOPTIONS));
  632.   cb->Insert(*new TButtonGadget(CM_ABOUT, CM_ABOUT));
  633.   cb->Attr.Style |= WS_CLIPSIBLINGS;    // since toolbar may move around
  634.   cb->Attr.X = cb->Attr.Y = 0;
  635.   cb->Attr.W = 9999;
  636.   cb->Attr.Id = IDW_TOOLBAR;
  637.   return cb;
  638. }
  639.  
  640. TGameView::~TGameView()
  641. {
  642.   if (Document)
  643.     Document->Close();           // close all the embedded parts first
  644.   if (RemView && !IsEmbedded)
  645.     RemView->ReleaseObject();
  646.   delete Document;
  647.   Game.GetApplication()->OcApp->Release();
  648.  
  649.   delete [] Board;
  650.   delete [] ContainerName;
  651. }
  652.  
  653. void
  654. TGameView::SetupWindow()
  655. {
  656.   TWindow::SetupWindow();
  657.   SetFocus();
  658.   ToolBar = BuildControlBar(this, TControlBar::Horizontal);
  659.   ToolBar->Attr.Style &= ~WS_VISIBLE;
  660.   ToolBar->Create();
  661. }
  662.  
  663. void
  664. TGameView::CleanupWindow()
  665. {
  666.   if (RemView && !IsEmbedded){
  667.     RemView->EvClose();
  668.   }
  669.   TToolBox::CleanupWindow();
  670. }
  671.  
  672. void
  673. TGameView::GameOver(TEndReason why)
  674. {
  675.   static char* msgs[] = { "Scratch", "You won!", "I won!" };
  676.   MessageBox(msgs[why], "Game Over", MB_OK);
  677. }
  678.  
  679. LRESULT
  680. TGameView::EvCommand(UINT id, HWND hWndCtl, UINT notifyCode)
  681. {
  682.   if (id >= CM_SQUARE
  683.       && id < CM_SQUARE+Game.GetDimension()*Game.GetDimension()
  684.       && !hWndCtl) {
  685.  
  686.     int square = id - CM_SQUARE;
  687.  
  688.     if (Game.GetState(square) != SqsEmpty)// || !Game->IsPlaying())
  689.       return 0;
  690.  
  691.     Game.UserTurn(square);
  692.  
  693.     if (Game.IsWon())
  694.       GameOver(UserWon);
  695.  
  696.     else if (Game.IsOver())
  697.       GameOver(Scratch);
  698.  
  699.     else {
  700.       Game.ComputerTurn();
  701.  
  702.       // See if the game is over now.
  703.       //
  704.       if (Game.IsWon())
  705.         GameOver(ComputerWon);
  706.  
  707.       else if (Game.IsOver())
  708.         GameOver(Scratch);
  709.     }
  710.     return 0;
  711.   }
  712.   return TToolBox::EvCommand(id, hWndCtl, notifyCode);
  713. }
  714.  
  715. //
  716. // Handle the command Ids for the TTT squares by hand, otherwise, if embeded
  717. // route them normally, else forward to base
  718. //
  719. void
  720. TGameView::EvCommandEnable(TCommandEnabler& ce)
  721. {
  722.   if (ce.Id >= CM_SQUARE
  723.       && ce.Id < CM_SQUARE+Game.GetDimension()*Game.GetDimension()) {
  724.     ce.Enable(Game.IsPlaying());
  725.   }
  726.   else if (IsEmbedded) {
  727.     // Get the focus, in case it is a child that should receive the cmds
  728.     // fall back to this window in case the Ole menu bar stole focus!
  729.     //
  730.     HWND  hCmdTarget = ::GetFocus();
  731.     if (hCmdTarget != HWindow && !IsChild(hCmdTarget))
  732.       hCmdTarget = HWindow;
  733.  
  734.     RouteCommandEnable(hCmdTarget, ce);
  735.   }
  736.   else
  737.     TToolBox::EvCommandEnable(ce);
  738. }
  739.  
  740. LRESULT
  741. TGameView::EvGameViewSync(WPARAM wParam, LPARAM)
  742. {
  743.   if (wParam == 0xFFFF)
  744.     for (int i = 0; i < Dim*Dim; i++)
  745.       Board[i]->SetGlyph(Game.GetState(i));
  746.  
  747.   else
  748.     Board[wParam]->SetGlyph(Game.GetState(wParam));
  749.  
  750.   if (RemView)
  751.     RemView->Invalidate(invView);
  752.  
  753.   return 0;
  754. }
  755.  
  756. //
  757. // Handle & sub-dispatch the OC event message.
  758. //
  759. LRESULT
  760. TGameView::EvOcEvent(WPARAM wParam, LPARAM lParam)
  761. {
  762.   TEventHandler::TEventInfo eventInfo(WM_OCEVENT, wParam);  //WM_OWLNOTIFY
  763.   if (Find(eventInfo))
  764.     return Dispatch(eventInfo, wParam, lParam);
  765.   return 0;
  766. }
  767.  
  768. //
  769. // Return our frame's title
  770. //
  771. const char far*
  772. TGameView::EvOcViewTitle()
  773. {
  774.   Parent->GetWindowText(ContainerName, 255 - 1);
  775.   return ContainerName;
  776. }
  777.  
  778. //
  779. // Ask server to close the document
  780. //
  781. bool
  782. TGameView::EvOcViewClose()
  783. {
  784.   if (Document)
  785.     Document->Close();
  786.   return true;
  787. }
  788.  
  789.  
  790. //
  791. // Attach this view back to its owl parent for either open editing, or
  792. // mearly inplace de-activating
  793. //
  794. bool
  795. TGameView::EvOcViewAttachWindow(bool attach)
  796. {
  797.  
  798.   TFrameWindow* mainWindow = GetApplication()->GetMainWindow();
  799.  
  800.   if (attach) {
  801.     if (RemView->GetState()==TOcRemView::OpenEditing) {
  802.       mainWindow->Show(SW_SHOW);    // in case it was hidden
  803.       mainWindow->BringWindowToTop();
  804.  
  805.       // Derived class needs to managed setting up frame differently, like
  806.       // for MDI etc.
  807.       //
  808.       mainWindow->SetClientWindow(this);
  809.     }
  810.   }
  811.  
  812.   return true;
  813. }
  814.  
  815. //
  816. // Save the game to the IStorage provided by the container
  817. //
  818. bool
  819. TGameView::EvOcViewSavePart(TOcSaveLoad far& ocSave)
  820. {
  821.   PRECONDITION(ocSave.StorageI);
  822.  
  823.   Document->SetStorage(ocSave.StorageI);
  824.  
  825.   // Save remote view info such as origin and extent
  826.   //
  827.   RemView->Save(ocSave.StorageI);
  828.  
  829.   // Write out the embedded objects, if any
  830.   //
  831.  
  832.   // Create/open a stream in our storage to save part information
  833.   //
  834.   TOcStorage Storage(ocSave.StorageI);
  835.   STATSTG  statstg;
  836.   if (!HRSucceeded(Storage.Stat(&statstg, STATFLAG_NONAME)))
  837.     return false;
  838.  
  839.   TOcStream  stream(Storage, ::GameStreamName, true, statstg.grfMode);
  840.  
  841.   // Write Game data into stream
  842.   //
  843.   ulong count;
  844.   if (!(SUCCEEDED(stream.Write(&Game.Dim, sizeof(int), &count)) &&
  845.       SUCCEEDED(stream.Write(&Game.UserBoardMap, sizeof(int), &count)) &&
  846.       SUCCEEDED(stream.Write(&Game.ComputerBoardMap, sizeof(int), &count)) &&
  847.       SUCCEEDED(stream.Write(&Game.UserSide, sizeof(TSquareState), &count)) &&
  848.       SUCCEEDED(stream.Write(&Game.ComputerSide, sizeof(TSquareState), &count)) &&
  849.       SUCCEEDED(stream.Write(&Game.ComputerGoesFirst, sizeof(bool), &count)) &&
  850.       SUCCEEDED(stream.Write(&Game.Playing, sizeof(bool), &count))))
  851.     return false;
  852.  
  853.   for (int i = 0; i < Dim; i++)
  854.     for (int j = 0; j < Dim; j++) {
  855.       TSquare* sq = Board[i*Dim + j];
  856.       if (!SUCCEEDED(stream.Write(&sq->Glyph, sizeof(int), &count)))
  857.         return false;
  858.     }
  859.  
  860.   return true;
  861. }
  862.  
  863. //
  864. // Load the game from the IStorage provided by the container
  865. //
  866. bool
  867. TGameView::EvOcViewLoadPart(TOcSaveLoad far& ocLoad)
  868. {
  869.   PRECONDITION(ocLoad.StorageI);
  870.  
  871.   // Assign new storage to OcDocument
  872.   //
  873.   Document->SetStorage(ocLoad.StorageI);
  874.  
  875.   // Load remote view info such as origin and extent
  876.   //
  877.   RemView->Load(ocLoad.StorageI);
  878.  
  879.   // Read in the embedded objects, if any
  880.   //
  881.   // Create/open a stream in our storage to save part information
  882.   //
  883.   TOcStorage Storage(ocLoad.StorageI);
  884.   STATSTG  statstg;
  885.   if (!SUCCEEDED(Storage.Stat(&statstg, STATFLAG_NONAME)))
  886.     return false;
  887.  
  888.   TOcStream  stream(Storage, ::GameStreamName, false, statstg.grfMode);
  889.  
  890.  
  891.   // Read in the game data
  892.   //
  893.   ulong count;
  894.   if (!(SUCCEEDED(stream.Read(&Game.Dim, sizeof(int), &count)) &&
  895.       SUCCEEDED(stream.Read(&Game.UserBoardMap, sizeof(int), &count)) &&
  896.       SUCCEEDED(stream.Read(&Game.ComputerBoardMap, sizeof(int), &count)) &&
  897.       SUCCEEDED(stream.Read(&Game.UserSide, sizeof(TSquareState), &count)) &&
  898.       SUCCEEDED(stream.Read(&Game.ComputerSide, sizeof(TSquareState), &count)) &&
  899.       SUCCEEDED(stream.Read(&Game.ComputerGoesFirst, sizeof(bool), &count)) &&
  900.       SUCCEEDED(stream.Read(&Game.Playing, sizeof(bool), &count))))
  901.     return false;
  902.  
  903.   for (int i = 0; i < Dim; i++)
  904.     for (int j = 0; j < Dim; j++) {
  905.       TSquare* sq = Board[i*Dim + j];
  906.       if (!SUCCEEDED(stream.Read(&sq->Glyph, sizeof(int), &count)))
  907.         return false;
  908.     }
  909.  
  910.   if (! ocLoad.Remember)
  911.     Document->SetStorage((IStorage*)0);
  912.  
  913.   PostMessage(WM_GAMEVIEWSYNC, 0xFFFF);
  914.  
  915.   return true;
  916. }
  917.  
  918. bool
  919. TGameView::EvOcViewPaint(TOcViewPaint far& vp)
  920. {
  921.   // paint according to the view paint structure
  922.   //
  923.   TDC dc(vp.DC);
  924.  
  925.   Dim = Game.GetDimension();
  926.   for (int i = 0; i < Dim; i++)
  927.     for (int j = 0; j < Dim; j++) {
  928.       TSquare* sq = Board[i*Dim + j];
  929.       TPoint pt(-sq->GetBounds().left, -sq->GetBounds().top);
  930.       dc.SetWindowOrg(pt);
  931.       sq->Paint(dc);
  932.     }
  933.   return true;
  934. }
  935.  
  936. bool
  937. TGameView::EvOcViewInsMenus(TOcMenuDescr far& sharedMenu)
  938. {
  939.   // Recreate a temporary composite menu for frame and child
  940.   //
  941.   TMenuDescr compMenuDesc; // empty menudescr
  942.   compMenuDesc.Merge(TMenuDescr("IDM_TTTSVRGAME",0,0,0,1,0,1));
  943.   compMenuDesc.Merge(TMenuDescr(0,  -1, 0, -1, 0, -1, 0));
  944.  
  945.   TMenuDescr shMenuDescr(sharedMenu.HMenu,
  946.                          sharedMenu.Width[0],
  947.                          sharedMenu.Width[1],
  948.                          sharedMenu.Width[2],
  949.                          sharedMenu.Width[3],
  950.                          sharedMenu.Width[4],
  951.                          sharedMenu.Width[5]);
  952.   shMenuDescr.Merge(compMenuDesc);
  953.  
  954.   for (int i = 0; i < 6; i++)
  955.     sharedMenu.Width[i] = shMenuDescr.GetGroupCount(i);
  956.  
  957.   return true;
  958. }
  959.  
  960. //
  961. // Let OC have our toolbar to insert
  962. //
  963. bool
  964. TGameView::EvOcViewShowTools(TOcToolBarInfo far& tbi)
  965. {
  966.   tbi.HTopTB = *ToolBar;
  967. //  tbi.HBottomTB = *ToolBar;  // Can put it on the bottom too
  968.   return true;
  969. }
  970.  
  971. //
  972. // Get server's color palette
  973. //
  974. bool
  975. TGameView::EvOcViewGetPalette(LOGPALETTE far* far*)
  976. {
  977.   return false;
  978. }
  979.  
  980. //
  981. // Ask server to provide data according to the format in a handle
  982. //
  983. bool
  984. TGameView::EvOcViewClipData(TOcFormatData far&)
  985. {
  986.   return 0;
  987. }
  988.  
  989. void
  990. TGameView::CmGameNew()
  991. {
  992.   Game.New();
  993. }
  994.  
  995. void
  996. TGameView::CmGameOptions()
  997. {
  998.   TGameOptionsBox(this, &Game).Execute();
  999. }
  1000.  
  1001. static void
  1002. DoIdleAction(TWindow* win, void* idleCount)
  1003. {
  1004.   win->IdleAction(*(long*)idleCount);
  1005. }
  1006.  
  1007. //
  1008. // TFrameWindow processes idle action occurs once per block of messages
  1009. //
  1010. bool
  1011. TGameView::IdleAction(long idleCount)
  1012. {
  1013.   if (idleCount == 0) {
  1014.     // give child windows an opportunity to do any idle processing
  1015.     //
  1016.     ForEach(DoIdleAction, &idleCount);
  1017.   }
  1018.   return false;  // we don't need any more time for now
  1019. }
  1020.  
  1021. //----------------------------------------------------------------------------
  1022.  
  1023. class TAboutBox : public TDialog {
  1024.   public:
  1025.     TAboutBox::TAboutBox(TWindow* parent, TResId dlgId, const char far* msg);
  1026. };
  1027.  
  1028. TAboutBox::TAboutBox(TWindow* parent, TResId dlgId, const char far* msg)
  1029. :
  1030.   TDialog(parent, dlgId)
  1031. {
  1032.   TStatic* stat = new TStatic(this, IDSTATIC, msg, 23, 20, 190, 45, 0);
  1033.   stat->Attr.Style |= SS_CENTER;
  1034.   new TButton(this, IDOK, "OK", 80, 90, 40, 40, true);
  1035. }
  1036.  
  1037. //----------------------------------------------------------------------------
  1038.  
  1039. class TAppFrame : public TFrameWindow {
  1040.   public:
  1041.     TAppFrame(const char far* title,
  1042.               TResId          menuResId,
  1043.               TGameApp*       module);
  1044.    ~TAppFrame();
  1045.  
  1046.   private:
  1047.     void       SetupWindow();
  1048.     void       CleanupWindow();
  1049.  
  1050.     LRESULT    EvOcEvent(WPARAM wParam, LPARAM lParam);
  1051.     bool       EvOcAppShutdown();
  1052.     void       EvTimer(uint timerId);
  1053.  
  1054.     TGameApp*  GameApp;
  1055.  
  1056.   DECLARE_RESPONSE_TABLE(TAppFrame);
  1057. };
  1058. DEFINE_RESPONSE_TABLE1(TAppFrame, TFrameWindow)
  1059.   EV_WM_TIMER,
  1060.   EV_MESSAGE(WM_OCEVENT, EvOcEvent),
  1061.   EV_OC_APPSHUTDOWN,
  1062. END_RESPONSE_TABLE;
  1063.  
  1064. TAppFrame::TAppFrame(const char far* title,
  1065.                      TResId          menuResId,
  1066.                      TGameApp*       module)
  1067. :
  1068.   TFrameWindow(0, title, 0, true, module),
  1069.   GameApp(module)
  1070. {
  1071.   AssignMenu(menuResId);
  1072. }
  1073.  
  1074. TAppFrame::~TAppFrame()
  1075. {
  1076. }
  1077.  
  1078. void
  1079. TAppFrame::SetupWindow()
  1080. {
  1081.   TFrameWindow::SetupWindow();
  1082.  
  1083.   // Wire up ObjectConnections to our hWnd
  1084.   //
  1085.   GameApp->OcApp->SetupWindow(*this);
  1086.  
  1087.   // Create a timer to allow us to poll for idle time when we are a dll server
  1088.   //
  1089.   if (!GameApp->OcApp->IsOptionSet(amExeMode))
  1090.     SetTimer(TTT_DLLIDLE, DllIdleTime);
  1091. }
  1092.  
  1093. void
  1094. TAppFrame::CleanupWindow()
  1095. {
  1096.   if (!GameApp->OcApp->IsOptionSet(amExeMode))
  1097.     KillTimer(TTT_DLLIDLE);
  1098. }
  1099.  
  1100. bool
  1101. TAppFrame::EvOcAppShutdown()
  1102. {
  1103.   // called by TOcApp::ShutdownMaybe when last embedding is closed
  1104.   // if that's the only reason the app is up we need to shut ourselves down
  1105.   //
  1106.   SendMessage(WM_CLOSE);
  1107.   return true;
  1108. }
  1109.  
  1110. //
  1111. // Handle & sub-dispatch the OC event message to ourselves & to the app
  1112. //
  1113. LRESULT
  1114. TAppFrame::EvOcEvent(WPARAM wParam, LPARAM lParam)
  1115. {
  1116.   TEventHandler::TEventInfo eventInfo(WM_OCEVENT, wParam);
  1117.   if (Find(eventInfo))
  1118.     return Dispatch(eventInfo, wParam, lParam);
  1119.   if (GetApplication()->Find(eventInfo))
  1120.     return GetApplication()->Dispatch(eventInfo, wParam, lParam);
  1121.   return 0;
  1122. }
  1123.  
  1124. //
  1125. //
  1126. //
  1127. void
  1128. TAppFrame::EvTimer(uint timerId)
  1129. {
  1130.   if (timerId == TTT_DLLIDLE)
  1131.     GetApplication()->PostDispatchAction();
  1132.   TWindow::EvTimer(timerId);
  1133. }
  1134.  
  1135. //----------------------------------------------------------------------------
  1136.  
  1137. TGameApp::TGameApp()
  1138. :
  1139.   TApplication(::AppReg["description"], ::Module, &::AppDictionary)
  1140. {
  1141.   EnableBWCC();
  1142. }
  1143.  
  1144. TGameApp::~TGameApp()
  1145. {
  1146. }
  1147.  
  1148. void
  1149. TGameApp::InitMainWindow()
  1150. {
  1151.   nCmdShow = IsOptionSet(amEmbedding) ? SW_HIDE : SW_SHOWNORMAL;
  1152.   MainWindow = new TAppFrame(GetName(), "IDM_TTTGAME", this);
  1153.   MainWindow->Attr.Style &= ~(WS_THICKFRAME|WS_MAXIMIZEBOX);
  1154.   MainWindow->SetIcon(this, IDI_TTT);
  1155. }
  1156.  
  1157. TUnknown*
  1158. TGameApp::CreateOleObject(uint32 options, TRegLink* regLink)
  1159. {
  1160.   // create the only object we know about. If we served more objects, we would
  1161.   // need to examine regLink to determine which to create
  1162.   //
  1163.   TGame* game = new TGame;
  1164.   game->SetApplication(this);
  1165.   TGameView* view = new TGameView(*game);
  1166.  
  1167.   if (options & amRun)
  1168.     GetMainWindow()->SetClientWindow(view);
  1169.   else
  1170.     view->SetParent(GetMainWindow());
  1171.  
  1172.   if (!GetMainWindow()->HWindow)
  1173.     return 0;
  1174.  
  1175.   view->Create();
  1176.   return regLink ? view->SetupView(true) : 0;
  1177. }
  1178.  
  1179. void
  1180. TGameApp::CmAbout()
  1181. {
  1182.   TAboutBox(&TWindow(::GetFocus(), this),
  1183.             IDD_ABOUT,
  1184.             "Tic Tac Toe\n(C) Borland International\n 1992,1994"
  1185.             ).Execute();
  1186. }
  1187.  
  1188. //----------------------------------------------------------------------------
  1189.  
  1190. int
  1191. OwlMain(int /*argc*/, char* /*argv*/ [])
  1192. {
  1193.   try {
  1194.     // App registration object
  1195.     //
  1196.     Registrar = new TOcRegistrar(AppReg, TOleFactory<TGameApp>(),
  1197.                                  TApplication::GetCmdLine(), ::RegLinkHead);
  1198.  
  1199.     // We are all done if one of the action options was specified on the
  1200.     // cmdLine
  1201.     //
  1202.     if (Registrar->IsOptionSet(amAnyRegOption))
  1203.       return 0;  // Could display a msg box here if desired
  1204.     
  1205.     return Registrar->Run();
  1206.   }
  1207.   catch (xmsg& x) {
  1208.     return ::HandleGlobalException(x, "Exception");
  1209.   }
  1210. }
  1211.