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.

559 lines
14 KiB

  1. /***************************************************************************/
  2. /** Microsoft Windows **/
  3. /** Copyright(c) Microsoft Corp., 1991, 1992 **/
  4. /***************************************************************************/
  5. /****************************************************************************
  6. human.cpp
  7. Aug 92, JimH
  8. May 93, JimH chico port
  9. local_human and remote_human member functions
  10. ****************************************************************************/
  11. #include "hearts.h"
  12. #include "main.h" // friendly access
  13. #include "resource.h"
  14. #include "debug.h"
  15. #include <stdio.h>
  16. #include <stdlib.h> // abs() prototype
  17. static CRect rectCard; // used in timer callback
  18. // declare static members
  19. BOOL local_human::bTimerOn;
  20. CString local_human::m_StatusText;
  21. /****************************************************************************
  22. human constructor -- abstract class
  23. ****************************************************************************/
  24. human::human(int n, int pos) : player(n, pos)
  25. {
  26. }
  27. /****************************************************************************
  28. local_human::local_human()
  29. This is the constructor that initializes player::hWnd and player::hInst.
  30. It also creates the stretch bitmap that covers a card plus its popped
  31. height extension.
  32. ****************************************************************************/
  33. local_human::local_human(int n) : human(n, 0)
  34. {
  35. m_pStatusWnd = new CStatusBarCtrl();
  36. m_StatusText.LoadString(IDS_INTRO);
  37. CClientDC dc(::pMainWnd);
  38. m_pStatusWnd->Create(WS_CHILD|WS_VISIBLE|CCS_BOTTOM, CRect(), ::pMainWnd, 0);
  39. m_pStatusWnd->SetSimple();
  40. UpdateStatus();
  41. bTimerOn = FALSE;
  42. if (!m_bmStretchCard.CreateCompatibleBitmap(&dc, card::dxCrd,
  43. card::dyCrd + POPSPACING))
  44. {
  45. ::pMainWnd->FatalError(IDS_MEMORY);
  46. return;
  47. }
  48. }
  49. /****************************************************************************
  50. local_human destructor
  51. ****************************************************************************/
  52. local_human::~local_human()
  53. {
  54. m_bmStretchCard.DeleteObject();
  55. delete m_pStatusWnd;
  56. m_pStatusWnd = NULL;
  57. }
  58. /****************************************************************************
  59. local_human::Draw()
  60. This virtual function draws selected cards in the popped up position.
  61. ALL is not used for slot in this variant.
  62. ****************************************************************************/
  63. void local_human::Draw(CDC &dc, BOOL bCheating, SLOT slot)
  64. {
  65. DisplayName(dc);
  66. SLOT start = (slot == ALL ? 0 : slot);
  67. SLOT stop = (slot == ALL ? MAXSLOT : slot+1);
  68. SLOT playedslot = EMPTY; // must draw cards in play last for EGA
  69. for (SLOT s = start; s < stop; s++)
  70. {
  71. if (cd[s].IsPlayed())
  72. playedslot = s;
  73. else
  74. cd[s].PopDraw(dc); // pop up selected cards
  75. }
  76. if (playedslot != EMPTY)
  77. cd[playedslot].Draw(dc);
  78. }
  79. /****************************************************************************
  80. local_human::PopCard()
  81. handles mouse button selection of card to pass
  82. ****************************************************************************/
  83. void local_human::PopCard(CBrush &brush, int x, int y)
  84. {
  85. SLOT s = XYToCard(x, y);
  86. if (s == EMPTY)
  87. return;
  88. // count selected cards
  89. int c = 0;
  90. for (int i = 0; i < MAXSLOT; i++)
  91. if (cd[i].IsSelected())
  92. c++;
  93. if (cd[s].IsSelected() && (c == 3))
  94. {
  95. ::pMainWnd->PostMessage(WM_COMMAND, IDM_HIDEBUTTON);
  96. }
  97. else if (!cd[s].IsSelected())
  98. {
  99. if (c == 3) // only allow three selections
  100. return;
  101. else if (c == 2)
  102. ::pMainWnd->PostMessage(WM_COMMAND, IDM_SHOWBUTTON);
  103. }
  104. // toggle selection
  105. BOOL bSelected = cd[s].IsSelected();
  106. cd[s].Select(!bSelected);
  107. CClientDC dc(::pMainWnd);
  108. #ifdef USE_MIRRORING
  109. SetLayout(dc.m_hDC, 0);
  110. SetLayout(dc.m_hAttribDC, 0);
  111. #endif
  112. CDC memDC;
  113. memDC.CreateCompatibleDC(&dc);
  114. memDC.SelectObject(&m_bmStretchCard);
  115. memDC.SelectObject(&brush);
  116. memDC.PatBlt(0, 0, card::dxCrd, card::dyCrd + POPSPACING, PATCOPY);
  117. for (i = 0; i < MAXSLOT; i++)
  118. {
  119. if (abs(i - s) <= (card::dxCrd / HORZSPACING))
  120. {
  121. cd[i].Draw(memDC, // cdc
  122. (i - s) * HORZSPACING, // x
  123. cd[i].IsSelected() ? 0 : POPSPACING, // y
  124. FACEUP, // mode
  125. FALSE); // update loc?
  126. }
  127. }
  128. dc.BitBlt(loc.x + (HORZSPACING * s), loc.y - POPSPACING,
  129. card::dxCrd, card::dyCrd + POPSPACING,
  130. &memDC, 0, 0, SRCCOPY);
  131. }
  132. /****************************************************************************
  133. local_human::PlayCard()
  134. handles mouse button selection of card to play
  135. and ensures move is legal.
  136. PlayCard starts a timer that calls StartTimer() which calls TimerBadMove().
  137. Think of it as one long function with a timer delay half way through.
  138. ****************************************************************************/
  139. BOOL local_human::PlayCard(int x, int y, handinfotype &h, BOOL bCheating,
  140. BOOL bFlash)
  141. {
  142. SLOT s = XYToCard(x, y);
  143. if (s == EMPTY)
  144. return FALSE;
  145. card *cardled = h.cardplayed[h.playerled];
  146. BOOL bFirstTrick = (cardled != NULL && cardled->ID() == TWOCLUBS);
  147. /* check if selected card is valid */
  148. if (h.playerled == id) // if local human is leading...
  149. {
  150. if (cd[s].ID() != TWOCLUBS)
  151. {
  152. for (int i = 0; i < MAXSLOT; i++) // is there a two of clubs?
  153. {
  154. if ((i != s) && (cd[i].ID() == TWOCLUBS))
  155. {
  156. UpdateStatus(IDS_LEAD2C);
  157. if (bFlash)
  158. StartTimer(cd[s]);
  159. return FALSE;
  160. }
  161. }
  162. }
  163. if ((cd[s].Suit() == HEARTS) && (!h.bHeartsBroken)) // if hearts led
  164. {
  165. for (int i = 0; i < MAXSLOT; i++) // are there any non-hearts?
  166. {
  167. if ((!cd[i].IsEmpty()) && (cd[i].Suit() != HEARTS))
  168. {
  169. UpdateStatus(IDS_LEADHEARTS);
  170. if (bFlash)
  171. StartTimer(cd[s]);
  172. return FALSE;
  173. }
  174. }
  175. }
  176. }
  177. // if not following suit
  178. else if (cardled != NULL && (cd[s].Suit() != cardled->Suit()))
  179. {
  180. // make sure we're following suit if possible
  181. for (int i = 0; i < MAXSLOT; i++)
  182. {
  183. if ((!cd[i].IsEmpty()) && (cd[i].Suit()==cardled->Suit()))
  184. {
  185. CString s1, s2;
  186. s1.LoadString(IDS_BADMOVE);
  187. s2.LoadString(IDS_SUIT0+cardled->Suit());
  188. TCHAR string[80];
  189. wsprintf(string, s1, s2);
  190. if (bFlash)
  191. {
  192. UpdateStatus(string);
  193. StartTimer(cd[s]);
  194. }
  195. return FALSE;
  196. }
  197. }
  198. // make sure we're not trying to break the First Blood rule
  199. if (bFirstTrick && ::pMainWnd->IsFirstBloodEnforced())
  200. {
  201. BOOL bPointCard =
  202. (cd[s].Suit() == HEARTS || cd[s].ID() == BLACKLADY);
  203. BOOL bOthersAvailable = FALSE;
  204. for (int i = 0; i < MAXSLOT; i++)
  205. if ((!cd[i].IsEmpty()) && (cd[i].Suit() != HEARTS))
  206. if (cd[i].ID() != BLACKLADY)
  207. bOthersAvailable = TRUE;
  208. if (bPointCard && bOthersAvailable)
  209. {
  210. UpdateStatus(IDS_BADBLOOD);
  211. if (bFlash)
  212. StartTimer(cd[s]);
  213. return FALSE;
  214. }
  215. }
  216. }
  217. SetMode(WAITING);
  218. cd[s].Play();
  219. h.cardplayed[id] = &(cd[s]);
  220. ::move.playerid = id;
  221. ::move.cardid = cd[s].ID();
  222. ::move.playerled = h.playerled;
  223. ::move.turn = h.turn;
  224. ::pMainWnd->OnRef();
  225. return TRUE;
  226. }
  227. void local_human::StartTimer(card &c)
  228. {
  229. CClientDC dc(::pMainWnd);
  230. #ifdef USE_MIRRORING
  231. SetLayout(dc.m_hDC, 0);
  232. SetLayout(dc.m_hAttribDC, 0);
  233. #endif
  234. c.Draw(dc, HILITE); // flash
  235. c.GetRect(rectCard);
  236. if (::pMainWnd->SetTimer(1, 250, TimerBadMove))
  237. {
  238. bTimerOn = TRUE;
  239. }
  240. else
  241. {
  242. bTimerOn = FALSE;
  243. ::pMainWnd->InvalidateRect(&rectCard, FALSE);
  244. }
  245. }
  246. // MFC2 changes same as SetTimer in main2.cpp
  247. #if defined (MFC1)
  248. UINT FAR PASCAL EXPORT
  249. TimerBadMove(HWND hWnd, UINT nMsg, int nIDEvent, DWORD dwTime)
  250. {
  251. ::KillTimer(hWnd, 1);
  252. local_human::bTimerOn = FALSE;
  253. ::InvalidateRect(hWnd, &rectCard, FALSE);
  254. return 0;
  255. }
  256. #else
  257. void FAR PASCAL EXPORT
  258. TimerBadMove(HWND hWnd, UINT nMsg, UINT_PTR nIDEvent, DWORD dwTime)
  259. {
  260. ::KillTimer(hWnd, 1);
  261. local_human::bTimerOn = FALSE;
  262. #ifdef USE_MIRRORING
  263. CRect rect;
  264. int i;
  265. DWORD ProcessDefaultLayout;
  266. if (GetProcessDefaultLayout(&ProcessDefaultLayout))
  267. if (ProcessDefaultLayout == LAYOUT_RTL)
  268. {
  269. GetClientRect(hWnd, &rect);
  270. rectCard.left = abs(rect.right - rect.left) - rectCard.left;
  271. rectCard.right = abs(rect.right - rect.left) - rectCard.right;
  272. i = rectCard.left;
  273. rectCard.left = rectCard.right;
  274. rectCard.right = i;
  275. }
  276. #endif
  277. ::InvalidateRect(hWnd, &rectCard, FALSE);
  278. }
  279. #endif
  280. /****************************************************************************
  281. local_human::XYToCard()
  282. returns a card slot number (or EMPTY) given a mouse location
  283. ****************************************************************************/
  284. int local_human::XYToCard(int x, int y)
  285. {
  286. // check that we are in the right general area on the screen
  287. if (y < (loc.y - POPSPACING))
  288. return EMPTY;
  289. if (y > (loc.y + card::dyCrd))
  290. return EMPTY;
  291. if (x < loc.x)
  292. return EMPTY;
  293. if (x > (loc.x + (12 * HORZSPACING) + card::dxCrd))
  294. return EMPTY;
  295. // Take first stab at card selected.
  296. SLOT s = (x - loc.x) / HORZSPACING;
  297. if (s > 12)
  298. s = 12;
  299. // If the click is ABOVE the top of the normal card location,
  300. // check to see if this is a selected card.
  301. if (y < loc.y)
  302. {
  303. // If the card is bSelected, then we have it. If not, it could
  304. // be overhanging other cards.
  305. if (!cd[s].IsSelected())
  306. {
  307. for (;;)
  308. {
  309. if (s == 0)
  310. return EMPTY;
  311. s--;
  312. // if this card doesn't extend as far as x, give up
  313. if ((loc.x + (s * HORZSPACING) + card::dxCrd) < x)
  314. return EMPTY;
  315. // if this card is selected, we've got it
  316. if (cd[s].IsSelected())
  317. break;
  318. }
  319. }
  320. }
  321. // a similar check is used to make sure we pick a card not yet played
  322. if (!cd[s].IsInHand())
  323. {
  324. for (;;)
  325. {
  326. if (s == 0)
  327. return EMPTY;
  328. s--;
  329. // if this card doesn't extend as far as x, give up
  330. if ((loc.x + (s * HORZSPACING) + card::dxCrd) < x)
  331. return EMPTY;
  332. // if this card is selected, we've got it
  333. if (cd[s].IsInHand())
  334. break;
  335. }
  336. }
  337. return s;
  338. }
  339. /****************************************************************************
  340. local_human::SelectCardsToPass()
  341. This virtual function allows mouse clicks to mean select a card to play.
  342. ****************************************************************************/
  343. void local_human::SelectCardsToPass()
  344. {
  345. SetMode(SELECTING);
  346. }
  347. /****************************************************************************
  348. local_human::SelectCardToPlay
  349. Computer versions of this virtual function actually do the card selection.
  350. This local_human version marks the player as ready to select a card to
  351. play with the mouse, and updates the status to reflect this.
  352. ****************************************************************************/
  353. void local_human::SelectCardToPlay(handinfotype &h, BOOL bCheating)
  354. {
  355. SetMode(PLAYING);
  356. UpdateStatus(IDS_GO);
  357. }
  358. /****************************************************************************
  359. local_human::UpdateStatus
  360. The status bar can be updated either by manually filling m_StatusText
  361. or by passing a string resource id.
  362. ****************************************************************************/
  363. void local_human::UpdateStatus(void)
  364. {
  365. m_pStatusWnd->SetText(m_StatusText, 255, 0);
  366. }
  367. void local_human::UpdateStatus(int stringid)
  368. {
  369. status = stringid;
  370. m_StatusText.LoadString(stringid);
  371. UpdateStatus();
  372. }
  373. void local_human::UpdateStatus(const TCHAR *string)
  374. {
  375. m_StatusText = string;
  376. UpdateStatus();
  377. }
  378. /****************************************************************************
  379. local_human::ReceiveSelectedCards
  380. The parameter c[] is an array of three cards being passed from another
  381. player.
  382. ****************************************************************************/
  383. void local_human::ReceiveSelectedCards(int c[])
  384. {
  385. for (int i = 0, j = 0; j < 3; i++)
  386. {
  387. if (cd[i].IsSelected())
  388. cd[i].SetID(c[j++]);
  389. ASSERT(i < MAXSLOT);
  390. }
  391. SetMode(ACCEPTING);
  392. UpdateStatus(IDS_ACCEPT);
  393. }
  394. /****************************************************************************
  395. local_human::WaitMessage()
  396. Makes and shows the "Waiting for %s to move..." message
  397. ****************************************************************************/
  398. void local_human::WaitMessage(const TCHAR *name)
  399. {
  400. TCHAR buf[100];
  401. CString s;
  402. s.LoadString(IDS_WAIT);
  403. wsprintf(buf, s, name);
  404. UpdateStatus(buf);
  405. }