Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

909 lines
23 KiB

  1. /***************************************************************************/
  2. /** Microsoft Windows **/
  3. /** Copyright(c) Microsoft Corp., 1991, 1992 **/
  4. /***************************************************************************/
  5. /****************************************************************************
  6. main.cpp
  7. Aug 92, JimH
  8. May 93, JimH chico port
  9. Main window callback functions
  10. Other CMainWindow member functions are in main2.cpp, welcome.cpp and ddecb.cpp
  11. ****************************************************************************/
  12. #include "hearts.h"
  13. #include "main.h"
  14. #include "resource.h"
  15. #include "debug.h"
  16. #include <regstr.h>
  17. #if defined (WINDOWS_ME) && ! defined (USE_MIRRORING)
  18. DWORD meMsgBox=0;
  19. DWORD meSystem=0;
  20. #define NLS_RESOURCE_LOCALE_KEY "Control Panel\\desktop\\ResourceLocale"
  21. #endif
  22. // declare static memberes
  23. CBrush CMainWindow::m_BgndBrush;
  24. CRect CMainWindow::m_TableRect;
  25. // declare globals
  26. CMainWindow *pMainWnd;
  27. DDE *dde; // same as either ddeClient or ddeServer
  28. HSZ hszJoin; // string handles used by DDE
  29. HSZ hszPass;
  30. HSZ hszMove;
  31. HSZ hszStatus;
  32. HSZ hszGameNumber;
  33. HSZ hszPassUpdate;
  34. MOVE move; // describes move for DDE transaction
  35. MOVE moveq[8]; // queue of moves waiting to be handled
  36. int cQdMoves; // number of moves in above queue
  37. PASS3 passq[4]; // queue of passes waiting to be handled
  38. int cQdPasses; // number of passes in above queue
  39. int nStatusHeight; // height of status window
  40. // Do not translate these registry strings
  41. const TCHAR szRegPath[] = REGSTR_PATH_WINDOWSAPPLETS TEXT("\\Hearts");
  42. const TCHAR regvalSound[] = TEXT("sound");
  43. const TCHAR regvalName[] = TEXT("name");
  44. const TCHAR regvalRole[] = TEXT("gamemeister");
  45. const TCHAR regvalServer[] = TEXT("server");
  46. const TCHAR regvalSpeed[] = TEXT("speed");
  47. const TCHAR *regvalPName[3] = { TEXT("p1name"), TEXT("p2name"), TEXT("p3name") };
  48. const TCHAR szHelpFileName[] = TEXT("mshearts.chm");
  49. const TCHAR szShareName[] = TEXT("HEARTS$");
  50. CTheApp theApp; // start Hearts and run it!
  51. /****************************************************************************
  52. CTheApp::InitInstance
  53. ****************************************************************************/
  54. BOOL CTheApp::InitInstance()
  55. {
  56. m_pMainWnd = new CMainWindow(m_lpCmdLine);
  57. m_pMainWnd->ShowWindow(SW_SHOW); // instead of m_nCmdShow
  58. m_pMainWnd->UpdateWindow();
  59. // Start the app off by posting Welcome dialog.
  60. m_pMainWnd->PostMessage(WM_COMMAND, IDM_WELCOME);
  61. return TRUE;
  62. }
  63. BEGIN_MESSAGE_MAP( CMainWindow, CFrameWnd )
  64. ON_COMMAND(IDM_ABOUT, OnAbout)
  65. ON_COMMAND(IDM_BOSSKEY, OnBossKey)
  66. ON_COMMAND(IDM_CHEAT, OnCheat)
  67. ON_COMMAND(IDM_EXIT, OnExit)
  68. ON_COMMAND(IDM_HELP, OnHelp)
  69. // ON_COMMAND(IDM_HELPONHELP, OnHelpOnHelp)
  70. ON_COMMAND(IDM_HIDEBUTTON, OnHideButton)
  71. // ON_COMMAND(IDM_SEARCH, OnSearch)
  72. ON_COMMAND(IDM_NEWGAME, OnNewGame)
  73. ON_COMMAND(IDM_OPTIONS, OnOptions)
  74. ON_COMMAND(IDM_QUOTE, OnQuote)
  75. ON_COMMAND(IDM_REF, OnRef)
  76. ON_COMMAND(IDM_SHOWBUTTON, OnShowButton)
  77. ON_COMMAND(IDM_SCORE, OnScore)
  78. ON_COMMAND(IDM_SOUND, OnSound)
  79. ON_COMMAND(IDM_WELCOME, OnWelcome)
  80. ON_BN_CLICKED(IDM_BUTTON, OnPass)
  81. ON_WM_CHAR()
  82. ON_MESSAGE(WM_PRINTCLIENT, OnPrintClient)
  83. ON_WM_CLOSE()
  84. ON_WM_CREATE()
  85. ON_WM_ERASEBKGND()
  86. ON_WM_LBUTTONDOWN()
  87. ON_WM_PAINT()
  88. END_MESSAGE_MAP()
  89. /****************************************************************************
  90. CMainWindow constructor
  91. creates green background brush, and main hearts window
  92. ****************************************************************************/
  93. CMainWindow::CMainWindow(LPTSTR lpCmdLine) :
  94. m_lpCmdLine(lpCmdLine), passdir(LEFT), bCheating(FALSE), bSoundOn(FALSE),
  95. bTimerOn(FALSE), bConstructed(TRUE), m_FatalErrno(0),
  96. bEnforceFirstBlood(TRUE)
  97. {
  98. #if !defined (MFC1)
  99. m_bAutoMenuEnable = FALSE; // MFC 1.0 compatibility, required for MFC2
  100. #endif
  101. ::cQdMoves = 0; // no moves in move queue
  102. ::cQdPasses = 0; // no passes either
  103. for (int i = 0; i < MAXPLAYER; i++)
  104. p[i] = NULL;
  105. ResetHandInfo(-1); // set handinfo struct to default values
  106. // Check for monochrome
  107. CDC ic;
  108. ic.CreateIC(TEXT("DISPLAY"), NULL, NULL, NULL);
  109. if (ic.GetDeviceCaps(NUMCOLORS) == 2) // if monochrome
  110. m_bkgndcolor = RGB(255, 255, 255); // white background for mono
  111. else
  112. m_bkgndcolor = RGB(0, 127, 0);
  113. ic.DeleteDC();
  114. m_BgndBrush.CreateSolidBrush(m_bkgndcolor); // destroyed in OnClose()
  115. LoadAccelTable( TEXT("HeartsAccel") );
  116. RECT rc;
  117. SystemParametersInfo(SPI_GETWORKAREA, 0, &rc, 0);
  118. CRect rect;
  119. int dy = min(WINHEIGHT, (rc.bottom - rc.top));
  120. int x, y;
  121. if (GetSystemMetrics(SM_CYSCREEN) <= 480) // VGA
  122. {
  123. x = (((rc.right - rc.left) - WINWIDTH) / 2) + rc.left; // centered
  124. y = rc.top;
  125. }
  126. else
  127. {
  128. x = CW_USEDEFAULT;
  129. y = CW_USEDEFAULT;
  130. }
  131. rect.SetRect(x, y, x+WINWIDTH, y+dy);
  132. CString sAppname;
  133. sAppname.LoadString(IDS_APPNAME);
  134. #if defined (WINDOWS_ME) && ! defined (USE_MIRRORING)
  135. if (GetSystemMetrics(SM_MIDEASTENABLED))
  136. {
  137. char sz[10];
  138. long cb = sizeof(sz);
  139. //
  140. // as we are releasing an enabled version, we need to check the
  141. // resource locale as well.
  142. //
  143. sz[0] = '\0';
  144. if( RegQueryValue( HKEY_CURRENT_USER, NLS_RESOURCE_LOCALE_KEY, sz, &cb) == ERROR_SUCCESS)
  145. if ( (cb == 9) && (sz[6] == '0') && ((sz[7] == '1') || (sz[7] == 'd') || (sz[7] == 'D')) )
  146. {
  147. meSystem = TRUE;
  148. meMsgBox = MB_RIGHT | MB_RTLREADING;
  149. }
  150. }
  151. #endif
  152. #if defined (WINDOWS_ME) && ! defined (USE_MIRRORING)
  153. Create( NULL, // default class
  154. sAppname, // window title
  155. WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU |
  156. WS_MINIMIZEBOX | WS_CLIPCHILDREN, // window style
  157. rect, // size
  158. NULL, // parent
  159. TEXT("HeartsMenu"), // menu
  160. (meSystem ? WS_EX_RTLREADING | WS_EX_RIGHT : 0)); // dwStyle
  161. #else
  162. Create( NULL, // default class
  163. sAppname, // window title
  164. WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU |
  165. WS_MINIMIZEBOX | WS_CLIPCHILDREN, // window style
  166. rect, // size
  167. NULL, // parent
  168. TEXT("HeartsMenu")); // menu
  169. #endif
  170. }
  171. /****************************************************************************
  172. CMainWindow::OnAbout
  173. displays about box
  174. ****************************************************************************/
  175. //extern "C" int WINAPI ShellAbout(HWND, LPCSTR, LPCSTR, HICON);
  176. void CMainWindow::OnAbout()
  177. {
  178. HICON hIcon = ::LoadIcon(AfxGetInstanceHandle(),
  179. MAKEINTRESOURCE(AFX_IDI_STD_FRAME));
  180. CString s;
  181. s.LoadString(IDS_NETWORK);
  182. ShellAbout(m_hWnd, s, NULL, hIcon);
  183. }
  184. /****************************************************************************
  185. CMainWindow::OnQuote
  186. displays quote box and plays quote.
  187. ****************************************************************************/
  188. void CMainWindow::OnQuote()
  189. {
  190. CQuoteDlg quote(this);
  191. // HeartsPlaySound(SND_QUOTE);
  192. quote.DoModal();
  193. HeartsPlaySound(OFF);
  194. }
  195. /****************************************************************************
  196. CMainWindow::OnChar, looks space, plays first legal move, or pushes button
  197. ****************************************************************************/
  198. void CMainWindow::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
  199. {
  200. // We know the cast below is legal because position 0 is always
  201. // the local human.
  202. local_human *p0 = (local_human *)p[0];
  203. int mode = p0->GetMode();
  204. if ((nChar != (UINT)' ') || (p0->IsTimerOn()))
  205. return;
  206. if (mode != PLAYING)
  207. return;
  208. p0->SetMode(WAITING);
  209. POINT loc;
  210. for (SLOT s = 0; s < MAXSLOT; s++)
  211. {
  212. if (p0->GetCardLoc(s, loc))
  213. {
  214. if (p0->PlayCard(loc.x, loc.y, handinfo, bCheating, FALSE))
  215. {
  216. return;
  217. }
  218. }
  219. }
  220. p0->SetMode(PLAYING);
  221. }
  222. /****************************************************************************
  223. CMainWindow::OnCheat -- toggles bCheating used to show all cards face up.
  224. ****************************************************************************/
  225. void CMainWindow::OnCheat()
  226. {
  227. RegEntry Reg(szRegPath);
  228. const TCHAR val[] = TEXT("ZB");
  229. TCHAR buf[20];
  230. Reg.GetString(val, buf, sizeof(buf));
  231. if (buf[0] != TEXT('4') || buf[1] != TEXT('2'))
  232. return;
  233. bCheating = !bCheating;
  234. InvalidateRect(NULL, TRUE); // redraw main hearts window
  235. CMenu *pMenu = GetMenu();
  236. pMenu->CheckMenuItem(IDM_CHEAT, bCheating ? MF_CHECKED : MF_UNCHECKED);
  237. }
  238. /****************************************************************************
  239. CMainWindow::OnClose -- cleans up background brush, deletes players, etc.
  240. ****************************************************************************/
  241. void CMainWindow::OnClose()
  242. {
  243. m_BgndBrush.DeleteObject();
  244. for (int i = 0; i < 4; i++)
  245. {
  246. if (p[i])
  247. {
  248. delete p[i];
  249. p[i] = NULL;
  250. }
  251. }
  252. DestroyStrHandles();
  253. if (ddeClient)
  254. delete ddeClient;
  255. if (ddeServer)
  256. delete ddeServer;
  257. dde = NULL;
  258. ddeClient = NULL;
  259. ddeServer = NULL;
  260. ::HtmlHelp(::GetDesktopWindow(), szHelpFileName, HH_CLOSE_ALL, 0);
  261. {
  262. RegEntry Reg(szRegPath);
  263. Reg.FlushKey();
  264. }
  265. DestroyWindow();
  266. }
  267. /****************************************************************************
  268. CMainWindow::OnCreate -- creates pass button child window & player objects.
  269. also initializes some of the data members
  270. ****************************************************************************/
  271. int CMainWindow::OnCreate(LPCREATESTRUCT lpCreateStruct)
  272. {
  273. ::pMainWnd = this;
  274. if (!bConstructed)
  275. {
  276. FatalError(IDS_MEMORY);
  277. return -1;
  278. }
  279. // Check for existence of cards.dll
  280. SetErrorMode(SEM_NOOPENFILEERRORBOX);
  281. HINSTANCE hCardsDLL = LoadLibrary(TEXT("CARDS.DLL"));
  282. if (hCardsDLL < (HINSTANCE)HINSTANCE_ERROR)
  283. {
  284. FatalError(IDS_CARDSDLL);
  285. bConstructed = FALSE;
  286. return -1;
  287. }
  288. ::FreeLibrary(hCardsDLL);
  289. CClientDC dc(this);
  290. TEXTMETRIC tm;
  291. ::srand((unsigned) ::time(NULL)); // set rand() seed
  292. ddeClient = NULL;
  293. ddeServer = NULL;
  294. dc.GetTextMetrics(&tm);
  295. int nTextHeight = tm.tmHeight + tm.tmExternalLeading;
  296. m_StatusHeight = nTextHeight + 11;
  297. GetClientRect(m_TableRect);
  298. m_TableRect.bottom -= m_StatusHeight;
  299. bConstructed = TRUE;
  300. // Player 0 is constructed as the gamemeister. This
  301. // initializes lots of good stuff which is used later.
  302. // If player 0 doesn't happen to be a real gamemeister,
  303. // this gets fixed up in OnWelcome().
  304. p[0] = new local_human(0); // display status bar
  305. if (p[0] == NULL)
  306. {
  307. bConstructed = FALSE;
  308. return -1;
  309. }
  310. // Construct pushbutton
  311. int cxChar = tm.tmAveCharWidth;
  312. int cyChar = tm.tmHeight + tm.tmExternalLeading;
  313. int nWidth = (60 * cxChar) / 4;
  314. int nHeight = (14 * cyChar) / 8;
  315. int x = (m_TableRect.right / 2) - (nWidth / 2);
  316. int y = m_TableRect.bottom - card::dyCrd - (2 * POPSPACING) - nHeight;
  317. CRect rect;
  318. rect.SetRect(x, y, x+nWidth, y+nHeight);
  319. if (!m_Button.Create(TEXT(""), WS_CHILD | BS_PUSHBUTTON, rect, this, IDM_BUTTON))
  320. {
  321. bConstructed = FALSE;
  322. return -1;
  323. }
  324. // check for sound capability
  325. RegEntry Reg(szRegPath);
  326. bHasSound = SoundInit();
  327. if (bHasSound)
  328. {
  329. if (Reg.GetNumber(regvalSound, FALSE))
  330. {
  331. CMenu *pMenu = GetMenu();
  332. pMenu->CheckMenuItem(IDM_SOUND, MF_CHECKED);
  333. bSoundOn = TRUE;
  334. }
  335. }
  336. else
  337. {
  338. CMenu *pMenu = GetMenu();
  339. pMenu->EnableMenuItem(IDM_SOUND, MF_GRAYED);
  340. }
  341. card c;
  342. int nStepSize;
  343. DWORD dwSpeed = Reg.GetNumber(regvalSpeed, IDC_NORMAL);
  344. if (dwSpeed == IDC_FAST)
  345. nStepSize = 60;
  346. else if (dwSpeed == IDC_SLOW)
  347. nStepSize = 5;
  348. else
  349. nStepSize = 15;
  350. c.SetStepSize(nStepSize);
  351. return (bConstructed ? 0 : -1);
  352. }
  353. /****************************************************************************
  354. CMainWindow::OnEraseBkgnd -- required to draw background green
  355. ****************************************************************************/
  356. BOOL CMainWindow::OnEraseBkgnd(CDC *pDC)
  357. {
  358. if (!m_BgndBrush.m_hObject) // if background brush is not valid
  359. return FALSE;
  360. m_BgndBrush.UnrealizeObject();
  361. CBrush *pOldBrush = pDC->SelectObject(&m_BgndBrush);
  362. pDC->PatBlt(0, 0, WINWIDTH, WINHEIGHT, PATCOPY);
  363. pDC->SelectObject(pOldBrush);
  364. return FALSE;
  365. }
  366. /****************************************************************************
  367. CMainWindow::OnLButtonDown
  368. Handles human selecting card to play or pass.
  369. ****************************************************************************/
  370. void CMainWindow::OnLButtonDown(UINT nFlags, CPoint point)
  371. {
  372. // We know the cast below is legal because position 0 is always
  373. // the local human.
  374. #ifdef USE_MIRRORING
  375. CRect rect;
  376. DWORD ProcessDefaultLayout;
  377. if (GetProcessDefaultLayout(&ProcessDefaultLayout))
  378. if (ProcessDefaultLayout == LAYOUT_RTL)
  379. {
  380. GetClientRect(&rect);
  381. point.x = rect.right - rect.left - point.x;
  382. }
  383. #endif
  384. local_human *p0 = (local_human *)p[0];
  385. if (p0->IsTimerOn()) // ignore mouse clicks if timer running
  386. return;
  387. modetype mode = p0->GetMode();
  388. if (mode == SELECTING)
  389. {
  390. p0->PopCard(m_BgndBrush, point.x, point.y);
  391. return;
  392. }
  393. else if (mode != PLAYING)
  394. return;
  395. p0->SetMode(WAITING);
  396. if (p0->PlayCard(point.x, point.y, handinfo, bCheating)) // valid card?
  397. return;
  398. // move wasn't legal, so back to PLAYING mode
  399. p0->SetMode(PLAYING);
  400. }
  401. /****************************************************************************
  402. CMainWindow::OnNewGame
  403. ****************************************************************************/
  404. void CMainWindow::OnNewGame()
  405. {
  406. passdir = LEFT; // each new game must start with LEFT
  407. bAutostarted = FALSE; // means dealer has agreed to play at least
  408. CMenu *pMenu = GetMenu();
  409. pMenu->EnableMenuItem(IDM_NEWGAME, MF_GRAYED);
  410. if (role == GAMEMEISTER)
  411. {
  412. BOOL bNewPlayers = FALSE;
  413. for (int i = 1; i < MAXPLAYER; i++)
  414. {
  415. if (!p[i])
  416. {
  417. bNewPlayers = TRUE;
  418. p[i] = new computer(i);
  419. if (!p[i])
  420. {
  421. bConstructed = FALSE;
  422. return;
  423. }
  424. }
  425. }
  426. if (bNewPlayers)
  427. ddeServer->PostAdvise(hszStatus);
  428. m_gamenumber = ::rand();
  429. ddeServer->PostAdvise(hszGameNumber);
  430. }
  431. ResetHandInfo(-1);
  432. ::srand(m_gamenumber);
  433. {
  434. CScoreDlg score(this);
  435. score.ResetScore();
  436. } // destruct score
  437. TRACE1("\n\ngame number is %d\n\n", m_gamenumber);
  438. DUMP();
  439. TRACE0("\n\n");
  440. Shuffle();
  441. }
  442. /****************************************************************************
  443. CMainWindow::OnOptions -- user requests options dialog from menu
  444. ****************************************************************************/
  445. void CMainWindow::OnOptions()
  446. {
  447. COptionsDlg optionsdlg(this);
  448. optionsdlg.DoModal();
  449. }
  450. /****************************************************************************
  451. CMainWindow::OnPaint
  452. ****************************************************************************/
  453. void CMainWindow::OnPaint()
  454. {
  455. CPaintDC dc( this );
  456. #ifdef USE_MIRRORING
  457. SetLayout(dc.m_hDC, 0);
  458. SetLayout(dc.m_hAttribDC, 0);
  459. #endif
  460. // players must be painted in order starting with playerled so that
  461. // cards in centre overlap correctly
  462. if (bConstructed)
  463. {
  464. int start = Id2Pos(handinfo.playerled % 4);
  465. // check that someone has started
  466. if (start >= 0)
  467. {
  468. for (int i = start; i < (MAXPLAYER+start); i++)
  469. {
  470. int pos = i % 4;
  471. if (p[pos])
  472. {
  473. if (p[pos]->GetMode() == SCORING)
  474. {
  475. p[pos]->DisplayHeartsWon(dc);
  476. }
  477. else
  478. {
  479. p[pos]->Draw(dc, bCheating);
  480. p[pos]->MarkSelectedCards(dc);
  481. }
  482. }
  483. }
  484. }
  485. }
  486. }
  487. /****************************************************************************
  488. CMainWindow::OnPass
  489. This function handles the local human pressing the button either to
  490. pass selected cards or to accept cards passed.
  491. ****************************************************************************/
  492. void CMainWindow::OnPass()
  493. {
  494. if (p[0]->GetMode() == ACCEPTING) // OK (accepting passed cards)
  495. {
  496. m_Button.ShowWindow(SW_HIDE);
  497. m_Button.SetWindowText(TEXT(""));
  498. p[0]->SetMode(WAITING); // local human pushed the button
  499. CRect rect;
  500. p[0]->GetCoverRect(rect);
  501. for (SLOT s = 0; s < MAXSLOT; s++)
  502. p[0]->Select(s, FALSE);
  503. InvalidateRect(&rect, TRUE);
  504. UpdateWindow();
  505. FirstMove();
  506. for (int i = 0; i < ::cQdMoves; i++)
  507. HandleMove(::moveq[i]);
  508. ::cQdMoves = 0;
  509. ::cQdPasses = 0;
  510. return;
  511. }
  512. m_Button.EnableWindow(FALSE);
  513. p[0]->SetMode(DONE_SELECTING);
  514. BOOL bReady = TRUE;
  515. for (int i = 1; i < MAXPLAYER; i++)
  516. if (p[i]->GetMode() != DONE_SELECTING)
  517. bReady = FALSE;
  518. if (!bReady)
  519. p[0]->UpdateStatus(IDS_PASSWAIT);
  520. if (role == GAMEMEISTER)
  521. {
  522. ddeServer->PostAdvise(hszPass); // let other players know
  523. }
  524. else
  525. {
  526. PASS3 pass3;
  527. pass3.id = m_myid;
  528. pass3.passdir = passdir;
  529. p[0]->ReturnSelectedCards(pass3.cardid);
  530. ddeClient->Poke(hszPass, &pass3, sizeof(pass3));
  531. }
  532. if (bReady)
  533. HandlePassing();
  534. }
  535. /****************************************************************************
  536. CMainWindow::OnRef
  537. After a human or a computer plays a card, they must
  538. PostMessage(WM_COMMAND, IDM_REF)
  539. which causes this routine (the referee) to be called.
  540. Ref does the following:
  541. - updates handinfo data struct
  542. - calls HeartsPlaySound() if appropriate
  543. - determines if the hand is over or, if not, whose turn is next
  544. ****************************************************************************/
  545. void CMainWindow::OnRef()
  546. {
  547. card *c = handinfo.cardplayed[handinfo.turn];
  548. if (!handinfo.bHeartsBroken)
  549. {
  550. if (c->Suit() == HEARTS)
  551. {
  552. handinfo.bHeartsBroken = TRUE;
  553. HeartsPlaySound(SND_BREAK);
  554. }
  555. }
  556. if (c->ID() == BLACKLADY)
  557. {
  558. handinfo.bQSPlayed = TRUE;
  559. HeartsPlaySound(SND_QUEEN);
  560. }
  561. /* ------------------------------------------------
  562. #if defined(_DEBUG)
  563. TRACE("[%d] ", m_myid);
  564. TRACE("h.turn %d, ", handinfo.turn);
  565. TRACE("led %d, ", handinfo.playerled);
  566. for (int i = 0; i < 4; i++)
  567. {
  568. if (handinfo.cardplayed[i])
  569. { CDNAME(handinfo.cardplayed[i]); }
  570. else
  571. { TRACE("-- "); }
  572. }
  573. TRACE("\n",);
  574. #endif
  575. ------------------------------------------------ */
  576. int pos = Id2Pos(handinfo.turn);
  577. SLOT slot = p[pos]->GetSlot(handinfo.cardplayed[handinfo.turn]->ID());
  578. #if defined(_DEBUG)
  579. if (p[pos]->IsHuman())
  580. ((human *)p[pos])->DebugMove(slot);
  581. #endif
  582. p[pos]->GlideToCentre(slot, pos==0 ? TRUE : bCheating);
  583. handinfo.turn++;
  584. handinfo.turn %= 4;
  585. int newpos = Id2Pos(handinfo.turn);
  586. if (handinfo.turn == handinfo.playerled)
  587. {
  588. EndHand();
  589. }
  590. else
  591. {
  592. p[newpos]->SelectCardToPlay(handinfo, bCheating);
  593. if (newpos != 0)
  594. ((local_human *)p[0])->WaitMessage(p[newpos]->GetName());
  595. }
  596. }
  597. /****************************************************************************
  598. CMainWindow::OnScore -- user requests score dialog from menu
  599. ****************************************************************************/
  600. void CMainWindow::OnScore()
  601. {
  602. CScoreDlg scoredlg(this); // this constructor does not add new info
  603. scoredlg.DoModal();
  604. }
  605. /****************************************************************************
  606. CMainWindow::DoSort
  607. ****************************************************************************/
  608. void CMainWindow::DoSort()
  609. {
  610. for (int i = 0; i < (bCheating ? MAXPLAYER : 1); i++)
  611. {
  612. CRect rect;
  613. int id; // card in play for this player
  614. if (handinfo.cardplayed[i] == NULL)
  615. id = EMPTY;
  616. else
  617. id = handinfo.cardplayed[i]->ID();
  618. p[i]->Sort();
  619. if (id != EMPTY) // if this player has a card in play, restore it
  620. {
  621. for (SLOT s = 0; s < MAXSLOT; s++)
  622. {
  623. if (p[i]->GetID(s) == id)
  624. {
  625. handinfo.cardplayed[i] = p[i]->Card(s);
  626. break;
  627. }
  628. }
  629. }
  630. p[i]->GetCoverRect(rect);
  631. InvalidateRect(&rect, TRUE);
  632. }
  633. }
  634. /****************************************************************************
  635. CMainWindow::OnSound()
  636. request sound on or off from menu.
  637. ****************************************************************************/
  638. void CMainWindow::OnSound()
  639. {
  640. RegEntry Reg(szRegPath);
  641. bSoundOn = !bSoundOn;
  642. CMenu *pMenu = GetMenu();
  643. pMenu->CheckMenuItem(IDM_SOUND, bSoundOn ? MF_CHECKED : MF_UNCHECKED);
  644. if (bSoundOn)
  645. Reg.SetValue(regvalSound, 1);
  646. else
  647. Reg.DeleteValue(regvalSound);
  648. }
  649. /****************************************************************************
  650. CMainWindow::OnPrintClient()
  651. Draw background into the specified HDC. This is used when drawing
  652. the "Pass" button in the Luna style.
  653. ****************************************************************************/
  654. LRESULT CMainWindow::OnPrintClient(WPARAM wParam, LPARAM lParam)
  655. {
  656. CDC dc;
  657. CRect rect;
  658. dc.Attach((HDC)wParam);
  659. GetClientRect(&rect);
  660. dc.FillRect(&rect, &m_BgndBrush);
  661. dc.Detach();
  662. return 1;
  663. }