]> Shamusworld >> Repos - warehouse-man-deluxe/blob - src/editorwidget.cpp
1431edc243c3db38397d694558e28d24f0d4f356
[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
135
136 void EditorWidget::mousePressEvent(QMouseEvent * event)
137 {
138         if (event->button() == Qt::LeftButton)
139         {
140                 event->accept();
141         }
142 }
143
144
145 void EditorWidget::mouseMoveEvent(QMouseEvent * event)
146 {
147         if (event->buttons() & Qt::LeftButton)
148         {
149                 event->accept();
150         }
151 }
152
153
154 void EditorWidget::mouseReleaseEvent(QMouseEvent * event)
155 {
156         if (event->button() == Qt::LeftButton)
157         {
158                 event->accept();
159         }
160 }
161
162
163 void EditorWidget::mouseDoubleClickEvent(QMouseEvent * event)
164 {
165         if (event->button() == Qt::LeftButton)
166         {
167                 event->accept();
168         }
169 }
170
171
172 void EditorWidget::keyPressEvent(QKeyEvent * event)
173 {
174         int key = event->key();
175         Level & level = levelStorage[currentLevel];
176         Point & cursor = level.cursor;
177         Point & corner = level.corner;
178
179         if (key == Qt::Key_Up)
180         {
181                 if (event->modifiers() == Qt::ShiftModifier)
182                         ShiftLevel(0, -1);
183                 else
184                 {
185                         if (cursor.y > 0)
186                                 cursor.y--;
187
188                         if (((cursor.y - corner.y) == 0) && (corner.y > -1))
189                                 corner.y--;
190                 }
191         }
192         else if (key == Qt::Key_Down)
193         {
194                 if (event->modifiers() == Qt::ShiftModifier)
195                         ShiftLevel(0, +1);
196                 else
197                 {
198                         if (cursor.y < (BOARDSIZE - 1))
199                                 cursor.y++;
200
201                         if (cursor.y >= (range.y + corner.y - 1))
202                         {
203                                 if (corner.y < (BOARDSIZE - range.y))
204                                         corner.y++;
205                         }
206                 }
207         }
208         else if (key == Qt::Key_Left)
209         {
210                 if (event->modifiers() == Qt::ShiftModifier)
211                         ShiftLevel(-1, 0);
212                 else
213                 {
214                         if (cursor.x > 0)
215                                 cursor.x--;
216
217                         if (((cursor.x - corner.x) == 0) && (corner.x > -1))
218                                 corner.x--;
219                 }
220         }
221         else if (key == Qt::Key_Right)
222         {
223                 if (event->modifiers() == Qt::ShiftModifier)
224                         ShiftLevel(+1, 0);
225                 else
226                 {
227                         if (cursor.x < (BOARDSIZE - 1))
228                                 cursor.x++;
229
230                         if (cursor.x >= (range.x + corner.x - 1))
231                         {
232                                 if (corner.x < (BOARDSIZE - range.x))
233                                         corner.x++;
234                         }
235                 }
236         }
237         else if (key == Qt::Key_Period)
238         {
239                 level.board[cursor.x][cursor.y] ^= GTBoxSpot;
240         }
241         else if (key == Qt::Key_B)
242         {
243                 level.board[cursor.x][cursor.y] &= ~(GTSpace | GTWall | GTBox);
244                 level.board[cursor.x][cursor.y] |= GTBox;
245         }
246         else if (key == Qt::Key_W)
247         {
248                 level.board[cursor.x][cursor.y] = GTWall;
249         }
250         else if (key == Qt::Key_Space)
251         {
252                 level.board[cursor.x][cursor.y] &= ~(GTSpace | GTWall | GTBox);
253                 level.board[cursor.x][cursor.y] |= GTSpace;
254         }
255         else if (key == Qt::Key_O)
256         {
257                 // There can be only one!
258                 for(int x=0; x<BOARDSIZE; x++)
259                         for(int y=0; y<BOARDSIZE; y++)
260                                 level.board[x][y] &= ~GTMan;
261
262                 // Also, he can only be on a space!
263                 level.board[cursor.x][cursor.y] &= GTBoxSpot;
264                 level.board[cursor.x][cursor.y] |= GTMan;
265         }
266         else if (key == Qt::Key_V)
267         {
268                 level.board[cursor.x][cursor.y] = GTNull;
269         }
270         else
271                 return;         // Only update screen if keypress was recognized
272
273         update();
274 }
275
276
277 void EditorWidget::keyReleaseEvent(QKeyEvent * /*event*/)
278 {
279 }
280
281
282 void EditorWidget::resizeEvent(QResizeEvent * /*event*/)
283 {
284 //      QSize s = event->size();
285
286 //printf("Size of window is: %i x %i\n", s.width(), s.height());
287 //printf("Size of game grid is: %i x %i\n", gameBoard->width, gameBoard->height);
288         ResizeGrid();
289 }
290
291
292 void EditorWidget::CreateBackground(void)
293 {
294 #if 0
295         char BGRes[27][64] = {
296                 ":/res/grfttile.bmp",
297                 ":/res/cloth_6.bmp",
298                 ":/res/bg_tech_3.bmp",
299                 ":/res/bg_tech_2.bmp",
300                 ":/res/bg_tech_1.bmp",
301                 ":/res/bg_weave_3.bmp",
302                 ":/res/bg_weave_2.bmp",
303                 ":/res/bg_clouds_2.bmp",
304                 ":/res/bg_floor_plate.bmp",
305                 ":/res/bg_marble_b.bmp",
306                 ":/res/bg_marble_g.bmp",
307                 ":/res/bg_marble_p.bmp",
308                 ":/res/bg_marble_r.bmp",
309                 ":/res/bg_marble_rb.bmp",
310                 ":/res/bg_money_1.bmp",
311                 ":/res/bg_pinstripe2.bmp",
312                 ":/res/bg_pinstripe7.bmp",
313                 ":/res/bg_raindrops_large.bmp",
314                 ":/res/bg_raindrops_small.bmp",
315                 ":/res/bg_stucco.bmp",
316                 ":/res/bg_wood_w.bmp",
317                 ":/res/bg_wood_b1.bmp",
318                 ":/res/bg_wood_d.bmp",
319                 ":/res/bg_wood_f.bmp",
320                 ":/res/bg_wood_mh.bmp",
321                 ":/res/bg_wood_mv.bmp",
322                 ":/res/bg_wood_ro.bmp"
323         };
324
325         QPalette pal = palette();
326         pal.setBrush(backgroundRole(), QBrush(QPixmap(BGRes[m_nBackground])));
327         setAutoFillBackground(true);
328         setPalette(pal);
329
330         return true; // Ignore errors for now...
331 #else
332 //      QPalette pal = palette();
333 //      pal.setBrush(backgroundRole(), QBrush(QPixmap(":/bg_marble_g.bmp")));
334 //      setAutoFillBackground(true);
335 //      setPalette(pal);
336 #endif
337 }
338
339
340 void EditorWidget::ClearLevel(void)
341 {
342 //      gameBoard->ResetGame();
343 //      memset(board, 0, sizeof(board));
344         update();
345 }
346
347
348 bool EditorWidget::Load(void)
349 {
350         FILE * f = fopen("./wmd-level.data", "rb");
351
352         if (f)
353         {
354                 int numberOfLevels;
355                 fscanf(f, "%i\n", &numberOfLevels);
356 //printf("Load: Looking for %i levels...\n", numberOfLevels);
357
358                 for(int i=0; i<numberOfLevels; i++)
359                 {
360                         Level level;
361                         Point size, corner;
362                         memset(&level, 0, sizeof(Level));
363
364                         fscanf(f, "%i\n%i\n%i\n%i\n", &size.x, &size.y, &corner.x, &corner.y);
365                         fscanf(f, "%i\n%i\n%i\n%i\n", &level.corner.x, &level.corner.y, &level.cursor.x, &level.cursor.y);
366                         fread(level.name, 1, 41, f);
367 //printf("Load: name=\"%s\"\n", level.name);
368 //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);
369
370                         for(int k=0; k<size.y; k++)
371                                 for(int j=0; j<size.x; j++)
372                                         level.board[corner.x + j][corner.y + k] = fgetc(f);
373
374                         levelStorage.push_back(level);
375                 }
376
377                 fclose(f);
378                 return true;
379         }
380
381         // There is no save file, so use the internal levels
382         for(uint32_t i=0; i<NUMBER_OF_BOARDS; i++)
383         {
384                 Level l;
385                 memset(&l, 0, sizeof(Level));
386                 l.corner.x = l.corner.y = -1;
387
388                 // Create a GameBoard object for level #i (1-based)...
389                 GameBoard b(i + 1);
390
391                 for(int32_t x=0; x<b.width; x++)
392                         for(int32_t y=0; y<b.height; y++)
393                                 l.board[x][y] = b.board[(y * b.width) + x];
394
395                 l.board[b.playerX][b.playerY] |= GTMan;
396                 strncpy(l.name, b.name, 40);    // NULL is provided by the memset() above
397                 levelStorage.push_back(l);
398         }
399
400         return false;
401 }
402
403
404 bool EditorWidget::Save(void)
405 {
406         FILE * f = fopen("./wmd-level.data", "wb");
407
408         if (!f)
409         {
410                 printf("Could not open 'wmd-level.data' for writing!\n");
411                 return false;
412         }
413
414         fprintf(f, "%lu\n", levelStorage.size());
415
416         for(uint32_t i=0; i<levelStorage.size(); i++)
417         {
418                 Level & level = levelStorage[i];
419                 Point size, corner;
420                 GetSizeAndCorner(&level, size, corner);
421
422                 fprintf(f, "%i\n%i\n%i\n%i\n", size.x, size.y, corner.x, corner.y);
423                 fprintf(f, "%i\n%i\n%i\n%i\n", level.corner.x, level.corner.y, level.cursor.x, level.cursor.y);
424                 fwrite(level.name, 1, 41, f);
425
426                 for(int k=0; k<size.y; k++)
427                         for(int j=0; j<size.x; j++)
428                                 fputc(level.board[corner.x + j][corner.y + k], f);
429         }
430
431         fclose(f);
432         return true;
433 }
434
435
436 void EditorWidget::SetNameOnCurrentLevel(const char * newName)
437 {
438         Level & level = levelStorage[currentLevel];
439         memset(level.name, 0, 41);
440         strncpy(level.name, newName, 40);
441 }
442
443
444 void EditorWidget::AddNewLevelAtCurrentPosition(void)
445 {
446         Level l;
447         memset(&l, 0, sizeof(l));
448         l.corner.x = l.corner.y = -1;
449
450         levelStorage.insert(levelStorage.begin() + currentLevel, l);
451 }
452
453
454 // Note: Only one parameter can be non-zero if you want expected behavior!
455 void EditorWidget::ShiftLevel(int dx, int dy)
456 {
457         Level & level = levelStorage[currentLevel];
458
459         // Shift grid in the X direction
460         if (dy == 0)
461         {
462                 for(int y=0; y<BOARDSIZE; y++)
463                 {
464                         if (dx == 1)
465                         {
466                                 uint8_t temp = level.board[BOARDSIZE - 1][y];
467
468                                 for(int x=BOARDSIZE-1; x>0; x--)
469                                         level.board[x][y] = level.board[x - 1][y];
470
471                                 level.board[0][y] = temp;
472                         }
473                         else
474                         {
475                                 uint8_t temp = level.board[0][y];
476
477                                 for(int x=0; x<BOARDSIZE; x++)
478                                         level.board[x][y] = level.board[x + 1][y];
479
480                                 level.board[BOARDSIZE - 1][y] = temp;
481                         }
482                 }
483         }
484         // Shift grid in the Y direction
485         else
486         {
487                 for(int x=0; x<BOARDSIZE; x++)
488                 {
489                         if (dy == 1)
490                         {
491                                 uint8_t temp = level.board[x][BOARDSIZE - 1];
492
493                                 for(int y=BOARDSIZE-1; y>0; y--)
494                                         level.board[x][y] = level.board[x][y - 1];
495
496                                 level.board[x][0] = temp;
497                         }
498                         else
499                         {
500                                 uint8_t temp = level.board[x][0];
501
502                                 for(int y=0; y<BOARDSIZE; y++)
503                                         level.board[x][y] = level.board[x][y + 1];
504
505                                 level.board[x][BOARDSIZE - 1] = temp;
506                         }
507                 }
508         }
509 }
510
511
512 void EditorWidget::GetSizeAndCorner(Level * level, Point & size, Point & corner)
513 {
514         size.x = size.y = corner.x = corner.y = 0;
515         Point min, max;
516         min.x = min.y = BOARDSIZE;
517
518         for(int x=0; x<BOARDSIZE; x++)
519         {
520                 for(int y=0; y<BOARDSIZE; y++)
521                 {
522                         if (level->board[x][y] == 0)
523                                 continue;
524
525                         if (min.x > x)
526                                 min.x = x;
527
528                         if (min.y > y)
529                                 min.y = y;
530
531                         if (max.x < x)
532                                 max.x = x;
533
534                         if (max.y < y)
535                                 max.y = y;
536                 }
537         }
538
539         size.x = max.x - min.x + 1;
540         size.y = max.y - min.y + 1;
541         corner.x = min.x;
542         corner.y = min.y;
543 }
544
545
546 void EditorWidget::ResizeGrid(void)
547 {
548         clientArea = size();
549         range.x = clientArea.width() / GRIDSIZE;
550         range.y = clientArea.height() / GRIDSIZE;
551 #if 0
552         QSize s = size();
553
554         // Set some room for the board title (7.5%)
555         float titleHeight = s.height() * 0.075;
556
557         // Find the constraints
558         float boxSizeX = s.width() / gameBoard->width;
559         float boxSizeY = (s.height() - titleHeight) / gameBoard->height;
560
561         maxLength = (int)(boxSizeX > boxSizeY ? boxSizeY : boxSizeX);
562
563         offsetX = (s.width() - (maxLength * gameBoard->width)) / 2;
564         offsetY = ((s.height() - titleHeight) - (maxLength * gameBoard->height)) / 2;
565         titleBox.setRect(0, offsetY, s.width(), titleHeight);
566         offsetY += titleHeight; // Add in the title's height
567 #endif
568 }
569
570
571 //
572 // Halt processing for 'count' milliseconds
573 //
574 void EditorWidget::Pause(int count)
575 {
576 //      DWORD endCount = GetTickCount() + count;
577 //      while (GetTickCount() < endCount) {}     // Still crude, but better control
578 #if 1
579         usleep(count * 1000);
580 #else
581         // This causes it to lock up randomly. :-/
582         QTime time;
583         time.start();
584
585         while (time.msec() < count)
586                 ; // Do nothing...
587 #endif
588 }
589