windows-nt/Source/XPSP1/NT/shell/osshell/ep/winmine/rtns.c
2020-09-26 16:20:57 +08:00

644 lines
15 KiB
C

/**********/
/* 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();
}