bombs1.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // Name: bombs1.cpp
  3. // Purpose: Bombs game
  4. // Author: P. Foggia 1996
  5. // Modified by: Wlodzimierz Skiba (ABX) since 2003
  6. // Created: 1996
  7. // Copyright: (c) 1996 P. Foggia
  8. // Licence: wxWindows licence
  9. ///////////////////////////////////////////////////////////////////////////////
  10. /*
  11. * implementation of the methods DrawField and OnEvent of the
  12. * class BombsCanvas
  13. */
  14. #include "wx/wxprec.h"
  15. #ifdef __BORLANDC__
  16. # pragma hdrstop
  17. #endif
  18. #ifndef WX_PRECOMP
  19. # include "wx/wx.h"
  20. #endif //precompiled headers
  21. #include "bombs.h"
  22. // Draws the field on the device context dc
  23. // xc1,yc1 etc. are the (inclusive) limits of the area to be drawn,
  24. // expressed in cells.
  25. void BombsCanvas::DrawField(wxDC *dc, int xc1, int yc1, int xc2, int yc2)
  26. {
  27. wxString buf;
  28. wxCoord chw, chh;
  29. wxColour wxYellow = wxTheColourDatabase->Find(wxT("YELLOW"));
  30. wxColour wxFocused = wxTheColourDatabase->Find(wxT("GREY"));
  31. wxPen *bluePen = wxThePenList->FindOrCreatePen(*wxBLUE, 1, wxSOLID);
  32. wxBrush *focusedBrush = wxTheBrushList->FindOrCreateBrush(wxFocused, wxSOLID);
  33. wxBrush *yellowBrush = wxTheBrushList->FindOrCreateBrush(wxYellow, wxSOLID);
  34. dc->SetPen(*wxBLACK_PEN);
  35. int x, y;
  36. int xMax = this->GetGridSizeInPixels().GetWidth();
  37. int yMax = this->GetGridSizeInPixels().GetHeight();
  38. for(x=xc1; x<=xc2; x++)
  39. dc->DrawLine(x*m_cellWidth*X_UNIT, 0, x*m_cellWidth*X_UNIT, yMax);
  40. for(y=xc1; y<=yc2; y++)
  41. dc->DrawLine(0, y*m_cellHeight*Y_UNIT, xMax, y*m_cellHeight*Y_UNIT);
  42. wxFont font= BOMBS_FONT;
  43. dc->SetFont(font);
  44. for(x=xc1; x<=xc2; x++)
  45. for(y=yc1; y<=yc2; y++)
  46. {
  47. if (m_game->IsMarked(x,y))
  48. {
  49. dc->SetPen(*wxBLACK_PEN);
  50. if (m_game->IsFocussed(x, y))
  51. dc->SetBrush(*focusedBrush);
  52. else
  53. dc->SetBrush(*wxLIGHT_GREY_BRUSH);
  54. dc->DrawRectangle( x*m_cellWidth*X_UNIT, y*m_cellHeight*Y_UNIT,
  55. m_cellWidth*X_UNIT+1, m_cellHeight*Y_UNIT+1);
  56. buf = wxT("M");
  57. if (!m_game->IsHidden(x,y) && m_game->IsBomb(x,y))
  58. dc->SetTextForeground(*wxBLUE);
  59. else
  60. dc->SetTextForeground(*wxRED);
  61. dc->SetTextBackground(*wxLIGHT_GREY);
  62. dc->GetTextExtent(buf, &chw, &chh);
  63. dc->DrawText( buf,
  64. x*m_cellWidth*X_UNIT + (m_cellWidth*X_UNIT-chw)/2,
  65. y*m_cellHeight*Y_UNIT + (m_cellHeight*Y_UNIT-chh)/2 );
  66. if (!m_game->IsHidden(x,y) && m_game->IsBomb(x,y))
  67. {
  68. dc->SetPen(*wxRED_PEN);
  69. dc->DrawLine(x*m_cellWidth*X_UNIT, y*m_cellHeight*Y_UNIT,
  70. (x+1)*m_cellWidth*X_UNIT, (y+1)*m_cellHeight*Y_UNIT);
  71. dc->DrawLine(x*m_cellWidth*X_UNIT, (y+1)*m_cellHeight*Y_UNIT,
  72. (x+1)*m_cellWidth*X_UNIT, y*m_cellHeight*Y_UNIT);
  73. }
  74. }
  75. else if (m_game->IsHidden(x,y))
  76. {
  77. dc->SetPen(*wxBLACK_PEN);
  78. if (m_game->IsFocussed(x, y))
  79. dc->SetBrush(*focusedBrush);
  80. else
  81. dc->SetBrush(*wxLIGHT_GREY_BRUSH);
  82. dc->DrawRectangle( x*m_cellWidth*X_UNIT, y*m_cellHeight*Y_UNIT,
  83. m_cellWidth*X_UNIT+1, m_cellHeight*Y_UNIT+1);
  84. }
  85. else if (m_game->IsBomb(x,y))
  86. {
  87. dc->SetPen(*wxBLACK_PEN);
  88. dc->SetBrush(*wxRED_BRUSH);
  89. dc->DrawRectangle( x*m_cellWidth*X_UNIT, y*m_cellHeight*Y_UNIT,
  90. m_cellWidth*X_UNIT+1, m_cellHeight*Y_UNIT+1);
  91. buf = wxT("B");
  92. dc->SetTextForeground(*wxBLACK);
  93. dc->SetTextBackground(*wxRED);
  94. dc->GetTextExtent(buf, &chw, &chh);
  95. dc->DrawText( buf,
  96. x*m_cellWidth*X_UNIT + (m_cellWidth*X_UNIT-chw)/2,
  97. y*m_cellHeight*Y_UNIT + (m_cellHeight*Y_UNIT-chh)/2);
  98. if (m_game->IsExploded(x,y))
  99. {
  100. dc->SetPen(*bluePen);
  101. dc->DrawLine(x*m_cellWidth*X_UNIT, y*m_cellHeight*Y_UNIT,
  102. (x+1)*m_cellWidth*X_UNIT, (y+1)*m_cellHeight*Y_UNIT);
  103. dc->DrawLine(x*m_cellWidth*X_UNIT, (y+1)*m_cellHeight*Y_UNIT,
  104. (x+1)*m_cellWidth*X_UNIT, y*m_cellHeight*Y_UNIT);
  105. }
  106. }
  107. else // Display a digit
  108. {
  109. dc->SetPen(*wxBLACK_PEN);
  110. if (m_game->IsFocussed(x, y))
  111. dc->SetBrush(*focusedBrush);
  112. else if (m_game->IsSelected(x,y))
  113. dc->SetBrush(*wxWHITE_BRUSH);
  114. else
  115. dc->SetBrush(*yellowBrush);
  116. dc->DrawRectangle( x*m_cellWidth*X_UNIT, y*m_cellHeight*Y_UNIT,
  117. m_cellWidth*X_UNIT+1, m_cellHeight*Y_UNIT+1);
  118. int digit_value = m_game->Get(x,y) & BG_MASK;
  119. switch(digit_value)
  120. {
  121. case 0:
  122. buf = wxT("0");
  123. dc->SetTextForeground(*wxGREEN);
  124. break;
  125. case 1:
  126. buf = wxT("1");
  127. dc->SetTextForeground(*wxBLUE);
  128. break;
  129. default:
  130. buf.Printf(wxT("%d"),digit_value);
  131. dc->SetTextForeground(*wxBLACK);
  132. break;
  133. }
  134. dc->GetTextExtent(buf, &chw, &chh);
  135. dc->SetTextBackground(*wxWHITE);
  136. dc->DrawText( buf,
  137. x*m_cellWidth*X_UNIT + (m_cellWidth*X_UNIT-chw)/2,
  138. y*m_cellHeight*Y_UNIT + (m_cellHeight*Y_UNIT-chh)/2);
  139. }
  140. }
  141. dc->SetFont(wxNullFont);
  142. wxString msg;
  143. msg.Printf(wxT("%d bombs, %u marked, %d remaining cells"),
  144. m_game->GetNumBombs(), m_game->GetNumMarkedCells(),
  145. m_game->GetNumRemainingCells() );
  146. #if wxUSE_LOG && wxUSE_STATUSBAR
  147. wxLogStatus(msg);
  148. #else
  149. this->GetParent()->SetTitle(msg);
  150. #endif
  151. }
  152. // Refreshes the field image
  153. // xc1,yc1 etc. are the (inclusive) limits of the area to be drawn,
  154. // expressed in cells.
  155. void BombsCanvas::RefreshField(int xc1, int yc1, int xc2, int yc2)
  156. {
  157. wxClientDC dc(this);
  158. DrawField(& dc, xc1, yc1, xc2, yc2);
  159. if (m_bmp)
  160. {
  161. wxMemoryDC memDC;
  162. memDC.SelectObject(*m_bmp);
  163. DrawField(&memDC, xc1, yc1, xc2, yc2);
  164. memDC.SelectObject(wxNullBitmap);
  165. }
  166. }
  167. // Called when uncovering a cell.
  168. void BombsCanvas::Uncover(int x, int y)
  169. {
  170. m_game->Unhide(x,y,true);
  171. RefreshField(x, y, x, y);
  172. const int gridWidth = m_game->GetWidth();
  173. const int gridHeight = m_game->GetHeight();
  174. const bool hasWon = m_game->GetNumRemainingCells() == 0;
  175. if (m_game->IsBomb(x,y) || hasWon)
  176. {
  177. wxBell();
  178. if (hasWon)
  179. {
  180. wxMessageBox(wxT("Nice! You found all the bombs!"),
  181. wxT("wxWin Bombs"), wxOK|wxCENTRE);
  182. }
  183. else // x,y is a bomb
  184. {
  185. m_game->Explode(x, y);
  186. }
  187. for(x=0; x<gridWidth; x++)
  188. for(y=0; y<gridHeight; y++)
  189. m_game->Unhide(x,y,false);
  190. RefreshField(0, 0, gridWidth-1, gridHeight-1);
  191. }
  192. else if (0 == (m_game->Get(x, y) & BG_MASK))
  193. {
  194. int left = ( x > 0 ) ? x-1 : 0;
  195. int right = ( x < gridWidth - 1 )
  196. ? x+1
  197. : gridWidth - 1;
  198. int top = ( y > 0 ) ? y-1 : 0;
  199. int bottom = ( y < gridHeight - 1 )
  200. ? y+1
  201. : gridHeight - 1;
  202. int i, j;
  203. for (j=top; j<=bottom; j++)
  204. for (i=left; i<=right; i++)
  205. if ( (i != x || j != y) && m_game->IsHidden(i, j)
  206. && !m_game->IsMarked(i, j) )
  207. {
  208. Uncover(i, j);
  209. }
  210. }
  211. }
  212. // Called when the canvas receives a mouse event.
  213. void BombsCanvas::OnMouseEvent(wxMouseEvent& event)
  214. {
  215. const int gridWidth = m_game->GetWidth();
  216. const int gridHeight = m_game->GetHeight();
  217. wxCoord fx, fy;
  218. event.GetPosition(&fx, &fy);
  219. int x = fx/(m_cellWidth*X_UNIT);
  220. int y = fy/(m_cellHeight*Y_UNIT);
  221. if (x<gridWidth && y<gridHeight)
  222. {
  223. if ( (event.RightDown() || (event.LeftDown() && event.ShiftDown()))
  224. && (m_game->IsHidden(x,y)
  225. || !m_game->GetNumRemainingCells() ) )
  226. {
  227. // store previous and current field
  228. int prevFocusX = m_game->m_gridFocusX;
  229. int prevFocusY = m_game->m_gridFocusY;
  230. m_game->m_gridFocusX = x;
  231. m_game->m_gridFocusY = y;
  232. RefreshField(prevFocusX, prevFocusY, prevFocusX, prevFocusY);
  233. m_game->Mark(x, y);
  234. RefreshField(x, y, x, y);
  235. return;
  236. }
  237. else if (event.LeftDown() && m_game->IsHidden(x,y)
  238. && !m_game->IsMarked(x,y))
  239. {
  240. // store previous and current field
  241. int prevGridFocusX = m_game->m_gridFocusX;
  242. int prevGridFocusY = m_game->m_gridFocusY;
  243. m_game->m_gridFocusX = x;
  244. m_game->m_gridFocusY = y;
  245. RefreshField(prevGridFocusX, prevGridFocusY,
  246. prevGridFocusX, prevGridFocusY);
  247. Uncover(x, y);
  248. return;
  249. }
  250. }
  251. }
  252. void BombsCanvas::OnChar(wxKeyEvent& event)
  253. {
  254. int keyCode = event.GetKeyCode();
  255. int prevGridFocusX = m_game->m_gridFocusX;
  256. int prevGridFocusY = m_game->m_gridFocusY;
  257. const int gridWidth = m_game->GetWidth();
  258. const int gridHeight = m_game->GetHeight();
  259. switch(keyCode)
  260. {
  261. case WXK_RIGHT:
  262. m_game->m_gridFocusX++;
  263. if (m_game->m_gridFocusX >= gridWidth) m_game->m_gridFocusX = 0;
  264. break;
  265. case WXK_LEFT:
  266. m_game->m_gridFocusX--;
  267. if (m_game->m_gridFocusX<0) m_game->m_gridFocusX = gridWidth-1;
  268. break;
  269. case WXK_DOWN:
  270. m_game->m_gridFocusY++;
  271. if (m_game->m_gridFocusY >= gridHeight) m_game->m_gridFocusY = 0;
  272. break;
  273. case WXK_UP:
  274. m_game->m_gridFocusY--;
  275. if (m_game->m_gridFocusY<0) m_game->m_gridFocusY = gridHeight-1;
  276. break;
  277. case WXK_RETURN:
  278. if ( (prevGridFocusX == m_game->m_gridFocusX)
  279. && (prevGridFocusY == m_game->m_gridFocusY)
  280. && (m_game->IsHidden(m_game->m_gridFocusX, m_game->m_gridFocusY)) )
  281. {
  282. m_game->Mark(m_game->m_gridFocusX, m_game->m_gridFocusY);
  283. if (!m_game->IsMarked(m_game->m_gridFocusX, m_game->m_gridFocusY))
  284. {
  285. Uncover(m_game->m_gridFocusX, m_game->m_gridFocusY);
  286. }
  287. RefreshField(m_game->m_gridFocusX, m_game->m_gridFocusY,
  288. m_game->m_gridFocusX, m_game->m_gridFocusY);
  289. }
  290. break;
  291. default:
  292. event.Skip();
  293. }
  294. if ((prevGridFocusX != m_game->m_gridFocusX)
  295. || (prevGridFocusY != m_game->m_gridFocusY))
  296. {
  297. // cause focused field to be visible after first key hit after launching new game
  298. if( m_game->m_gridFocusX < 0 ) m_game->m_gridFocusX = 0;
  299. if( m_game->m_gridFocusY < 0 ) m_game->m_gridFocusY = 0;
  300. // refresh previous field and focused field
  301. RefreshField(prevGridFocusX, prevGridFocusY,
  302. prevGridFocusX, prevGridFocusY);
  303. RefreshField(m_game->m_gridFocusX, m_game->m_gridFocusY,
  304. m_game->m_gridFocusX, m_game->m_gridFocusY);
  305. }
  306. }