/**********/ /* mine.c */ /**********/ #define _WINDOWS #include #include #include "res.h" #include "main.h" #include "rtns.h" #include "util.h" #include "grafix.h" #include "sound.h" #include "pref.h" /*** External Data ***/ extern HWND hwndMain; /*** Global/Local Variables ***/ PREF Preferences; INT xBoxMac; /* Current width of field */ INT yBoxMac; /* Current height of field */ INT dxWindow; /* current width of window */ INT dyWindow; INT wGameType; /* Type of game */ INT iButtonCur = iButtonHappy; INT cBombStart; /* Count of bombs in field */ INT cBombLeft; /* Count of bomb locations left */ INT cBoxVisit; /* Count of boxes visited */ INT cBoxVisitMac; /* count of boxes need to visit */ INT cSec; /* Count of seconds remaining */ BOOL fTimer = fFalse; BOOL fOldTimerStatus = fFalse; INT xCur = -1; /* Current position of down box */ INT yCur = -1; CHAR rgBlk[cBlkMax]; #define iStepMax 100 INT rgStepX[iStepMax]; INT rgStepY[iStepMax]; INT iStepMac; /*** Global/External Variables ***/ extern BOOL fBlock; extern INT fStatus; /****** F C H E C K W I N ******/ /* Return TRUE if player won the game */ #if 0 BOOL fCheckWin(VOID) { if (cBombLeft) return (fFalse); else return ((cBoxVisit + cBombStart) == (xBoxMac*yBoxMac)); } #else #define fCheckWin() (cBoxVisit == cBoxVisitMac) #endif /****** C H A N G E B L K ******/ VOID ChangeBlk(INT x, INT y, INT iBlk) { SetBlk(x,y, iBlk); DisplayBlk(x,y); } /****** C L E A R F I E L D ******/ VOID ClearField(VOID) { REGISTER i; for (i = cBlkMax; i-- != 0; ) /* zero all of data */ rgBlk[i] = (CHAR) iBlkBlankUp; for (i = xBoxMac+2; i-- != 0; ) /* initialize border */ { SetBorder(i,0); SetBorder(i,yBoxMac+1); } for (i = yBoxMac+2; i-- != 0;) { SetBorder(0,i); SetBorder(xBoxMac+1,i); } } /******* C O U N T B O M B S *******/ /* Count the bombs surrounding the point */ INT CountBombs(INT xCenter, INT yCenter) { REGISTER INT x; REGISTER INT y; INT cBombs = 0; for(y = yCenter-1; y <= yCenter+1; y++) for(x = xCenter-1; x <= xCenter+1; x++) if(fISBOMB(x,y)) cBombs++; return(cBombs); } /****** S H O W B O M B S ******/ /* Display hidden bombs and wrong bomb guesses */ VOID ShowBombs(INT iBlk) { REGISTER INT x; REGISTER INT y; for(y = 1; y <= yBoxMac; y++) { for(x = 1; x <= xBoxMac; x++) { if (!fVISIT(x,y)) { if (fISBOMB(x,y)) { if (!fGUESSBOMB(x,y) ) SetBlk(x,y, iBlk); } else if (fGUESSBOMB(x,y)) SetBlk(x,y, iBlkWrong); } } } DisplayGrid(); } /****** G A M E O V E R ******/ VOID GameOver(BOOL fWinLose) { fTimer = fFalse; DisplayButton(iButtonCur = fWinLose ? iButtonWin : iButtonLose); ShowBombs(fWinLose ? iBlkBombUp : iBlkBombDn); if (fWinLose && (cBombLeft != 0)) UpdateBombCount(-cBombLeft); PlayTune(fWinLose ? TUNE_WINGAME : TUNE_LOSEGAME); SetStatusDemo; if (fWinLose && (Preferences.wGameType != wGameOther) && (cSec < Preferences.rgTime[Preferences.wGameType])) { Preferences.rgTime[Preferences.wGameType] = cSec; DoEnterName(); DoDisplayBest(); } } /****** D O T I M E R ******/ VOID DoTimer(VOID) { if (fTimer && (cSec < 999)) { cSec++; DisplayTime(); PlayTune(TUNE_TICK); } } /****** S T E P X Y ******/ VOID StepXY(INT x, INT y) { INT cBombs; INT iBlk = (y<<5) + x; BLK blk = rgBlk[iBlk]; if ( (blk & MaskVisit) || ((blk &= MaskData) == iBlkMax) || (blk == iBlkBombUp) ) return; cBoxVisit++; rgBlk[iBlk] = (CHAR) (MaskVisit | (cBombs = CountBombs(x,y))); // // SetDIBitsToDevice(hDCCapture, // (x<<4)+(dxGridOff-dxBlk), (y<<4)+(dyGridOff-dyBlk), // dxBlk, dyBlk, 0, 0, 0, dyBlk, // lpDibBlks + rgDibOff[cBombs], // (LPBITMAPINFO) lpDibBlks, DIB_RGB_COLORS); // DisplayBlk(x,y); if (cBombs != 0) return; rgStepX[iStepMac] = x; rgStepY[iStepMac] = y; if (++iStepMac == iStepMax) iStepMac = 0; } /****** S T E P B O X ******/ VOID StepBox(INT x, INT y) { INT iStepCur = 0; iStepMac = 1; StepXY(x,y); if (++iStepCur != iStepMac) while (iStepCur != iStepMac) { x = rgStepX[iStepCur]; y = rgStepY[iStepCur]; StepXY(x-1, --y); StepXY(x, y); StepXY(x+1, y); StepXY(x-1, ++y); StepXY(x+1, y); StepXY(x-1, ++y); StepXY(x, y); StepXY(x+1, y); if (++iStepCur == iStepMax) iStepCur = 0; } } /****** S T E P S Q U A R E ******/ /* Step on a single square */ VOID StepSquare(INT x, INT y) { if (fISBOMB(x,y)) { if (cBoxVisit == 0) { INT xT, yT; for (yT = 1; yT < yBoxMac; yT++) for (xT = 1; xT < xBoxMac; xT++) if (!fISBOMB(xT,yT)) { IBLK(x,y) = (CHAR) iBlkBlankUp; /* Move bomb out of way */ SetBomb(xT, yT); StepBox(x,y); return; } } else { ChangeBlk(x, y, MaskVisit | iBlkExplode); GameOver(fLose); } } else { StepBox(x,y); if (fCheckWin()) GameOver(fWin); } } /******* C O U N T M A R K S *******/ /* Count the bomb marks surrounding the point */ INT CountMarks(INT xCenter, INT yCenter) { REGISTER INT x; REGISTER INT y; INT cBombs = 0; for(y = yCenter-1; y <= yCenter+1; y++) for(x = xCenter-1; x <= xCenter+1; x++) if (fGUESSBOMB(x,y)) cBombs++; return(cBombs); } /****** S T E P B L O C K ******/ /* Step in a block around a single square */ VOID StepBlock(INT xCenter, INT yCenter) { REGISTER INT x; REGISTER INT y; BOOL fGameOver = fFalse; if ( (!fVISIT(xCenter,yCenter)) /* || fGUESSBOMB(xCenter,yCenter) */ || (iBLK(xCenter,yCenter) != CountMarks(xCenter,yCenter)) ) { /* not a safe thing to do */ TrackMouse(-2, -2); /* pop up the blocks */ return; } for(y=yCenter-1; y<=yCenter+1; y++) for(x=xCenter-1; x<=xCenter+1; x++) { if (!fGUESSBOMB(x,y) && fISBOMB(x,y)) { fGameOver = fTrue; ChangeBlk(x, y, MaskVisit | iBlkExplode); } else StepBox(x,y); } if (fGameOver) GameOver(fLose); else if (fCheckWin()) GameOver(fWin); } /****** S T A R T G A M E *******/ VOID StartGame(VOID) { BOOL fAdjust; INT x; INT y; fTimer = fFalse; fAdjust = (Preferences.Width != xBoxMac || Preferences.Height != yBoxMac) ? (fResize | fDisplay) : fDisplay; xBoxMac = Preferences.Width; yBoxMac = Preferences.Height; ClearField(); iButtonCur = iButtonHappy; cBombStart = Preferences.Mines; do { do { x = Rnd(xBoxMac) + 1; y = Rnd(yBoxMac) + 1; } while ( fISBOMB(x,y) ); SetBomb(x,y); } while(--cBombStart); cSec = 0; cBombLeft = cBombStart = Preferences.Mines; cBoxVisit = 0; cBoxVisitMac = (xBoxMac * yBoxMac) - cBombLeft; SetStatusPlay; UpdateBombCount(0); AdjustWindow(fAdjust); } #define fValidStep(x,y) (! (fVISIT(x,y) || fGUESSBOMB(x,y)) ) /****** P U S H B O X ******/ VOID PushBoxDown(INT x, INT y) { BLK iBlk = iBLK(x,y); if (iBlk == iBlkGuessUp) iBlk = iBlkGuessDn; else if (iBlk == iBlkBlankUp) iBlk = iBlkBlank; SetBlk(x,y,iBlk); } /****** P O P B O X U P ******/ VOID PopBoxUp(INT x, INT y) { BLK iBlk = iBLK(x,y); if (iBlk == iBlkGuessDn) iBlk = iBlkGuessUp; else if (iBlk == iBlkBlank) iBlk = iBlkBlankUp; SetBlk(x,y,iBlk); } /****** T R A C K M O U S E ******/ VOID TrackMouse(INT xNew, INT yNew) { if((xNew == xCur) && (yNew == yCur)) return; { INT xOld = xCur; INT yOld = yCur; xCur = xNew; yCur = yNew; if (fBlock) { INT x; INT y; BOOL fValidNew = fInRange(xNew, yNew); BOOL fValidOld = fInRange(xOld, yOld); INT yOldMin = max(yOld-1,1); INT yOldMax = min(yOld+1,yBoxMac); INT yCurMin = max(yCur-1,1); INT yCurMax = min(yCur+1,yBoxMac); INT xOldMin = max(xOld-1,1); INT xOldMax = min(xOld+1,xBoxMac); INT xCurMin = max(xCur-1,1); INT xCurMax = min(xCur+1,xBoxMac); if (fValidOld) for (y=yOldMin; y<=yOldMax; y++) for (x=xOldMin; x<=xOldMax; x++) if (!fVISIT(x,y)) PopBoxUp(x, y); if (fValidNew) for (y=yCurMin; y<=yCurMax; y++) for (x=xCurMin; x<=xCurMax; x++) if (!fVISIT(x,y)) PushBoxDown(x, y); if (fValidOld) for (y=yOldMin; y<=yOldMax; y++) for (x=xOldMin; x<=xOldMax; x++) DisplayBlk(x, y); if (fValidNew) for (y=yCurMin; y<=yCurMax; y++) for (x=xCurMin; x<=xCurMax; x++) DisplayBlk(x, y); } else { if (fInRange(xOld, yOld) && !fVISIT(xOld,yOld) ) { PopBoxUp(xOld, yOld); DisplayBlk(xOld, yOld); } if (fInRange(xNew, yNew) && fValidStep(xNew, yNew)) { PushBoxDown(xCur, yCur); DisplayBlk(xCur, yCur); } } } } /****** M A K E G U E S S ******/ VOID MakeGuess(INT x, INT y) { BLK iBlk; if(fInRange(x,y)) { if(!fVISIT(x,y)) { if(fGUESSBOMB(x,y)) { if (Preferences.fMark) iBlk = iBlkGuessUp; else iBlk = iBlkBlankUp; UpdateBombCount(+1); } else if(fGUESSMARK(x,y)) { iBlk = iBlkBlankUp; } else { iBlk = iBlkBombUp; UpdateBombCount(-1); } ChangeBlk(x,y, iBlk); if (fGUESSBOMB(x,y) && fCheckWin()) GameOver(fWin); } } } /****** D O B U T T O N 1 U P ******/ VOID DoButton1Up(VOID) { if (fInRange(xCur, yCur)) { if ((cBoxVisit == 0) && (cSec == 0)) { PlayTune(TUNE_TICK); cSec++; DisplayTime(); fTimer = fTrue; // Start the timer now. If we had started it earlier, // the interval between tick 1 and 2 is not correct. if (SetTimer(hwndMain, ID_TIMER, 1000 , NULL) == 0) { ReportErr(ID_ERR_TIMER); } } if (!fStatusPlay) xCur = yCur = -2; if (fBlock) StepBlock(xCur, yCur); else if (fValidStep(xCur, yCur)) StepSquare(xCur, yCur); } DisplayButton(iButtonCur); } /****** P A U S E G A M E ******/ VOID PauseGame(VOID) { EndTunes(); // remember the oldtimer status. if (!fStatusPause) fOldTimerStatus = fTimer; if (fStatusPlay) fTimer = fFalse; SetStatusPause; } /****** R E S U M E G A M E ******/ VOID ResumeGame(VOID) { // restore to the old timer status. if (fStatusPlay) fTimer = fOldTimerStatus; ClrStatusPause; } /****** U P D A T E B O M B C O U N T ******/ VOID UpdateBombCount(INT BombAdjust) { cBombLeft += BombAdjust; DisplayBombCount(); }