// Name: bombs1.cpp
// Purpose: Bombs game
// Author: P. Foggia 1996
-// Modified by:
+// Modified by: Wlodzimierz Skiba (ABX) since 2003
// Created: 1996
// RCS-ID: $Id$
// Copyright: (c) 1996 P. Foggia
* class BombsCanvas
*/
-#ifdef __GNUG__
-#pragma implementation
-#endif
-
#include "wx/wxprec.h"
+#ifdef __BORLANDC__
+# pragma hdrstop
+#endif
+
#ifndef WX_PRECOMP
- #include "wx/wx.h"
+# include "wx/wx.h"
#endif //precompiled headers
#include "bombs.h"
-/*-------- BombCanvasClass::DrawField(dc, xc1, yc1, xc2, yc2) -------*/
-/* Draws the field on the device context dc */
-/* xc1,yc1 etc. are the (inclusive) limits of the area to be drawn, */
-/* expressed in cells. */
-/*---------------------------------------------------------------------*/
-void BombsCanvasClass::DrawField(wxDC *dc, int xc1, int yc1, int xc2, int yc2)
-{ int x,y,xmax,ymax;
- char buf[2];
- long chw, chh;
-
- wxColour *wxBlack = wxTheColourDatabase->FindColour("BLACK");
- wxColour *wxWhite = wxTheColourDatabase->FindColour("WHITE");
- wxColour *wxRed = wxTheColourDatabase->FindColour("RED");
- wxColour *wxBlue = wxTheColourDatabase->FindColour("BLUE");
- wxColour *wxGrey = wxTheColourDatabase->FindColour("LIGHT GREY");
- wxColour *wxGreen = wxTheColourDatabase->FindColour("GREEN");
-
- wxPen *blackPen = wxThePenList->FindOrCreatePen(*wxBlack, 1, wxSOLID);
- wxPen *redPen = wxThePenList->FindOrCreatePen(*wxRed, 1, wxSOLID);
- wxPen *bluePen = wxThePenList->FindOrCreatePen(*wxBlue, 1, wxSOLID);
- wxBrush *whiteBrush = wxTheBrushList->FindOrCreateBrush(*wxWhite, wxSOLID);
- wxBrush *greyBrush = wxTheBrushList->FindOrCreateBrush(*wxGrey, wxSOLID);
- wxBrush *redBrush = wxTheBrushList->FindOrCreateBrush(*wxRed, wxSOLID);
-
- xmax=field_width*x_cell*X_UNIT;
- ymax=field_height*y_cell*Y_UNIT;
-
-
- dc->SetPen(* blackPen);
- for(x=xc1; x<=xc2; x++)
- dc->DrawLine(x*x_cell*X_UNIT, 0, x*x_cell*X_UNIT, ymax);
- for(y=xc1; y<=yc2; y++)
- dc->DrawLine(0, y*y_cell*Y_UNIT, xmax, y*y_cell*Y_UNIT);
-
-
- wxFont font= BOMBS_FONT;
- dc->SetFont(font);
-
- buf[1]='\0';
- for(x=xc1; x<=xc2; x++)
- for(y=yc1; y<=yc2; y++)
- { if (wxGetApp().Game.IsMarked(x,y))
- { dc->SetPen(* blackPen);
- dc->SetBrush(* greyBrush);
- dc->DrawRectangle( x*x_cell*X_UNIT, y*y_cell*Y_UNIT,
- x_cell*X_UNIT+1, y_cell*Y_UNIT+1);
- *buf='M';
- if (!wxGetApp().Game.IsHidden(x,y) && wxGetApp().Game.IsBomb(x,y))
- dc->SetTextForeground(*wxBlue);
- else
- dc->SetTextForeground(*wxRed);
- dc->SetTextBackground(*wxGrey);
- dc->GetTextExtent(buf, &chw, &chh);
- dc->DrawText( buf,
- x*x_cell*X_UNIT + (x_cell*X_UNIT-chw)/2,
- y*y_cell*Y_UNIT + (y_cell*Y_UNIT-chh)/2
- );
- if (!wxGetApp().Game.IsHidden(x,y) && wxGetApp().Game.IsBomb(x,y))
- { dc->SetPen(*redPen);
- dc->DrawLine(x*x_cell*X_UNIT, y*y_cell*Y_UNIT,
- (x+1)*x_cell*X_UNIT, (y+1)*y_cell*Y_UNIT);
- dc->DrawLine(x*x_cell*X_UNIT, (y+1)*y_cell*Y_UNIT,
- (x+1)*x_cell*X_UNIT, y*y_cell*Y_UNIT);
- }
- }
- else if (wxGetApp().Game.IsHidden(x,y))
- { dc->SetPen(*blackPen);
- dc->SetBrush(*greyBrush);
- dc->DrawRectangle( x*x_cell*X_UNIT, y*y_cell*Y_UNIT,
- x_cell*X_UNIT+1, y_cell*Y_UNIT+1);
- }
- else if (wxGetApp().Game.IsBomb(x,y))
- { dc->SetPen(* blackPen);
- dc->SetBrush(* redBrush);
- dc->DrawRectangle( x*x_cell*X_UNIT, y*y_cell*Y_UNIT,
- x_cell*X_UNIT+1, y_cell*Y_UNIT+1);
- *buf='B';
- dc->SetTextForeground(* wxBlack);
- dc->SetTextBackground(* wxRed);
- dc->GetTextExtent(buf, &chw, &chh);
- dc->DrawText( buf,
- x*x_cell*X_UNIT + (x_cell*X_UNIT-chw)/2,
- y*y_cell*Y_UNIT + (y_cell*Y_UNIT-chh)/2
- );
- if (wxGetApp().Game.IsExploded(x,y))
- { dc->SetPen(* bluePen);
- dc->DrawLine(x*x_cell*X_UNIT, y*y_cell*Y_UNIT,
- (x+1)*x_cell*X_UNIT, (y+1)*y_cell*Y_UNIT);
- dc->DrawLine(x*x_cell*X_UNIT, (y+1)*y_cell*Y_UNIT,
- (x+1)*x_cell*X_UNIT, y*y_cell*Y_UNIT);
- }
- }
- else // Display a digit
- { dc->SetPen(* blackPen);
- dc->SetBrush(* whiteBrush);
- dc->DrawRectangle( x*x_cell*X_UNIT, y*y_cell*Y_UNIT,
- x_cell*X_UNIT+1, y_cell*Y_UNIT+1);
- *buf = (wxGetApp().Game.Get(x,y) & BG_MASK) + '0';
+// Draws the field on the device context dc
+// xc1,yc1 etc. are the (inclusive) limits of the area to be drawn,
+// expressed in cells.
+void BombsCanvas::DrawField(wxDC *dc, int xc1, int yc1, int xc2, int yc2)
+{
+ wxString buf;
+ long chw, chh;
+
+ wxColour wxYellow = wxTheColourDatabase->Find(wxT("YELLOW"));
+ wxColour wxFocused = wxTheColourDatabase->Find(wxT("GREY"));
+
+ wxPen *bluePen = wxThePenList->FindOrCreatePen(*wxBLUE, 1, wxSOLID);
+
+ wxBrush *focusedBrush = wxTheBrushList->FindOrCreateBrush(wxFocused, wxSOLID);
+ wxBrush *yellowBrush = wxTheBrushList->FindOrCreateBrush(wxYellow, wxSOLID);
+
+ dc->SetPen(*wxBLACK_PEN);
+
+ int x, y;
+ int xMax = this->GetGridSizeInPixels().GetWidth();
+ int yMax = this->GetGridSizeInPixels().GetHeight();
+ for(x=xc1; x<=xc2; x++)
+ dc->DrawLine(x*m_cellWidth*X_UNIT, 0, x*m_cellWidth*X_UNIT, yMax);
+ for(y=xc1; y<=yc2; y++)
+ dc->DrawLine(0, y*m_cellHeight*Y_UNIT, xMax, y*m_cellHeight*Y_UNIT);
+
+
+ wxFont font= BOMBS_FONT;
+ dc->SetFont(font);
+
+ for(x=xc1; x<=xc2; x++)
+ for(y=yc1; y<=yc2; y++)
+ {
+ if (m_game->IsMarked(x,y))
+ {
+ dc->SetPen(*wxBLACK_PEN);
+
+ if (m_game->IsFocussed(x, y))
+ dc->SetBrush(*focusedBrush);
+ else
+ dc->SetBrush(*wxLIGHT_GREY_BRUSH);
+
+ dc->DrawRectangle( x*m_cellWidth*X_UNIT, y*m_cellHeight*Y_UNIT,
+ m_cellWidth*X_UNIT+1, m_cellHeight*Y_UNIT+1);
+ buf = wxT("M");
+ if (!m_game->IsHidden(x,y) && m_game->IsBomb(x,y))
+ dc->SetTextForeground(*wxBLUE);
+ else
+ dc->SetTextForeground(*wxRED);
+
+ dc->SetTextBackground(*wxLIGHT_GREY);
+ dc->GetTextExtent(buf, &chw, &chh);
+ dc->DrawText( buf,
+ x*m_cellWidth*X_UNIT + (m_cellWidth*X_UNIT-chw)/2,
+ y*m_cellHeight*Y_UNIT + (m_cellHeight*Y_UNIT-chh)/2 );
+
+ if (!m_game->IsHidden(x,y) && m_game->IsBomb(x,y))
+ {
+ dc->SetPen(*wxRED_PEN);
+ dc->DrawLine(x*m_cellWidth*X_UNIT, y*m_cellHeight*Y_UNIT,
+ (x+1)*m_cellWidth*X_UNIT, (y+1)*m_cellHeight*Y_UNIT);
+ dc->DrawLine(x*m_cellWidth*X_UNIT, (y+1)*m_cellHeight*Y_UNIT,
+ (x+1)*m_cellWidth*X_UNIT, y*m_cellHeight*Y_UNIT);
+ }
+ }
+ else if (m_game->IsHidden(x,y))
+ {
+ dc->SetPen(*wxBLACK_PEN);
+ if (m_game->IsFocussed(x, y))
+ dc->SetBrush(*focusedBrush);
+ else
+ dc->SetBrush(*wxLIGHT_GREY_BRUSH);
+
+ dc->DrawRectangle( x*m_cellWidth*X_UNIT, y*m_cellHeight*Y_UNIT,
+ m_cellWidth*X_UNIT+1, m_cellHeight*Y_UNIT+1);
+ }
+ else if (m_game->IsBomb(x,y))
+ {
+ dc->SetPen(*wxBLACK_PEN);
+ dc->SetBrush(*wxRED_BRUSH);
+ dc->DrawRectangle( x*m_cellWidth*X_UNIT, y*m_cellHeight*Y_UNIT,
+ m_cellWidth*X_UNIT+1, m_cellHeight*Y_UNIT+1);
+ buf = wxT("B");
+ dc->SetTextForeground(*wxBLACK);
+ dc->SetTextBackground(*wxRED);
+ dc->GetTextExtent(buf, &chw, &chh);
+ dc->DrawText( buf,
+ x*m_cellWidth*X_UNIT + (m_cellWidth*X_UNIT-chw)/2,
+ y*m_cellHeight*Y_UNIT + (m_cellHeight*Y_UNIT-chh)/2);
+ if (m_game->IsExploded(x,y))
+ {
+ dc->SetPen(*bluePen);
+ dc->DrawLine(x*m_cellWidth*X_UNIT, y*m_cellHeight*Y_UNIT,
+ (x+1)*m_cellWidth*X_UNIT, (y+1)*m_cellHeight*Y_UNIT);
+ dc->DrawLine(x*m_cellWidth*X_UNIT, (y+1)*m_cellHeight*Y_UNIT,
+ (x+1)*m_cellWidth*X_UNIT, y*m_cellHeight*Y_UNIT);
+ }
+ }
+ else // Display a digit
+ {
+ dc->SetPen(*wxBLACK_PEN);
+ if (m_game->IsFocussed(x, y))
+ dc->SetBrush(*focusedBrush);
+ else if (m_game->IsSelected(x,y))
+ dc->SetBrush(*wxWHITE_BRUSH);
+ else
+ dc->SetBrush(*yellowBrush);
+ dc->DrawRectangle( x*m_cellWidth*X_UNIT, y*m_cellHeight*Y_UNIT,
+ m_cellWidth*X_UNIT+1, m_cellHeight*Y_UNIT+1);
+
+ int digit_value = m_game->Get(x,y) & BG_MASK;
+ switch(digit_value)
+ {
+ case 0:
+ buf = wxT("0");
+ dc->SetTextForeground(*wxGREEN);
+ break;
+ case 1:
+ buf = wxT("1");
+ dc->SetTextForeground(*wxBLUE);
+ break;
+ default:
+ buf.Printf(wxT("%d"),digit_value);
+ dc->SetTextForeground(*wxBLACK);
+ break;
+ }
dc->GetTextExtent(buf, &chw, &chh);
- switch(*buf)
- { case '0': dc->SetTextForeground(* wxGreen); break;
- case '1': dc->SetTextForeground(* wxBlue); break;
- default: dc->SetTextForeground(* wxBlack); break;
- }
- dc->SetTextBackground(* wxWhite);
+ dc->SetTextBackground(*wxWHITE);
dc->DrawText( buf,
- x*x_cell*X_UNIT + (x_cell*X_UNIT-chw)/2,
- y*y_cell*Y_UNIT + (y_cell*Y_UNIT-chh)/2
- );
- }
- }
- dc->SetFont(wxNullFont);
-
- if (wxGetApp().BombsFrame)
- { char buf[80];
- sprintf(buf, "%d bombs %d remaining cells",
- wxGetApp().Game.GetBombs(), wxGetApp().Game.GetRemainingCells());
- wxGetApp().BombsFrame->SetStatusText(buf, 0);
+ x*m_cellWidth*X_UNIT + (m_cellWidth*X_UNIT-chw)/2,
+ y*m_cellHeight*Y_UNIT + (m_cellHeight*Y_UNIT-chh)/2);
+ }
}
+ dc->SetFont(wxNullFont);
+
+ wxString msg;
+ msg.Printf(wxT("%d bombs, %u marked, %d remaining cells"),
+ m_game->GetNumBombs(), m_game->GetNumMarkedCells(),
+ m_game->GetNumRemainingCells() );
+
+#if wxUSE_LOG && wxUSE_STATUSBAR
+ wxLogStatus(msg);
+#else
+ this->GetParent()->SetTitle(msg);
+#endif
}
-/*-------- BombCanvasClass::Refresh(xc1, yc1, xc2, yc2) -------------*/
-/* Refreshes the field image */
-/* xc1,yc1 etc. are the (inclusive) limits of the area to be drawn, */
-/* expressed in cells. */
-/*---------------------------------------------------------------------*/
-void BombsCanvasClass::Refresh(int xc1, int yc1, int xc2, int yc2)
- {
+// Refreshes the field image
+// xc1,yc1 etc. are the (inclusive) limits of the area to be drawn,
+// expressed in cells.
+void BombsCanvas::RefreshField(int xc1, int yc1, int xc2, int yc2)
+{
wxClientDC dc(this);
DrawField(& dc, xc1, yc1, xc2, yc2);
- if (bmp)
- { wxMemoryDC memDC;
- memDC.SelectObject(* bmp);
+ if (m_bmp)
+ {
+ wxMemoryDC memDC;
+ memDC.SelectObject(*m_bmp);
DrawField(&memDC, xc1, yc1, xc2, yc2);
memDC.SelectObject(wxNullBitmap);
- }
- }
+ }
+}
-// Called when the canvas receives a mouse event.
-void BombsCanvasClass::OnEvent(wxMouseEvent& event)
+// Called when uncovering a cell.
+void BombsCanvas::Uncover(int x, int y)
{
- wxCoord fx, fy;
- event.GetPosition(&fx, &fy);
- int x = fx/(x_cell*X_UNIT);
- int y = fy/(y_cell*Y_UNIT);
- if (x<field_width && y<field_height)
- { if ( (event.RightDown() || (event.LeftDown() && event.ShiftDown()))
- && (wxGetApp().Game.IsHidden(x,y)
- || wxGetApp().Game.GetRemainingCells()==0))
- { wxGetApp().Game.Mark(x,y);
- Refresh(x, y, x, y);
- return;
+ m_game->Unhide(x,y,true);
+ RefreshField(x, y, x, y);
+
+ const int gridWidth = m_game->GetWidth();
+ const int gridHeight = m_game->GetHeight();
+
+ const bool hasWon = m_game->GetNumRemainingCells() == 0;
+ if (m_game->IsBomb(x,y) || hasWon)
+ {
+ wxBell();
+ if (hasWon)
+ {
+ wxMessageBox(wxT("Nice! You found all the bombs!"),
+ wxT("wxWin Bombs"), wxOK|wxCENTRE);
}
- else if (event.LeftDown() && wxGetApp().Game.IsHidden(x,y)
- && !wxGetApp().Game.IsMarked(x,y))
- { wxGetApp().Game.Unhide(x,y);
- Refresh(x, y, x, y);
- if (wxGetApp().Game.IsBomb(x,y) || wxGetApp().Game.GetRemainingCells()==0)
- { wxBell();
- if (!wxGetApp().Game.IsBomb(x,y))
- { wxMessageBox("Nice! You found all the bombs!", "wxWin Bombs",
- wxOK|wxCENTRE, wxGetApp().BombsFrame);
- }
- else // x,y is a bomb
- { wxGetApp().Game.Explode(x, y);
+ else // x,y is a bomb
+ {
+ m_game->Explode(x, y);
+ }
+
+ for(x=0; x<gridWidth; x++)
+ for(y=0; y<gridHeight; y++)
+ m_game->Unhide(x,y,false);
+
+ RefreshField(0, 0, gridWidth-1, gridHeight-1);
+ }
+ else if (0 == (m_game->Get(x, y) & BG_MASK))
+ {
+ int left = ( x > 0 ) ? x-1 : 0;
+ int right = ( x < gridWidth - 1 )
+ ? x+1
+ : gridWidth - 1;
+ int top = ( y > 0 ) ? y-1 : 0;
+ int bottom = ( y < gridHeight - 1 )
+ ? y+1
+ : gridHeight - 1;
+
+ int i, j;
+ for (j=top; j<=bottom; j++)
+ for (i=left; i<=right; i++)
+ if ( (i != x || j != y) && m_game->IsHidden(i, j)
+ && !m_game->IsMarked(i, j) )
+ {
+ Uncover(i, j);
}
- for(x=0; x<field_width; x++)
- for(y=0; y<field_height; y++)
- wxGetApp().Game.Unhide(x,y);
- Refresh(0, 0, field_width-1, field_height-1);
- }
- return;
+ }
+}
+
+// Called when the canvas receives a mouse event.
+void BombsCanvas::OnMouseEvent(wxMouseEvent& event)
+{
+ const int gridWidth = m_game->GetWidth();
+ const int gridHeight = m_game->GetHeight();
+
+ wxCoord fx, fy;
+ event.GetPosition(&fx, &fy);
+ int x = fx/(m_cellWidth*X_UNIT);
+ int y = fy/(m_cellHeight*Y_UNIT);
+ if (x<gridWidth && y<gridHeight)
+ {
+ if ( (event.RightDown() || (event.LeftDown() && event.ShiftDown()))
+ && (m_game->IsHidden(x,y)
+ || !m_game->GetNumRemainingCells() ) )
+ {
+ // store previous and current field
+ int prevFocusX = m_game->m_gridFocusX;
+ int prevFocusY = m_game->m_gridFocusY;
+ m_game->m_gridFocusX = x;
+ m_game->m_gridFocusY = y;
+ RefreshField(prevFocusX, prevFocusY, prevFocusX, prevFocusY);
+ m_game->Mark(x, y);
+ RefreshField(x, y, x, y);
+ return;
+ }
+ else if (event.LeftDown() && m_game->IsHidden(x,y)
+ && !m_game->IsMarked(x,y))
+ {
+ // store previous and current field
+ int prevGridFocusX = m_game->m_gridFocusX;
+ int prevGridFocusY = m_game->m_gridFocusY;
+ m_game->m_gridFocusX = x;
+ m_game->m_gridFocusY = y;
+ RefreshField(prevGridFocusX, prevGridFocusY,
+ prevGridFocusX, prevGridFocusY);
+ Uncover(x, y);
+ return;
}
}
}
+void BombsCanvas::OnChar(wxKeyEvent& event)
+{
+ int keyCode = event.GetKeyCode();
+ int prevGridFocusX = m_game->m_gridFocusX;
+ int prevGridFocusY = m_game->m_gridFocusY;
+
+ const int gridWidth = m_game->GetWidth();
+ const int gridHeight = m_game->GetHeight();
+
+ switch(keyCode)
+ {
+
+ case WXK_RIGHT:
+ m_game->m_gridFocusX++;
+ if (m_game->m_gridFocusX >= gridWidth) m_game->m_gridFocusX = 0;
+ break;
+
+ case WXK_LEFT:
+ m_game->m_gridFocusX--;
+ if (m_game->m_gridFocusX<0) m_game->m_gridFocusX = gridWidth-1;
+ break;
+
+ case WXK_DOWN:
+ m_game->m_gridFocusY++;
+ if (m_game->m_gridFocusY >= gridHeight) m_game->m_gridFocusY = 0;
+ break;
+
+ case WXK_UP:
+ m_game->m_gridFocusY--;
+ if (m_game->m_gridFocusY<0) m_game->m_gridFocusY = gridHeight-1;
+ break;
+
+ case WXK_RETURN:
+ if ( (prevGridFocusX == m_game->m_gridFocusX)
+ && (prevGridFocusY == m_game->m_gridFocusY)
+ && (m_game->IsHidden(m_game->m_gridFocusX, m_game->m_gridFocusY)) )
+ {
+ m_game->Mark(m_game->m_gridFocusX, m_game->m_gridFocusY);
+ if (!m_game->IsMarked(m_game->m_gridFocusX, m_game->m_gridFocusY))
+ {
+ Uncover(m_game->m_gridFocusX, m_game->m_gridFocusY);
+ }
+ RefreshField(m_game->m_gridFocusX, m_game->m_gridFocusY,
+ m_game->m_gridFocusX, m_game->m_gridFocusY);
+ }
+ break;
+
+ default:
+ event.Skip();
+
+ }
+
+ if ((prevGridFocusX != m_game->m_gridFocusX)
+ || (prevGridFocusY != m_game->m_gridFocusY))
+ {
+ // cause focused field to be visible after first key hit after launching new game
+ if( m_game->m_gridFocusX < 0 ) m_game->m_gridFocusX = 0;
+ if( m_game->m_gridFocusY < 0 ) m_game->m_gridFocusY = 0;
+
+ // refresh previous field and focused field
+ RefreshField(prevGridFocusX, prevGridFocusY,
+ prevGridFocusX, prevGridFocusY);
+ RefreshField(m_game->m_gridFocusX, m_game->m_gridFocusY,
+ m_game->m_gridFocusX, m_game->m_gridFocusY);
+ }
+}