]> Shamusworld >> Repos - warehouse-man-deluxe/blob - src/editorwidget.cpp
Added/fixed editor, added play level functionality.
[warehouse-man-deluxe] / src / editorwidget.cpp
1 //
2 // editorwidget.cpp: Game editor window widget
3 //
4 // by James Hammons
5 // (C) 2014 Underground Software
6 //
7 // JLH = James Hammons <jlhamm@acm.org>
8 //
9 // Who  When        What
10 // ---  ----------  ------------------------------------------------------------
11 // JLH  07/01/2014  Created this file
12 //
13
14 #include "editorwidget.h"
15 #include <unistd.h>                     // for usleep()
16 #include <string.h>
17 #include "boards.h"
18 #include "gameboard.h"
19
20
21 #define GRIDSIZE        40
22
23
24 EditorWidget::EditorWidget(QWidget * parent/*= 0*/): QWidget(parent),
25         currentLevel(0)
26 {
27 //      memset(&currentLevel, 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);
35
36         setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
37         setFocusPolicy(Qt::StrongFocus);        // Without this, it gets no keys
38         Load();
39 }
40
41
42 // This never gets called...!
43 EditorWidget::~EditorWidget(void)
44 {
45         Save();
46 }
47
48
49 QSize EditorWidget::sizeHint() const
50 {
51         return QSize(400, 400);
52 }
53
54
55 void EditorWidget::paintEvent(QPaintEvent * /*event*/)
56 {
57         QPainter painter(this);
58         QFont font;
59         Level & level = levelStorage[currentLevel];
60
61         for(int y=0; y<=clientArea.height()/GRIDSIZE; y++)
62         {
63                 for(int x=0; x<=clientArea.width()/GRIDSIZE; x++)
64                 {
65                         Point current(level.corner.x + x, level.corner.y + y);
66
67                         if ((current.x < 0) && (current.y < 0))
68                         {
69                                 painter.setBrush(Qt::black);
70                                 painter.drawRect(x + (GRIDSIZE / 2), y + (GRIDSIZE / 2), GRIDSIZE / 2, GRIDSIZE / 2); 
71                         }
72                         else if (current.x < 0)
73                         {
74                                 painter.setBrush(Qt::black);
75                                 painter.drawRect(x + (GRIDSIZE / 2), y * GRIDSIZE, GRIDSIZE / 2, GRIDSIZE); 
76                         }
77                         else if (current.y < 0)
78                         {
79                                 painter.setBrush(Qt::black);
80                                 painter.drawRect(x * GRIDSIZE, y + (GRIDSIZE / 2), GRIDSIZE, GRIDSIZE / 2); 
81                         }
82                         else
83                         {
84                                 uint8_t tile = level.board[current.x][current.y];
85
86                                 painter.setBrush(Qt::transparent);
87                                 painter.setPen(Qt::black);
88                                 painter.drawRect(x * GRIDSIZE, y * GRIDSIZE, GRIDSIZE, GRIDSIZE);
89
90                                 if (tile & (GTWall | GTSpace | GTBox))
91                                 {
92                                         if (tile & GTWall)
93                                         {
94                                                 painter.setBrush(Qt::white);
95                                                 painter.drawRect(x * GRIDSIZE, y * GRIDSIZE, GRIDSIZE, GRIDSIZE);
96                                         }
97                                         else if (tile & GTBox)
98                                         {
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);
102                                         }
103                                 }
104                                 else if (tile & GTNull)
105                                 {
106                                         painter.setBrush(Qt::black);
107 //                                      painter.setPen(Qt::black);
108                                         painter.drawRect(x * GRIDSIZE, y * GRIDSIZE, GRIDSIZE, GRIDSIZE);
109                                 }
110                                 else if (tile & GTMan)
111                                 {
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);
115                                 }
116
117                                 if ((tile & GTBoxSpot) && !(tile & (GTWall | GTNull)))
118                                 {
119                                         painter.setBrush(Qt::magenta);
120                                         painter.drawRect((x * GRIDSIZE) + (GRIDSIZE / 3),
121                                                 (y * GRIDSIZE) + (GRIDSIZE / 3), GRIDSIZE / 3, GRIDSIZE / 3);
122                                 }
123                         }
124                 }
125         }
126
127         int x = level.cursor.x - level.corner.x;
128         int y = level.cursor.y - level.corner.y;
129
130         painter.setBrush(Qt::transparent);
131         painter.setPen(Qt::darkGreen);
132         painter.drawEllipse((x * GRIDSIZE) + 4, (y * GRIDSIZE) + 4, GRIDSIZE - 8, GRIDSIZE - 8);
133
134         char s[256];
135         int boxes, spots;
136         CountBoxesAndSpots(boxes, spots);
137
138         if (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"));
144
145         painter.setPen(Qt::blue);
146         painter.drawText(0, 0, clientArea.width(), clientArea.height(),
147                 Qt::AlignRight | Qt::AlignBottom, QString(s));
148 }
149
150
151 void EditorWidget::mousePressEvent(QMouseEvent * event)
152 {
153         if (event->button() == Qt::LeftButton)
154         {
155                 event->accept();
156         }
157 }
158
159
160 void EditorWidget::mouseMoveEvent(QMouseEvent * event)
161 {
162         if (event->buttons() & Qt::LeftButton)
163         {
164                 event->accept();
165         }
166 }
167
168
169 void EditorWidget::mouseReleaseEvent(QMouseEvent * event)
170 {
171         if (event->button() == Qt::LeftButton)
172         {
173                 event->accept();
174         }
175 }
176
177
178 void EditorWidget::mouseDoubleClickEvent(QMouseEvent * event)
179 {
180         if (event->button() == Qt::LeftButton)
181         {
182                 event->accept();
183         }
184 }
185
186
187 void EditorWidget::keyPressEvent(QKeyEvent * event)
188 {
189         int key = event->key();
190         Level & level = levelStorage[currentLevel];
191         Point & cursor = level.cursor;
192         Point & corner = level.corner;
193
194         if (key == Qt::Key_Up)
195         {
196                 if (event->modifiers() == Qt::ShiftModifier)
197                         ShiftLevel(0, -1);
198                 else
199                 {
200                         if (cursor.y > 0)
201                                 cursor.y--;
202
203                         if (((cursor.y - corner.y) == 0) && (corner.y > -1))
204                                 corner.y--;
205                 }
206         }
207         else if (key == Qt::Key_Down)
208         {
209                 if (event->modifiers() == Qt::ShiftModifier)
210                         ShiftLevel(0, +1);
211                 else
212                 {
213                         if (cursor.y < (BOARDSIZE - 1))
214                                 cursor.y++;
215
216                         if (cursor.y >= (range.y + corner.y - 1))
217                         {
218                                 if (corner.y < (BOARDSIZE - range.y))
219                                         corner.y++;
220                         }
221                 }
222         }
223         else if (key == Qt::Key_Left)
224         {
225                 if (event->modifiers() == Qt::ShiftModifier)
226                         ShiftLevel(-1, 0);
227                 else
228                 {
229                         if (cursor.x > 0)
230                                 cursor.x--;
231
232                         if (((cursor.x - corner.x) == 0) && (corner.x > -1))
233                                 corner.x--;
234                 }
235         }
236         else if (key == Qt::Key_Right)
237         {
238                 if (event->modifiers() == Qt::ShiftModifier)
239                         ShiftLevel(+1, 0);
240                 else
241                 {
242                         if (cursor.x < (BOARDSIZE - 1))
243                                 cursor.x++;
244
245                         if (cursor.x >= (range.x + corner.x - 1))
246                         {
247                                 if (corner.x < (BOARDSIZE - range.x))
248                                         corner.x++;
249                         }
250                 }
251         }
252         else if (key == Qt::Key_Period)
253         {
254                 if (!(level.board[cursor.x][cursor.y] & (GTWall | GTNull)))
255                         level.board[cursor.x][cursor.y] ^= GTBoxSpot;
256         }
257         else if (key == Qt::Key_B)
258         {
259                 level.board[cursor.x][cursor.y] &= ~(GTSpace | GTWall | GTNull);
260                 level.board[cursor.x][cursor.y] ^= GTBox;
261         }
262         else if (key == Qt::Key_W)
263         {
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;
267                 else
268                         level.board[cursor.x][cursor.y] = GTSpace;
269         }
270         else if (key == Qt::Key_Space)
271         {
272                 level.board[cursor.x][cursor.y] &= ~(GTSpace | GTWall | GTBox | GTNull);
273                 level.board[cursor.x][cursor.y] |= GTSpace;
274         }
275         else if (key == Qt::Key_O)
276         {
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;
281
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;
285         }
286         else if (key == Qt::Key_V)
287         {
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;
291                 else
292                         level.board[cursor.x][cursor.y] = GTSpace;
293         }
294         else
295                 return;         // Only update screen if keypress was recognized
296
297         update();
298 }
299
300
301 void EditorWidget::keyReleaseEvent(QKeyEvent * /*event*/)
302 {
303 }
304
305
306 void EditorWidget::resizeEvent(QResizeEvent * /*event*/)
307 {
308 //      QSize s = event->size();
309
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);
312         ResizeGrid();
313 }
314
315
316 void EditorWidget::CreateBackground(void)
317 {
318 #if 0
319         char BGRes[27][64] = {
320                 ":/res/grfttile.bmp",
321                 ":/res/cloth_6.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"
347         };
348
349         QPalette pal = palette();
350         pal.setBrush(backgroundRole(), QBrush(QPixmap(BGRes[m_nBackground])));
351         setAutoFillBackground(true);
352         setPalette(pal);
353
354         return true; // Ignore errors for now...
355 #else
356 //      QPalette pal = palette();
357 //      pal.setBrush(backgroundRole(), QBrush(QPixmap(":/bg_marble_g.bmp")));
358 //      setAutoFillBackground(true);
359 //      setPalette(pal);
360 #endif
361 }
362
363
364 void EditorWidget::ClearLevel(void)
365 {
366 //      gameBoard->ResetGame();
367 //      memset(board, 0, sizeof(board));
368         update();
369 }
370
371
372 bool EditorWidget::Load(void)
373 {
374         FILE * f = fopen("./wmd-level.data", "rb");
375
376         if (f)
377         {
378                 int numberOfLevels;
379                 fscanf(f, "%i\n", &numberOfLevels);
380 //printf("Load: Looking for %i levels...\n", numberOfLevels);
381
382                 for(int i=0; i<numberOfLevels; i++)
383                 {
384                         Level level;
385                         Point size, corner;
386                         memset(&level, 0, sizeof(Level));
387
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);
393
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);
397
398                         levelStorage.push_back(level);
399                 }
400
401                 fclose(f);
402                 return true;
403         }
404
405         // There is no save file, so use the internal levels
406         for(uint32_t i=0; i<NUMBER_OF_BOARDS; i++)
407         {
408                 Level l;
409                 memset(&l, 0, sizeof(Level));
410                 l.corner.x = l.corner.y = -1;
411
412                 // Create a GameBoard object for level #i (1-based)...
413                 GameBoard b(i + 1);
414
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];
418
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);
422         }
423
424         return false;
425 }
426
427
428 bool EditorWidget::Save(void)
429 {
430         FILE * f = fopen("./wmd-level.data", "wb");
431
432         if (!f)
433         {
434                 printf("Could not open 'wmd-level.data' for writing!\n");
435                 return false;
436         }
437
438         fprintf(f, "%lu\n", levelStorage.size());
439
440         for(uint32_t i=0; i<levelStorage.size(); i++)
441         {
442                 Level & level = levelStorage[i];
443                 Point size, corner;
444                 GetSizeAndCorner(&level, size, corner);
445
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);
449
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);
453         }
454
455         fclose(f);
456         return true;
457 }
458
459
460 void EditorWidget::SetNameOnCurrentLevel(const char * newName)
461 {
462         Level & level = levelStorage[currentLevel];
463         memset(level.name, 0, 41);
464         strncpy(level.name, newName, 40);
465 }
466
467
468 void EditorWidget::AddNewLevelAtCurrentPosition(void)
469 {
470         Level l;
471         memset(&l, 0, sizeof(l));
472         l.corner.x = l.corner.y = -1;
473
474         levelStorage.insert(levelStorage.begin() + currentLevel, l);
475 }
476
477
478 void EditorWidget::CountBoxesAndSpots(int & boxes, int & spots)
479 {
480         Level & level = levelStorage[currentLevel];
481         boxes = spots = 0;
482
483         for(int x=0; x<BOARDSIZE; x++)
484         {
485                 for(int y=0; y<BOARDSIZE; y++)
486                 {
487                         if (level.board[x][y] & GTBox)
488                                 boxes++;
489
490                         if (level.board[x][y] & GTBoxSpot)
491                                 spots++;
492                 }
493         }
494 }
495
496
497 // Note: Only one parameter can be non-zero if you want expected behavior!
498 void EditorWidget::ShiftLevel(int dx, int dy)
499 {
500         Level & level = levelStorage[currentLevel];
501
502         // Shift grid in the X direction
503         if (dy == 0)
504         {
505                 for(int y=0; y<BOARDSIZE; y++)
506                 {
507                         if (dx == 1)
508                         {
509                                 uint8_t temp = level.board[BOARDSIZE - 1][y];
510
511                                 for(int x=BOARDSIZE-1; x>0; x--)
512                                         level.board[x][y] = level.board[x - 1][y];
513
514                                 level.board[0][y] = temp;
515                         }
516                         else
517                         {
518                                 uint8_t temp = level.board[0][y];
519
520                                 for(int x=0; x<BOARDSIZE; x++)
521                                         level.board[x][y] = level.board[x + 1][y];
522
523                                 level.board[BOARDSIZE - 1][y] = temp;
524                         }
525                 }
526         }
527         // Shift grid in the Y direction
528         else
529         {
530                 for(int x=0; x<BOARDSIZE; x++)
531                 {
532                         if (dy == 1)
533                         {
534                                 uint8_t temp = level.board[x][BOARDSIZE - 1];
535
536                                 for(int y=BOARDSIZE-1; y>0; y--)
537                                         level.board[x][y] = level.board[x][y - 1];
538
539                                 level.board[x][0] = temp;
540                         }
541                         else
542                         {
543                                 uint8_t temp = level.board[x][0];
544
545                                 for(int y=0; y<BOARDSIZE; y++)
546                                         level.board[x][y] = level.board[x][y + 1];
547
548                                 level.board[x][BOARDSIZE - 1] = temp;
549                         }
550                 }
551         }
552 }
553
554
555 /*static*/ void EditorWidget::GetSizeAndCorner(Level * level, Point & size, Point & corner)
556 {
557         size.x = size.y = corner.x = corner.y = 0;
558         Point min, max;
559         min.x = min.y = BOARDSIZE;
560
561         for(int x=0; x<BOARDSIZE; x++)
562         {
563                 for(int y=0; y<BOARDSIZE; y++)
564                 {
565                         if (level->board[x][y] == 0)
566                                 continue;
567
568                         if (min.x > x)
569                                 min.x = x;
570
571                         if (min.y > y)
572                                 min.y = y;
573
574                         if (max.x < x)
575                                 max.x = x;
576
577                         if (max.y < y)
578                                 max.y = y;
579                 }
580         }
581
582         size.x = max.x - min.x + 1;
583         size.y = max.y - min.y + 1;
584         corner.x = min.x;
585         corner.y = min.y;
586 }
587
588
589 void EditorWidget::ResizeGrid(void)
590 {
591         clientArea = size();
592         range.x = clientArea.width() / GRIDSIZE;
593         range.y = clientArea.height() / GRIDSIZE;
594 #if 0
595         QSize s = size();
596
597         // Set some room for the board title (7.5%)
598         float titleHeight = s.height() * 0.075;
599
600         // Find the constraints
601         float boxSizeX = s.width() / gameBoard->width;
602         float boxSizeY = (s.height() - titleHeight) / gameBoard->height;
603
604         maxLength = (int)(boxSizeX > boxSizeY ? boxSizeY : boxSizeX);
605
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
610 #endif
611 }
612
613
614 //
615 // Halt processing for 'count' milliseconds
616 //
617 void EditorWidget::Pause(int count)
618 {
619 //      DWORD endCount = GetTickCount() + count;
620 //      while (GetTickCount() < endCount) {}     // Still crude, but better control
621 #if 1
622         usleep(count * 1000);
623 #else
624         // This causes it to lock up randomly. :-/
625         QTime time;
626         time.start();
627
628         while (time.msec() < count)
629                 ; // Do nothing...
630 #endif
631 }
632