Leaked source code of windows server 2003
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.

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