1 ///////////////////////////////////////////////////////////////////////////////
2 // Name:        bombs.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 #include "wx/wxprec.h"
12 
13 #ifdef __BORLANDC__
14 #   pragma hdrstop
15 #endif
16 
17 #ifndef  WX_PRECOMP
18 #   include "wx/wx.h"
19 #endif //precompiled headers
20 
21 #include "wx/stockitem.h"
22 
23 #include "bombs.h"
24 
25 #include <stdlib.h>
26 
27 #ifndef __WXWINCE__
28 #   include <time.h>
29 #endif
30 
31 #ifndef wxHAS_IMAGES_IN_RESOURCES
32 #   include "bombs.xpm"
33 #endif
34 
35 IMPLEMENT_APP(BombsApp)
36 
37 #ifdef __WXWINCE__
38     STDAPI_(__int64) CeGetRandomSeed();
39 #endif
40 
41 // Called to initialize the program
OnInit()42 bool BombsApp::OnInit()
43 {
44 #ifdef __WXWINCE__
45     srand((unsigned) CeGetRandomSeed());
46 #else
47     srand((unsigned) time(NULL));
48 #endif
49 
50     m_frame = new BombsFrame(&m_game);
51 
52     m_frame->NewGame(bombsID_EASY, false);
53 
54     return true;
55 }
56 
BEGIN_EVENT_TABLE(BombsFrame,wxFrame)57 BEGIN_EVENT_TABLE(BombsFrame, wxFrame)
58     EVT_MENU(wxID_NEW,           BombsFrame::OnNewGame)
59     EVT_MENU(bombsID_EASY,       BombsFrame::OnEasyGame)
60     EVT_MENU(bombsID_MEDIUM,     BombsFrame::OnMediumGame)
61     EVT_MENU(bombsID_HARD,       BombsFrame::OnHardGame)
62     EVT_MENU(bombsID_EASYCORNER, BombsFrame::OnEasyCorner)
63     EVT_MENU(wxID_EXIT,          BombsFrame::OnExit)
64     EVT_MENU(wxID_ABOUT,         BombsFrame::OnAbout)
65 END_EVENT_TABLE()
66 
67 BombsFrame::BombsFrame(BombsGame *game)
68     : wxFrame(NULL, wxID_ANY, wxT("wxBombs"), wxDefaultPosition,
69         wxSize(300, 300), wxDEFAULT_DIALOG_STYLE|wxMINIMIZE_BOX)
70 {
71     m_game = game;
72     m_easyCorner = false;
73     m_lastLevel = bombsID_EASY;
74 
75     SetIcon(wxICON(bombs));
76 
77 #if wxUSE_STATUSBAR
78     CreateStatusBar();
79 #endif
80 
81     // Create a menu bar for the frame
82     wxMenuBar *menuBar = new wxMenuBar;
83     wxMenu *menuFile = new wxMenu;
84     wxMenu *menuLevel = new wxMenu;
85     menuLevel->AppendRadioItem(bombsID_EASY, wxT("&Easy (10x10)\tCtrl-1"));
86     menuLevel->AppendRadioItem(bombsID_MEDIUM, wxT("&Medium (15x15)\tCtrl-2"));
87     menuLevel->AppendRadioItem(bombsID_HARD, wxT("&Hard (25x20)\tCtrl-3"));
88 
89     menuFile->Append(wxID_NEW, wxT("&New game\tCtrl-N"));
90     menuFile->Append(bombsID_LEVEL, wxT("&Level"),menuLevel, wxT("Starts a new game"));
91     menuFile->AppendCheckItem(bombsID_EASYCORNER, wxT("&Easy corner"));
92 
93     menuFile->AppendSeparator();
94     menuFile->Append(wxID_EXIT, wxGetStockLabel(wxID_EXIT), wxT("Quits the application"));
95 
96     menuBar->Append(menuFile, wxT("&File"));
97 
98 
99     wxMenu *menuHelp = new wxMenu;
100     menuHelp->Append(wxID_ABOUT, wxT("&About"),
101         wxT("Displays the program information") );
102 
103     menuBar->Append(menuHelp, wxT("&Help"));
104 
105     SetMenuBar(menuBar);
106 
107     // Create child subwindows.
108     m_canvas = new BombsCanvas(this, m_game);
109 
110     // Ensure the subwindows get resized o.k.
111     //  OnSize(width, height);
112 
113     // Centre frame on the screen.
114     Centre(wxBOTH);
115 
116     // Show the frame.
117     Show();
118 }
119 
OnExit(wxCommandEvent & WXUNUSED (event))120 void BombsFrame::OnExit(wxCommandEvent& WXUNUSED(event))
121 {
122     Close();
123 }
124 
NewGame(int level,bool query)125 void BombsFrame::NewGame(int level, bool query)
126 {
127     if(query)
128     {
129        int ok = wxMessageBox(
130                   wxT("Start new game regardless previous board?"),
131                   wxT("Confirm"),
132                   wxYES_NO | wxICON_QUESTION,
133                   this
134                 );
135        if(ok!=wxYES)return;
136     }
137 
138     int numHorzCells = 20, numVertCells = 20;
139     m_lastLevel = level;
140 
141     switch(level)
142     {
143     case bombsID_EASY:
144         numHorzCells = numVertCells = 10;
145         break;
146 
147     case bombsID_MEDIUM:
148         numHorzCells = numVertCells = 15;
149         break;
150 
151     case bombsID_HARD:
152         numHorzCells = 25; numVertCells = 20;
153         break;
154 
155     default :
156         wxFAIL_MSG(wxT("Invalid level"));
157         break;
158     }
159 
160     m_game->Init(numHorzCells, numVertCells, m_easyCorner);
161 
162     GetMenuBar()->Check(level, true);
163 
164     m_canvas->UpdateGridSize();
165     SetClientSize(m_canvas->GetGridSizeInPixels());
166 }
167 
OnAbout(wxCommandEvent & WXUNUSED (event))168 void BombsFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
169 {
170     wxMessageBox(
171         wxT("wxBombs (c) 1996 by P. Foggia\n<foggia@amalfi.dis.unina.it>"),
172         wxT("About wxBombs") );
173 }
174 
OnNewGame(wxCommandEvent & WXUNUSED (event))175 void BombsFrame::OnNewGame(wxCommandEvent& WXUNUSED(event))
176 {
177     NewGame(m_lastLevel, true);
178 }
179 
OnEasyGame(wxCommandEvent & WXUNUSED (event))180 void BombsFrame::OnEasyGame(wxCommandEvent& WXUNUSED(event))
181 {
182     NewGame(bombsID_EASY, true);
183 }
184 
OnMediumGame(wxCommandEvent & WXUNUSED (event))185 void BombsFrame::OnMediumGame(wxCommandEvent& WXUNUSED(event))
186 {
187     NewGame(bombsID_MEDIUM, true);
188 }
189 
OnHardGame(wxCommandEvent & WXUNUSED (event))190 void BombsFrame::OnHardGame(wxCommandEvent& WXUNUSED(event))
191 {
192     NewGame(bombsID_HARD, true);
193 }
194 
OnEasyCorner(wxCommandEvent & WXUNUSED (event))195 void BombsFrame::OnEasyCorner(wxCommandEvent& WXUNUSED(event))
196 {
197     wxString msg;
198     if(m_easyCorner)
199         msg = wxT("enable");
200     else
201         msg = wxT("disable");
202 
203     msg = wxT("Do you really want to ") + msg + wxT(" having\ntop left corner always empty for easier start?");
204 
205     int ok = wxMessageBox(
206                msg,
207                wxT("Confirm"),
208                wxYES_NO | wxICON_QUESTION,
209                this
210              );
211 
212     if(ok!=wxYES)return;
213 
214     m_easyCorner = !m_easyCorner;
215 
216     NewGame(m_lastLevel, true);
217 }
218 
BEGIN_EVENT_TABLE(BombsCanvas,wxPanel)219 BEGIN_EVENT_TABLE(BombsCanvas, wxPanel)
220     EVT_PAINT(BombsCanvas::OnPaint)
221     EVT_MOUSE_EVENTS(BombsCanvas::OnMouseEvent)
222     EVT_CHAR(BombsCanvas::OnChar)
223 END_EVENT_TABLE()
224 
225 BombsCanvas::BombsCanvas(wxFrame *parent, BombsGame *game)
226     : wxPanel(parent, wxID_ANY)
227 {
228     m_game = game;
229     int sx, sy;
230     wxClientDC dc(this);
231     wxFont font= BOMBS_FONT;
232     dc.SetFont(font);
233 
234     wxCoord chw, chh;
235     wxString buf = wxT("M");
236 
237     dc.GetTextExtent(buf, &chw, &chh);
238     dc.SetFont(wxNullFont);
239 
240     dc.SetMapMode(wxMM_METRIC);
241 
242     int xcm = dc.LogicalToDeviceX(10);
243     int ycm = dc.LogicalToDeviceY(10);
244     // To have a square cell, there must be :
245     //    sx*ycm == sy*xcm
246     if (chw*ycm < chh*xcm)
247     {
248         sy = chh;
249         sx = chh*xcm/ycm;
250     }
251     else
252     {
253         sx = chw;
254         sy = chw*ycm/xcm;
255     }
256 
257     m_cellWidth = (sx+3+X_UNIT)/X_UNIT;
258     m_cellHeight = (sy+3+Y_UNIT)/Y_UNIT;
259     dc.SetMapMode(wxMM_TEXT);
260     m_bmp = NULL;
261 }
262 
~BombsCanvas()263 BombsCanvas::~BombsCanvas()
264 {
265     if (m_bmp)
266     {
267         delete m_bmp;
268         m_bmp = NULL;
269     }
270 }
271 
272 // Called when canvas needs to be repainted.
OnPaint(wxPaintEvent & WXUNUSED (event))273 void BombsCanvas::OnPaint(wxPaintEvent& WXUNUSED(event))
274 {
275     wxPaintDC dc(this);
276 
277     const int numHorzCells = m_game->GetWidth();
278     const int numVertCells = m_game->GetHeight();
279     // Insert your drawing code here.
280     if (!m_bmp)
281     {
282         wxSize size = dc.GetSize();
283         m_bmp = new wxBitmap(size.GetWidth(), size.GetHeight());
284         if (m_bmp)
285         {
286             wxMemoryDC memDC;
287             memDC.SelectObject(*m_bmp);
288             DrawField(&memDC, 0, 0, numHorzCells-1, numVertCells-1);
289             memDC.SelectObject(wxNullBitmap);
290         }
291     }
292 
293     if (m_bmp)
294     {
295         wxMemoryDC memDC;
296         memDC.SelectObject(*m_bmp);
297         wxSize size = dc.GetSize();
298         dc.Blit(0, 0, size.GetWidth(), size.GetHeight(),
299             &memDC, 0, 0, wxCOPY);
300       memDC.SelectObject(wxNullBitmap);
301     }
302     else
303     {
304         DrawField(&dc, 0, 0, numHorzCells-1, numVertCells-1);
305     }
306 }
307 
UpdateGridSize()308 void BombsCanvas::UpdateGridSize()
309 {
310 
311     if (m_bmp)
312     {
313         delete m_bmp;
314         m_bmp = NULL;
315     }
316     SetSize(GetGridSizeInPixels());
317     Refresh();
318 }
319 
GetGridSizeInPixels() const320 wxSize BombsCanvas::GetGridSizeInPixels() const
321 {
322     return wxSize(m_cellWidth*X_UNIT*m_game->GetWidth(),
323         m_cellHeight*Y_UNIT*m_game->GetHeight());
324 }
325 
326