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.

614 lines
16 KiB

  1. /***************************************************************************/
  2. /** Microsoft Windows **/
  3. /** Copyright(c) Microsoft Corp., 1991, 1992 **/
  4. /***************************************************************************/
  5. /****************************************************************************
  6. player.cpp
  7. Aug 92, JimH
  8. May 93, JimH chico port
  9. Methods for player objects
  10. ****************************************************************************/
  11. #include "hearts.h"
  12. #include "main.h" // friendly access
  13. #include "resource.h"
  14. #include "debug.h"
  15. #include <stdlib.h> // qsort() prototype
  16. #include <stdio.h>
  17. extern "C" { // compare routine for qsort()
  18. int __cdecl CompareCards(card *c1, card *c2);
  19. }
  20. /****************************************************************************
  21. player::player
  22. ****************************************************************************/
  23. player::player(int n, int pos) : id(n), position(pos)
  24. {
  25. // Set up font
  26. BYTE charset = 0;
  27. int fontsize = 0;
  28. CString fontname, charsetstr, fontsizestr;
  29. fontname.LoadString(IDS_FONTFACE);
  30. charsetstr.LoadString(IDS_CHARSET);
  31. fontsizestr.LoadString(IDS_FONTSIZE);
  32. charset = (BYTE)_ttoi(charsetstr);
  33. fontsize = _ttoi(fontsizestr);
  34. font.CreateFont(fontsize, 0, 0, 0, 700, 0, 0, 0, charset, 0, 0, 0, 0, fontname);
  35. CRect rect = CMainWindow::m_TableRect;
  36. POINT centre;
  37. const int offset = 30; // offset from centre for playloc
  38. mode = STARTING;
  39. centre.x = (rect.right / 2) - (card::dxCrd / 2);
  40. centre.y = (rect.bottom / 2) - (card::dyCrd / 2);
  41. playloc = centre;
  42. score = 0;
  43. CClientDC dc(::pMainWnd);
  44. TEXTMETRIC tm;
  45. dc.GetTextMetrics(&tm);
  46. int nTextHeight = tm.tmHeight + tm.tmExternalLeading;
  47. switch (position) {
  48. case 0:
  49. loc.x = (rect.right - (12 * HORZSPACING + card::dxCrd)) / 2;
  50. loc.y = rect.bottom - card::dyCrd - IDGE;
  51. dx = HORZSPACING;
  52. dy = 0;
  53. playloc.x -= 5;
  54. playloc.y += offset;
  55. dotloc.x = loc.x + (HORZSPACING / 2);
  56. dotloc.y = loc.y - IDGE;
  57. homeloc.x = playloc.x;
  58. homeloc.y = rect.bottom + card::dyCrd;
  59. nameloc.x = loc.x + card::dxCrd + IDGE;
  60. nameloc.y = rect.bottom - nTextHeight - IDGE;
  61. break;
  62. case 1:
  63. loc.x = 3 * IDGE;
  64. loc.y = (rect.bottom - (12 * VERTSPACING + card::dyCrd)) / 2;
  65. dx = 0;
  66. dy = VERTSPACING;
  67. playloc.x -= offset;
  68. playloc.y -= 5;
  69. dotloc.x = loc.x + card::dxCrd + IDGE;
  70. dotloc.y = loc.y + (VERTSPACING / 2);
  71. homeloc.x = -card::dxCrd;
  72. homeloc.y = playloc.y;
  73. nameloc.x = loc.x + 2;
  74. nameloc.y = loc.y - nTextHeight;
  75. break;
  76. case 2:
  77. loc.x = ((rect.right - (12 * HORZSPACING + card::dxCrd)) / 2)
  78. + (12 * HORZSPACING);
  79. loc.y = IDGE;
  80. dx = -HORZSPACING;
  81. dy = 0;
  82. playloc.x += 5;
  83. playloc.y -= offset;
  84. dotloc.x = loc.x + card::dxCrd - (HORZSPACING / 2);
  85. dotloc.y = loc.y + card::dyCrd + IDGE;
  86. homeloc.x = playloc.x;
  87. homeloc.y = -card::dyCrd;
  88. nameloc.x = ((rect.right - (12 * HORZSPACING + card::dxCrd)) / 2)
  89. + (12 * HORZSPACING) + card::dxCrd + IDGE;
  90. nameloc.y = IDGE;
  91. break;
  92. case 3:
  93. loc.x = rect.right - (card::dxCrd + (3 * IDGE));
  94. loc.y = ((rect.bottom - (12 * VERTSPACING + card::dyCrd)) / 2)
  95. + (12 * VERTSPACING);
  96. dx = 0;
  97. dy = -VERTSPACING;
  98. playloc.x += offset;
  99. playloc.y += 5;
  100. dotloc.x = loc.x - IDGE;
  101. dotloc.y = loc.y + card::dyCrd - (VERTSPACING / 2);
  102. homeloc.x = rect.right;
  103. homeloc.y = playloc.y;
  104. nameloc.x = ((rect.right - (12 * HORZSPACING + card::dxCrd)) / 2)
  105. - IDGE - 2;
  106. nameloc.y = ((rect.bottom - (12 * VERTSPACING + card::dyCrd)) / 2)
  107. + (12 * VERTSPACING) + card::dyCrd;
  108. break;
  109. }
  110. ResetLoc();
  111. }
  112. /****************************************************************************
  113. player::ResetLoc
  114. This routine puts cards in locations based on their slot number.
  115. It is used to initialize their x,y locs, or after cards have been sorted.
  116. ****************************************************************************/
  117. void player::ResetLoc()
  118. {
  119. int x = loc.x;
  120. int y = loc.y;
  121. for (SLOT s = 0; s < MAXSLOT; s++)
  122. {
  123. if (cd[s].IsInHand())
  124. cd[s].SetLoc(x, y);
  125. x += dx;
  126. y += dy;
  127. }
  128. }
  129. /****************************************************************************
  130. player::Sort
  131. ****************************************************************************/
  132. void player::Sort()
  133. {
  134. qsort( (void *)cd,
  135. MAXSLOT,
  136. sizeof(card),
  137. (int (__cdecl *)(const void *, const void *))CompareCards );
  138. ResetLoc();
  139. }
  140. /****************************************************************************
  141. CompareCards
  142. This is the compare function for player::Sort.
  143. Aces are high, cards not in hand sort high, and order of suits is
  144. clubs, diamonds, spades, hearts (alternating colours)
  145. ****************************************************************************/
  146. int __cdecl CompareCards(card *c1, card *c2)
  147. {
  148. int v1 = c1->Value2();
  149. int v2 = c2->Value2();
  150. int s1 = c1->Suit();
  151. int s2 = c2->Suit();
  152. if (!(c1->IsInHand()))
  153. v1 = EMPTY;
  154. if (!(c2->IsInHand()))
  155. v2 = EMPTY;
  156. if (v1 == EMPTY || v2 == EMPTY)
  157. {
  158. if (v1 == v2) // they're both EMPTY
  159. return 0;
  160. else if (v1 == EMPTY)
  161. return 1;
  162. else
  163. return -1;
  164. }
  165. if (s1 != s2) // different suits?
  166. {
  167. if (s1 == HEARTS && s2 == SPADES) // these two suits reversed
  168. return 1;
  169. else if (s1 == SPADES && s2 == HEARTS)
  170. return -1;
  171. else
  172. return (s1 - s2);
  173. }
  174. return (v1 - v2);
  175. }
  176. /****************************************************************************
  177. player::GetSlot
  178. converts a card id to a slot number
  179. ****************************************************************************/
  180. SLOT player::GetSlot(int id)
  181. {
  182. SLOT s = EMPTY;
  183. for (int num = 0; num < MAXSLOT; num++)
  184. {
  185. if (GetID(num) == id)
  186. {
  187. s = num;
  188. break;
  189. }
  190. }
  191. ASSERT(s != EMPTY);
  192. return s;
  193. }
  194. /****************************************************************************
  195. player::GetCardLoc
  196. Loc gets location of upper-left corner of specified card slot.
  197. Returns true if slot s is valid.
  198. ****************************************************************************/
  199. BOOL player::GetCardLoc(SLOT s, POINT& loc)
  200. {
  201. if (!cd[s].IsValid())
  202. return FALSE;
  203. loc.x = cd[s].GetX();
  204. loc.y = cd[s].GetY();
  205. return TRUE;
  206. }
  207. /****************************************************************************
  208. player::GetCoverRect
  209. returns a rect that covers all cards in hand
  210. ****************************************************************************/
  211. CRect &player::GetCoverRect(CRect& rect)
  212. {
  213. rect.left = (dx < 0 ? loc.x + 12 * dx : loc.x);
  214. rect.right = rect.left + (dx != 0 ?
  215. card::dxCrd + 12 * abs(dx) : card::dxCrd);
  216. rect.top = (dy < 0 ? loc.y + 12 * dy : loc.y);
  217. rect.bottom = rect.top + (dy != 0 ?
  218. card::dyCrd + 12 * abs(dy) : card::dyCrd);
  219. // expand rect to include selection indicators
  220. if (position == 0)
  221. rect.top -= POPSPACING;
  222. else if (position == 1)
  223. rect.right += 2 * IDGE;
  224. else if (position == 2)
  225. rect.bottom += 2 * IDGE;
  226. else
  227. rect.left -= 2 * IDGE;
  228. return rect;
  229. }
  230. /****************************************************************************
  231. rect::GetMarkingRect
  232. returns a rect that covers all selection marking dots
  233. ****************************************************************************/
  234. CRect &player::GetMarkingRect(CRect& rect)
  235. {
  236. rect.left = (dx < 0 ? dotloc.x + (12 * dx) : dotloc.x);
  237. rect.right = (dx < 0 ? dotloc.x + 2 : dotloc.x + (12 * dx) + 2);
  238. rect.top = (dy < 0 ? dotloc.y + (12 * dy) : dotloc.y);
  239. rect.bottom = (dy < 0 ? dotloc.y + 2 : dotloc.y + (12 * dy) + 2);
  240. return rect;
  241. }
  242. /****************************************************************************
  243. player::Draw
  244. Draws all the cards belonging to this player. bCheating defaults to
  245. FALSE, and SLOT defaults to ALL.
  246. ****************************************************************************/
  247. void player::Draw(CDC &dc, BOOL bCheating, SLOT slot)
  248. {
  249. DisplayName(dc);
  250. SLOT start = (slot == ALL ? 0 : slot);
  251. SLOT stop = (slot == ALL ? MAXSLOT : slot+1);
  252. SLOT playedslot = EMPTY; // must draw cards in play last for EGA
  253. for (SLOT s = start; s < stop; s++)
  254. {
  255. if (cd[s].IsPlayed())
  256. playedslot = s; // save and draw later
  257. else if (bCheating)
  258. cd[s].Draw(dc);
  259. else
  260. cd[s].Draw(dc, FACEDOWN);
  261. }
  262. if (playedslot != EMPTY)
  263. cd[playedslot].Draw(dc);
  264. }
  265. void player::DisplayName(CDC &dc)
  266. {
  267. CFont *oldfont = dc.SelectObject(&font);
  268. dc.SetBkColor(::pMainWnd->GetBkColor());
  269. dc.TextOut(nameloc.x, nameloc.y, name, name.GetLength());
  270. dc.SelectObject(oldfont);
  271. }
  272. void player::SetName(CString& newname, CDC& dc)
  273. {
  274. static RECT rect; // client rect of main window
  275. static BOOL bFirst = TRUE; // first time through this routine?
  276. if (bFirst)
  277. ::pMainWnd->GetClientRect(&rect);
  278. if (rect.right > 100) // app started non-iconic
  279. bFirst = FALSE;
  280. name = newname;
  281. CFont *oldfont = dc.SelectObject(&font);
  282. if (position == 0)
  283. {
  284. CSize size = dc.GetTextExtent(name, name.GetLength());
  285. nameloc.x = ((rect.right - (12 * HORZSPACING + card::dxCrd)) / 2)
  286. - IDGE - size.cx;
  287. }
  288. else if (position == 3)
  289. {
  290. CSize size = dc.GetTextExtent(name, name.GetLength());
  291. nameloc.x = rect.right - size.cx - (3*IDGE) - 2;
  292. }
  293. dc.SelectObject(oldfont);
  294. }
  295. /****************************************************************************
  296. player::ReturnSelectedCards
  297. player::ReceiveSelectedCards
  298. When cards are passed from player to player, the first function is used
  299. to return the selected cards. The second is used to pass another player's
  300. selections in.
  301. ****************************************************************************/
  302. void player::ReturnSelectedCards(int c[])
  303. {
  304. c[0] = EMPTY; // default
  305. c[1] = EMPTY;
  306. c[2] = EMPTY;
  307. if (mode == STARTING || mode == SELECTING)
  308. return;
  309. for (int i = 0, j = 0; j < 3; i++)
  310. {
  311. if (cd[i].IsSelected())
  312. c[j++] = cd[i].ID();
  313. if (i >= MAXSLOT)
  314. { ASSERT(i < MAXSLOT); }
  315. }
  316. }
  317. void player::ReceiveSelectedCards(int c[])
  318. {
  319. for (int i = 0, j = 0; j < 3; i++)
  320. {
  321. if (cd[i].IsSelected())
  322. {
  323. cd[i].SetID(c[j++]);
  324. cd[i].Select(FALSE);
  325. }
  326. ASSERT(i < MAXSLOT);
  327. }
  328. SetMode(WAITING);
  329. }
  330. /****************************************************************************
  331. player::MarkSelectedCards
  332. This virtual function puts white dots beside selected cards for all
  333. non-local_human players.
  334. ****************************************************************************/
  335. void player::MarkSelectedCards(CDC &dc)
  336. {
  337. COLORREF color = RGB(255, 255, 255);
  338. for (int s = 0; s < MAXSLOT; s++)
  339. {
  340. if (cd[s].IsSelected())
  341. {
  342. int x = dotloc.x + (s * dx);
  343. int y = dotloc.y + (s * dy);
  344. dc.SetPixel(x, y, color);
  345. dc.SetPixel(x+1, y, color);
  346. dc.SetPixel(x, y+1, color);
  347. dc.SetPixel(x+1, y+1, color);
  348. }
  349. }
  350. }
  351. /****************************************************************************
  352. player::GlideToCentre
  353. This function takes a selected card and glides it to its play location.
  354. The other normal cards (cards still in hand) are each checked to see if
  355. the card is to be moved. If so, their image is drawn into the background
  356. bitmap.
  357. ****************************************************************************/
  358. void player::GlideToCentre(SLOT s, BOOL bFaceup)
  359. {
  360. CRect rectCard, rectSrc, rectDummy;
  361. CClientDC dc(::pMainWnd);
  362. #ifdef USE_MIRRORING
  363. SetLayout(dc.m_hDC, 0);
  364. SetLayout(dc.m_hAttribDC, 0);
  365. #endif
  366. CDC *memdc = new CDC;
  367. memdc->CreateCompatibleDC(&dc);
  368. memdc->SelectObject(&card::m_bmBgnd);
  369. memdc->SelectObject(&CMainWindow::m_BgndBrush);
  370. memdc->PatBlt(0, 0, card::dxCrd, card::dyCrd, PATCOPY);
  371. cd[s].GetRect(rectCard);
  372. for (SLOT i = 0; i < MAXSLOT; i++)
  373. {
  374. if (cd[i].IsNormal() && (i != s))
  375. {
  376. cd[i].GetRect(rectSrc);
  377. if (IntersectRect(&rectDummy, &rectSrc, &rectCard))
  378. {
  379. cd[i].Draw(*memdc, // CDC
  380. rectSrc.left-rectCard.left, // x
  381. rectSrc.top-rectCard.top, // y
  382. bFaceup ? FACEUP : FACEDOWN, // mode
  383. FALSE); // don't update loc
  384. }
  385. }
  386. }
  387. delete memdc; // must delete before Glide() called
  388. cd[s].CleanDraw(dc);
  389. cd[s].Glide(dc, playloc.x, playloc.y); // glide to play location
  390. cd[s].Play(); // mark card as played
  391. SetMode(WAITING);
  392. }
  393. /****************************************************************************
  394. player::ResetCardsWon
  395. cardswon[] keeps track of point cards won this hand. This function
  396. clears this data for a new hand.
  397. ****************************************************************************/
  398. void player::ResetCardsWon()
  399. {
  400. for (int i = 0; i < MAXCARDSWON; i++)
  401. cardswon[i] = EMPTY;
  402. numcardswon = 0;
  403. }
  404. /****************************************************************************
  405. player::WinCard
  406. Cards won in tricks are passed in. If they are point cards (hearts
  407. or queen on spades) the id is saved in cardswon[].
  408. ****************************************************************************/
  409. void player::WinCard(CDC &dc, card *c)
  410. {
  411. if ((c->IsHeart()) || (c->ID() == BLACKLADY))
  412. cardswon[numcardswon++] = c->ID();
  413. RegEntry Reg(szRegPath);
  414. DWORD dwSpeed = Reg.GetNumber(regvalSpeed, IDC_NORMAL);
  415. int oldstep = c->SetStepSize(dwSpeed == IDC_SLOW ? 5 : 30);
  416. c->Glide(dc, homeloc.x, homeloc.y);
  417. c->SetStepSize(oldstep);
  418. }
  419. /****************************************************************************
  420. player::EvaluateScore
  421. Points stored in cardswon[] are added to players total score.
  422. ****************************************************************************/
  423. int player::EvaluateScore(BOOL &bMoonShot)
  424. {
  425. for (int i = 0; i < MAXCARDSWON; i++)
  426. {
  427. if (cardswon[i] == BLACKLADY)
  428. score += 13;
  429. else if (cardswon[i] != EMPTY)
  430. score++;
  431. }
  432. if (cardswon[MAXCARDSWON-1] != EMPTY) // if player got ALL point cards
  433. bMoonShot = TRUE;
  434. else
  435. bMoonShot = FALSE;
  436. return score;
  437. }
  438. /****************************************************************************
  439. player::DisplayHeartsWon
  440. ****************************************************************************/
  441. void player::DisplayHeartsWon(CDC &dc)
  442. {
  443. card c;
  444. int x = loc.x;
  445. int y = loc.y;
  446. x += ((MAXCARDSWON - numcardswon) / 2) * dx;
  447. y += ((MAXCARDSWON - numcardswon) / 2) * dy;
  448. for (int i = 0; i < numcardswon; i++)
  449. {
  450. c.SetID(cardswon[i]);
  451. c.SetLoc(x, y);
  452. c.Draw(dc);
  453. x += dx;
  454. y += dy;
  455. }
  456. DisplayName(dc);
  457. }