2 // editorwidget.cpp: Game editor window widget
5 // (C) 2014 Underground Software
7 // JLH = James Hammons <jlhamm@acm.org>
10 // --- ---------- ------------------------------------------------------------
11 // JLH 07/01/2014 Created this file
14 #include "editorwidget.h"
15 #include <unistd.h> // for usleep()
18 #include "gameboard.h"
24 EditorWidget::EditorWidget(QWidget * parent/*= 0*/): QWidget(parent),
27 // memset(¤tLevel, 0, sizeof(currentLevel));
28 // currentLevel.corner.x = -1;
29 // currentLevel.corner.y = -1;
30 // levelStorage.push_back(currentLevel);
31 // Level * b1 = &level[0];
32 // memset(board, 0, sizeof(board));
33 // CreateBackground();
34 // score->setTextFormat(Qt::PlainText);
36 setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
37 setFocusPolicy(Qt::StrongFocus); // Without this, it gets no keys
42 // This never gets called...!
43 EditorWidget::~EditorWidget(void)
49 QSize EditorWidget::sizeHint() const
51 return QSize(400, 400);
55 void EditorWidget::paintEvent(QPaintEvent * /*event*/)
57 QPainter painter(this);
59 Level & level = levelStorage[currentLevel];
61 for(int y=0; y<=clientArea.height()/GRIDSIZE; y++)
63 for(int x=0; x<=clientArea.width()/GRIDSIZE; x++)
65 Point current(level.corner.x + x, level.corner.y + y);
67 if ((current.x < 0) && (current.y < 0))
69 painter.setBrush(Qt::black);
70 painter.drawRect(x + (GRIDSIZE / 2), y + (GRIDSIZE / 2), GRIDSIZE / 2, GRIDSIZE / 2);
72 else if (current.x < 0)
74 painter.setBrush(Qt::black);
75 painter.drawRect(x + (GRIDSIZE / 2), y * GRIDSIZE, GRIDSIZE / 2, GRIDSIZE);
77 else if (current.y < 0)
79 painter.setBrush(Qt::black);
80 painter.drawRect(x * GRIDSIZE, y + (GRIDSIZE / 2), GRIDSIZE, GRIDSIZE / 2);
84 uint8_t tile = level.board[current.x][current.y];
86 painter.setBrush(Qt::transparent);
87 painter.setPen(Qt::black);
88 painter.drawRect(x * GRIDSIZE, y * GRIDSIZE, GRIDSIZE, GRIDSIZE);
90 if (tile & (GTWall | GTSpace | GTBox))
94 painter.setBrush(Qt::white);
95 painter.drawRect(x * GRIDSIZE, y * GRIDSIZE, GRIDSIZE, GRIDSIZE);
97 else if (tile & GTBox)
99 painter.setBrush(Qt::red);
100 painter.drawRect((x * GRIDSIZE) + (GRIDSIZE * 0.1),
101 (y * GRIDSIZE) + (GRIDSIZE * 0.1), GRIDSIZE * 0.8, GRIDSIZE * 0.8);
104 else if (tile & GTNull)
106 painter.setBrush(Qt::black);
107 // painter.setPen(Qt::black);
108 painter.drawRect(x * GRIDSIZE, y * GRIDSIZE, GRIDSIZE, GRIDSIZE);
110 else if (tile & GTMan)
112 painter.setBrush(Qt::yellow);
113 painter.drawEllipse((x * GRIDSIZE) + (GRIDSIZE * 0.1),
114 (y * GRIDSIZE) + (GRIDSIZE * 0.1), GRIDSIZE * 0.8, GRIDSIZE * 0.8);
117 if ((tile & GTBoxSpot) && !(tile & (GTWall | GTNull)))
119 painter.setBrush(Qt::magenta);
120 painter.drawRect((x * GRIDSIZE) + (GRIDSIZE / 3),
121 (y * GRIDSIZE) + (GRIDSIZE / 3), GRIDSIZE / 3, GRIDSIZE / 3);
127 int x = level.cursor.x - level.corner.x;
128 int y = level.cursor.y - level.corner.y;
130 painter.setBrush(Qt::transparent);
131 painter.setPen(Qt::darkGreen);
132 painter.drawEllipse((x * GRIDSIZE) + 4, (y * GRIDSIZE) + 4, GRIDSIZE - 8, GRIDSIZE - 8);
136 CountBoxesAndSpots(boxes, spots);
139 sprintf(s, "Boxes = Spots");
140 else if (boxes < spots)
141 sprintf(s, "Need %i more box%s", spots - boxes, (spots - boxes == 1 ? "" : "es"));
142 else if (spots < boxes)
143 sprintf(s, "Need %i more spot%s", boxes - spots, (boxes - spots == 1 ? "" : "s"));
145 painter.setPen(Qt::blue);
146 painter.drawText(0, 0, clientArea.width(), clientArea.height(),
147 Qt::AlignRight | Qt::AlignBottom, QString(s));
151 void EditorWidget::mousePressEvent(QMouseEvent * event)
153 if (event->button() == Qt::LeftButton)
160 void EditorWidget::mouseMoveEvent(QMouseEvent * event)
162 if (event->buttons() & Qt::LeftButton)
169 void EditorWidget::mouseReleaseEvent(QMouseEvent * event)
171 if (event->button() == Qt::LeftButton)
178 void EditorWidget::mouseDoubleClickEvent(QMouseEvent * event)
180 if (event->button() == Qt::LeftButton)
187 void EditorWidget::keyPressEvent(QKeyEvent * event)
189 int key = event->key();
190 Level & level = levelStorage[currentLevel];
191 Point & cursor = level.cursor;
192 Point & corner = level.corner;
194 if (key == Qt::Key_Up)
196 if (event->modifiers() == Qt::ShiftModifier)
203 if (((cursor.y - corner.y) == 0) && (corner.y > -1))
207 else if (key == Qt::Key_Down)
209 if (event->modifiers() == Qt::ShiftModifier)
213 if (cursor.y < (BOARDSIZE - 1))
216 if (cursor.y >= (range.y + corner.y - 1))
218 if (corner.y < (BOARDSIZE - range.y))
223 else if (key == Qt::Key_Left)
225 if (event->modifiers() == Qt::ShiftModifier)
232 if (((cursor.x - corner.x) == 0) && (corner.x > -1))
236 else if (key == Qt::Key_Right)
238 if (event->modifiers() == Qt::ShiftModifier)
242 if (cursor.x < (BOARDSIZE - 1))
245 if (cursor.x >= (range.x + corner.x - 1))
247 if (corner.x < (BOARDSIZE - range.x))
252 else if (key == Qt::Key_Period)
254 if (!(level.board[cursor.x][cursor.y] & (GTWall | GTNull)))
255 level.board[cursor.x][cursor.y] ^= GTBoxSpot;
257 else if (key == Qt::Key_B)
259 level.board[cursor.x][cursor.y] &= ~(GTSpace | GTWall | GTNull);
260 level.board[cursor.x][cursor.y] ^= GTBox;
262 else if (key == Qt::Key_W)
264 // If it's not a wall, just stick one in; otherwise, toggle it off
265 if (level.board[cursor.x][cursor.y] != GTWall)
266 level.board[cursor.x][cursor.y] = GTWall;
268 level.board[cursor.x][cursor.y] = GTSpace;
270 else if (key == Qt::Key_Space)
272 level.board[cursor.x][cursor.y] &= ~(GTSpace | GTWall | GTBox | GTNull);
273 level.board[cursor.x][cursor.y] |= GTSpace;
275 else if (key == Qt::Key_O)
277 // There can be only one!
278 for(int x=0; x<BOARDSIZE; x++)
279 for(int y=0; y<BOARDSIZE; y++)
280 level.board[x][y] &= ~GTMan;
282 // Also, he can only be on a space!
283 level.board[cursor.x][cursor.y] &= GTBoxSpot;
284 level.board[cursor.x][cursor.y] |= GTMan;
286 else if (key == Qt::Key_V)
288 // If it's not a void, just stick one in; otherwise, toggle it off
289 if (level.board[cursor.x][cursor.y] != GTNull)
290 level.board[cursor.x][cursor.y] = GTNull;
292 level.board[cursor.x][cursor.y] = GTSpace;
295 return; // Only update screen if keypress was recognized
301 void EditorWidget::keyReleaseEvent(QKeyEvent * /*event*/)
306 void EditorWidget::resizeEvent(QResizeEvent * /*event*/)
308 // QSize s = event->size();
310 //printf("Size of window is: %i x %i\n", s.width(), s.height());
311 //printf("Size of game grid is: %i x %i\n", gameBoard->width, gameBoard->height);
316 void EditorWidget::CreateBackground(void)
319 char BGRes[27][64] = {
320 ":/res/grfttile.bmp",
322 ":/res/bg_tech_3.bmp",
323 ":/res/bg_tech_2.bmp",
324 ":/res/bg_tech_1.bmp",
325 ":/res/bg_weave_3.bmp",
326 ":/res/bg_weave_2.bmp",
327 ":/res/bg_clouds_2.bmp",
328 ":/res/bg_floor_plate.bmp",
329 ":/res/bg_marble_b.bmp",
330 ":/res/bg_marble_g.bmp",
331 ":/res/bg_marble_p.bmp",
332 ":/res/bg_marble_r.bmp",
333 ":/res/bg_marble_rb.bmp",
334 ":/res/bg_money_1.bmp",
335 ":/res/bg_pinstripe2.bmp",
336 ":/res/bg_pinstripe7.bmp",
337 ":/res/bg_raindrops_large.bmp",
338 ":/res/bg_raindrops_small.bmp",
339 ":/res/bg_stucco.bmp",
340 ":/res/bg_wood_w.bmp",
341 ":/res/bg_wood_b1.bmp",
342 ":/res/bg_wood_d.bmp",
343 ":/res/bg_wood_f.bmp",
344 ":/res/bg_wood_mh.bmp",
345 ":/res/bg_wood_mv.bmp",
346 ":/res/bg_wood_ro.bmp"
349 QPalette pal = palette();
350 pal.setBrush(backgroundRole(), QBrush(QPixmap(BGRes[m_nBackground])));
351 setAutoFillBackground(true);
354 return true; // Ignore errors for now...
356 // QPalette pal = palette();
357 // pal.setBrush(backgroundRole(), QBrush(QPixmap(":/bg_marble_g.bmp")));
358 // setAutoFillBackground(true);
364 void EditorWidget::ClearLevel(void)
366 // gameBoard->ResetGame();
367 // memset(board, 0, sizeof(board));
372 bool EditorWidget::Load(void)
374 FILE * f = fopen("./wmd-level.data", "rb");
379 fscanf(f, "%i\n", &numberOfLevels);
380 //printf("Load: Looking for %i levels...\n", numberOfLevels);
382 for(int i=0; i<numberOfLevels; i++)
386 memset(&level, 0, sizeof(Level));
388 fscanf(f, "%i\n%i\n%i\n%i\n", &size.x, &size.y, &corner.x, &corner.y);
389 fscanf(f, "%i\n%i\n%i\n%i\n", &level.corner.x, &level.corner.y, &level.cursor.x, &level.cursor.y);
390 fread(level.name, 1, 41, f);
391 //printf("Load: name=\"%s\"\n", level.name);
392 //printf("Load: size=%i, %i; corner=%i, %i; level corner=%i, %i; cursor=%i, %i\n", size.x, size.y, corner.x, corner.y, level.corner.x, level.corner.y, level.cursor.x, level.cursor.y);
394 for(int k=0; k<size.y; k++)
395 for(int j=0; j<size.x; j++)
396 level.board[corner.x + j][corner.y + k] = fgetc(f);
398 levelStorage.push_back(level);
405 // There is no save file, so use the internal levels
406 for(uint32_t i=0; i<NUMBER_OF_BOARDS; i++)
409 memset(&l, 0, sizeof(Level));
410 l.corner.x = l.corner.y = -1;
412 // Create a GameBoard object for level #i (1-based)...
415 for(int32_t x=0; x<b.width; x++)
416 for(int32_t y=0; y<b.height; y++)
417 l.board[x][y] = b.board[(y * b.width) + x];
419 l.board[b.playerX][b.playerY] |= GTMan;
420 strncpy(l.name, b.name, 40); // NULL is provided by the memset() above
421 levelStorage.push_back(l);
428 bool EditorWidget::Save(void)
430 FILE * f = fopen("./wmd-level.data", "wb");
434 printf("Could not open 'wmd-level.data' for writing!\n");
438 fprintf(f, "%lu\n", levelStorage.size());
440 for(uint32_t i=0; i<levelStorage.size(); i++)
442 Level & level = levelStorage[i];
444 GetSizeAndCorner(&level, size, corner);
446 fprintf(f, "%i\n%i\n%i\n%i\n", size.x, size.y, corner.x, corner.y);
447 fprintf(f, "%i\n%i\n%i\n%i\n", level.corner.x, level.corner.y, level.cursor.x, level.cursor.y);
448 fwrite(level.name, 1, 41, f);
450 for(int k=0; k<size.y; k++)
451 for(int j=0; j<size.x; j++)
452 fputc(level.board[corner.x + j][corner.y + k], f);
460 void EditorWidget::SetNameOnCurrentLevel(const char * newName)
462 Level & level = levelStorage[currentLevel];
463 memset(level.name, 0, 41);
464 strncpy(level.name, newName, 40);
468 void EditorWidget::AddNewLevelAtCurrentPosition(void)
471 memset(&l, 0, sizeof(l));
472 l.corner.x = l.corner.y = -1;
474 levelStorage.insert(levelStorage.begin() + currentLevel, l);
478 void EditorWidget::CountBoxesAndSpots(int & boxes, int & spots)
480 Level & level = levelStorage[currentLevel];
483 for(int x=0; x<BOARDSIZE; x++)
485 for(int y=0; y<BOARDSIZE; y++)
487 if (level.board[x][y] & GTBox)
490 if (level.board[x][y] & GTBoxSpot)
497 // Note: Only one parameter can be non-zero if you want expected behavior!
498 void EditorWidget::ShiftLevel(int dx, int dy)
500 Level & level = levelStorage[currentLevel];
502 // Shift grid in the X direction
505 for(int y=0; y<BOARDSIZE; y++)
509 uint8_t temp = level.board[BOARDSIZE - 1][y];
511 for(int x=BOARDSIZE-1; x>0; x--)
512 level.board[x][y] = level.board[x - 1][y];
514 level.board[0][y] = temp;
518 uint8_t temp = level.board[0][y];
520 for(int x=0; x<BOARDSIZE; x++)
521 level.board[x][y] = level.board[x + 1][y];
523 level.board[BOARDSIZE - 1][y] = temp;
527 // Shift grid in the Y direction
530 for(int x=0; x<BOARDSIZE; x++)
534 uint8_t temp = level.board[x][BOARDSIZE - 1];
536 for(int y=BOARDSIZE-1; y>0; y--)
537 level.board[x][y] = level.board[x][y - 1];
539 level.board[x][0] = temp;
543 uint8_t temp = level.board[x][0];
545 for(int y=0; y<BOARDSIZE; y++)
546 level.board[x][y] = level.board[x][y + 1];
548 level.board[x][BOARDSIZE - 1] = temp;
555 /*static*/ void EditorWidget::GetSizeAndCorner(Level * level, Point & size, Point & corner)
557 size.x = size.y = corner.x = corner.y = 0;
559 min.x = min.y = BOARDSIZE;
561 for(int x=0; x<BOARDSIZE; x++)
563 for(int y=0; y<BOARDSIZE; y++)
565 if (level->board[x][y] == 0)
582 size.x = max.x - min.x + 1;
583 size.y = max.y - min.y + 1;
589 void EditorWidget::ResizeGrid(void)
592 range.x = clientArea.width() / GRIDSIZE;
593 range.y = clientArea.height() / GRIDSIZE;
597 // Set some room for the board title (7.5%)
598 float titleHeight = s.height() * 0.075;
600 // Find the constraints
601 float boxSizeX = s.width() / gameBoard->width;
602 float boxSizeY = (s.height() - titleHeight) / gameBoard->height;
604 maxLength = (int)(boxSizeX > boxSizeY ? boxSizeY : boxSizeX);
606 offsetX = (s.width() - (maxLength * gameBoard->width)) / 2;
607 offsetY = ((s.height() - titleHeight) - (maxLength * gameBoard->height)) / 2;
608 titleBox.setRect(0, offsetY, s.width(), titleHeight);
609 offsetY += titleHeight; // Add in the title's height
615 // Halt processing for 'count' milliseconds
617 void EditorWidget::Pause(int count)
619 // DWORD endCount = GetTickCount() + count;
620 // while (GetTickCount() < endCount) {} // Still crude, but better control
622 usleep(count * 1000);
624 // This causes it to lock up randomly. :-/
628 while (time.msec() < count)