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