]> Shamusworld >> Repos - warehouse-man-deluxe/blob - src/gamewidget.cpp
Added undo move system, various improvements.
[warehouse-man-deluxe] / src / gamewidget.cpp
1 //
2 // gamewidget.cpp: Main game window widget
3 //
4 // by James Hammons
5 // (C) 2013 Underground Software
6 //
7 // JLH = James Hammons <jlhamm@acm.org>
8 //
9 // Who  When        What
10 // ---  ----------  ------------------------------------------------------------
11 // JLH  03/01/2014  Created this file
12 //
13
14 #include "gamewidget.h"
15 #include <unistd.h>                     // for usleep()
16 #include "gameboard.h"
17
18
19 GameWidget::GameWidget(QWidget * parent/*= 0*/): QWidget(parent),
20         level(1), gameBoard(new GameBoard(level)),
21         animating(false), boxMoving(false)
22 //      score(new QLabel)
23 {
24         CreateBackground();
25 //      score->setTextFormat(Qt::PlainText);
26 //      setFixedSize(580, 520);
27 //      gameBoard = new GameBoard(1);
28 }
29
30
31 GameWidget::~GameWidget(void)
32 {
33 }
34
35
36 void GameWidget::paintEvent(QPaintEvent * /*event*/)
37 {
38         // TO DO:
39         // Optimizations: Create a member variable that has a bitmap in it,
40         // tile it with the felt in OnCreate(), blit as background instead of
41         // FillRect(r, brWhite). Also need to keep track of client rect.
42         // Possibly have 2 bitmaps as member vars, so keep bm construction to a minimum...
43
44         QPainter painter(this);
45 //      QRect rcUpdate = dc.m_ps.rcPaint; // Update rect...
46 //      QRect rcUpdate = QRect(0, 0, 580, 520);                 // Update rect?
47
48         painter.translate(QPoint(offsetX, offsetY));
49 //      maxLength = 60;
50         int ptr = 0;
51
52         for(int y=0; y<gameBoard->height; y++)
53         {
54                 for(int x=0; x<gameBoard->width; x++)
55                 {
56                         int tile = gameBoard->board[ptr++];
57                         painter.setPen(QPen(Qt::black, 2.0, Qt::SolidLine));
58                         painter.setBrush(QBrush(Qt::black));
59                         int tileType = tile & (~GTBoxSpot);
60
61                         if (tileType == GTWall)
62                         {
63                                 painter.setBrush(QBrush(Qt::white));
64                                 painter.drawRect(x * maxLength, y * maxLength, maxLength, maxLength);
65                         }
66                         else if ((tileType == GTBox)
67                                 && (!(boxMoving && (movingBoxPositionX == x) && (movingBoxPositionY == y))))
68                         {
69                                 painter.setBrush(QBrush(tile & GTBoxSpot ? Qt::green : Qt::red));
70                                 painter.drawRect(x * maxLength, y * maxLength, maxLength, maxLength);
71                         }
72 #if 0
73                         else if (tile == GTBoxSpot)
74                         {
75                                 painter.setBrush(QBrush(Qt::magenta));
76 //                              painter.drawRect((x * maxLength) + 20, (y * maxLength) + 20, maxLength - 40, maxLength - 40);
77                                 painter.drawRect((x * maxLength) + (int)(20.0/60.0*(float)maxLength), (y * maxLength) + (int)(20.0/60.0*(float)maxLength), maxLength - (int)(40.0/60.0*(float)maxLength), maxLength - (int)(40.0/60.0*(float)maxLength));
78                         }
79                         else if (tile == (GTBox | GTBoxSpot))
80                         {
81                                 if (!(boxMoving && (movingBoxPositionX == x) && (movingBoxPositionY == y)))
82                                 {
83                                         painter.setBrush(QBrush(Qt::green));
84                                         painter.drawRect(x * maxLength, y * maxLength, maxLength, maxLength);
85                                 }
86                                 else
87                                 {
88                                         painter.setBrush(QBrush(Qt::magenta));
89 //                                      painter.drawRect((x * maxLength) + 20, (y * maxLength) + 20, maxLength - 40, maxLength - 40);
90                                 painter.drawRect((x * maxLength) + (int)(20.0/60.0*(float)maxLength), (y * maxLength) + (int)(20.0/60.0*(float)maxLength), maxLength - (int)(40.0/60.0*(float)maxLength), maxLength - (int)(40.0/60.0*(float)maxLength));
91                                 }
92                         }
93 #endif
94                         else if ((tileType == GTSpace)
95                                 || ((tileType == GTBox) && (boxMoving && (movingBoxPositionX == x) && (movingBoxPositionY == y))))
96                         {
97                                 painter.setBrush(QBrush(QPixmap(":/bg_marble_g.bmp")));
98                                 painter.drawRect(x * maxLength, y * maxLength, maxLength, maxLength);
99
100                                 if (tile & GTBoxSpot)
101                                 {
102                                         painter.setBrush(QBrush(Qt::magenta));
103 //                              painter.drawRect((x * maxLength) + 20, (y * maxLength) + 20, maxLength - 40, maxLength - 40);
104                                         painter.drawRect((x * maxLength) + (int)(20.0/60.0*(float)maxLength), (y * maxLength) + (int)(20.0/60.0*(float)maxLength), maxLength - (int)(40.0/60.0*(float)maxLength), maxLength - (int)(40.0/60.0*(float)maxLength));
105                                 }
106                         }
107
108                         if ((gameBoard->playerX == x) && (gameBoard->playerY == y) && !animating)
109                         {
110                                 painter.setBrush(QBrush(Qt::yellow));
111 //                              painter.drawEllipse((x * maxLength) + 10, (y * maxLength) + 10, maxLength - 20, maxLength - 20);
112                                 painter.drawEllipse((x * maxLength) + (int)(10.0/60.0*(float)maxLength), (y * maxLength) + (int)(10.0/60.0*(float)maxLength), maxLength - (int)(20.0/60.0*(float)maxLength), maxLength - (int)(20.0/60.0*(float)maxLength));
113                         }
114                 }
115
116                 if (animating)
117                 {
118                         painter.setBrush(QBrush(Qt::yellow));
119 //                      painter.drawEllipse(playerX + 10, playerY + 10, maxLength - 20, maxLength - 20);
120                         painter.drawEllipse(playerX + (int)(10.0/60.0*(float)maxLength), playerY + (int)(10.0/60.0*(float)maxLength), maxLength - (int)(20.0/60.0*(float)maxLength), maxLength - (int)(20.0/60.0*(float)maxLength));
121                 }
122
123                 if (boxMoving)
124                 {
125                         painter.setBrush(QBrush(Qt::red));
126                         painter.drawRect(boxX, boxY, maxLength, maxLength);
127                 }
128         }
129 }
130
131
132 void GameWidget::mousePressEvent(QMouseEvent * event)
133 {
134         if (event->button() == Qt::LeftButton)
135         {
136                 event->accept();
137         }
138 }
139
140
141 void GameWidget::mouseMoveEvent(QMouseEvent * event)
142 {
143         if (event->buttons() & Qt::LeftButton)
144         {
145                 event->accept();
146         }
147 }
148
149
150 void GameWidget::mouseReleaseEvent(QMouseEvent * event)
151 {
152         if (event->button() == Qt::LeftButton)
153         {
154                 event->accept();
155         }
156 }
157
158
159 void GameWidget::mouseDoubleClickEvent(QMouseEvent * event)
160 {
161         if (event->button() == Qt::LeftButton)
162         {
163                 event->accept();
164         }
165 }
166
167
168 void GameWidget::keyPressEvent(QKeyEvent * event)
169 {
170         int key = event->key();
171         float deltaX = 0, deltaY = 0;
172         float px = (float)(gameBoard->playerX * maxLength);
173         float py = (float)(gameBoard->playerY * maxLength);
174         float bx = px, by = py;
175
176         if (key == Qt::Key_Up)
177         {
178                 boxMoving = gameBoard->IsBoxNOfPlayer();
179                 int moveType = gameBoard->MovePlayerN();
180
181                 if (moveType == PMInvalid)
182                         return;
183
184                 deltaY = -1.0;
185         }
186         else if (key == Qt::Key_Down)
187         {
188                 boxMoving = gameBoard->IsBoxSOfPlayer();
189
190                 if (gameBoard->MovePlayerS() == PMInvalid)
191                         return;
192
193                 deltaY = +1.0;
194         }
195         else if (key == Qt::Key_Left)
196         {
197                 boxMoving = gameBoard->IsBoxWOfPlayer();
198
199                 if (gameBoard->MovePlayerW() == PMInvalid)
200                         return;
201
202                 deltaX = -1.0;
203         }
204         else if (key == Qt::Key_Right)
205         {
206                 boxMoving = gameBoard->IsBoxEOfPlayer();
207
208                 if (gameBoard->MovePlayerE() == PMInvalid)
209                         return;
210
211                 deltaX = +1.0;
212         }
213         else
214                 return;
215
216         animating = true;
217 //      update();
218
219         if (boxMoving)
220         {
221                 movingBoxPositionX = gameBoard->playerX + (int)deltaX;
222                 movingBoxPositionY = gameBoard->playerY + (int)deltaY;
223                 bx += deltaX * (float)maxLength;
224                 by += deltaY * (float)maxLength;
225         }
226
227         int steps = 15;
228         float stepSize = (float)maxLength / (float)steps;
229         deltaX *= stepSize, deltaY *= stepSize;
230
231         for(int i=0; i<steps; i++)
232         {
233                 px += deltaX;
234                 py += deltaY;
235                 playerX = (int)px;
236                 playerY = (int)py;
237                 bx += deltaX;
238                 by += deltaY;
239                 boxX = (int)bx;
240                 boxY = (int)by;
241                 repaint();
242                 Pause(3);
243         }
244
245         animating = boxMoving = false;
246
247         // Only update if a key we recognize has been pressed!
248         update();
249
250         if (gameBoard->GameHasBeenWon())
251                 emit GameWasWon();
252 }
253
254
255 void GameWidget::keyReleaseEvent(QKeyEvent * /*event*/)
256 {
257 }
258
259
260 void GameWidget::resizeEvent(QResizeEvent * /*event*/)
261 {
262 //      QSize s = event->size();
263
264 //printf("Size of window is: %i x %i\n", s.width(), s.height());
265 //printf("Size of game grid is: %i x %i\n", gameBoard->width, gameBoard->height);
266 #if 0
267         // Find the constraints
268         float boxSizeX = s.width() / gameBoard->width;
269         float boxSizeY = s.height() / gameBoard->height;
270
271         maxLength = (int)(boxSizeX > boxSizeY ? boxSizeY : boxSizeX);
272 #else
273         ResizeGrid();
274 #endif
275 }
276
277
278 void GameWidget::CreateBackground(void)
279 {
280 #if 0
281         char BGRes[27][64] = {
282                 ":/res/grfttile.bmp",
283                 ":/res/cloth_6.bmp",
284                 ":/res/bg_tech_3.bmp",
285                 ":/res/bg_tech_2.bmp",
286                 ":/res/bg_tech_1.bmp",
287                 ":/res/bg_weave_3.bmp",
288                 ":/res/bg_weave_2.bmp",
289                 ":/res/bg_clouds_2.bmp",
290                 ":/res/bg_floor_plate.bmp",
291                 ":/res/bg_marble_b.bmp",
292                 ":/res/bg_marble_g.bmp",
293                 ":/res/bg_marble_p.bmp",
294                 ":/res/bg_marble_r.bmp",
295                 ":/res/bg_marble_rb.bmp",
296                 ":/res/bg_money_1.bmp",
297                 ":/res/bg_pinstripe2.bmp",
298                 ":/res/bg_pinstripe7.bmp",
299                 ":/res/bg_raindrops_large.bmp",
300                 ":/res/bg_raindrops_small.bmp",
301                 ":/res/bg_stucco.bmp",
302                 ":/res/bg_wood_w.bmp",
303                 ":/res/bg_wood_b1.bmp",
304                 ":/res/bg_wood_d.bmp",
305                 ":/res/bg_wood_f.bmp",
306                 ":/res/bg_wood_mh.bmp",
307                 ":/res/bg_wood_mv.bmp",
308                 ":/res/bg_wood_ro.bmp"
309         };
310
311         QPalette pal = palette();
312         pal.setBrush(backgroundRole(), QBrush(QPixmap(BGRes[m_nBackground])));
313         setAutoFillBackground(true);
314         setPalette(pal);
315
316         return true; // Ignore errors for now...
317 #else
318 //      QPalette pal = palette();
319 //      pal.setBrush(backgroundRole(), QBrush(QPixmap(":/bg_marble_g.bmp")));
320 //      setAutoFillBackground(true);
321 //      setPalette(pal);
322 #endif
323 }
324
325
326 void GameWidget::NextLevel(void)
327 {
328         level++;
329         delete gameBoard;
330         gameBoard = new GameBoard(level);
331         ResizeGrid();
332         update();
333 }
334
335
336 void GameWidget::ResetLevel(void)
337 {
338         gameBoard->ResetGame();
339         update();
340 }
341
342
343 void GameWidget::UndoLastMove(void)
344 {
345         int dx, dy, type;
346
347         float deltaX = 0, deltaY = 0;
348         float px = (float)(gameBoard->playerX * maxLength);
349         float py = (float)(gameBoard->playerY * maxLength);
350         float bx = px, by = py;
351
352         // Return if nothing to undo
353         if (!gameBoard->UndoLastMove(dx, dy, type))
354                 return;
355
356         deltaX = (float)-dx;
357         deltaY = (float)-dy;
358
359         if (type == PMPush)
360                 boxMoving = true;
361
362         animating = true;
363 //      update();
364
365         if (boxMoving)
366         {
367 //              movingBoxPositionX = gameBoard->playerX + (int)deltaX;
368 //              movingBoxPositionY = gameBoard->playerY + (int)deltaY;
369                 movingBoxPositionX = gameBoard->playerX + dx;
370                 movingBoxPositionY = gameBoard->playerY + dy;
371 //              bx += deltaX * (float)maxLength;
372 //              by += deltaY * (float)maxLength;
373                 bx += (float)(dx * maxLength);
374                 by += (float)(dy * maxLength);
375         }
376
377         int steps = 15;
378         float stepSize = (float)maxLength / (float)steps;
379         deltaX *= stepSize, deltaY *= stepSize;
380
381         for(int i=0; i<steps; i++)
382         {
383                 px += deltaX;
384                 py += deltaY;
385                 playerX = (int)px;
386                 playerY = (int)py;
387                 bx += deltaX;
388                 by += deltaY;
389                 boxX = (int)bx;
390                 boxY = (int)by;
391                 repaint();
392                 Pause(3);
393         }
394
395         animating = boxMoving = false;
396         update();
397 }
398
399
400 #if 0
401 void GameWidget::DrawBoard(QPainter * painter, QRect r)
402 {
403         // Use "r" as clipping rect--only draw what's necessary
404
405 //      pDC->BitBlt(r.left, r.top, r.Width(), r.Height(), pDC2, r.left, r.top, SRCCOPY);
406
407         // Draw the solitaire board...
408
409         for(int i=0; i<7; i++)
410         {
411                 int y = 126; //130-4;
412
413                 for(int j=0; j<19; j++)
414                 {
415                         int card = solBoard[i][j];
416
417                         if (card != -1 && !(hitStack && (i == stackStart.x()) && (j >= stackStart.y())))
418                         {
419                                 int nLinesToDraw = 0; // Default--draws whole card
420
421                                 if (solBoard[i][j + 1] != -1 && !(hitStack && (i == stackStart.x()) && (j + 1 >= stackStart.y())))
422                                 {
423                                         nLinesToDraw = 6;
424
425                                         if (myDeck.IsFaceUp(card))
426                                                 nLinesToDraw += 14;
427                                 }
428
429                                 int x = 10 + (i * (CARD_WIDTH + 8));//, y = 130 + (j * 4);
430                                 y += 4;
431
432                                 if (j > 0)
433                                 {
434                                         if (myDeck.IsFaceUp(solBoard[i][j - 1]))  // Previous card...
435                                                 y += 14;
436                                 }
437
438                                 //wil wok??? mebbe... YESH!!!!!!!!!!!!!
439                                 QRect cardRect(x, y, CARD_WIDTH, (nLinesToDraw ? nLinesToDraw : CARD_HEIGHT));
440
441                                 if (r.intersects(cardRect))
442                                         cdtDraw(painter, x, y, (myDeck.IsFaceUp(card) ? myDeck.GetCardAtPos(card)
443                                                 : nCardBack), FACEUP, nLinesToDraw);
444                         }
445                 }
446         }
447
448         for(int i=0; i<4; i++)
449         {
450                 if (nHitAce == i + 1)
451                 {
452                         if (((nAce[i] - 1) % 13) != 0)
453                                 cdtDraw(painter, 200 + ((CARD_WIDTH + 4) * i), 7, nAce[i] - 1, FACEUP);
454                         else
455                                 cdtDraw(painter, 200 + ((CARD_WIDTH + 4) * i), 7, 0, INVISIBLEGHOST);
456                 }
457                 else
458                 {
459                         if (nAce[i] != -1)
460                                 cdtDraw(painter, 200 + ((CARD_WIDTH + 4) * i), 7, nAce[i], FACEUP);
461                         else
462                                 cdtDraw(painter, 200 + ((CARD_WIDTH + 4) * i), 7, 0, INVISIBLEGHOST);
463                 }
464         }
465         
466         if (stack1p != -1)
467                 cdtDraw(painter, 5, 7, nCardBack, FACEUP);
468         else
469         {
470 #if 0
471                 if (m_bShowX)
472                         cdtDraw(painter, 5, 7, 0, DECKX);
473                 else
474                         cdtDraw(painter, 5, 7, 0, DECKO);
475 #else
476                 cdtDraw(painter, 5, 7, 0, (m_bShowX ? DECKX : DECKO));
477 #endif
478         }
479
480         if (stack2p != -1)
481         {
482                 if (!hitDiscard)
483                 {
484                         for(int k=0; k<m_nNumToSplay; k++)
485                                 cdtDraw(painter, 5 + CARD_WIDTH + 6 + (k * 12), 7 + (k * 2),
486                                         myDeck.GetCardAtPos(stack2[stack2p - (m_nNumToSplay - k - 1)]), FACEUP);
487                 }
488                 else
489                 {
490                         if (stack2p != 0)
491                         {
492                                 if (m_nNumToSplay == 1)
493                                         cdtDraw(painter, 5 + CARD_WIDTH + 6, 7, myDeck.GetCardAtPos(stack2[stack2p - 1]), FACEUP);
494                                 else
495                                         for(int k=0; k<m_nNumToSplay-1; k++)
496                                                 cdtDraw(painter, 5 + CARD_WIDTH + 6 + (k * 12), 7 + (k * 2),
497                                                         myDeck.GetCardAtPos(stack2[stack2p - (m_nNumToSplay - k - 1)]), FACEUP);
498                         }
499                 }
500         }
501 }
502
503
504 void GameWidget::OnLButtonDown(QPoint point) 
505 {
506         dcHitStack = dcHitDiscard = false;  // For double clicking...
507         m_bTouchedGame = true;              // Game has been attempted!
508
509         if (!allowUserInput)
510                 return;
511
512         mouseDown = true;
513
514         // Set undo up...
515         for(int i=0; i<7; i++)
516                 for(int j=0; j<20; j++)
517                         solBoardUndo[i][j] = solBoard[i][j];
518
519         for(int i=0; i<24; i++)
520                 stack1Undo[i] = stack1[i], stack2Undo[i] = stack2[i];
521
522         for(int i=0; i<4; i++)
523                 nAceUndo[i] = nAce[i];
524
525         stack1pUndo = stack1p, stack2pUndo = stack2p;
526         m_nScoreUndo = m_nScore;
527         m_nExhaustedDeckUndo = m_nExhaustedDeck;
528         m_nNumToSplayUndo = m_nNumToSplay;
529         m_bShowXUndo = m_bShowX;
530         m_bCanUndo = false;
531
532         // Check for a hit on the tableaux...
533
534         for(int i=0; i<7; i++)
535         {
536                 QRect r;
537                 r.setLeft(10 + (i * (CARD_WIDTH + 8)));
538                 r.setRight(r.left() + CARD_WIDTH - 1);
539                 r.setTop(130);
540                 int nCards = 0;
541
542                 for(int j=0; j<19; j++)
543                 {
544                         if (solBoard[i][j] != -1)
545                         {
546                                 if (myDeck.IsFaceUp(solBoard[i][j]))
547                                 {
548                                         if ((j == 18) || (solBoard[i][j + 1] == -1))
549                                                 r.setBottom(r.top() + CARD_HEIGHT - 1);
550                                         else
551                                                 r.setBottom(r.top() + 17);
552
553                                         if (r.contains(point))
554                                         {
555                                                 hitStack = dcHitStack = true;
556                                                 stackStart = QPoint(i, j);
557                                                 mouseOffset = QPoint(point.x() - r.left(), point.y() - r.top());
558                                                 stackPos = QPoint(point.x() - mouseOffset.x(), point.y() - mouseOffset.y());
559                                                 QRect rcUpdate(r.left(), r.top(), r.width(), CARD_HEIGHT - 1); //wil wok?
560                                                 return;
561                                         }
562
563                                         r.setTop(r.top() + 18);
564                                 }
565                                 else
566                                 {
567                                         if (j != 18)
568                                         {
569                                                 if (solBoard[i][j + 1] == -1)
570                                                 {
571                                                         r.setBottom(r.top() + CARD_HEIGHT - 1);
572
573                                                         if (r.contains(point))
574                                                         {
575                                                                 myDeck.ToggleCardFacing(solBoard[i][j]);  // Turn over that last card
576
577 #if HAVE_SOUND
578                                                                 if (bSoundOn)
579                                                                         PlaySound(IDW_CARDFLIP);
580 #endif
581
582                                                                 update(r); //wil wok?
583
584                                                                 // Scoring...
585                                                                 if (!m_bVegasStyle)
586                                                                 {
587                                                                         m_nScore += 5;
588                                                                         emit UpdateScore(m_nScore);
589                                                                 }
590
591                                                                 return;
592                                                         }
593                                                 }
594                                         }
595
596                                         r.setTop(r.top() + 4);
597                                 }
598
599                                 nCards++;
600                         }
601                 }
602         }
603
604         // Check for hit on discard stack
605
606         int nCX = 5 + CARD_WIDTH + 6 + ((m_nNumToSplay - 1) * 12);
607         int nCY = 7 + ((m_nNumToSplay - 1) * 2);
608
609         if (QRect(nCX, nCY, CARD_WIDTH - 1, CARD_HEIGHT - 1).contains(point))
610         {
611                 if (stack2p != -1)
612                 {
613                         hitDiscard = dcHitDiscard = true;
614                         mouseOffset = QPoint(point.x() - (5 + CARD_WIDTH + 6 + ((m_nNumToSplay - 1) * 12)),
615                                 point.y() - (7 + ((m_nNumToSplay - 1) * 2)));
616                         stackPos = QPoint(point.x() - mouseOffset.x(), point.y() - mouseOffset.y());
617                         return;
618                 }
619         }
620
621         // Check for hit on remaining deck
622
623         if (QRect(5, 7, 5 + CARD_WIDTH - 1, 7 + CARD_HEIGHT - 1).contains(point))
624         {
625                 m_bCanUndo = true;
626
627                 if (stack1p == -1)  // I.e. it's empty...
628                 {
629                         // Scoring...
630                         if ((m_bDrawThree && (m_nExhaustedDeck == 3))
631                                 || (!m_bDrawThree && (m_nExhaustedDeck == 1)))
632                         {
633                                 if (!m_bVegasStyle)
634                                 {
635                                         m_nExhaustedDeck = 0;
636                                         m_nScore -= (m_bDrawThree ? 20 : 100);
637
638                                         if (m_nScore < 0)
639                                                 m_nScore = 0;
640
641                                         emit UpdateScore(m_nScore);
642                                 }
643                         }
644                         if (!m_bVegasStyle || (m_bVegasStyle && ((m_bDrawThree && (m_nExhaustedDeck < 3))
645                                         || (!m_bDrawThree && (m_nExhaustedDeck < 1)))))
646                         {
647                                 for(; stack2p != -1; stack2p--)
648                                 {
649                                         stack1p++;
650                                         stack1[stack1p] = stack2[stack2p];
651                                 }
652
653 #if HAVE_SOUND
654                                 if (bSoundOn)
655                                         PlaySound(IDW_CARDKNOCK);
656 #endif
657                         }
658                 }
659                 else
660                 {
661                         m_nNumToSplay = 0;
662
663                         for(int i=0; i<(m_bDrawThree ? 3 : 1); i++)
664                         {
665                                 if (stack1p != -1)  // I.e., there are cards left...
666                                 {
667                                         stack2[++stack2p] = stack1[stack1p--];
668
669 #if HAVE_SOUND
670                                         if (bSoundOn)
671                                         {
672                                                 PlaySound(IDW_CARDFLIP);
673                                                 // Pause
674                                                 Pause(55);
675                                         }
676 #endif
677
678                                         m_nNumToSplay++;
679                                 }
680                         }
681
682                         if (stack1p == -1)  // This is done here because it's right!
683                         {
684                                 m_nExhaustedDeck++;
685
686                                 if (m_bVegasStyle && ((m_bDrawThree && (m_nExhaustedDeck == 3))
687                                         || (!m_bDrawThree && (m_nExhaustedDeck == 1))))
688                                         m_bShowX = true;
689                         }
690                 }
691
692                 mouseOffset = QPoint(point.x() - 5, point.y() - 7);
693
694                 QRect inv1(5, 7, CARD_WIDTH, CARD_HEIGHT),
695                         inv2(5 + CARD_WIDTH + 6, 7, (2 * 12) + CARD_WIDTH, (2 * 2) + CARD_HEIGHT);
696                 update(inv1);
697                 update(inv2);
698         }
699
700         // Check for hit on ace piles
701
702         for(int i=0; i<4; i++)
703         {
704                 QRect aceRect(200 + ((CARD_WIDTH + 4) * i), 7, CARD_WIDTH - 1, CARD_HEIGHT - 1);
705
706                 if (aceRect.contains(point) && (nAce[i] > -1))
707                 {
708                         nHitAce = i + 1;
709 //                      mouseOffset = QPoint(point.x() - (200 + ((CARD_WIDTH + 4) * i)), point.y() - 7);
710                         mouseOffset = QPoint(point.x() - aceRect.x(), point.y() - aceRect.y());
711                         stackPos = QPoint(point.x() - mouseOffset.x(), point.y() - mouseOffset.y());
712                         return;
713                 }
714         }
715 }
716
717
718 void GameWidget::OnLButtonUp(QPoint point) 
719 {
720         if (!allowUserInput)
721                 return;
722
723         point -= mouseOffset; // ?? bad form!
724
725         if (hitStack || hitDiscard || (nHitAce != 0))
726         {
727                 QRect tabl[7];
728
729                 for(int i=0; i<7; i++)  // Compute valid rects at bottoms of stacks...
730                 {
731                         tabl[i].setLeft(10 + (i * (CARD_WIDTH + 8)));
732                         tabl[i].setRight(tabl[i].left() + CARD_WIDTH - 1);
733                         tabl[i].setTop(130);
734
735                         for(int j=0; j<19; j++)
736                         {
737                                 if ((solBoard[i][j] == -1)
738                                         || (hitStack && (i == stackStart.x()) && (j == stackStart.y())))
739                                 {
740                                         if (j > 0)
741                                         {
742                                                 for(int k=0; k<j-1; k++)
743                                                 {
744                                                         if (!myDeck.IsFaceUp(solBoard[i][k]))
745                                                                 tabl[i].setTop(tabl[i].top() + 4);
746                                                         else
747                                                                 tabl[i].setTop(tabl[i].top() + 17);
748                                                 }
749                                         }
750
751                                         tabl[i].setBottom(tabl[i].top() + CARD_HEIGHT - 1);
752                                         break;
753                                 }
754                         }
755                 }
756
757 //              stackPos = QPoint(point.x() - mouseOffset.x(), point.y() - mouseOffset.y());
758 //              QRect c(point.x(), point.y(), CARD_WIDTH - 1, CARD_HEIGHT - 1);
759 //              QRect c(point.x() - mouseOffset.x(), point.y() - mouseOffset.y(), CARD_WIDTH - 1, CARD_HEIGHT - 1);
760                 QRect c(stackPos.x(), stackPos.y(), CARD_WIDTH - 1, CARD_HEIGHT - 1);
761                 QRect a[4];
762                 a[0] = QRect(200, 7, CARD_WIDTH - 1, CARD_HEIGHT - 1);
763                 a[1] = QRect(200 + ((CARD_WIDTH + 4) * 1), 7, CARD_WIDTH - 1, CARD_HEIGHT - 1);
764                 a[2] = QRect(200 + ((CARD_WIDTH + 4) * 2), 7, CARD_WIDTH - 1, CARD_HEIGHT - 1);
765                 a[3] = QRect(200 + ((CARD_WIDTH + 4) * 3), 7, CARD_WIDTH - 1, CARD_HEIGHT - 1);
766
767                 bool bHitAce[4];
768                 bHitAce[0] = c.intersects(a[0]);
769                 bHitAce[1] = c.intersects(a[1]);
770                 bHitAce[2] = c.intersects(a[2]);
771                 bHitAce[3] = c.intersects(a[3]);
772
773                 // Check to see if hit more than one ace & pick the one that's closer
774                 for(int i=0; i<3; i++)
775                 {
776                         if (bHitAce[i] && bHitAce[i + 1] && (nAce[i] == -1) && (nAce[i + 1] == -1))
777                         {
778                                 if (c.intersected(a[i]).width() > c.intersected(a[i + 1]).width())
779                                         bHitAce[i + 1] = false;
780                                 else
781                                         bHitAce[i] = false;
782
783                                 break;
784                         }
785                 }
786
787                 bool bMovedToAce = false;
788
789                 for(int i=0; i<4; i++)
790                 {
791                         if (bHitAce[i] && IsValidMoveToAce(nAce[i]))
792                         {
793                                 m_bCanUndo = true;
794
795                                 if (hitStack)
796                                         nAce[i] = myDeck.GetCardAtPos(solBoard[stackStart.x()][stackStart.y()]),
797                                         solBoard[stackStart.x()][stackStart.y()] = -1;
798
799                                 if (hitDiscard)
800                                 {
801                                         nAce[i] = myDeck.GetCardAtPos(stack2[stack2p--]);
802
803                                         if (m_nNumToSplay != 1)
804                                                 m_nNumToSplay--;
805                                 }
806
807                                 if (nHitAce != 0)
808                                 {
809                                         nAce[i] = nAce[nHitAce - 1];
810                                         int nCard = nAce[nHitAce - 1];
811                                         nAce[nHitAce - 1] = ((nCard - 1) % 13 == 0 ? -1 : nCard - 1);
812                                         break;
813                                 }
814
815 #if HAVE_SOUND
816                                 if (bSoundOn)
817                                         PlaySound(IDW_CARDPLACE);
818 #endif
819
820                                 bMovedToAce = true;
821
822                                 // Scoring...
823 #if 0
824                                 if (m_bVegasStyle)
825                                         m_nScore += 5;
826                                 else
827                                         m_nScore += 10;
828 #else
829                                 m_nScore += (m_bVegasStyle ? 5 : 10);
830 #endif
831
832                                 emit UpdateScore(m_nScore);
833                                 break;
834                         }
835                 }
836
837                 if (!bMovedToAce) // No aces, so check for stacks
838                 {
839                         for(int i=0; i<7; i++)
840                         {
841                                 if (c.intersects(tabl[i]) && IsValidMoveToTableaux(i))
842                                 {
843                                         m_bCanUndo = true;
844
845 #if HAVE_SOUND
846                                         if (bSoundOn)
847                                                 PlaySound(IDW_CARDPLACE);
848 #endif
849
850                                         if (hitStack && (i != stackStart.x()))
851                                         {
852                                                 int cnt = stackStart.y();
853
854                                                 for(int k=0; k<19; k++)
855                                                 {
856                                                         if (solBoard[i][k] == -1)
857                                                         {
858                                                                 solBoard[i][k] = solBoard[stackStart.x()][cnt];
859                                                                 solBoard[stackStart.x()][cnt] = -1;
860                                                                 cnt++;
861                                                         }
862
863                                                         if (solBoard[stackStart.x()][cnt] == -1) // Done copying?
864                                                                 break;
865                                                 }
866
867                                                 break;
868                                         }
869
870                                         if (hitDiscard)
871                                         {
872                                                 for(int k=0; k<19; k++)
873                                                 {
874                                                         if (solBoard[i][k] == -1)
875                                                         {
876                                                                 solBoard[i][k] = stack2[stack2p--];
877                                                                 myDeck.SetCardFaceUp(solBoard[i][k]);
878
879                                                                 // Scoring...
880                                                                 if (!m_bVegasStyle)
881                                                                 {
882                                                                         m_nScore += 5;
883                                                                         emit UpdateScore(m_nScore);
884                                                                 }
885
886                                                                 if (m_nNumToSplay != 1)
887                                                                         m_nNumToSplay--;
888
889                                                                 break;
890                                                         }
891                                                 }
892
893                                                 break;
894                                         }
895
896                                         if (nHitAce != 0)
897                                         {
898                                                 // handle moving to tableaux here...
899                                                 for(int k=0; k<19; k++)
900                                                 {
901                                                         if (solBoard[i][k] == -1)
902                                                         {
903                                                                 int nCard = nAce[nHitAce - 1];
904
905                                                                 for(int t=0; t<52; t++)  // We have to find da damn thing...
906                                                                 {
907                                                                         if (myDeck.GetCardAtPos(t) == nCard)
908                                                                         {
909                                                                                 solBoard[i][k] = t;
910                                                                                 break;
911                                                                         }
912                                                                 }
913
914                                                                 nAce[nHitAce - 1] = ((nCard - 1) % 13 == 0 ? -1 : nCard - 1);
915                                                                 myDeck.SetCardFaceUp(solBoard[i][k]);
916
917                                                                 // Scoring...
918 #if 0
919                                                                 if (!m_bVegasStyle)
920                                                                         m_nScore -= 15;
921                                                                 else
922                                                                         m_nScore -= 5;
923 #else
924                                                                 m_nScore -= (m_bVegasStyle ? 5 : 15);
925 #endif
926
927                                                                 emit UpdateScore(m_nScore);
928                                                                 break;
929                                                         }
930                                                 }
931
932                                                 break;
933                                         }
934                                 }
935                         }
936                 }
937
938                 update();
939         }
940
941         mouseDown = hitStack = hitDiscard = false;
942         nHitAce = 0;
943
944         if (bAutoRemove)
945                 HandleAutoRemove();
946
947         if (PlayerWon())
948         {
949                 emit UpdateScore(m_nScore);
950                 HandleStatistics();
951                 m_bWonLastGame = true;
952                 m_bCanUndo = false;
953
954 #if HAVE_SOUND
955                 if (bSoundOn)
956                 {
957                         QString id[] = { IDW_WINNER1, IDW_WINNER2, IDW_WINNER3, IDW_WINNER4, IDW_WINNER5 };
958                         srand((unsigned)time(NULL));
959                         int nWaveNum = rand() % 5;
960                         PlaySound(id[nWaveNum]);
961                 }
962 #endif
963
964                 QMessageBox::information(this, "MAC Solitaire", "Congratulations!\nYou won!");
965                 allowUserInput = false;
966         }
967 }
968
969
970 void GameWidget::OnMouseMove(QPoint point) 
971 {
972         if (mouseDown && (hitStack || hitDiscard || (nHitAce != 0)))
973         {
974                 int nHeight = 0;
975
976                 if (hitStack)
977                 {
978                         for(int i=stackStart.y(); i<19; i++)
979                                 if (solBoard[stackStart.x()][i] != -1)
980                                         nHeight += 18;
981                 }
982                 else
983                         nHeight = 18;
984
985                 nHeight += CARD_HEIGHT - 18;
986
987                 QRect rcOld(stackPos.x(), stackPos.y(), CARD_WIDTH,
988                         nHeight); // Find old position for repainting...
989
990                 stackPos = QPoint(point.x() - mouseOffset.x(), point.y() - mouseOffset.y());
991
992                 QRect rcNew(stackPos.x(), stackPos.y(), CARD_WIDTH,
993                         nHeight); // Find new position
994                 QRect rcUpdate = rcOld.united(rcNew);
995                 update(rcUpdate); //wil wok? YESH!
996         }
997 }
998
999
1000 void GameWidget::OnLButtonDblClk(QPoint point) 
1001 {
1002         if (dcHitStack || dcHitDiscard)
1003         {
1004                 hitStack = dcHitStack, hitDiscard = dcHitDiscard;
1005
1006                 for(int i=0; i<4; i++)
1007                 {
1008                         if (IsValidMoveToAce(nAce[i]))
1009                         {
1010                                 if (hitStack)
1011                                 {
1012                                         nAce[i] = myDeck.GetCardAtPos(solBoard[stackStart.x()][stackStart.y()]);
1013                                         solBoard[stackStart.x()][stackStart.y()] = -1;
1014                                 }
1015                                 else
1016                                 {
1017                                         nAce[i] = myDeck.GetCardAtPos(stack2[stack2p--]);
1018
1019                                         if (m_nNumToSplay != 1)
1020                                                 m_nNumToSplay--;
1021                                 }
1022
1023                                 update();
1024
1025 #if HAVE_SOUND
1026                                 if (bSoundOn)
1027                                         PlaySound(IDW_ZIP);
1028 #endif
1029
1030                                 // Scoring...
1031 #if 0
1032                                 if (m_bVegasStyle)
1033                                         m_nScore += 5;
1034                                 else
1035                                         m_nScore += 10;
1036 #else
1037                                 m_nScore += (m_bVegasStyle ? 5 : 10);
1038 #endif
1039
1040                                 emit UpdateScore(m_nScore);
1041                                 break;
1042                         }
1043                 }
1044                 
1045                 dcHitStack = hitStack = dcHitDiscard = hitDiscard = false;
1046         }
1047         else
1048                 OnLButtonDown(point); // Either was on draw pile or somewhere else...
1049 }
1050
1051
1052 // It's behaving strangely, especially with kings in the ace piles...
1053 // It's becuase of the mod 13 function: kings(13) get whacked to 0 this way...
1054 void GameWidget::HandleAutoRemove(void)
1055 {
1056         bool bCheck = true;
1057
1058         while (bCheck)
1059         {
1060                 bCheck = false;
1061
1062                 int nLowestAce = (nAce[0] == -1 ? 0 : ((nAce[0] - 1) % 13) + 1); // Aces are 1-based, cards 1-based
1063
1064                 for(int i=1; i<4; i++)
1065                 {
1066                         int nTemp = (nAce[i] == -1 ? 0 : ((nAce[i] - 1) % 13) + 1);
1067
1068                         if (nTemp < nLowestAce)
1069                                 nLowestAce = nTemp;
1070                 }
1071
1072                 for(int i=0; i<7; i++)  // Compare cards that *can* go
1073                 {
1074                         for(int j=18; j>=0; j--)
1075                         {
1076                                 if (solBoard[i][j] != -1)
1077                                 {
1078                                         if (myDeck.IsFaceUp(solBoard[i][j]))
1079                                         {
1080                                                 int nCard = myDeck.GetCardAtPos(solBoard[i][j]);
1081
1082                                                 for(int k=0; k<4; k++)
1083                                                 {
1084                                                         if (IsValidMoveToAce(nAce[k], nCard))
1085                                                         {
1086                                                                 // Ranking/suiting doesn't work if nAce == -1... FIX!
1087                                                                 // Should be fixed now...
1088                                                                 // Figure out some way to simplify this tortuous logic, for cryin' out loud!
1089                                                                 int nSuit[4], nRank[4];
1090
1091                                                                 for(int t=0; t<4; t++)
1092                                                                 {
1093                                                                         if (nAce[t] != -1)
1094                                                                                 nSuit[t] = ((nAce[t] > 13) && (nAce[t] < 40) ? 0 : 1);
1095                                                                         else
1096                                                                                 nSuit[t] = -1;
1097
1098                                                                         nRank[t] = ((nAce[t] - 1) % 13) + 1;
1099                                                                 }
1100
1101                                                                 int nCardSuit = ((nCard > 13) && (nCard < 40) ? 0 : 1),
1102                                                                         nCardRank = ((nCard - 1) % 13) + 1;
1103                                                                 bool bSpecial = false;
1104                                                                 int nCR[2], nCnt = 0;
1105
1106                                                                 for(int t=0; t<4; t++)
1107                                                                         if ((nCardSuit != nSuit[t]) && (t != k) && (nSuit[t] != -1))
1108                                                                                 nCR[nCnt++] = nRank[t];
1109
1110                                                                 if ((nCnt == 2) && (nCR[0] == nCR[1])
1111                                                                         && (nCR[0] - nLowestAce == 2) && (nCardRank - nLowestAce == 3))
1112                                                                         bSpecial = true;
1113
1114                                                                 if (((((nCard - 1) % 13) + 1) - nLowestAce) <= 2 || bSpecial)
1115                                                                 // OR difference is 3 and both opposite color are at 2
1116 //                                                              if (((nCard%13) - nLowestAce) <= 2)
1117                                                                 {
1118                                                                         solBoard[i][j] = -1;
1119
1120                                                                         if (m_bAnimationsOn)
1121                                                                                 AnimateCards(nCard, k, i, j);
1122
1123                                                                         nAce[k] = nCard;
1124                                                                         bCheck = true;
1125
1126                                                                         // Scoring...
1127 #if 0
1128                                                                         if (m_bVegasStyle)
1129                                                                                 m_nScore += 5;
1130                                                                         else
1131                                                                                 m_nScore += 10;
1132 #else
1133                                                                         m_nScore += (m_bVegasStyle ? 5 : 10);
1134 #endif
1135                                                                         emit UpdateScore(m_nScore);
1136                                                                         break;
1137                                                                 }
1138                                                         }
1139                                                 }
1140                                         }
1141
1142                                         break;
1143                                 }
1144                         }
1145                 }
1146
1147                 if (stack2p != -1)
1148                 {
1149                         int nCard = myDeck.GetCardAtPos(stack2[stack2p]);
1150
1151                         for(int k=0; k<4; k++)
1152                         {
1153                                 if (IsValidMoveToAce(nAce[k], nCard))
1154                                 {
1155                                         // Ranking/suiting doesn't work if nAce == -1... FIX!
1156                                         // Should be fixed now...
1157                                         // Figure out some way to simplify this tortuous logic, for cryin' out loud!
1158                                         int nSuit[4], nRank[4];
1159
1160                                         for(int t=0; t<4; t++)
1161                                         {
1162                                                 if (nAce[t] != -1)
1163                                                         nSuit[t] = ((nAce[t] > 13) && (nAce[t] < 40) ? 0 : 1);
1164                                                 else
1165                                                         nSuit[t] = -1;
1166
1167                                                 nRank[t] = ((nAce[t] - 1) % 13) + 1;
1168                                         }
1169
1170                                         int nCardSuit = ((nCard > 13) && (nCard < 40) ? 0 : 1),
1171                                                 nCardRank = ((nCard - 1) % 13) + 1;
1172                                         bool bSpecial = false;
1173                                         int nCR[2], nCnt = 0;
1174
1175                                         for(int t=0; t<4; t++)
1176                                         {
1177                                                 if ((nCardSuit != nSuit[t]) && (t != k) && (nSuit[t] != -1))
1178                                                         nCR[nCnt++] = nRank[t];
1179                                         }
1180
1181                                         if ((nCnt == 2) && (nCR[0] == nCR[1])
1182                                                 && (nCR[0] - nLowestAce == 2) && (nCardRank - nLowestAce == 3))
1183                                                 bSpecial = true;
1184
1185                                         if (((((nCard - 1) % 13) + 1) - nLowestAce) <= 2 || bSpecial)
1186                                         // OR difference is 3 and both opposite color are at 2 (tortuously checked above)
1187                                         {
1188                                                 stack2p--;
1189
1190                                                 if (m_nNumToSplay != 1)
1191                                                         m_nNumToSplay--;
1192
1193                                                 if (m_bAnimationsOn)
1194                                                         AnimateCards(nCard, k, -1, -1);
1195
1196                                                 nAce[k] = nCard;
1197                                                 bCheck = true;
1198
1199                                                 // Scoring...
1200 #if 0
1201                                                 if (m_bVegasStyle)
1202                                                         m_nScore += 5;
1203                                                 else
1204                                                         m_nScore += 10;
1205 #else
1206                                                 m_nScore += (m_bVegasStyle ? 5 : 10);
1207 #endif
1208
1209                                                 emit UpdateScore(m_nScore);
1210                                                 break;
1211                                         }
1212                                 }
1213                         }
1214                 }
1215         }
1216 }
1217
1218
1219 // Have two routines? One to initiate, the other to handle card movements?
1220 // Good idea! Implement it, you schmendrick!
1221 void GameWidget::AnimateCards(int nCard, int nAce, int nTabX, int nTabY)
1222 {
1223 //no mas--jeff no likee CWaitCursor wc;   // Automagically reverts when it goes out of scope
1224         int nCX, nCY, nDX, nDY;
1225
1226         // Step 1: figure out where card started from
1227         if (nTabX == -1)
1228         {
1229 //              nCX = 5+CARD_WIDTH+6, nCY = 5;
1230                 nCX = 5 + CARD_WIDTH + 6 + ((m_nNumToSplay - 1) * 12);
1231                 nCY = 7 + ((m_nNumToSplay - 1) * 2);
1232         }
1233         else
1234         {
1235                 nCX = 10 + (nTabX * (CARD_WIDTH + 8)), nCY = 130;
1236
1237                 for(int j=0; j<nTabY; j++)
1238                 {
1239                         if (solBoard[nTabX][j] != -1)
1240                         {
1241                                 if (myDeck.IsFaceUp(solBoard[nTabX][j]))
1242                                         nCY += 18;
1243                                 else
1244                                         nCY += 4;
1245                         }
1246                 }
1247         }
1248         // Step 2: figure out where card is going
1249         nDX = 200 + ((CARD_WIDTH + 4) * nAce), nDY = 7;
1250         // Step 3: animate card flying from start to destination
1251         // Use Bresenham's algorithm to figure path...
1252         // (ideas for movement: increasing acceleration, curved paths, more than one at a time)
1253         m_bFreeCard = true;
1254         m_pFirstCard = new SCardInfo(nCard);
1255         int nDeltaX = nDX - nCX, nDeltaY = nDY - nCY;
1256         int nError = 0;
1257         int nUpdate = 0;
1258         update(); //will do it??? Seems to...
1259 //Doing this causes an image of the card to be drawn at (0, 0) :-/
1260 //      repaint();
1261         QRect rcOld(nCX, nCY, CARD_WIDTH, CARD_HEIGHT), rcNew, rcUpdate;
1262
1263         if (abs(nDeltaX) > abs(nDeltaY))
1264         {
1265                 for(int i=0; i<abs(nDeltaX); i++)
1266                 {
1267                         // Put card draw stuff into OnDraw? (probably best way to do it...)
1268                         nError += abs(nDeltaY);
1269
1270                         if (nError > abs(nDeltaX))
1271                                 nCY += (nDeltaY < 0 ? -1 : +1), nError -= abs(nDeltaX);
1272
1273                         m_pFirstCard->nXPos = nCX + (nDeltaX < 0 ? -i : +i), m_pFirstCard->nYPos = nCY;
1274                         // Draw card
1275                         nUpdate++;
1276
1277                         if (nUpdate == 10)
1278                         {
1279                                 rcNew = QRect(m_pFirstCard->nXPos, m_pFirstCard->nYPos,
1280                                         CARD_WIDTH, CARD_HEIGHT);
1281                                 rcUpdate = rcOld.united(rcNew);
1282                                 nUpdate = 0;
1283                                 repaint(rcUpdate);
1284                                 rcOld = rcNew;
1285                                 // Pause
1286                                 Pause(3);
1287                         }
1288                         // calc new positions
1289                 }
1290
1291                 m_pFirstCard->nXPos = nDX, m_pFirstCard->nYPos = nDY;
1292                 rcNew = QRect(nDX, nDY, CARD_WIDTH, CARD_HEIGHT);
1293                 rcUpdate = rcOld.united(rcNew);
1294                 repaint(rcUpdate);
1295         }
1296         else
1297         {
1298                 for(int i=0; i<abs(nDeltaY); i++)
1299                 {
1300                         // Put card draw stuff into OnDraw? (probably best way to do it...)
1301                         nError += abs(nDeltaX);
1302
1303                         if (nError > abs(nDeltaY))
1304                                 nCX += (nDeltaX < 0 ? -1 : +1), nError -= abs(nDeltaY);
1305
1306                         m_pFirstCard->nXPos = nCX, m_pFirstCard->nYPos = nCY + (nDeltaY < 0 ? -i : +i);
1307                         // Draw card
1308                         nUpdate++;
1309
1310                         if (nUpdate == 10)
1311                         {
1312                                 rcNew = QRect(m_pFirstCard->nXPos, m_pFirstCard->nYPos,
1313                                         CARD_WIDTH, CARD_HEIGHT);
1314                                 rcUpdate = rcOld.united(rcNew);
1315                                 nUpdate = 0;
1316                                 repaint(rcUpdate);//this is crappy. should only update what's needed!
1317                                 rcOld = rcNew;
1318                                 // Pause
1319                                 Pause(3);
1320                         }
1321                         // calc new positions
1322                 }
1323
1324                 m_pFirstCard->nXPos = nDX, m_pFirstCard->nYPos = nDY;
1325                 rcNew = QRect(nDX, nDY, CARD_WIDTH, CARD_HEIGHT);
1326                 rcUpdate = rcOld.united(rcNew);
1327                 repaint(rcUpdate);
1328         }
1329
1330         m_bFreeCard = false;
1331         delete m_pFirstCard;
1332 }
1333
1334
1335 bool GameWidget::IsValidMoveToAce(int nAceM)
1336 {
1337         int nCards = 0;
1338
1339         for(int k=stackStart.y(); k<19; k++)
1340         {
1341                 if (solBoard[stackStart.x()][k] != -1)
1342                         nCards++;
1343         }
1344
1345         if ((hitStack && (nCards == 1)) || hitDiscard)
1346         {
1347                 int nCardHit = (hitStack ? myDeck.GetCardAtPos(solBoard[stackStart.x()][stackStart.y()])
1348                         : myDeck.GetCardAtPos(stack2[stack2p]));
1349                 return IsValidMoveToAce(nAceM, nCardHit);
1350         }
1351         else if (nHitAce != 0)
1352         {
1353                 return IsValidMoveToAce(nAceM, nAce[nHitAce - 1]);
1354         }
1355
1356         return false;
1357 }
1358
1359
1360 bool GameWidget::IsValidMoveToAce(int nAce, int nCard)
1361 {
1362         if (((nAce == -1) && ((nCard % 13) == 1))
1363                 || ((nAce == (nCard - 1)) && ((nAce % 13) != 0)))
1364                 return true;
1365
1366         return false;
1367 }
1368
1369
1370 bool GameWidget::IsValidMoveToTableaux(int nStack)
1371 {
1372         int nBottomCard = -1, nTopCard;
1373
1374         for(int i=0; i<19; i++)
1375         {
1376                 if ((solBoard[nStack][i] != -1) && (myDeck.IsFaceUp(solBoard[nStack][i])))
1377                         nBottomCard = myDeck.GetCardAtPos(solBoard[nStack][i]);
1378         }
1379
1380         if (hitStack)
1381                 nTopCard = myDeck.GetCardAtPos(solBoard[stackStart.x()][stackStart.y()]);
1382         else if (hitDiscard)
1383                 nTopCard = myDeck.GetCardAtPos(stack2[stack2p]);
1384         else if (nHitAce != 0)
1385                 nTopCard = nAce[nHitAce - 1];
1386
1387         int colorBC = ((nBottomCard > 13) && (nBottomCard < 40) ? 0 : 1);
1388         int colorTC = ((nTopCard > 13) && (nTopCard < 40) ? 0 : 1);
1389         int rankBC = (nBottomCard - 1) % 13;
1390         int rankTC = (nTopCard - 1) % 13;
1391
1392         if (((rankBC == (rankTC + 1)) && (colorBC != colorTC))
1393                 || ((nBottomCard == -1) && (rankTC == 12)))
1394                 return true;
1395         
1396         return false;
1397 }
1398
1399
1400 bool GameWidget::PlayerWon(void)
1401 {
1402         for(int i=0; i<7; i++)
1403                 if (solBoard[i][0] != -1)
1404                   return false;
1405
1406         if ((stack1p != -1) || (stack2p != -1))
1407                 return false;
1408
1409         return true;
1410 }
1411
1412
1413 void GameWidget::HandleStatistics(void)
1414 {
1415         if (PlayerWon())
1416         {
1417                 m_nWins++;
1418
1419                 if (m_bWonLastGame)
1420                         m_nStreakC++;
1421                 else
1422                         m_nStreakC = 1;
1423         }
1424         else
1425         {
1426                 m_nLosses++;
1427
1428                 if (!m_bWonLastGame)
1429                         m_nStreakC--;
1430                 else
1431                         m_nStreakC = -1;
1432         }
1433
1434         if (m_nStreakC < 0)    // Beat largest losing streak?
1435         {
1436                 if (abs(m_nStreakC) > m_nStreakL)
1437                         m_nStreakL = abs(m_nStreakC);
1438         }
1439         else                   // Check for longest winning streak
1440         {
1441                 if (m_nStreakC > m_nStreakW)
1442                         m_nStreakW = m_nStreakC;
1443         }
1444
1445         if (m_bVegasStyle)     // Check for high score
1446         {
1447                 if (m_nScore > m_nVHiScore)
1448                         m_nVHiScore = m_nScore;
1449         }
1450         else
1451         {
1452                 if (m_nScore > m_nHiScore)
1453                         m_nHiScore = m_nScore;
1454         }
1455 }
1456 #endif
1457
1458
1459 void GameWidget::ResizeGrid(void)
1460 {
1461         QSize s = size();
1462
1463         // Find the constraints
1464         float boxSizeX = s.width() / gameBoard->width;
1465         float boxSizeY = s.height() / gameBoard->height;
1466
1467         maxLength = (int)(boxSizeX > boxSizeY ? boxSizeY : boxSizeX);
1468
1469         offsetX = (s.width() - (maxLength * gameBoard->width)) / 2;
1470         offsetY = (s.height() - (maxLength * gameBoard->height)) / 2;
1471 }
1472
1473
1474 //
1475 // Halt processing for 'count' milliseconds
1476 //
1477 void GameWidget::Pause(int count)
1478 {
1479 //      DWORD endCount = GetTickCount() + count;
1480 //      while (GetTickCount() < endCount) {}     // Still crude, but better control
1481 #if 1
1482         usleep(count * 1000);
1483 #else
1484         // This causes it to lock up randomly. :-/
1485         QTime time;
1486         time.start();
1487
1488         while (time.msec() < count)
1489                 ; // Do nothing...
1490 #endif
1491 }
1492