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.

643 lines
15 KiB

  1. /**********/
  2. /* mine.c */
  3. /**********/
  4. #define _WINDOWS
  5. #include <windows.h>
  6. #include <port1632.h>
  7. #include "res.h"
  8. #include "main.h"
  9. #include "rtns.h"
  10. #include "util.h"
  11. #include "grafix.h"
  12. #include "sound.h"
  13. #include "pref.h"
  14. /*** External Data ***/
  15. extern HWND hwndMain;
  16. /*** Global/Local Variables ***/
  17. PREF Preferences;
  18. INT xBoxMac; /* Current width of field */
  19. INT yBoxMac; /* Current height of field */
  20. INT dxWindow; /* current width of window */
  21. INT dyWindow;
  22. INT wGameType; /* Type of game */
  23. INT iButtonCur = iButtonHappy;
  24. INT cBombStart; /* Count of bombs in field */
  25. INT cBombLeft; /* Count of bomb locations left */
  26. INT cBoxVisit; /* Count of boxes visited */
  27. INT cBoxVisitMac; /* count of boxes need to visit */
  28. INT cSec; /* Count of seconds remaining */
  29. BOOL fTimer = fFalse;
  30. BOOL fOldTimerStatus = fFalse;
  31. INT xCur = -1; /* Current position of down box */
  32. INT yCur = -1;
  33. CHAR rgBlk[cBlkMax];
  34. #define iStepMax 100
  35. INT rgStepX[iStepMax];
  36. INT rgStepY[iStepMax];
  37. INT iStepMac;
  38. /*** Global/External Variables ***/
  39. extern BOOL fBlock;
  40. extern INT fStatus;
  41. /****** F C H E C K W I N ******/
  42. /* Return TRUE if player won the game */
  43. #if 0
  44. BOOL fCheckWin(VOID)
  45. {
  46. if (cBombLeft)
  47. return (fFalse);
  48. else
  49. return ((cBoxVisit + cBombStart) == (xBoxMac*yBoxMac));
  50. }
  51. #else
  52. #define fCheckWin() (cBoxVisit == cBoxVisitMac)
  53. #endif
  54. /****** C H A N G E B L K ******/
  55. VOID ChangeBlk(INT x, INT y, INT iBlk)
  56. {
  57. SetBlk(x,y, iBlk);
  58. DisplayBlk(x,y);
  59. }
  60. /****** C L E A R F I E L D ******/
  61. VOID ClearField(VOID)
  62. {
  63. REGISTER i;
  64. for (i = cBlkMax; i-- != 0; ) /* zero all of data */
  65. rgBlk[i] = (CHAR) iBlkBlankUp;
  66. for (i = xBoxMac+2; i-- != 0; ) /* initialize border */
  67. {
  68. SetBorder(i,0);
  69. SetBorder(i,yBoxMac+1);
  70. }
  71. for (i = yBoxMac+2; i-- != 0;)
  72. {
  73. SetBorder(0,i);
  74. SetBorder(xBoxMac+1,i);
  75. }
  76. }
  77. /******* C O U N T B O M B S *******/
  78. /* Count the bombs surrounding the point */
  79. INT CountBombs(INT xCenter, INT yCenter)
  80. {
  81. REGISTER INT x;
  82. REGISTER INT y;
  83. INT cBombs = 0;
  84. for(y = yCenter-1; y <= yCenter+1; y++)
  85. for(x = xCenter-1; x <= xCenter+1; x++)
  86. if(fISBOMB(x,y))
  87. cBombs++;
  88. return(cBombs);
  89. }
  90. /****** S H O W B O M B S ******/
  91. /* Display hidden bombs and wrong bomb guesses */
  92. VOID ShowBombs(INT iBlk)
  93. {
  94. REGISTER INT x;
  95. REGISTER INT y;
  96. for(y = 1; y <= yBoxMac; y++)
  97. {
  98. for(x = 1; x <= xBoxMac; x++)
  99. {
  100. if (!fVISIT(x,y))
  101. {
  102. if (fISBOMB(x,y))
  103. {
  104. if (!fGUESSBOMB(x,y) )
  105. SetBlk(x,y, iBlk);
  106. }
  107. else if (fGUESSBOMB(x,y))
  108. SetBlk(x,y, iBlkWrong);
  109. }
  110. }
  111. }
  112. DisplayGrid();
  113. }
  114. /****** G A M E O V E R ******/
  115. VOID GameOver(BOOL fWinLose)
  116. {
  117. fTimer = fFalse;
  118. DisplayButton(iButtonCur = fWinLose ? iButtonWin : iButtonLose);
  119. ShowBombs(fWinLose ? iBlkBombUp : iBlkBombDn);
  120. if (fWinLose && (cBombLeft != 0))
  121. UpdateBombCount(-cBombLeft);
  122. PlayTune(fWinLose ? TUNE_WINGAME : TUNE_LOSEGAME);
  123. SetStatusDemo;
  124. if (fWinLose && (Preferences.wGameType != wGameOther)
  125. && (cSec < Preferences.rgTime[Preferences.wGameType]))
  126. {
  127. Preferences.rgTime[Preferences.wGameType] = cSec;
  128. DoEnterName();
  129. DoDisplayBest();
  130. }
  131. }
  132. /****** D O T I M E R ******/
  133. VOID DoTimer(VOID)
  134. {
  135. if (fTimer && (cSec < 999))
  136. {
  137. cSec++;
  138. DisplayTime();
  139. PlayTune(TUNE_TICK);
  140. }
  141. }
  142. /****** S T E P X Y ******/
  143. VOID StepXY(INT x, INT y)
  144. {
  145. INT cBombs;
  146. INT iBlk = (y<<5) + x;
  147. BLK blk = rgBlk[iBlk];
  148. if ( (blk & MaskVisit) ||
  149. ((blk &= MaskData) == iBlkMax) ||
  150. (blk == iBlkBombUp) )
  151. return;
  152. cBoxVisit++;
  153. rgBlk[iBlk] = (CHAR) (MaskVisit | (cBombs = CountBombs(x,y)));
  154. //
  155. // SetDIBitsToDevice(hDCCapture,
  156. // (x<<4)+(dxGridOff-dxBlk), (y<<4)+(dyGridOff-dyBlk),
  157. // dxBlk, dyBlk, 0, 0, 0, dyBlk,
  158. // lpDibBlks + rgDibOff[cBombs],
  159. // (LPBITMAPINFO) lpDibBlks, DIB_RGB_COLORS);
  160. //
  161. DisplayBlk(x,y);
  162. if (cBombs != 0)
  163. return;
  164. rgStepX[iStepMac] = x;
  165. rgStepY[iStepMac] = y;
  166. if (++iStepMac == iStepMax)
  167. iStepMac = 0;
  168. }
  169. /****** S T E P B O X ******/
  170. VOID StepBox(INT x, INT y)
  171. {
  172. INT iStepCur = 0;
  173. iStepMac = 1;
  174. StepXY(x,y);
  175. if (++iStepCur != iStepMac)
  176. while (iStepCur != iStepMac)
  177. {
  178. x = rgStepX[iStepCur];
  179. y = rgStepY[iStepCur];
  180. StepXY(x-1, --y);
  181. StepXY(x, y);
  182. StepXY(x+1, y);
  183. StepXY(x-1, ++y);
  184. StepXY(x+1, y);
  185. StepXY(x-1, ++y);
  186. StepXY(x, y);
  187. StepXY(x+1, y);
  188. if (++iStepCur == iStepMax)
  189. iStepCur = 0;
  190. }
  191. }
  192. /****** S T E P S Q U A R E ******/
  193. /* Step on a single square */
  194. VOID StepSquare(INT x, INT y)
  195. {
  196. if (fISBOMB(x,y))
  197. {
  198. if (cBoxVisit == 0)
  199. {
  200. INT xT, yT;
  201. for (yT = 1; yT < yBoxMac; yT++)
  202. for (xT = 1; xT < xBoxMac; xT++)
  203. if (!fISBOMB(xT,yT))
  204. {
  205. IBLK(x,y) = (CHAR) iBlkBlankUp; /* Move bomb out of way */
  206. SetBomb(xT, yT);
  207. StepBox(x,y);
  208. return;
  209. }
  210. }
  211. else
  212. {
  213. ChangeBlk(x, y, MaskVisit | iBlkExplode);
  214. GameOver(fLose);
  215. }
  216. }
  217. else
  218. {
  219. StepBox(x,y);
  220. if (fCheckWin())
  221. GameOver(fWin);
  222. }
  223. }
  224. /******* C O U N T M A R K S *******/
  225. /* Count the bomb marks surrounding the point */
  226. INT CountMarks(INT xCenter, INT yCenter)
  227. {
  228. REGISTER INT x;
  229. REGISTER INT y;
  230. INT cBombs = 0;
  231. for(y = yCenter-1; y <= yCenter+1; y++)
  232. for(x = xCenter-1; x <= xCenter+1; x++)
  233. if (fGUESSBOMB(x,y))
  234. cBombs++;
  235. return(cBombs);
  236. }
  237. /****** S T E P B L O C K ******/
  238. /* Step in a block around a single square */
  239. VOID StepBlock(INT xCenter, INT yCenter)
  240. {
  241. REGISTER INT x;
  242. REGISTER INT y;
  243. BOOL fGameOver = fFalse;
  244. if ( (!fVISIT(xCenter,yCenter))
  245. /* || fGUESSBOMB(xCenter,yCenter) */
  246. || (iBLK(xCenter,yCenter) != CountMarks(xCenter,yCenter)) )
  247. {
  248. /* not a safe thing to do */
  249. TrackMouse(-2, -2); /* pop up the blocks */
  250. return;
  251. }
  252. for(y=yCenter-1; y<=yCenter+1; y++)
  253. for(x=xCenter-1; x<=xCenter+1; x++)
  254. {
  255. if (!fGUESSBOMB(x,y) && fISBOMB(x,y))
  256. {
  257. fGameOver = fTrue;
  258. ChangeBlk(x, y, MaskVisit | iBlkExplode);
  259. }
  260. else
  261. StepBox(x,y);
  262. }
  263. if (fGameOver)
  264. GameOver(fLose);
  265. else if (fCheckWin())
  266. GameOver(fWin);
  267. }
  268. /****** S T A R T G A M E *******/
  269. VOID StartGame(VOID)
  270. {
  271. BOOL fAdjust;
  272. INT x;
  273. INT y;
  274. fTimer = fFalse;
  275. fAdjust = (Preferences.Width != xBoxMac || Preferences.Height != yBoxMac)
  276. ? (fResize | fDisplay) : fDisplay;
  277. xBoxMac = Preferences.Width;
  278. yBoxMac = Preferences.Height;
  279. ClearField();
  280. iButtonCur = iButtonHappy;
  281. cBombStart = Preferences.Mines;
  282. do
  283. {
  284. do
  285. {
  286. x = Rnd(xBoxMac) + 1;
  287. y = Rnd(yBoxMac) + 1;
  288. }
  289. while ( fISBOMB(x,y) );
  290. SetBomb(x,y);
  291. }
  292. while(--cBombStart);
  293. cSec = 0;
  294. cBombLeft = cBombStart = Preferences.Mines;
  295. cBoxVisit = 0;
  296. cBoxVisitMac = (xBoxMac * yBoxMac) - cBombLeft;
  297. SetStatusPlay;
  298. UpdateBombCount(0);
  299. AdjustWindow(fAdjust);
  300. }
  301. #define fValidStep(x,y) (! (fVISIT(x,y) || fGUESSBOMB(x,y)) )
  302. /****** P U S H B O X ******/
  303. VOID PushBoxDown(INT x, INT y)
  304. {
  305. BLK iBlk = iBLK(x,y);
  306. if (iBlk == iBlkGuessUp)
  307. iBlk = iBlkGuessDn;
  308. else if (iBlk == iBlkBlankUp)
  309. iBlk = iBlkBlank;
  310. SetBlk(x,y,iBlk);
  311. }
  312. /****** P O P B O X U P ******/
  313. VOID PopBoxUp(INT x, INT y)
  314. {
  315. BLK iBlk = iBLK(x,y);
  316. if (iBlk == iBlkGuessDn)
  317. iBlk = iBlkGuessUp;
  318. else if (iBlk == iBlkBlank)
  319. iBlk = iBlkBlankUp;
  320. SetBlk(x,y,iBlk);
  321. }
  322. /****** T R A C K M O U S E ******/
  323. VOID TrackMouse(INT xNew, INT yNew)
  324. {
  325. if((xNew == xCur) && (yNew == yCur))
  326. return;
  327. {
  328. INT xOld = xCur;
  329. INT yOld = yCur;
  330. xCur = xNew;
  331. yCur = yNew;
  332. if (fBlock)
  333. {
  334. INT x;
  335. INT y;
  336. BOOL fValidNew = fInRange(xNew, yNew);
  337. BOOL fValidOld = fInRange(xOld, yOld);
  338. INT yOldMin = max(yOld-1,1);
  339. INT yOldMax = min(yOld+1,yBoxMac);
  340. INT yCurMin = max(yCur-1,1);
  341. INT yCurMax = min(yCur+1,yBoxMac);
  342. INT xOldMin = max(xOld-1,1);
  343. INT xOldMax = min(xOld+1,xBoxMac);
  344. INT xCurMin = max(xCur-1,1);
  345. INT xCurMax = min(xCur+1,xBoxMac);
  346. if (fValidOld)
  347. for (y=yOldMin; y<=yOldMax; y++)
  348. for (x=xOldMin; x<=xOldMax; x++)
  349. if (!fVISIT(x,y))
  350. PopBoxUp(x, y);
  351. if (fValidNew)
  352. for (y=yCurMin; y<=yCurMax; y++)
  353. for (x=xCurMin; x<=xCurMax; x++)
  354. if (!fVISIT(x,y))
  355. PushBoxDown(x, y);
  356. if (fValidOld)
  357. for (y=yOldMin; y<=yOldMax; y++)
  358. for (x=xOldMin; x<=xOldMax; x++)
  359. DisplayBlk(x, y);
  360. if (fValidNew)
  361. for (y=yCurMin; y<=yCurMax; y++)
  362. for (x=xCurMin; x<=xCurMax; x++)
  363. DisplayBlk(x, y);
  364. }
  365. else
  366. {
  367. if (fInRange(xOld, yOld) && !fVISIT(xOld,yOld) )
  368. {
  369. PopBoxUp(xOld, yOld);
  370. DisplayBlk(xOld, yOld);
  371. }
  372. if (fInRange(xNew, yNew) && fValidStep(xNew, yNew))
  373. {
  374. PushBoxDown(xCur, yCur);
  375. DisplayBlk(xCur, yCur);
  376. }
  377. }
  378. }
  379. }
  380. /****** M A K E G U E S S ******/
  381. VOID MakeGuess(INT x, INT y)
  382. {
  383. BLK iBlk;
  384. if(fInRange(x,y))
  385. {
  386. if(!fVISIT(x,y))
  387. {
  388. if(fGUESSBOMB(x,y))
  389. {
  390. if (Preferences.fMark)
  391. iBlk = iBlkGuessUp;
  392. else
  393. iBlk = iBlkBlankUp;
  394. UpdateBombCount(+1);
  395. }
  396. else if(fGUESSMARK(x,y))
  397. {
  398. iBlk = iBlkBlankUp;
  399. }
  400. else
  401. {
  402. iBlk = iBlkBombUp;
  403. UpdateBombCount(-1);
  404. }
  405. ChangeBlk(x,y, iBlk);
  406. if (fGUESSBOMB(x,y) && fCheckWin())
  407. GameOver(fWin);
  408. }
  409. }
  410. }
  411. /****** D O B U T T O N 1 U P ******/
  412. VOID DoButton1Up(VOID)
  413. {
  414. if (fInRange(xCur, yCur))
  415. {
  416. if ((cBoxVisit == 0) && (cSec == 0))
  417. {
  418. PlayTune(TUNE_TICK);
  419. cSec++;
  420. DisplayTime();
  421. fTimer = fTrue;
  422. // Start the timer now. If we had started it earlier,
  423. // the interval between tick 1 and 2 is not correct.
  424. if (SetTimer(hwndMain, ID_TIMER, 1000 , NULL) == 0)
  425. {
  426. ReportErr(ID_ERR_TIMER);
  427. }
  428. }
  429. if (!fStatusPlay)
  430. xCur = yCur = -2;
  431. if (fBlock)
  432. StepBlock(xCur, yCur);
  433. else
  434. if (fValidStep(xCur, yCur))
  435. StepSquare(xCur, yCur);
  436. }
  437. DisplayButton(iButtonCur);
  438. }
  439. /****** P A U S E G A M E ******/
  440. VOID PauseGame(VOID)
  441. {
  442. EndTunes();
  443. // remember the oldtimer status.
  444. if (!fStatusPause)
  445. fOldTimerStatus = fTimer;
  446. if (fStatusPlay)
  447. fTimer = fFalse;
  448. SetStatusPause;
  449. }
  450. /****** R E S U M E G A M E ******/
  451. VOID ResumeGame(VOID)
  452. {
  453. // restore to the old timer status.
  454. if (fStatusPlay)
  455. fTimer = fOldTimerStatus;
  456. ClrStatusPause;
  457. }
  458. /****** U P D A T E B O M B C O U N T ******/
  459. VOID UpdateBombCount(INT BombAdjust)
  460. {
  461. cBombLeft += BombAdjust;
  462. DisplayBombCount();
  463. }