|
|
/**********/ /* mine.c */ /**********/
#define _WINDOWS
#include <windows.h>
#include <port1632.h>
#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(); }
|