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.

1214 lines
32 KiB

  1. #include "sol.h"
  2. VSZASSERT
  3. /* Klondike init stuff */
  4. LRESULT KlondGmProc(GM *pgm, INT msgg, WPARAM wp1, LPARAM wp2);
  5. LRESULT DeckColProc(COL *pcol, INT msgc, WPARAM wp1, LPARAM wp2);
  6. LRESULT DiscardColProc(COL *pcol, INT msgc, WPARAM wp1, LPARAM wp2);
  7. LRESULT TabColProc(COL *pcol, INT msgc, WPARAM wp1, LPARAM wp2);
  8. LRESULT FoundColProc(COL *pcol, INT msgc, WPARAM wp1, LPARAM wp2);
  9. // Imported from Win3.1
  10. BOOL FInitKlondGm()
  11. {
  12. COLCLS *pcolcls;
  13. GM *pgm;
  14. DX dxCrdOffUp;
  15. DX dyCrdOffUp;
  16. DX dyCrdOffDn;
  17. int icol;
  18. int icrdMax;
  19. /* KLUDGE to get klondike going */
  20. FreeGm(pgmCur);
  21. if((pgm = pgmCur = PAlloc(sizeof(GM)+(13-1)*sizeof(COL *))) == NULL)
  22. return fFalse;
  23. pgm->lpfnGmProc = KlondGmProc;
  24. SendGmMsg(pgm, msggInit, fTrue, 0);
  25. pgm->icolMax = 13;
  26. pgm->dqsecScore = 10*4;
  27. if(!FInitUndo(&pgm->udr))
  28. goto OOM;
  29. /* Initialize all the column types but don't position yet */
  30. for(icol = 0; icol < pgm->icolMax; icol++)
  31. {
  32. switch(icol)
  33. {
  34. case icolDeck:
  35. pcolcls = PcolclsCreate(tclsDeck, (COLCLSCREATEFUNC)DeckColProc,
  36. 0, 0, 2, 1, 1, 10);
  37. icrdMax = icrdDeckMax;
  38. break;
  39. case icolDiscard:
  40. dxCrdOffUp = dxCrd / 5;
  41. pcolcls = PcolclsCreate(tclsDiscard, (COLCLSCREATEFUNC)DiscardColProc,
  42. dxCrdOffUp, 1, 2, 1, 1, 10);
  43. icrdMax = icrdDiscardMax;
  44. break;
  45. case icolFoundFirst:
  46. pcolcls = PcolclsCreate(tclsFound, (COLCLSCREATEFUNC)FoundColProc,
  47. 2, 1, 0, 0, 4, 1);
  48. Assert(icol - 1 == icolDiscard);
  49. icrdMax = icrdFoundMax;
  50. break;
  51. case icolTabFirst:
  52. Assert(fHalfCards == 1 || fHalfCards == 0);
  53. dyCrdOffUp = dyCrd * 4 / 25 - fHalfCards;
  54. dyCrdOffDn = dyCrd / 25;
  55. pgm->dyDragMax = dyCrd + 12 * dyCrdOffUp;
  56. pcolcls = PcolclsCreate(tclsTab, (COLCLSCREATEFUNC)TabColProc,
  57. 0, dyCrdOffUp, 0, dyCrdOffDn, 1, 1);
  58. icrdMax = icrdTabMax;
  59. break;
  60. }
  61. if(pcolcls == NULL)
  62. {
  63. OOM:
  64. OOM();
  65. FreeGm(pgmCur);
  66. Assert(pgmCur == NULL);
  67. return fFalse;
  68. }
  69. if((pgm->rgpcol[icol] = PcolCreate(pcolcls, 0, 0, 0, 0, icrdMax))
  70. == NULL)
  71. {
  72. FreeP(pcolcls);
  73. goto OOM;
  74. }
  75. pgm->icolMac++;
  76. }
  77. /* Return without positioning the cards. This will be done at
  78. * WM_SIZE message time.
  79. */
  80. return TRUE;
  81. }
  82. /* PositionCols
  83. * Positions the card columns. Note that this has been revised to
  84. * allow card positioning at times other than at the start of the
  85. * game.
  86. */
  87. BOOL PositionCols(void)
  88. {
  89. DX dxMarg;
  90. DY dyMarg;
  91. DX dx;
  92. X xLeft;
  93. X xRight;
  94. Y yTop;
  95. Y yBot;
  96. int icol;
  97. DY dyCrdOffUp;
  98. DY dyCrdOffDn;
  99. COL *pcol;
  100. GM *pgm;
  101. WORD i;
  102. /* The game we're using is always the current one */
  103. pgm = pgmCur;
  104. /* Before doing the column classes, replace all card X coordinates with
  105. * offsets from the column class.
  106. */
  107. for (icol = 0 ; icol < 13 ; ++icol)
  108. {
  109. /* Get a pointer to this COL structure */
  110. pcol = pgm->rgpcol[icol];
  111. /* Loop through all the cards in this column */
  112. for (i = 0 ; i < pcol->icrdMax ; ++i)
  113. pcol->rgcrd[i].pt.x -= pcol->rc.xLeft;
  114. }
  115. /* Set the card margins. Note that xCardMargin is computed in SOL.C
  116. * at the time the original window is created and is changed on
  117. * WM_SIZE messages.
  118. */
  119. dxMarg = xCardMargin;
  120. dyMarg = MulDiv(dyCrd, 5, 100);
  121. /* Loop through all column types */
  122. for(icol = 0 ; icol < 13 ; icol++)
  123. {
  124. switch(icol)
  125. {
  126. case icolDeck:
  127. xLeft = dxMarg;
  128. yTop = dyMarg;
  129. xRight = xLeft + dxCrd + icrdDeckMax / 10 * 2;
  130. yBot = yTop + dyCrd + icrdDeckMax / 10;
  131. dx = 0;
  132. break;
  133. case icolDiscard:
  134. xLeft += dxMarg + dxCrd;
  135. xRight = xLeft + 7 * dxCrd / 5 + icrdDiscardMax / 10 * 2;
  136. break;
  137. case icolFoundFirst:
  138. xLeft = 4 * dxMarg + 3 * dxCrd;
  139. xRight = xLeft + dxCrd + icrdFoundMax / 4 * 2;
  140. dx = dxMarg + dxCrd;
  141. break;
  142. case icolTabFirst:
  143. dyCrdOffUp = dyCrd * 4 / 25 - fHalfCards;
  144. dyCrdOffDn = dyCrd / 25;
  145. xLeft = dxMarg;
  146. xRight = xLeft + dxCrd;
  147. yTop = yBot + 1;
  148. yBot = yTop + 12 * dyCrdOffUp + dyCrd + 6 * dyCrdOffDn;
  149. break;
  150. }
  151. /* Set this information into the structure */
  152. pcol = pgm->rgpcol[icol];
  153. pcol->rc.xLeft = xLeft;
  154. pcol->rc.yTop = yTop;
  155. pcol->rc.xRight = xRight;
  156. pcol->rc.yBot = yBot;
  157. /* Prepare for the next loop */
  158. xLeft += dx;
  159. xRight += dx;
  160. }
  161. /* Now that the column offsets are correct, move the cards back */
  162. for (icol = 0 ; icol < 13 ; ++icol)
  163. {
  164. /* Get a pointer to this COL structure */
  165. pcol = pgm->rgpcol[icol];
  166. /* Loop through all the cards in this column */
  167. for (i = 0 ; i < pcol->icrdMax ; ++i)
  168. pcol->rgcrd[i].pt.x += pcol->rc.xLeft;
  169. }
  170. return TRUE;
  171. }
  172. /* TABLEAU col Proc stuff */
  173. BOOL FTabValidMove(COL *pcolDest, COL *pcolSrc)
  174. {
  175. RA raSrc, raDest;
  176. SU suSrc, suDest;
  177. INT icrdSel;
  178. CD cd;
  179. Assert(pcolSrc->pmove != NULL);
  180. icrdSel = pcolSrc->pmove->icrdSel;
  181. Assert(icrdSel < pcolSrc->icrdMac);
  182. Assert(pcolSrc->icrdMac > 0);
  183. cd = pcolSrc->rgcrd[icrdSel].cd;
  184. raSrc = RaFromCd(cd);
  185. suSrc = SuFromCd(cd);
  186. if(raSrc == raKing)
  187. return (pcolDest->icrdMac == 0);
  188. if(pcolDest->icrdMac == 0)
  189. return fFalse;
  190. if(!pcolDest->rgcrd[pcolDest->icrdMac-1].fUp)
  191. return fFalse;
  192. cd = pcolDest->rgcrd[pcolDest->icrdMac-1].cd;
  193. raDest = RaFromCd(cd);
  194. suDest = SuFromCd(cd);
  195. /* invalid moves */
  196. Assert((suClub ^ suSpade) == 0x03);
  197. Assert((suHeart ^ suDiamond) == 0x03);
  198. /* valid moves */
  199. Assert((suClub ^ suDiamond) < 0x03);
  200. Assert((suClub ^ suHeart) < 0x03);
  201. Assert((suSpade ^ suDiamond) < 0x03);
  202. Assert((suSpade ^ suHeart) < 0x03);
  203. return (((suSrc ^ suDest) < 0x03) && suSrc != suDest && raSrc+1 == raDest);
  204. }
  205. INT TabHit(COL *pcol, PT *ppt, INT icrdMin)
  206. {
  207. CRD *pcrd;
  208. if(pcol->icrdMac > 0 && !(pcrd=&pcol->rgcrd[pcol->icrdMac-1])->fUp && FPtInCrd(pcrd, *ppt))
  209. {
  210. SendGmMsg(pgmCur, msggKillUndo, 0, 0);
  211. SendColMsg(pcol, msgcSel, icrdEnd, 1);
  212. SendColMsg(pcol, msgcFlip, fTrue, 0);
  213. SendColMsg(pcol, msgcComputeCrdPos, pcol->icrdMac-1, fFalse);
  214. SendColMsg(pcol, msgcRender, pcol->icrdMac-1, icrdToEnd);
  215. SendGmMsg(pgmCur, msggChangeScore, csKlondTabFlip, 0);
  216. SendColMsg(pcol, msgcEndSel, fFalse, 0);
  217. /* should I return this? */
  218. return icrdNil;
  219. }
  220. return DefColProc(pcol, msgcHit, (INT_PTR) ppt, icrdMin);
  221. }
  222. BOOL TabDiscardDblClk(COL *pcol, PT *ppt, INT icol)
  223. {
  224. CRD *pcrd;
  225. INT icolDest;
  226. COL *pcolDest;
  227. BOOL fResult;
  228. fResult = fFalse;
  229. if(pcol->icrdMac > 0 && (pcrd=&pcol->rgcrd[pcol->icrdMac-1])->fUp && FPtInCrd(pcrd, *ppt))
  230. {
  231. if(pcol->pmove == NULL)
  232. SendColMsg(pcol, msgcSel, icrdEnd, ccrdToEnd);
  233. Assert(pcol->pmove != NULL);
  234. for(icolDest = icolFoundFirst; icolDest < icolFoundFirst+ccolFound; icolDest++)
  235. {
  236. pcolDest = pgmCur->rgpcol[icolDest];
  237. if(SendColMsg(pcolDest, msgcValidMove, (INT_PTR)pcol, 0))
  238. {
  239. SendGmMsg(pgmCur, msggSaveUndo, icolDest, icol);
  240. fResult = SendColMsg(pcolDest, msgcMove, (INT_PTR) pcol, icrdToEnd) &&
  241. (fOutlineDrag || SendColMsg(pcol, msgcRender, pcol->icrdMac-1, icrdToEnd)) &&
  242. SendGmMsg(pgmCur, msggScore, (INT_PTR) pcolDest, (INT_PTR) pcol);
  243. if(SendGmMsg(pgmCur, msggIsWinner, 0, 0))
  244. SendGmMsg(pgmCur, msggWinner, 0, 0);
  245. goto Return;
  246. }
  247. }
  248. SendColMsg(pcol, msgcEndSel, fFalse, 0);
  249. }
  250. Return:
  251. return fResult;
  252. }
  253. LRESULT TabColProc(COL *pcol, INT msgc, WPARAM wp1, LPARAM wp2)
  254. {
  255. switch(msgc)
  256. {
  257. case msgcHit:
  258. /* should this go in DefProc? */
  259. return TabHit(pcol, (PT *)wp1, (INT)wp2);
  260. case msgcDblClk:
  261. return TabDiscardDblClk(pcol, (PT *)wp1, (INT)wp2);
  262. case msgcValidMove:
  263. return FTabValidMove(pcol, (COL *) wp1);
  264. }
  265. return DefColProc(pcol, msgc, wp1, wp2);
  266. }
  267. BOOL FFoundRender(COL *pcol, INT icrdFirst, INT icrdLast)
  268. {
  269. #define dxFoundDn 2
  270. #define dyFoundDn 1
  271. if(pcol->icrdMac == 0 || icrdLast == 0)
  272. {
  273. if(!FGetHdc())
  274. return fFalse;
  275. DrawCardExt((PT *)(&pcol->rc.xLeft), 0, GHOST);
  276. DrawBackExcl(pcol, (PT *) &pcol->rc);
  277. ReleaseHdc();
  278. return fTrue;
  279. }
  280. else
  281. return DefColProc(pcol, msgcRender, icrdFirst, icrdLast);
  282. }
  283. BOOL FFoundValidMove(COL *pcolDest, COL *pcolSrc)
  284. {
  285. RA raSrc;
  286. SU suSrc;
  287. INT icrdSel;
  288. Assert(pcolSrc->pmove != NULL);
  289. icrdSel = pcolSrc->pmove->icrdSel;
  290. Assert(icrdSel < pcolSrc->icrdMac);
  291. Assert(pcolSrc->icrdMac > 0);
  292. if(pcolSrc->pmove->ccrdSel != 1)
  293. return fFalse;
  294. raSrc = RaFromCd(pcolSrc->rgcrd[icrdSel].cd);
  295. suSrc = SuFromCd(pcolSrc->rgcrd[icrdSel].cd);
  296. if(pcolDest->icrdMac == 0)
  297. return(raSrc == raAce);
  298. return (raSrc == RaFromCd(pcolDest->rgcrd[pcolDest->icrdMac-1].cd)+1 &&
  299. suSrc == SuFromCd(pcolDest->rgcrd[pcolDest->icrdMac-1].cd));
  300. }
  301. /* Foundation stuff */
  302. LRESULT FoundColProc(COL *pcol, INT msgc, WPARAM wp1, LPARAM wp2)
  303. {
  304. switch(msgc)
  305. {
  306. case msgcValidMove:
  307. return FFoundValidMove(pcol, (COL *) wp1);
  308. case msgcRender:
  309. return FFoundRender(pcol, (INT)wp1, (INT)wp2);
  310. }
  311. return DefColProc(pcol, msgc, wp1, wp2);
  312. }
  313. /* DeckStuff */
  314. BOOL DeckInit(COL *pcol)
  315. {
  316. CRD *pcrd;
  317. INT icrd;
  318. Assert(pcol->icrdMax == icrdDeckMax);
  319. for(icrd = 0; icrd < icrdDeckMax; icrd++)
  320. {
  321. pcrd = &pcol->rgcrd[icrd];
  322. pcrd->cd = (unsigned short)icrd;
  323. pcrd->pt = *(PT *)&pcol->rc;
  324. pcrd->fUp = fFalse;
  325. }
  326. pcol->icrdMac = icrdDeckMax;
  327. SendColMsg(pcol, msgcShuffle, 0, 0);
  328. SendColMsg(pcol, msgcComputeCrdPos, 0, fFalse);
  329. return fTrue;
  330. }
  331. INT DeckHit(COL *pcol, PT *ppt, INT icrdMin)
  332. {
  333. RC rc;
  334. INT ccrd;
  335. if(pcol->icrdMac == 0)
  336. {
  337. CrdRcFromPt((PT *) &pcol->rc, &rc);
  338. if(PtInRect((LPRECT) &rc, *(POINT *)ppt))
  339. return icrdEmpty;
  340. else
  341. return icrdNil;
  342. }
  343. else
  344. if(!FPtInCrd(&pcol->rgcrd[pcol->icrdMac-1], *ppt))
  345. return icrdNil;
  346. ccrd = ((GetKeyState(VK_SHIFT) & GetKeyState(VK_CONTROL) & GetKeyState(VK_MENU)) < 0) ? 1 : pgmCur->ccrdDeal;
  347. move.icrdSel = WMax(pcol->icrdMac-ccrd, 0);
  348. move.ccrdSel = pcol->icrdMac - move.icrdSel;
  349. Assert(pcol->pmove == NULL);
  350. pcol->pmove = &move;
  351. return move.icrdSel;
  352. }
  353. BOOL FDeckRender(COL *pcol, INT icrdFirst, INT icrdLast)
  354. {
  355. INT mode;
  356. BOOL f;
  357. PT pt;
  358. /* to avoid redrawing the deck multiple times during dealing */
  359. if(!pgmCur->fDealt && pcol->icrdMac%10 != 9)
  360. return fTrue;
  361. if(!FGetHdc())
  362. return fFalse;
  363. if(pcol->icrdMac == 0)
  364. {
  365. mode = (smd == smdVegas && pgmCur->irep == ccrdDeal-1) ? DECKX : DECKO;
  366. DrawCardExt((PT *) &pcol->rc, 0, mode);
  367. DrawBackExcl(pcol, (PT *) &pcol->rc);
  368. f = fTrue;
  369. }
  370. else
  371. {
  372. f = DefColProc(pcol, msgcRender, icrdFirst, icrdLast);
  373. if((icrdLast == pcol->icrdMac || icrdLast == icrdToEnd) && !fHalfCards)
  374. {
  375. pt.x = pcol->rgcrd[pcol->icrdMac-1].pt.x+dxCrd-1;
  376. pt.y = pcol->rgcrd[pcol->icrdMac-1].pt.y+dyCrd-1;
  377. SetPixel(hdcCur, pt.x-xOrgCur, pt.y-yOrgCur, rgbTable);
  378. SetPixel(hdcCur, pt.x-1-xOrgCur, pt.y-yOrgCur, rgbTable);
  379. SetPixel(hdcCur, pt.x-xOrgCur, pt.y-1-yOrgCur, rgbTable);
  380. }
  381. }
  382. ReleaseHdc();
  383. return f;
  384. }
  385. VOID DrawAnimate(INT cd, PT *ppt, INT iani)
  386. {
  387. if(!FGetHdc())
  388. return;
  389. cdtAnimate(hdcCur, cd, ppt->x, ppt->y, iani);
  390. ReleaseHdc();
  391. }
  392. BOOL DeckAnimate(COL *pcol, INT iqsec)
  393. {
  394. INT iani;
  395. PT pt;
  396. // we removed the older card decks that required Animation. The new
  397. // card deck doesn't involve any animation.
  398. #ifdef UNUSEDCODE
  399. if(pcol->icrdMac > 0 && !fHalfCards)
  400. {
  401. pt = pcol->rgcrd[pcol->icrdMac-1].pt;
  402. switch(modeFaceDown)
  403. {
  404. case IDFACEDOWN3:
  405. DrawAnimate(IDFACEDOWN3, &pt, iqsec % 4);
  406. break;
  407. case IDFACEDOWN10: /* krazy kastle */
  408. DrawAnimate(IDFACEDOWN10, &pt, iqsec % 2);
  409. break;
  410. case IDFACEDOWN11: /* sanflipe */
  411. if((iani = (iqsec+4) % (50*4)) < 4)
  412. DrawAnimate(IDFACEDOWN11, &pt, iani);
  413. else
  414. /* if a menu overlapps an ani while it is ani'ing, leaves deck
  415. bitmap in inconsistent state... */
  416. if(iani % 6 == 0)
  417. DrawAnimate(IDFACEDOWN11, &pt, 3);
  418. break;
  419. case IDFACEDOWN12: /* SLIME */
  420. if((iani = (iqsec+4) % (15*4)) < 4)
  421. DrawAnimate(IDFACEDOWN12, &pt, iani);
  422. else
  423. /* if a menu overlapps an ani while it is ani'ing, leaves deck
  424. bitmap in inconsistent state... */
  425. if(iani % 6 == 0)
  426. DrawAnimate(IDFACEDOWN12, &pt, 3);
  427. break;
  428. }
  429. }
  430. #endif
  431. return fTrue;
  432. }
  433. LRESULT DeckColProc(COL *pcol, INT msgc, WPARAM wp1, LPARAM wp2)
  434. {
  435. switch(msgc)
  436. {
  437. case msgcInit:
  438. return DeckInit(pcol);
  439. case msgcValidMove:
  440. case msgcDrawOutline:
  441. return fFalse;
  442. case msgcValidMovePt:
  443. return icrdNil;
  444. case msgcHit:
  445. return DeckHit(pcol, (PT *) wp1, (INT)wp2);
  446. case msgcRender:
  447. return FDeckRender(pcol, (INT) wp1, (INT) wp2);
  448. case msgcValidKbdColSel:
  449. return !wp1;
  450. case msgcValidKbdCrdSel:
  451. return pcol->icrdMac == 0 || wp1 == (WPARAM) pcol->icrdMac-1;
  452. case msgcAnimate:
  453. return DeckAnimate(pcol, (INT)wp1);
  454. }
  455. return DefColProc(pcol, msgc, wp1, wp2);
  456. }
  457. BOOL DiscardRemove(COL *pcol, COL *pcolDest, LPARAM wp2)
  458. {
  459. return DefColProc(pcol, msgcRemove, (INT_PTR) pcolDest, wp2);
  460. }
  461. BOOL DiscardMove(COL *pcolDest, COL *pcolSrc, INT icrd)
  462. {
  463. BOOL fResult;
  464. SendColMsg(pcolDest, msgcComputeCrdPos, WMax(0, pcolDest->icrdMac-3), fTrue);
  465. /* YUCK: Default ComputeCrdPos doesn't quite work for discard because
  466. up cards are handled specially for Discard piles. To keep
  467. code size down we have this global hack variable which DefComputeCrdPos
  468. uses.
  469. */
  470. fMegaDiscardHack = fTrue;
  471. fResult = DefColProc(pcolDest, msgcMove, (INT_PTR) pcolSrc, icrd);
  472. fMegaDiscardHack = fFalse;
  473. return fResult;
  474. }
  475. INT DiscardHit(COL *pcol, PT *ppt, INT icrdMin)
  476. {
  477. return DefColProc(pcol, msgcHit, (INT_PTR) ppt, WMax(0, pcol->icrdMac-1));
  478. }
  479. BOOL DiscardRender(COL *pcol, INT icrdFirst, INT icrdLast)
  480. {
  481. PT pt;
  482. INT icrd;
  483. COLCLS *pcolcls;
  484. if(DefColProc(pcol, msgcRender, icrdFirst, icrdLast))
  485. {
  486. if(FGetHdc())
  487. {
  488. pcolcls = pcol->pcolcls;
  489. for(icrd = pcol->icrdMac-1; icrd >= 0 && icrd >= pcol->icrdMac-2; icrd--)
  490. {
  491. pt = pcol->rgcrd[icrd].pt;
  492. /* 3 is a kludge value here */
  493. DrawBackground(pt.x+dxCrd-pcolcls->dxUp, pt.y-pcolcls->dyUp*3,
  494. pt.x+dxCrd, pt.y);
  495. }
  496. ReleaseHdc();
  497. }
  498. return fTrue;
  499. }
  500. return fFalse;
  501. }
  502. /* Discard Stuff */
  503. LRESULT DiscardColProc(COL *pcol, INT msgc, WPARAM wp1, LPARAM wp2)
  504. {
  505. switch(msgc)
  506. {
  507. case msgcDblClk:
  508. return TabDiscardDblClk(pcol, (PT *)wp1, (INT)wp2);
  509. case msgcHit:
  510. return DiscardHit(pcol, (PT *)wp1, (INT)wp2);
  511. case msgcMove:
  512. return DiscardMove(pcol, (COL *) wp1, (INT)wp2);
  513. case msgcRemove:
  514. return DiscardRemove(pcol, (COL *) wp1, wp2);
  515. case msgcValidMovePt:
  516. return icrdNil;
  517. case msgcValidKbdColSel:
  518. return !wp1;
  519. case msgcRender:
  520. return DiscardRender(pcol, (INT)wp1, (INT)wp2);
  521. case msgcValidKbdCrdSel:
  522. return pcol->icrdMac == 0 || wp1 == (WPARAM) pcol->icrdMac-1;
  523. }
  524. return DefColProc(pcol, msgc, wp1, wp2);
  525. }
  526. /* GAME stuff */
  527. BOOL KlondDeal(GM *pgm, BOOL fZeroScore)
  528. {
  529. INT icrdSel;
  530. INT icol;
  531. INT irw;
  532. COL *pcolDeck;
  533. VOID StatString();
  534. if(!FGetHdc())
  535. {
  536. OOM();
  537. return fFalse;
  538. }
  539. EraseScreen();
  540. for(icol = 0; icol < pgm->icolMac; icol++)
  541. SendColMsg(pgm->rgpcol[icol], msgcClearCol, 0, 0);
  542. pcolDeck = pgm->rgpcol[icolDeck];
  543. SendColMsg(pcolDeck, msgcInit, 0, 0);
  544. SendGmMsg(pgm, msggKillUndo, 0, 0);
  545. SendGmMsg(pgm, msggInit, !(smd == smdVegas && fKeepScore) || fZeroScore, 0);
  546. StatString(idsNil);
  547. pgm->fDealt = fTrue;
  548. SendGmMsg(pgm, msggChangeScore, csKlondDeal, 0);
  549. SendColMsg(pcolDeck, msgcRender, 0, icrdToEnd);
  550. pgm->fDealt = fFalse;
  551. for(icol = icolFoundFirst; icol < icolFoundFirst+ccolFound; icol++)
  552. SendColMsg(pgm->rgpcol[icol], msgcRender, 0, icrdToEnd);
  553. // BabakJ: What the %@!&$* is this?! irw is always less than irw + ccolTab!!!
  554. // Note: ccolTab if #ifdef'ed as 7
  555. // for(irw = 0; irw < irw+ccolTab; irw++)
  556. for(irw = 0; irw < ccolTab; irw++)
  557. for(icol = irw; icol < ccolTab; icol++)
  558. {
  559. icrdSel = SendColMsg(pcolDeck, msgcSel, icrdEnd, 0);
  560. if(icol == irw)
  561. SendColMsg(pcolDeck, msgcFlip, fTrue, 0);
  562. SendColMsg(pgm->rgpcol[icol+icolTabFirst], msgcMove, (INT_PTR) pcolDeck, icrdToEnd);
  563. SendColMsg(pcolDeck, msgcRender, icrdSel-1, icrdToEnd);
  564. }
  565. NewKbdColAbs(pgm, 0);
  566. pgm->fDealt = fTrue;
  567. ReleaseHdc();
  568. return fTrue;
  569. }
  570. BOOL KlondMouseDown(GM *pgm, PT *ppt)
  571. {
  572. INT icrdSel;
  573. INT icrd;
  574. COL *pcolDeck, *pcolDiscard;
  575. /* Kbd sel already in effect */
  576. if(FSelOfGm(pgm) || !pgm->fDealt)
  577. return fFalse;
  578. /* place the next cards on discard pile */
  579. if((icrd = SendColMsg(pgm->rgpcol[icolDeck], msgcHit, (INT_PTR) ppt, 0)) != icrdNil)
  580. {
  581. pgm->fInput = fTrue;
  582. pcolDeck = pgm->rgpcol[icolDeck];
  583. pcolDiscard = pgm->rgpcol[icolDiscard];
  584. if(icrd == icrdEmpty)
  585. {
  586. /* repeat */
  587. if(SendColMsg(pcolDiscard, msgcNumCards, 0, 0) == 0)
  588. {
  589. /* both deck and discard are empty */
  590. Assert(pcolDeck->pmove == NULL);
  591. return fFalse;
  592. }
  593. if(smd == smdVegas && pgm->irep == ccrdDeal-1)
  594. return fFalse;
  595. pgm->irep++;
  596. pgm->udr.fEndDeck = TRUE;
  597. return SendGmMsg(pgm, msggSaveUndo, icolDiscard, icolDeck) &&
  598. SendColMsg(pcolDiscard, msgcSel, 0, ccrdToEnd) != icrdNil &&
  599. SendColMsg(pcolDiscard, msgcFlip, fFalse, 0) &&
  600. SendColMsg(pcolDiscard, msgcInvert, 0, 0) &&
  601. SendGmMsg(pgm, msggScore, (INT_PTR) pcolDeck, (INT_PTR) pcolDiscard) &&
  602. SendColMsg(pcolDeck, msgcMove, (INT_PTR) pcolDiscard, icrdToEnd) &&
  603. SendColMsg(pcolDiscard, msgcRender, 0, icrdToEnd);
  604. }
  605. else
  606. {
  607. icrdSel = pcolDeck->pmove->icrdSel-1;
  608. /* deal next cards to discard */
  609. return SendGmMsg(pgm, msggSaveUndo, icolDiscard, icolDeck) &&
  610. SendColMsg(pcolDeck, msgcFlip, fTrue, 0) &&
  611. SendColMsg(pcolDeck, msgcInvert, 0, 0) &&
  612. SendColMsg(pcolDiscard, msgcMove, (INT_PTR)pcolDeck, icrdToEnd) &&
  613. SendColMsg(pcolDeck, msgcRender, icrdSel, icrdToEnd);
  614. }
  615. }
  616. return DefGmProc(pgm, msggMouseDown, (INT_PTR) ppt, icolDiscard);
  617. }
  618. BOOL KlondIsWinner(GM *pgm)
  619. {
  620. INT icol;
  621. for(icol = icolFoundFirst; icol < icolFoundFirst+ccolFound; icol++)
  622. if(pgm->rgpcol[icol]->icrdMac != icrdFoundMax)
  623. return fFalse;
  624. return fTrue;
  625. }
  626. BOOL FAbort()
  627. {
  628. MSG msg;
  629. if (MsgWaitForMultipleObjects(0, NULL, FALSE, 5, QS_ALLINPUT) != WAIT_OBJECT_0)
  630. return FALSE;
  631. if(PeekMessage(&msg, hwndApp, 0, 0, PM_NOREMOVE))
  632. {
  633. switch(msg.message)
  634. {
  635. case WM_LBUTTONDOWN:
  636. case WM_MBUTTONDOWN:
  637. case WM_RBUTTONDOWN:
  638. case WM_KEYDOWN:
  639. case WM_SYSKEYDOWN:
  640. case WM_MENUSELECT:
  641. case WM_NCLBUTTONDOWN:
  642. case WM_NCMBUTTONDOWN:
  643. case WM_NCRBUTTONDOWN:
  644. return fTrue;
  645. }
  646. PeekMessage(&msg, hwndApp, 0, 0, PM_REMOVE);
  647. TranslateMessage((LPMSG)&msg);
  648. DispatchMessage((LPMSG)&msg);
  649. }
  650. return fFalse;
  651. }
  652. // Hack for making winning animation faster:
  653. // At cascading time we have: KlondWinner -> DrawCardPt ->cdtDrawExt
  654. // so we set a flag so cdtDrawExt knows it is cascading and does not need
  655. // to round up corners.
  656. BOOL fKlondWinner = FALSE;
  657. BOOL KlondWinner(GM *pgm)
  658. {
  659. INT icol;
  660. INT icrd;
  661. CRD *pcrd;
  662. PT pt;
  663. PT ptV;
  664. INT dxp;
  665. INT dyp;
  666. RC rcT;
  667. INT dsco;
  668. TCHAR *pch;
  669. TCHAR szBonus[84];
  670. VOID StatString();
  671. UINT cchUsed, cchTmp;
  672. fKlondWinner = TRUE;
  673. dsco = (INT)SendGmMsg(pgmCur, msggChangeScore, csKlondWin, 0);
  674. pgm->udr.fAvail = fFalse;
  675. pgm->fDealt = fFalse;
  676. pgm->fWon = fTrue;
  677. if(smd == smdStandard)
  678. {
  679. cchUsed = CchString(szBonus, idsBonus, ARRAYSIZE(szBonus));
  680. pch = &szBonus[cchUsed];
  681. cchTmp = CchDecodeInt(pch, dsco);
  682. pch += cchTmp;
  683. cchUsed += cchTmp;
  684. *pch++ = TEXT(' ');
  685. cchUsed++;
  686. *pch++ = TEXT(' ');
  687. cchUsed++;
  688. }
  689. else
  690. {
  691. pch = szBonus;
  692. cchUsed = 0;
  693. }
  694. if (cchUsed < ARRAYSIZE(szBonus))
  695. {
  696. CchString(pch, idsEndWinner, ARRAYSIZE(szBonus) - cchUsed);
  697. }
  698. StatStringSz(szBonus);
  699. if(!FGetHdc())
  700. goto ByeNoRel;
  701. Assert(xOrgCur == 0);
  702. Assert(yOrgCur == 0);
  703. GetClientRect(hwndApp, (RECT *)&rcT);
  704. dxp = rcT.xRight;
  705. dyp = rcT.yBot - dyCrd;
  706. for(icrd = icrdFoundMax-1; icrd >= 0; icrd--)
  707. {
  708. for(icol = icolFoundFirst; icol < icolFoundFirst+ccolFound; icol++)
  709. {
  710. ptV.x = rand() % 110 - 65; /* favor up and to left */
  711. if(abs(ptV.x) < 15) /* kludge so doesn't bounce forever */
  712. ptV.x = -20;
  713. ptV.y = rand() % 110 - 75;
  714. pt = (pcrd = &pgm->rgpcol[icol]->rgcrd[icrd])->pt;
  715. while(pt.x > -dxCrd && pt.x < dxp)
  716. {
  717. DrawCardPt(pcrd, &pt);
  718. pt.x += ptV.x/10;
  719. pt.y += ptV.y/10;
  720. ptV.y+= 3;
  721. if(pt.y > dyp && ptV.y > 0)
  722. ptV.y = -(ptV.y*8)/10;
  723. if(FAbort())
  724. goto ByeBye;
  725. }
  726. }
  727. }
  728. ByeBye:
  729. ReleaseHdc();
  730. ByeNoRel:
  731. StatString(idsNil);
  732. EraseScreen();
  733. fKlondWinner = FALSE;
  734. return DefGmProc(pgm, msggWinner, 0, 0);
  735. }
  736. BOOL KlondForceWin(GM *pgm)
  737. {
  738. INT icol;
  739. CRD *pcrd;
  740. COL *pcol;
  741. RA ra;
  742. SU su;
  743. for(icol = 0; icol < pgm->icolMac; icol++)
  744. SendColMsg(pgm->rgpcol[icol], msgcClearCol, 0, 0);
  745. for(su = suFirst, icol = icolFoundFirst; icol < icolFoundFirst+ccolFound; icol++, su++)
  746. {
  747. Assert(raFirst == 0);
  748. for(ra = raFirst; ra < raMax; ra++)
  749. {
  750. pcol = pgm->rgpcol[icol];
  751. pcrd = &pcol->rgcrd[ra];
  752. pcrd->cd = Cd(ra, su);
  753. pcrd->pt.x = pcol->rc.xLeft;
  754. pcrd->pt.y = pcol->rc.yTop;
  755. pcrd->fUp = fTrue;
  756. }
  757. pgm->rgpcol[icol]->icrdMac = icrdFoundMax;
  758. }
  759. Assert(SendGmMsg(pgm, msggIsWinner, 0, 0));
  760. return (BOOL)SendGmMsg(pgm, msggWinner, 0, 0);
  761. }
  762. /* Note: assumes is called once a second */
  763. /* if pcolDest == pcolSrc == NULL, then is a timer msg */
  764. BOOL KlondScore(GM *pgm, COL *pcolDest, COL *pcolSrc)
  765. {
  766. INT cs;
  767. INT tclsSrc, tclsDest;
  768. if(smd == smdNone)
  769. return fTrue;
  770. cs = csNil;
  771. Assert(FValidCol(pcolSrc));
  772. Assert(FValidCol(pcolDest));
  773. tclsSrc = pcolSrc->pcolcls->tcls;
  774. tclsDest = pcolDest->pcolcls->tcls;
  775. switch(tclsDest)
  776. {
  777. default:
  778. return fTrue;
  779. case tclsDeck:
  780. if(tclsSrc == tclsDiscard)
  781. cs = csKlondDeckFlip;
  782. break;
  783. case tclsFound:
  784. switch(tclsSrc)
  785. {
  786. default:
  787. return fTrue;
  788. case tclsDiscard:
  789. case tclsTab:
  790. cs = csKlondFound;
  791. break;
  792. }
  793. break;
  794. case tclsTab:
  795. switch(tclsSrc)
  796. {
  797. default:
  798. return fTrue;
  799. case tclsDiscard:
  800. cs = csKlondTab;
  801. break;
  802. case tclsFound:
  803. cs = csKlondFoundTab;
  804. break;
  805. }
  806. break;
  807. }
  808. SendGmMsg(pgm, msggChangeScore, cs, 0);
  809. return fTrue;
  810. }
  811. INT mpcsdscoStd[] = { -2, -20, 10, 5, 5, -15, 0, 0};
  812. INT mpcsdscoVegas[] = {0, 0, 5, 0, 0, -5, -52, 0};
  813. BOOL KlondChangeScore(GM *pgm, INT cs, INT sco)
  814. {
  815. INT dsco;
  816. INT csNew;
  817. INT *pmpcsdsco;
  818. INT ret;
  819. if(cs < 0)
  820. return DefGmProc(pgm, msggChangeScore, cs, sco);
  821. Assert(FInRange(cs, 0, csKlondMax-1));
  822. switch(smd)
  823. {
  824. default:
  825. Assert(smd == smdNone);
  826. return fTrue;
  827. case smdVegas:
  828. pmpcsdsco = mpcsdscoVegas;
  829. break;
  830. case smdStandard:
  831. pmpcsdsco = mpcsdscoStd;
  832. if(cs == csKlondWin && fTimedGame)
  833. {
  834. #ifdef DEBUG
  835. pgm->iqsecScore = WMax(120, pgm->iqsecScore);
  836. #endif
  837. /* check if timer set properly */
  838. if(pgm->iqsecScore >= 120)
  839. dsco = (20000/(pgm->iqsecScore>>2))*(350/10);
  840. else
  841. dsco = 0;
  842. goto DoScore;
  843. }
  844. if(cs == csKlondDeckFlip)
  845. {
  846. if(ccrdDeal == 1 && pgm->irep >= 1)
  847. {
  848. dsco = -100;
  849. goto DoScore;
  850. }
  851. else if(ccrdDeal == 3 && pgm->irep > 3)
  852. break;
  853. else
  854. return fTrue;
  855. }
  856. break;
  857. }
  858. dsco = pmpcsdsco[cs];
  859. DoScore:
  860. csNew = smd == smdVegas ? csDel : csDelPos;
  861. ret = DefGmProc(pgm, msggChangeScore, csNew, dsco);
  862. if(cs == csKlondWin)
  863. return dsco;
  864. else
  865. return ret;
  866. }
  867. BOOL KlondTimer(GM *pgm, INT wp1, INT wp2)
  868. {
  869. if(fTimedGame && pgm->fDealt && pgm->fInput && !fIconic)
  870. {
  871. pgm->iqsecScore = WMin(pgm->iqsecScore+1, 0x7ffe);
  872. if(pgm->icolSel == icolNil)
  873. SendColMsg(pgm->rgpcol[icolDeck], msgcAnimate, pgm->iqsecScore, 0);
  874. if(pgm->dqsecScore != 0 && (pgm->iqsecScore)%pgm->dqsecScore == 0)
  875. {
  876. SendGmMsg(pgm, msggChangeScore, csKlondTime, 0);
  877. }
  878. else
  879. {
  880. /* update status bar once as second */
  881. if(~(pgm->iqsecScore & 0x03))
  882. StatUpdate();
  883. return fTrue;
  884. }
  885. }
  886. return fFalse;
  887. }
  888. BOOL KlondDrawStatus(GM *pgm, RC *prc)
  889. {
  890. TCHAR *pch;
  891. TCHAR sz[80];
  892. RC rc;
  893. LONG rgb;
  894. BOOL fNegSco;
  895. SIZE iSize;
  896. extern INT iCurrency;
  897. extern TCHAR szCurrency[];
  898. HFONT hFontOld = NULL;
  899. HFONT hStatusFont = NULL;
  900. // store the old font and replace the status font by MS Shell Dlg
  901. // as it supports FE characters as well as euro characters.
  902. hStatusFont = CreateFont(-MulDiv(9, GetDeviceCaps(hdcCur, LOGPIXELSY), 72), 0, 0, 0, FW_BOLD, 0, 0, 0,
  903. DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
  904. DEFAULT_PITCH, TEXT("MS Shell Dlg"));
  905. if (hStatusFont && hdcCur)
  906. hFontOld = SelectObject(hdcCur, hStatusFont);
  907. pch = sz;
  908. if(fTimedGame)
  909. {
  910. pch += CchString(pch, idsTime, ARRAYSIZE(sz));
  911. pch += CchDecodeInt(pch, (pgm->iqsecScore>>2));
  912. }
  913. #ifdef DEBUG
  914. if(!fScreenShots)
  915. {
  916. *pch++ = TEXT(' ');
  917. pch = PszCopy(TEXT("Game # "), pch);
  918. pch += CchDecodeInt(pch, igmCur);
  919. }
  920. #endif
  921. if(pch != sz)
  922. {
  923. DrawText(hdcCur, sz, (INT)(pch-sz), (LPRECT) prc, DT_RIGHT|DT_NOCLIP|DT_SINGLELINE);
  924. }
  925. if(smd != smdNone)
  926. {
  927. rc = *prc;
  928. GetTextExtentPoint32(hdcCur, sz, (INT)(pch-sz), &iSize);
  929. rc.xRight -= iSize.cx;
  930. pch = sz;
  931. if(fNegSco = pgm->sco < 0)
  932. *pch++ = TEXT('-');
  933. if(smd == smdVegas)
  934. {
  935. if(!(iCurrency&1))
  936. {
  937. pch = PszCopy(szCurrency, pch);
  938. if(iCurrency == 2)
  939. *pch++ = TEXT(' ');
  940. }
  941. }
  942. pch += CchDecodeInt(pch, fNegSco ? -pgm->sco : pgm->sco);
  943. if(smd == smdVegas)
  944. {
  945. if(iCurrency&1)
  946. {
  947. if(iCurrency == 3)
  948. *pch++ = TEXT(' ');
  949. pch = PszCopy(szCurrency, pch);
  950. }
  951. }
  952. *pch++ = TEXT(' ');
  953. rgb = SetTextColor(hdcCur, (!fBW && fNegSco) ? RGB(0xff, 0, 0) : RGB(0, 0, 0));
  954. DrawText(hdcCur, sz, (INT)(pch-sz), (LPRECT) &rc, DT_RIGHT|DT_NOCLIP|DT_SINGLELINE);
  955. SetTextColor(hdcCur, rgb);
  956. GetTextExtentPoint32(hdcCur, sz, (INT)(pch-sz), &iSize);
  957. rc.xRight -= iSize.cx;
  958. pch = PszCopy(szScore, sz);
  959. DrawText(hdcCur, sz, (INT)(pch-sz), (LPRECT) &rc, DT_RIGHT|DT_NOCLIP|DT_SINGLELINE);
  960. GetTextExtentPoint32(hdcCur, sz, (INT)(pch-sz), &iSize);
  961. rc.xRight -= iSize.cx;
  962. rc.xLeft = rc.xRight - 4 * dxChar;
  963. PatBlt(hdcCur, rc.xLeft, rc.yTop, rc.xRight-rc.xLeft, rc.yBot-rc.yTop, PATCOPY);
  964. }
  965. // restore the font
  966. if (hFontOld)
  967. SelectObject(hdcCur, hFontOld);
  968. // close the created font handle
  969. if (hStatusFont)
  970. DeleteObject(hStatusFont);
  971. return fTrue;
  972. }
  973. LRESULT KlondGmProc(GM *pgm, INT msgg, WPARAM wp1, LPARAM wp2)
  974. {
  975. switch(msgg)
  976. {
  977. case msggMouseDblClk:
  978. if(DefGmProc(pgm, msggMouseDblClk, wp1, wp2))
  979. return fTrue;
  980. /* fall thru so works for deck double clicks */
  981. case msggMouseDown:
  982. return KlondMouseDown(pgm, (PT *)wp1);
  983. case msggDeal:
  984. return KlondDeal(pgm, (BOOL)wp1);
  985. case msggIsWinner:
  986. return KlondIsWinner(pgm);
  987. case msggWinner:
  988. return KlondWinner(pgm);
  989. case msggForceWin:
  990. return KlondForceWin(pgm);
  991. case msggScore:
  992. return KlondScore(pgm, (COL *) wp1, (COL *)wp2);
  993. case msggChangeScore:
  994. return KlondChangeScore(pgm, (INT)wp1, (INT)wp2);
  995. case msggTimer:
  996. return KlondTimer(pgm, (INT)wp1, (INT)wp2);
  997. case msggDrawStatus:
  998. return KlondDrawStatus(pgm, (RC *) wp1);
  999. }
  1000. return DefGmProc(pgm, msgg, wp1, wp2);
  1001. }