// MineGameDlg.cpp : implementation file // #include "stdafx.h" #include "MineGame.h" #include "MineGameDlg.h" #include "DlgNewRecord.h" #include "HeroDlg.h" #include "ustomDlg.h" #include "Mmsystem.h" #include "CustomDlg.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////////// // CAboutDlg dialog used for App About #define ID_TIMER_EVENT WM_USER + 1 class CAboutDlg : public CDialog { public: CAboutDlg(); // Dialog Data //{{AFX_DATA(CAboutDlg) enum { IDD = IDD_ABOUTBOX }; //}}AFX_DATA // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CAboutDlg) protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support //}}AFX_VIRTUAL // Implementation protected: //{{AFX_MSG(CAboutDlg) //}}AFX_MSG DECLARE_MESSAGE_MAP() }; CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD) { //{{AFX_DATA_INIT(CAboutDlg) //}}AFX_DATA_INIT } void CAboutDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CAboutDlg) //}}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(CAboutDlg, CDialog) //{{AFX_MSG_MAP(CAboutDlg) // No message handlers //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CMineGameDlg dialog CMineGameDlg::CMineGameDlg(CWnd* pParent /*=NULL*/) : CDialog(CMineGameDlg::IDD, pParent) { //{{AFX_DATA_INIT(CMineGameDlg) // NOTE: the ClassWizard will add member initialization here //}}AFX_DATA_INIT m_uPrimary = DEFAULT_RECORD; m_szPrimary = "无"; m_uSecond = DEFAULT_RECORD; m_szSecond = "无"; m_uAdvance = DEFAULT_RECORD; m_szAdvance = "无"; QueryRecord("Primary",m_szPrimary,m_uPrimary); QueryRecord("Second",m_szSecond,m_uSecond); QueryRecord("Advance",m_szAdvance,m_uAdvance); m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); m_brBack.CreateSolidBrush(COLOR_GRAY); m_bmpFace.LoadBitmap(IDB_FACE_COLOR); m_uBtnState = FACE_NORMAL; m_bmpNumber.LoadBitmap(IDB_NUM_COLOR); m_bmpMine.LoadBitmap(IDB_MINE_COLOR); m_bColorful = true; m_uYNum = PRIMARY_XNUM; m_uXNum = PRIMARY_YNUM; m_uMineNum = PRIMARY_MINENUM; m_uLevel = LEVEL_CUSTOM; m_bSoundful = true; LoadWaveSrc(); } void CMineGameDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CMineGameDlg) // NOTE: the ClassWizard will add DDX and DDV calls here //}}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(CMineGameDlg, CDialog) //{{AFX_MSG_MAP(CMineGameDlg) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON() ON_WM_LBUTTONDOWN() ON_WM_LBUTTONUP() ON_WM_ERASEBKGND() ON_WM_TIMER() ON_WM_ACTIVATE() ON_WM_RBUTTONDOWN() ON_WM_RBUTTONUP() ON_COMMAND(IDM_PRIMARY, OnPrimary) ON_COMMAND(IDM_SECOND, OnSecond) ON_COMMAND(IDM_ADVANCE, OnAdvance) ON_COMMAND(IDM_CUSTOM, OnCustom) ON_COMMAND(IDM_START, OnStart) ON_WM_INITMENU() ON_COMMAND(IDM_COLOR, OnColor) ON_COMMAND(IDM_ABOUT, OnAbout) ON_COMMAND(IDM_HELP_USE, OnHelpUse) ON_COMMAND(IDM_HERO, OnHero) ON_COMMAND(IDM_SOUND, OnSound) ON_WM_MOUSEMOVE() ON_COMMAND(IDM_EXIT, OnExit) //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CMineGameDlg message handlers BOOL CMineGameDlg::OnInitDialog() { CDialog::OnInitDialog(); // Add "About..." menu item to system menu. // IDM_ABOUTBOX must be in the system command range. ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); ASSERT(IDM_ABOUTBOX < 0xF000); CMenu* pSysMenu = GetSystemMenu(FALSE); if (pSysMenu != NULL) { CString strAboutMenu; strAboutMenu.LoadString(IDS_ABOUTBOX); if (!strAboutMenu.IsEmpty()) { pSysMenu->AppendMenu(MF_SEPARATOR); pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); } } // Set the icon for this dialog. The framework does this automatically // when the application's main window is not a dialog SetIcon(m_hIcon, TRUE); // Set big icon SetIcon(m_hIcon, FALSE); // Set small icon // TODO: Add extra initialization here m_nLeaveNum = m_uMineNum; m_uSpendTime = 0; ReSizeWindow(); LayMines(m_uXNum, m_uYNum); m_uGameState = GS_WAIT; InitGame(); HKEY hKey; LPCTSTR data_Set = "Software\\MineGame\\Record"; long ret0 = (::RegOpenKeyEx(HKEY_CURRENT_USER, data_Set, 0, KEY_READ, &hKey)); if(ret0 != ERROR_SUCCESS) { ::RegCloseKey(hKey); if(RegCreateKey(HKEY_CURRENT_USER,data_Set,&hKey) != ERROR_SUCCESS) MessageBox("error"); } ::RegCloseKey(hKey); return TRUE; // return TRUE unless you set the focus to a control } void CMineGameDlg::ReSizeWindow() { UINT uWidth = DEFAULT_FRAME_X + m_uXNum * MINE_WIDTH + LINE_WIDTH_0 * 3 + SIDE_WIDTH_0 + SIDE_WIDTH_1; UINT uHeight = DEFAULT_FRAME_Y + m_uYNum * MINE_HEIGHT + LINE_WIDTH_0 * 3 + SIDE_WIDTH_0 * 2 + SIDE_WIDTH_1 + SHELL_S_H; SetWindowPos(&wndTopMost, 0, 0, uWidth, uHeight, SWP_NOZORDER | SWP_NOMOVE | SWP_NOCOPYBITS); // SWP_NOCOPYBITS does not do function??? GetClientRect(&m_rcClient); // Button Position m_uBtnRect[0] = m_rcClient.right / 2 - 12; // the left side of the start(state) button without 3d border m_uBtnRect[1] = m_rcClient.right / 2 - 13; // the left side of the start(state) button with 3d border m_uBtnRect[2] = m_rcClient.right / 2 + 12; // the right side of the start(state) button // Number Position m_uNumRect[0] = m_rcClient.right - 55; // the left side of the spend time rect with 3d border m_uNumRect[1] = m_rcClient.right - 15; // the right side of the spend time rect m_uNumRect[2] = m_rcClient.right - 54; // the left side of the spend time rect without 3d border // Shell Position m_uShellRcX[0] = m_rcClient.right; // m_uShellRcX[1] = m_rcClient.right - 14; // the width of the small(big) shell m_uShellRcY[0] = m_rcClient.bottom; // m_uShellRcY[1] = m_rcClient.bottom - SHELL_L_START_Y - 5; // the height of the big shell } void CMineGameDlg::OnSysCommand(UINT nID, LPARAM lParam) { if ((nID & 0xFFF0) == IDM_ABOUTBOX) { CAboutDlg dlgAbout; dlgAbout.DoModal(); } else { CDialog::OnSysCommand(nID, lParam); } } // If you add a minimize button to your dialog, you will need the code below // to draw the icon. For MFC applications using the document/view model, // this is automatically done for you by the framework. void CMineGameDlg::OnPaint() { CPaintDC dc(this); // 用以屏幕显示的设备 if (IsIconic()) { CPaintDC dc(this); // device context for painting SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0); // Center icon in client rectangle int cxIcon = GetSystemMetrics(SM_CXICON); int cyIcon = GetSystemMetrics(SM_CYICON); CRect rect; GetClientRect(&rect); int x = (rect.Width() - cxIcon + 1) / 2; int y = (rect.Height() - cyIcon + 1) / 2; // Draw the icon dc.DrawIcon(x, y, m_hIcon); } else { CDC dcMemory; // 内存设备 CBitmap bitmap; if (!dc.IsPrinting()) { // 与dc设备兼容 if (dcMemory.CreateCompatibleDC(&dc)) { // 使得bitmap与实际显示的设备兼容 if (bitmap.CreateCompatibleBitmap(&dc, m_rcClient.right, m_rcClient.bottom)) { // 内存设备选择物件-位图 dcMemory.SelectObject(&bitmap); //绘制背景框 dcMemory.FillRect(&m_rcClient, &m_brBack); DrawStartButton((CPaintDC&) dcMemory);//笑脸按钮绘图 DrawNumber((CPaintDC&) dcMemory);//文字绘图(计时器文字和剩余雷数文字) DrawShell((CPaintDC&) dcMemory);//3D效果外壳绘图 DrawMineArea((CPaintDC&) dcMemory);//雷区绘图 // 将内存设备的内容拷贝到实际屏幕显示的设备 dc.BitBlt(m_rcClient.left, m_rcClient.top, m_rcClient.right, m_rcClient.bottom, &dcMemory, 0, 0, SRCCOPY); bitmap.DeleteObject(); } } } } } void CMineGameDlg::DrawStartButton(CPaintDC &dc) { CDC cdc; cdc.CreateCompatibleDC(&dc); cdc.SelectObject(m_bmpFace); dc.StretchBlt(m_uBtnRect[0], 16, 24, 24, &cdc, 0, 24 * m_uBtnState, 24, 24, SRCCOPY); dc.Draw3dRect(m_uBtnRect[1], 15, 26, 26, m_clrDark, m_clrDark); } void CMineGameDlg::DrawNumber(CPaintDC &dc) { CDC dcMemory; //内存设备 dcMemory.CreateCompatibleDC(&dc); //创建设备兼容性 dcMemory.SelectObject(m_bmpNumber); //载入数字位图 //绘制剩余雷数的3D边框 dc.Draw3dRect(16, 15, 41, 25, m_clrDark, COLOR_WHITE); //绘制游戏时间显示区域的3D边框 dc.Draw3dRect(m_uNumRect[0], 15, 41, 25, m_clrDark, COLOR_WHITE); int num; //绘制剩余的雷数 num = (m_nLeaveNum<0) ? 11 : m_nLeaveNum/100; dc.StretchBlt(17, 16, 13, 23, &dcMemory, 0, 276-23*(num+1), 13, 23, SRCCOPY); num = (m_nLeaveNum < 0) ? (-m_nLeaveNum%100)/10 : (m_nLeaveNum%100)/10; dc.StretchBlt(30, 16, 13, 23, &dcMemory, 0, 276-23*(num+1), 13, 23, SRCCOPY); num = (m_nLeaveNum<=0) ? -m_nLeaveNum%10 : m_nLeaveNum%10; dc.StretchBlt(43, 16, 13, 23, &dcMemory, 0, 276-23*(num+1), 13, 23, SRCCOPY); // 绘制游戏时间 num = m_uSpendTime / 100; dc.StretchBlt(m_uNumRect[0], 16, 13, 23, &dcMemory, 0, 276-23*(num+1), 13, 23, SRCCOPY); num = (m_uSpendTime-num*100)/10; dc.StretchBlt(m_uNumRect[0] + 13, 16, 13, 23, &dcMemory, 0, 276-23*(num+1), 13, 23, SRCCOPY); num = m_uSpendTime%10; dc.StretchBlt(m_uNumRect[0]+26, 16, 13, 23, &dcMemory, 0, 276-23*(num+1), 13, 23, SRCCOPY); } void CMineGameDlg::DrawShell(CPaintDC &dc) { // 绘画2条白条 dc.FillSolidRect(0, 0, m_uShellRcX[0], LINE_WIDTH_0, COLOR_WHITE); dc.FillSolidRect(0, 0, LINE_WIDTH_0, m_uShellRcY[0], COLOR_WHITE); // 画小的外壳 dc.Draw3dRect(SHELL_S_START_X, SHELL_S_START_Y, m_uShellRcX[1], SHELL_S_H, m_clrDark, COLOR_WHITE); dc.Draw3dRect(SHELL_S_START_X + 1, SHELL_S_START_Y + 1, m_uShellRcX[1] - 2, SHELL_S_H - 2, m_clrDark, COLOR_WHITE); // 画大的外壳 dc.Draw3dRect(SHELL_L_START_X, SHELL_L_START_Y, m_uShellRcX[1], m_uShellRcY[1], m_clrDark, COLOR_WHITE); dc.Draw3dRect(SHELL_L_START_X + 1, SHELL_L_START_Y + 1, m_uShellRcX[1] - 2, m_uShellRcY[1] - 2, m_clrDark, COLOR_WHITE); dc.Draw3dRect(SHELL_L_START_X + 2, SHELL_L_START_Y + 2, m_uShellRcX[1] - 4, m_uShellRcY[1] - 4, m_clrDark, COLOR_WHITE); } void CMineGameDlg::DrawMineArea(CPaintDC &dc) { CDC dcMemory; //用作内存设备 dcMemory.CreateCompatibleDC(&dc); //使得这个设备与dc兼容 dcMemory.SelectObject(m_bmpMine); //将内存设备与位图资源关联 for (UINT i = 0; iuState == STATE_NORMAL) { m_pNewMine->uState = STATE_EMPTY; } if (m_pNewMine->uState == STATE_DICEY) { m_pNewMine->uState = STATE_DICEY_DOWN; } m_pOldMine = m_pNewMine; break; case GS_DEAD: case GS_VICTORY: return; break; default : break; } m_uBtnState = FACE_CLICK; InvalidateRect(rcBtn); // both of the left button and the right button are pushing down if (nFlags == (MK_LBUTTON | MK_RBUTTON)) { m_bLRBtnDown = TRUE; OnLRBtnDown(m_pOldMine->uRow, m_pOldMine->uCol); } InvalidateRect(rcMineArea); } else { // click in other area if (m_uGameState == GS_WAIT || m_uGameState == GS_RUN) { m_uBtnState = FACE_CLICK; InvalidateRect(rcBtn); } } CDialog::OnLButtonDown(nFlags, point); } void CMineGameDlg::OnLButtonUp(UINT nFlags, CPoint point) { //笑脸图按钮所在的区域 CRect rcBtn(m_uBtnRect[1], 15, m_uBtnRect[2], 39); //雷区所在的区域 CRect rcMineArea(MINE_AREA_LEFT, MINE_AREA_TOP, MINE_AREA_LEFT + m_uXNum * MINE_WIDTH, MINE_AREA_TOP + m_uYNum * MINE_HEIGHT); if (rcBtn.PtInRect(point)) {// 点击笑脸图 Invalidate(); InitGame(); } else if (rcMineArea.PtInRect(point)) {//点击雷区域 CString value; UINT around = 0; //根据不同的游戏状态作处理 switch(m_uGameState) { //游戏进行状态 case GS_WAIT: case GS_RUN: // first get the MINEWND which if pushing down m_pOldMine = GetMine(point.x, point.y); if (!m_pOldMine) { ReleaseCapture(); return; } // do normal process // judge whether the lr button are both pushed down //检测判断当前状态是否为左右鼠标同时按下 if (m_bLRBtnDown) { m_bLRBtnDown = FALSE; OnLRBtnUp(m_pOldMine->uRow, m_pOldMine->uCol); if (m_uGameState == GS_WAIT) { m_uBtnState = FACE_NORMAL; Invalidate(); ReleaseCapture(); return; } // if the around flags number equal to the around mines number, expand. //假若周围已经标识的雷=周围真正的雷数,拓展 if (m_pOldMine->uState != STATE_FLAG) { OpenAround(m_pOldMine->uRow, m_pOldMine->uCol); } // check whether the MINEWND around the special MINEWND is a mine, if it is then dead. if (ErrorAroundFlag(m_pOldMine->uRow, m_pOldMine->uCol)) { Dead(m_pOldMine->uRow, m_pOldMine->uCol); ReleaseCapture(); return; } } else { // start the game, init the mines area //如果游戏尚未开始,点击左键启动游戏 if (m_uGameState == GS_WAIT) { if (m_uTimer) { KillTimer(ID_TIMER_EVENT); m_uTimer = 0; } // the following five lines refresh the remining mine num rect immediately // when click in the mine area at the first time m_uSpendTime = 1; Invalidate(); if (m_bSoundful) { sndPlaySound((LPCTSTR)LockResource(m_pSndClock), SND_MEMORY | SND_ASYNC | SND_NODEFAULT); } //启动定时器 m_uTimer = SetTimer(ID_TIMER_EVENT, 1000, NULL); //布雷 LayMines(m_pOldMine->uRow, m_pOldMine->uCol); // lay all the mines down //改变游戏状态为"运行/GS_RUN" m_uGameState = GS_RUN; } if (m_pOldMine->uOldState == STATE_NORMAL) {//当该雷区域为正常未作标记才打开 // first judge if the special MINEWND is a mine //如果该区域为雷,则死亡 if (IsMine(m_pOldMine->uRow, m_pOldMine->uCol)) { Dead(m_pOldMine->uRow, m_pOldMine->uCol); ReleaseCapture(); return; } // the special MINEWND is not a mine //不是雷的时候,获取其周围的雷数目 around = GetAroundNum(m_pOldMine->uRow, m_pOldMine->uCol); // 如果为空白区域,拓展,否则打开该区域(显示周围有多少雷数) if (around == 0) ExpandMines(m_pOldMine->uRow, m_pOldMine->uCol); else DrawDownNum(m_pOldMine, around); } else if (m_pOldMine->uOldState == STATE_DICEY) {//标志为“?”问号的时候 m_pOldMine->uState = STATE_DICEY; } //判断是否为胜利 if (Victory()) { Invalidate(); ReleaseCapture(); return; } } break; case GS_VICTORY: case GS_DEAD: ReleaseCapture(); // release the cursor return; default : break; } m_uBtnState = FACE_NORMAL; Invalidate(); } else {//点击非雷区域 if (m_uGameState == GS_WAIT || m_uGameState == GS_RUN) { m_uBtnState = FACE_NORMAL; InvalidateRect(rcBtn); } } ReleaseCapture(); // release the cursor CDialog::OnLButtonUp(nFlags, point); } HMINEWND CMineGameDlg::GetMine(long x, long y) { //保证参数合格 if (x < MINEAREA_FRAME_X || y < MINEAREA_FRAME_Y) { return NULL; } //根据坐标值算出该小方块所在地图的行和列 UINT uCol = (UINT)(x-MINEAREA_FRAME_X) / 16; UINT uRow = (UINT)(y-MINEAREA_FRAME_Y) / 16; //返回该区域的雷信息 return &m_pMines[uRow][uCol]; } void CMineGameDlg::OnLRBtnDown(UINT row, UINT col) { UINT i, j; UINT minRow = (row == 0) ? 0 : row - 1; UINT maxRow = (row == m_uXNum) ? m_uXNum: row + 1; UINT minCol = (col == 0) ? 0 : col - 1; UINT maxCol = (col == m_uYNum) ? m_uYNum: col + 1; for (i = minRow; i <= maxRow; i++) { for (j = minCol; j <= maxCol; j++) { if (m_pMines[i][j].uState == STATE_NORMAL) { m_pMines[i][j].uState = STATE_EMPTY; } else if (m_pMines[i][j].uState == STATE_DICEY) { m_pMines[i][j].uState = STATE_DICEY_DOWN; } } } } void CMineGameDlg::OnLRBtnUp(UINT row, UINT col) { UINT i, j; UINT minRow = (row == 0) ? 0 : row - 1; UINT maxRow = (row == m_uXNum) ? m_uXNum: row + 1; UINT minCol = (col == 0) ? 0 : col - 1; UINT maxCol = (col == m_uYNum) ? m_uYNum: col + 1; for (i = minRow; i <= maxRow; i++) { for (j = minCol; j <= maxCol; j++) { if (m_pMines[i][j].uOldState == STATE_NORMAL) { m_pMines[i][j].uState = STATE_NORMAL; } else if (m_pMines[i][j].uOldState == STATE_DICEY) { m_pMines[i][j].uState = STATE_DICEY; } } } } void CMineGameDlg::OpenAround(UINT row, UINT col) { if (GetAroundFlags(row, col) != GetAroundNum(row, col)) return; UINT i, j; UINT around = 0; UINT minRow = (row == 0) ? 0 : row - 1; UINT maxRow = row + 2; UINT minCol = (col == 0) ? 0 : col - 1; UINT maxCol = col + 2; for (i = minRow; i < maxRow; i++) { for (j = minCol; j < maxCol; j++) { if (!IsInMineArea(i, j)) continue; if (m_pMines[i][j].uState == STATE_NORMAL) {//如果该区域为正常区域 //拓展该雷区 ExpandMines(i, j); around = GetAroundNum(i, j); m_pMines[i][j].uState = 15 - around; m_pMines[i][j].uOldState = 15 - around; } } } // 判断是否胜利,是则将地图中所有雷标识出来 if (Victory()) { for (i = 0; i < m_uYNum; i++) { for (j = 0; j < m_uXNum; j++) { if (m_pMines[i][j].uAttrib == ATTRIB_MINE) { m_pMines[i][j].uState = STATE_FLAG; m_pMines[i][j].uOldState = STATE_FLAG; } } } m_nLeaveNum = 0; Invalidate(); } } BOOL CMineGameDlg::ErrorAroundFlag(UINT row, UINT col) { if (GetAroundFlags(row, col) != GetAroundNum(row, col)) return FALSE; UINT i, j; UINT minRow = (row == 0) ? 0 : row - 1; UINT maxRow = row + 2; UINT minCol = (col == 0) ? 0 : col - 1; UINT maxCol = col + 2; for (i = minRow; i < maxRow; i++) { for (j = minCol; j < maxCol; j++) { if (!IsInMineArea(i, j)) continue; if (m_pMines[i][j].uState == STATE_FLAG) { if (m_pMines[i][j].uAttrib != ATTRIB_MINE) { Dead(i, j); return TRUE; } } } } return FALSE; } void CMineGameDlg::Dead(UINT row, UINT col) { //按钮所在的区域 CRect rcBtn(m_uBtnRect[1], 15, m_uBtnRect[2], 39); //雷区所在的区域 CRect rcMineArea(MINE_AREA_LEFT, MINE_AREA_TOP, MINE_AREA_LEFT + m_uXNum * MINE_WIDTH, MINE_AREA_TOP + m_uYNum * MINE_HEIGHT); UINT i, j; if (m_pMines[row][col].uAttrib == ATTRIB_MINE) {//失败--点中雷 for (i = 0; i < m_uYNum; i++) { for (j = 0; j < m_uXNum; j++) { m_pMines[row][col].uState = STATE_BLAST; m_pMines[row][col].uOldState = STATE_BLAST; if (m_pMines[i][j].uAttrib == ATTRIB_MINE && m_pMines[i][j].uState != STATE_FLAG) { m_pMines[i][j].uState = STATE_MINE; m_pMines[i][j].uOldState = STATE_MINE; } } } } else {//失败--错误雷 for (i = 0; i < m_uYNum; i++) { for (j = 0; j < m_uXNum; j++) { m_pMines[row][col].uState = STATE_ERROR; m_pMines[row][col].uOldState = STATE_ERROR; if (m_pMines[i][j].uAttrib == ATTRIB_MINE && m_pMines[i][j].uState != STATE_FLAG) { m_pMines[i][j].uState = STATE_MINE; m_pMines[i][j].uOldState = STATE_MINE; } } } } //失败处理 InvalidateRect(rcMineArea); m_uBtnState = FACE_DEAD; InvalidateRect(rcBtn); m_uGameState = GS_DEAD; if (m_uTimer != 0) {//将定时器去激活 KillTimer(ID_TIMER_EVENT); m_uTimer = 0; } if (m_bSoundful) {//失败声音播放 sndPlaySound((LPCTSTR)LockResource(m_pSndDead), SND_MEMORY | SND_ASYNC | SND_NODEFAULT); } } bool CMineGameDlg::IsMine(UINT row, UINT col) { return (m_pMines[row][col].uAttrib == ATTRIB_MINE); } UINT CMineGameDlg::GetAroundNum(UINT row, UINT col) { UINT i, j; UINT around = 0; UINT minRow = (row == 0) ? 0 : row - 1; UINT maxRow = row + 2; UINT minCol = (col == 0) ? 0 : col - 1; UINT maxCol = col + 2; for (i = minRow; i < maxRow; i++) { for (j = minCol; j < maxCol; j++) { if (!IsInMineArea(i, j)) continue; if (m_pMines[i][j].uAttrib == ATTRIB_MINE) around++; } } return around; } void CMineGameDlg::ExpandMines(UINT row, UINT col) { UINT i, j; UINT minRow = (row == 0) ? 0 : row - 1; UINT maxRow = row + 2; UINT minCol = (col == 0) ? 0 : col - 1; UINT maxCol = col + 2; UINT around = GetAroundNum(row, col); m_pMines[row][col].uState = 15 - around; m_pMines[row][col].uOldState = 15 - around; // “打开”该区域,重绘 DrawSpecialMine(row, col); //对周围一个雷都没有的空白区域 if (around == 0) { for (i = minRow; i < maxRow; i++) { for (j = minCol; j < maxCol; j++) {//对于周围可以拓展的区域进行的规拓展 if (!(i == row && j == col) && m_pMines[i][j].uState == STATE_NORMAL && m_pMines[i][j].uAttrib != ATTRIB_MINE) { if (!IsInMineArea(i, j)) continue; ExpandMines(i, j); } } } } } void CMineGameDlg::DrawDownNum(MINEWND *mine, UINT num) { mine->uState = 15 - num; mine->uOldState = 15 - num; CRect rcMine(mine->uCol * 16, mine->uRow * 16, (mine->uCol+1) *16, (mine->uRow+1) * 16); InvalidateRect(rcMine); } bool CMineGameDlg::Victory() { UINT i, j; CRect rcBtn(m_uBtnRect[1], 15, m_uBtnRect[2], 39); // 检测是否胜利 for (i = 0; i < m_uYNum; i++) { for (j = 0; j < m_uXNum; j++) { if (m_pMines[i][j].uState == STATE_NORMAL) return FALSE; if (m_pMines[i][j].uState == STATE_DICEY) return FALSE; } } //胜利则作胜利处理 m_uBtnState = FACE_VICTORY; m_uGameState = GS_VICTORY; Invalidate(); if (m_uTimer != 0) {//将定时器去激活 KillTimer(ID_TIMER_EVENT); m_uTimer = 0; } //胜利声音 if (m_bSoundful) { sndPlaySound((LPCTSTR)LockResource(m_pSndVictory), SND_MEMORY | SND_ASYNC | SND_NODEFAULT); } //英雄榜 UINT uRecord; if (m_uLevel == LEVEL_PRIMARY) uRecord = m_uPrimary; else if (m_uLevel == LEVEL_SECONDRY) uRecord = m_uSecond; else if (m_uLevel == LEVEL_ADVANCE) uRecord = m_uAdvance; if (uRecord > m_uSpendTime) { CDlgNewRecord dlg; dlg.InitLevel(m_uLevel); dlg.DoModal(); switch(m_uLevel) { case LEVEL_PRIMARY: m_uPrimary = m_uSpendTime; m_szPrimary = dlg.m_name; SetRecord("Primary",dlg.m_name,m_uSpendTime); break; case LEVEL_SECONDRY: m_uSecond = m_uSpendTime; m_szSecond = dlg.m_name; SetRecord("Second",dlg.m_name,m_uSpendTime); break; case LEVEL_ADVANCE: m_uAdvance = m_uSpendTime; m_szAdvance = dlg.m_name; SetRecord("Advance",dlg.m_name,m_uSpendTime); break; case LEVEL_CUSTOM: return TRUE; default: break; } OnHero(); } return TRUE; } bool CMineGameDlg::IsInMineArea(UINT row, UINT col) { return (row >= 0 && row < m_uYNum && col >= 0 && col < m_uXNum); } UINT CMineGameDlg::GetAroundFlags(UINT row, UINT col) { UINT i, j; UINT flags = 0; UINT minRow = (row == 0) ? 0 : row - 1; UINT maxRow = row + 2; UINT minCol = (col == 0) ? 0 : col - 1; UINT maxCol = col + 2; for (i = minRow; i < maxRow; i++) { for (j = minCol; j < maxCol; j++) { if (!IsInMineArea(i, j)) continue; if (m_pMines[i][j].uState == STATE_FLAG) flags++; } } return flags; } void CMineGameDlg::DrawSpecialMine(UINT row, UINT col) { CRect rcMine(col * 16, row * 16, (col+1) * 16, (row+1) * 16); InvalidateRect(rcMine); } BOOL CMineGameDlg::OnEraseBkgnd(CDC* pDC) { return true; return CDialog::OnEraseBkgnd(pDC); } void CMineGameDlg::OnTimer(UINT nIDEvent) { if (nIDEvent == ID_TIMER_EVENT) { if (m_bSoundful) { sndPlaySound((LPCTSTR)LockResource(m_pSndClock), SND_MEMORY | SND_ASYNC | SND_NODEFAULT); } m_uSpendTime++; CRect rcNum(m_uNumRect[0], 15, m_uNumRect[1], 39); // InvalidateRect(rcNum); Invalidate(); if (m_uSpendTime >= DEFAULT_RECORD) { KillTimer(ID_TIMER_EVENT); m_uTimer = 0; } } CDialog::OnTimer(nIDEvent); } void CMineGameDlg::OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized) { CDialog::OnActivate(nState, pWndOther, bMinimized); } void CMineGameDlg::OnRButtonDown(UINT nFlags, CPoint point) { //笑脸图按钮所在的区域 CRect rcBtn(m_uBtnRect[1], 15, m_uBtnRect[2], 39); //雷区所在的区域 CRect rcMineArea(MINE_AREA_LEFT, MINE_AREA_TOP, MINE_AREA_LEFT + m_uXNum * MINE_WIDTH, MINE_AREA_TOP + m_uYNum * MINE_HEIGHT); m_bLRBtnDown = FALSE; if (rcMineArea.PtInRect(point)) {//点击雷区域 if (m_uGameState == GS_WAIT || m_uGameState == GS_RUN) { m_pNewMine = GetMine(point.x, point.y); if (!m_pNewMine) return; // both of the left button and the right button are pushing down if (nFlags == (MK_LBUTTON | MK_RBUTTON)) { m_bLRBtnDown = TRUE; OnLRBtnDown(m_pNewMine->uRow, m_pNewMine->uCol); } else { switch(m_pNewMine->uState) { case STATE_NORMAL: m_pNewMine->uState = STATE_FLAG; m_pNewMine->uOldState = STATE_FLAG; m_nLeaveNum--; break; case STATE_FLAG: m_pNewMine->uState = STATE_DICEY; m_pNewMine->uOldState = STATE_DICEY; m_nLeaveNum++; break; case STATE_DICEY: m_pNewMine->uState = STATE_NORMAL; m_pNewMine->uOldState = STATE_NORMAL; break; default: break; } } Invalidate(); } } CDialog::OnRButtonDown(nFlags, point); } void CMineGameDlg::OnRButtonUp(UINT nFlags, CPoint point) { CRect rcBtn(m_uBtnRect[1], 15, m_uBtnRect[2], 39); CRect rcMineArea(MINE_AREA_LEFT, MINE_AREA_TOP, MINE_AREA_LEFT + m_uXNum * MINE_WIDTH, MINE_AREA_TOP + m_uYNum * MINE_HEIGHT); m_pOldMine = GetMine(point.x, point.y); if (!m_pOldMine) return; // 鼠标左右键同时按下 if (m_bLRBtnDown) { m_bLRBtnDown = FALSE; OnLRBtnUp(m_pOldMine->uRow, m_pOldMine->uCol); if (m_uGameState == GS_WAIT) { m_uBtnState = FACE_NORMAL; Invalidate(); return; } // 如果周围没有雷块,则展开周围区域 if (m_pOldMine->uState != STATE_FLAG) { OpenAround(m_pOldMine->uRow, m_pOldMine->uCol); } } else { Victory(); } CDialog::OnRButtonUp(nFlags, point); } void CMineGameDlg::OnPrimary() { m_uLevel = LEVEL_PRIMARY; m_uXNum = PRIMARY_XNUM; m_uYNum = PRIMARY_YNUM; m_uMineNum = PRIMARY_MINENUM; SetCheckedLevel(); InitGame(); Invalidate(); ReSizeWindow(); } void CMineGameDlg::OnSecond() { m_uLevel = LEVEL_SECONDRY; m_uXNum = SECONDRY_XNUM; m_uYNum = SECONDRY_YNUM; m_uMineNum = SECONDRY_MINENUM; SetCheckedLevel(); InitGame(); Invalidate(); ReSizeWindow(); } void CMineGameDlg::OnAdvance() { m_uLevel = LEVEL_ADVANCE; m_uXNum = ADVANCE_XNUM; m_uYNum = ADVANCE_YNUM; m_uMineNum = ADVANCE_MINENUM; SetCheckedLevel(); InitGame(); Invalidate(); ReSizeWindow(); } void CMineGameDlg::OnCustom() { m_uLevel = LEVEL_CUSTOM; SetCheckedLevel(); CCustomDlg dlg; dlg.SetData(m_uXNum, m_uYNum, m_uMineNum); if(dlg.DoModal() == IDOK) { dlg.GetData(&m_uXNum, &m_uYNum, &m_uMineNum); } InitGame(); Invalidate(); ReSizeWindow(); } void CMineGameDlg::OnStart() { InitGame(); Invalidate(); } void CMineGameDlg::OnInitMenu(CMenu* pMenu) { CDialog::OnInitMenu(pMenu); if ((m_pSubMenu = pMenu->GetSubMenu(0)) == 0) { AfxMessageBox("初始化菜单失败!"); PostQuitMessage(0); } else { SetCheckedLevel(); SetCheckedColor(); SetCheckedSound(); } } void CMineGameDlg::OnColor() { m_bColorful = !m_bColorful; LoadBitmap(); SetCheckedColor(); Invalidate(); } void CMineGameDlg::SetCheckedLevel() { if (m_pSubMenu) { m_pSubMenu->CheckMenuItem(IDM_PRIMARY, MF_UNCHECKED | MF_BYCOMMAND); m_pSubMenu->CheckMenuItem(IDM_SECOND, MF_UNCHECKED | MF_BYCOMMAND); m_pSubMenu->CheckMenuItem(IDM_ADVANCE, MF_UNCHECKED | MF_BYCOMMAND); m_pSubMenu->CheckMenuItem(IDM_CUSTOM, MF_UNCHECKED | MF_BYCOMMAND); switch(m_uLevel) { case LEVEL_PRIMARY: m_pSubMenu->CheckMenuItem(IDM_PRIMARY, MF_CHECKED | MF_BYCOMMAND); break; case LEVEL_SECONDRY: m_pSubMenu->CheckMenuItem(IDM_SECOND, MF_CHECKED | MF_BYCOMMAND); break; case LEVEL_ADVANCE: m_pSubMenu->CheckMenuItem(IDM_ADVANCE, MF_CHECKED | MF_BYCOMMAND); break; case LEVEL_CUSTOM: m_pSubMenu->CheckMenuItem(IDM_CUSTOM, MF_CHECKED | MF_BYCOMMAND); break; default: break; } } } void CMineGameDlg::SetCheckedColor() { if (m_pSubMenu) { if (m_bColorful) { m_pSubMenu->CheckMenuItem(IDM_COLOR, MF_CHECKED | MF_BYCOMMAND); } else { m_pSubMenu->CheckMenuItem(IDM_COLOR, MF_UNCHECKED | MF_BYCOMMAND); } } } void CMineGameDlg::SetCheckedSound() { if (m_pSubMenu) { if (m_bSoundful) { m_pSubMenu->CheckMenuItem(IDM_SOUND, MF_CHECKED | MF_BYCOMMAND); } else { m_pSubMenu->CheckMenuItem(IDM_SOUND, MF_UNCHECKED | MF_BYCOMMAND); } } } void CMineGameDlg::OnAbout() { ShellAbout(this->m_hWnd, "扫雷游戏", "tk_fly@sina.com",m_hIcon); } void CMineGameDlg::OnHelpUse() { ::WinExec("HH NTHelp.CHM", SW_SHOW); } LPBYTE CString_To_LPBYTE(CString str) { LPBYTE lpb=new BYTE[str.GetLength()+1]; for(int i=0;iuCol != m_pOldMine->uCol || m_pNewMine->uRow != m_pOldMine->uRow) { // change the new mine rect state switch(m_pNewMine->uState) { case STATE_NORMAL: m_pNewMine->uState = STATE_EMPTY; break; case STATE_DICEY: m_pNewMine->uState = STATE_DICEY_DOWN; break; } // resume the old mine rect state switch(m_pOldMine->uOldState) { case STATE_NORMAL: m_pOldMine->uState = STATE_NORMAL; break; case STATE_DICEY: m_pOldMine->uState = STATE_DICEY; break; default : break; } // judge whether the lr button are pushed down if (m_bLRBtnDown) { OnLRBtnUp(m_pOldMine->uRow, m_pOldMine->uCol); OnLRBtnDown(m_pNewMine->uRow, m_pNewMine->uCol); } m_pOldMine = m_pNewMine; } InvalidateRect(rcMineArea); break; case GS_VICTORY: case GS_DEAD: return; default: break; } } else { // point in other area switch(m_uGameState) { case GS_RUN: m_uBtnState = (m_bClickBtn) ? FACE_NORMAL : FACE_CLICK; if (m_pNewMine) { if (m_pNewMine->uOldState == STATE_NORMAL) { m_pNewMine->uState = STATE_NORMAL; } else if (m_pNewMine->uOldState == STATE_DICEY) { m_pNewMine->uState = STATE_DICEY; } } break; case GS_DEAD: m_uBtnState = FACE_DEAD; break; case GS_VICTORY: m_uBtnState = FACE_VICTORY; break; default: break; } Invalidate(); } } CWnd::OnMouseMove(nFlags, point); } void CMineGameDlg::OnExit() { // TODO: Add your command handler code here PostQuitMessage(0); }