--- /dev/null
+//
+// gamewidget.cpp: Main game window widget
+//
+// by James Hammons
+// (C) 2013 Underground Software
+//
+// JLH = James Hammons <jlhamm@acm.org>
+//
+// Who When What
+// --- ---------- ------------------------------------------------------------
+// JLH 03/01/2014 Created this file
+//
+
+#include "gamewidget.h"
+#include <unistd.h> // for usleep()
+#include "gameboard.h"
+
+
+GameWidget::GameWidget(QWidget * parent/*= 0*/): QWidget(parent)//,
+// score(new QLabel)
+{
+// score->setTextFormat(Qt::PlainText);
+ setFixedSize(580, 520);
+ gameBoard = new GameBoard(1);
+}
+
+
+GameWidget::~GameWidget(void)
+{
+}
+
+
+void GameWidget::paintEvent(QPaintEvent * /*event*/)
+{
+ // TO DO:
+ // Optimizations: Create a member variable that has a bitmap in it,
+ // tile it with the felt in OnCreate(), blit as background instead of
+ // FillRect(r, brWhite). Also need to keep track of client rect.
+ // Possibly have 2 bitmaps as member vars, so keep bm construction to a minimum...
+
+ QPainter painter(this);
+// QRect rcUpdate = dc.m_ps.rcPaint; // Update rect...
+// QRect rcUpdate = QRect(0, 0, 580, 520); // Update rect?
+
+ int maxLength = 60;
+ int ptr = 0;
+
+ for(int y=0; y<gameBoard->height; y++)
+ {
+ for(int x=0; x<gameBoard->width; x++)
+ {
+ int tile = gameBoard->board[ptr++];
+ painter.setPen(QPen(Qt::black, 2.0, Qt::SolidLine));
+ painter.setBrush(QBrush(Qt::black));
+
+ if (tile == GTWall)
+ {
+ painter.setBrush(QBrush(Qt::white));
+ painter.drawRect(x * maxLength, y * maxLength, maxLength, maxLength);
+ }
+ else if (tile == GTBox)
+ {
+ painter.setBrush(QBrush(Qt::red));
+ painter.drawRect(x * maxLength, y * maxLength, maxLength, maxLength);
+ }
+ else if (tile == GTBoxSpot)
+ {
+ painter.setBrush(QBrush(Qt::magenta));
+ painter.drawRect((x * maxLength) + 20, (y * maxLength) + 20, maxLength - 40, maxLength - 40);
+ }
+ else if (tile == (GTBox | GTBoxSpot))
+ {
+ painter.setBrush(QBrush(Qt::green));
+ painter.drawRect(x * maxLength, y * maxLength, maxLength, maxLength);
+ }
+
+ if ((gameBoard->playerX == x) && (gameBoard->playerY == y))
+ {
+ painter.setBrush(QBrush(Qt::yellow));
+ painter.drawEllipse((x * maxLength) + 10, (y * maxLength) + 10, maxLength - 20, maxLength - 20);
+// painter.drawRect(x * maxLength, y * maxLength, maxLength, maxLength);
+ }
+ }
+ }
+
+
+#if 0
+ DrawBoard(&painter, rcUpdate);
+
+ // Draw the "loose" cards....
+
+ if (hitStack)
+ {
+ for(int i=stackStart.y(); i<19; i++)
+ {
+ int card = solBoard[stackStart.x()][i];
+
+ if (card != -1)
+ {
+ if (solBoard[stackStart.x()][i + 1] == -1) // Draw full card
+ cdtDraw(&painter, stackPos.x(), stackPos.y() + ((i - stackStart.y()) * 18),
+ myDeck.GetCardAtPos(card), FACEUP);
+ else // Draw partial card
+ cdtDraw(&painter, stackPos.x(), stackPos.y() + ((i - stackStart.y()) * 18),
+ myDeck.GetCardAtPos(card), FACEUP, 20);
+ }
+ }
+ }
+
+ if (hitDiscard)
+ cdtDraw(&painter, stackPos.x(), stackPos.y(), myDeck.GetCardAtPos(stack2[stack2p]),
+ FACEUP);
+
+ if (nHitAce != 0)
+ cdtDraw(&painter, stackPos.x(), stackPos.y(), nAce[nHitAce - 1], FACEUP);
+
+ if (m_bFreeCard) // For card animations...
+ {
+ for(SCardInfo * pCard=m_pFirstCard; pCard; pCard=pCard->pNext)
+ cdtDraw(&painter, pCard->nXPos, pCard->nYPos, pCard->nCard, FACEUP);
+ }
+#endif
+}
+
+
+void GameWidget::mousePressEvent(QMouseEvent * event)
+{
+ if (event->button() == Qt::LeftButton)
+ {
+// OnLButtonDown(event->pos());
+ event->accept();
+ }
+}
+
+
+void GameWidget::mouseMoveEvent(QMouseEvent * event)
+{
+ if (event->buttons() & Qt::LeftButton)
+ {
+// OnMouseMove(event->pos());
+ event->accept();
+ }
+}
+
+
+void GameWidget::mouseReleaseEvent(QMouseEvent * event)
+{
+ if (event->button() == Qt::LeftButton)
+ {
+// OnLButtonUp(event->pos());
+ event->accept();
+ }
+}
+
+
+void GameWidget::mouseDoubleClickEvent(QMouseEvent * event)
+{
+ if (event->button() == Qt::LeftButton)
+ {
+// OnLButtonDblClk(event->pos());
+ event->accept();
+ }
+}
+
+
+void GameWidget::keyPressEvent(QKeyEvent * event)
+{
+ int key = event->key();
+
+ if (key == Qt::Key_Up)
+ {
+ if (gameBoard->MovePlayerN() == PMInvalid)
+ return;
+ }
+ else if (key == Qt::Key_Down)
+ {
+ if (gameBoard->MovePlayerS() == PMInvalid)
+ return;
+ }
+ else if (key == Qt::Key_Left)
+ {
+ if (gameBoard->MovePlayerW() == PMInvalid)
+ return;
+ }
+ else if (key == Qt::Key_Right)
+ {
+ if (gameBoard->MovePlayerE() == PMInvalid)
+ return;
+ }
+ else
+ return;
+
+ // Only update if a key we recognize has been pressed!
+ update();
+
+ if (gameBoard->GameHasBeenWon())
+ emit GameWasWon();
+}
+
+
+void GameWidget::keyReleaseEvent(QKeyEvent * event)
+{
+}
+
+
+void GameWidget::NextLevel(void)
+{
+ level++;
+ delete gameBoard;
+ gameBoard = new GameBoard(level);
+ update();
+}
+
+
+void GameWidget::ResetLevel(void)
+{
+ gameBoard->ResetGame();
+ update();
+}
+
+
+#if 0
+bool GameWidget::CreateBackground(void)
+{
+ char BGRes[27][64] = {
+ ":/res/grfttile.bmp",
+ ":/res/cloth_6.bmp",
+ ":/res/bg_tech_3.bmp",
+ ":/res/bg_tech_2.bmp",
+ ":/res/bg_tech_1.bmp",
+ ":/res/bg_weave_3.bmp",
+ ":/res/bg_weave_2.bmp",
+ ":/res/bg_clouds_2.bmp",
+ ":/res/bg_floor_plate.bmp",
+ ":/res/bg_marble_b.bmp",
+ ":/res/bg_marble_g.bmp",
+ ":/res/bg_marble_p.bmp",
+ ":/res/bg_marble_r.bmp",
+ ":/res/bg_marble_rb.bmp",
+ ":/res/bg_money_1.bmp",
+ ":/res/bg_pinstripe2.bmp",
+ ":/res/bg_pinstripe7.bmp",
+ ":/res/bg_raindrops_large.bmp",
+ ":/res/bg_raindrops_small.bmp",
+ ":/res/bg_stucco.bmp",
+ ":/res/bg_wood_w.bmp",
+ ":/res/bg_wood_b1.bmp",
+ ":/res/bg_wood_d.bmp",
+ ":/res/bg_wood_f.bmp",
+ ":/res/bg_wood_mh.bmp",
+ ":/res/bg_wood_mv.bmp",
+ ":/res/bg_wood_ro.bmp"
+ };
+
+ QPalette pal = palette();
+ pal.setBrush(backgroundRole(), QBrush(QPixmap(BGRes[m_nBackground])));
+ setAutoFillBackground(true);
+ setPalette(pal);
+
+ return true; // Ignore errors for now...
+}
+
+
+void GameWidget::DrawBoard(QPainter * painter, QRect r)
+{
+ // Use "r" as clipping rect--only draw what's necessary
+
+// pDC->BitBlt(r.left, r.top, r.Width(), r.Height(), pDC2, r.left, r.top, SRCCOPY);
+
+ // Draw the solitaire board...
+
+ for(int i=0; i<7; i++)
+ {
+ int y = 126; //130-4;
+
+ for(int j=0; j<19; j++)
+ {
+ int card = solBoard[i][j];
+
+ if (card != -1 && !(hitStack && (i == stackStart.x()) && (j >= stackStart.y())))
+ {
+ int nLinesToDraw = 0; // Default--draws whole card
+
+ if (solBoard[i][j + 1] != -1 && !(hitStack && (i == stackStart.x()) && (j + 1 >= stackStart.y())))
+ {
+ nLinesToDraw = 6;
+
+ if (myDeck.IsFaceUp(card))
+ nLinesToDraw += 14;
+ }
+
+ int x = 10 + (i * (CARD_WIDTH + 8));//, y = 130 + (j * 4);
+ y += 4;
+
+ if (j > 0)
+ {
+ if (myDeck.IsFaceUp(solBoard[i][j - 1])) // Previous card...
+ y += 14;
+ }
+
+ //wil wok??? mebbe... YESH!!!!!!!!!!!!!
+ QRect cardRect(x, y, CARD_WIDTH, (nLinesToDraw ? nLinesToDraw : CARD_HEIGHT));
+
+ if (r.intersects(cardRect))
+ cdtDraw(painter, x, y, (myDeck.IsFaceUp(card) ? myDeck.GetCardAtPos(card)
+ : nCardBack), FACEUP, nLinesToDraw);
+ }
+ }
+ }
+
+ for(int i=0; i<4; i++)
+ {
+ if (nHitAce == i + 1)
+ {
+ if (((nAce[i] - 1) % 13) != 0)
+ cdtDraw(painter, 200 + ((CARD_WIDTH + 4) * i), 7, nAce[i] - 1, FACEUP);
+ else
+ cdtDraw(painter, 200 + ((CARD_WIDTH + 4) * i), 7, 0, INVISIBLEGHOST);
+ }
+ else
+ {
+ if (nAce[i] != -1)
+ cdtDraw(painter, 200 + ((CARD_WIDTH + 4) * i), 7, nAce[i], FACEUP);
+ else
+ cdtDraw(painter, 200 + ((CARD_WIDTH + 4) * i), 7, 0, INVISIBLEGHOST);
+ }
+ }
+
+ if (stack1p != -1)
+ cdtDraw(painter, 5, 7, nCardBack, FACEUP);
+ else
+ {
+#if 0
+ if (m_bShowX)
+ cdtDraw(painter, 5, 7, 0, DECKX);
+ else
+ cdtDraw(painter, 5, 7, 0, DECKO);
+#else
+ cdtDraw(painter, 5, 7, 0, (m_bShowX ? DECKX : DECKO));
+#endif
+ }
+
+ if (stack2p != -1)
+ {
+ if (!hitDiscard)
+ {
+ for(int k=0; k<m_nNumToSplay; k++)
+ cdtDraw(painter, 5 + CARD_WIDTH + 6 + (k * 12), 7 + (k * 2),
+ myDeck.GetCardAtPos(stack2[stack2p - (m_nNumToSplay - k - 1)]), FACEUP);
+ }
+ else
+ {
+ if (stack2p != 0)
+ {
+ if (m_nNumToSplay == 1)
+ cdtDraw(painter, 5 + CARD_WIDTH + 6, 7, myDeck.GetCardAtPos(stack2[stack2p - 1]), FACEUP);
+ else
+ for(int k=0; k<m_nNumToSplay-1; k++)
+ cdtDraw(painter, 5 + CARD_WIDTH + 6 + (k * 12), 7 + (k * 2),
+ myDeck.GetCardAtPos(stack2[stack2p - (m_nNumToSplay - k - 1)]), FACEUP);
+ }
+ }
+ }
+}
+
+
+void GameWidget::OnLButtonDown(QPoint point)
+{
+ dcHitStack = dcHitDiscard = false; // For double clicking...
+ m_bTouchedGame = true; // Game has been attempted!
+
+ if (!allowUserInput)
+ return;
+
+ mouseDown = true;
+
+ // Set undo up...
+ for(int i=0; i<7; i++)
+ for(int j=0; j<20; j++)
+ solBoardUndo[i][j] = solBoard[i][j];
+
+ for(int i=0; i<24; i++)
+ stack1Undo[i] = stack1[i], stack2Undo[i] = stack2[i];
+
+ for(int i=0; i<4; i++)
+ nAceUndo[i] = nAce[i];
+
+ stack1pUndo = stack1p, stack2pUndo = stack2p;
+ m_nScoreUndo = m_nScore;
+ m_nExhaustedDeckUndo = m_nExhaustedDeck;
+ m_nNumToSplayUndo = m_nNumToSplay;
+ m_bShowXUndo = m_bShowX;
+ m_bCanUndo = false;
+
+ // Check for a hit on the tableaux...
+
+ for(int i=0; i<7; i++)
+ {
+ QRect r;
+ r.setLeft(10 + (i * (CARD_WIDTH + 8)));
+ r.setRight(r.left() + CARD_WIDTH - 1);
+ r.setTop(130);
+ int nCards = 0;
+
+ for(int j=0; j<19; j++)
+ {
+ if (solBoard[i][j] != -1)
+ {
+ if (myDeck.IsFaceUp(solBoard[i][j]))
+ {
+ if ((j == 18) || (solBoard[i][j + 1] == -1))
+ r.setBottom(r.top() + CARD_HEIGHT - 1);
+ else
+ r.setBottom(r.top() + 17);
+
+ if (r.contains(point))
+ {
+ hitStack = dcHitStack = true;
+ stackStart = QPoint(i, j);
+ mouseOffset = QPoint(point.x() - r.left(), point.y() - r.top());
+ stackPos = QPoint(point.x() - mouseOffset.x(), point.y() - mouseOffset.y());
+ QRect rcUpdate(r.left(), r.top(), r.width(), CARD_HEIGHT - 1); //wil wok?
+ return;
+ }
+
+ r.setTop(r.top() + 18);
+ }
+ else
+ {
+ if (j != 18)
+ {
+ if (solBoard[i][j + 1] == -1)
+ {
+ r.setBottom(r.top() + CARD_HEIGHT - 1);
+
+ if (r.contains(point))
+ {
+ myDeck.ToggleCardFacing(solBoard[i][j]); // Turn over that last card
+
+#if HAVE_SOUND
+ if (bSoundOn)
+ PlaySound(IDW_CARDFLIP);
+#endif
+
+ update(r); //wil wok?
+
+ // Scoring...
+ if (!m_bVegasStyle)
+ {
+ m_nScore += 5;
+ emit UpdateScore(m_nScore);
+ }
+
+ return;
+ }
+ }
+ }
+
+ r.setTop(r.top() + 4);
+ }
+
+ nCards++;
+ }
+ }
+ }
+
+ // Check for hit on discard stack
+
+ int nCX = 5 + CARD_WIDTH + 6 + ((m_nNumToSplay - 1) * 12);
+ int nCY = 7 + ((m_nNumToSplay - 1) * 2);
+
+ if (QRect(nCX, nCY, CARD_WIDTH - 1, CARD_HEIGHT - 1).contains(point))
+ {
+ if (stack2p != -1)
+ {
+ hitDiscard = dcHitDiscard = true;
+ mouseOffset = QPoint(point.x() - (5 + CARD_WIDTH + 6 + ((m_nNumToSplay - 1) * 12)),
+ point.y() - (7 + ((m_nNumToSplay - 1) * 2)));
+ stackPos = QPoint(point.x() - mouseOffset.x(), point.y() - mouseOffset.y());
+ return;
+ }
+ }
+
+ // Check for hit on remaining deck
+
+ if (QRect(5, 7, 5 + CARD_WIDTH - 1, 7 + CARD_HEIGHT - 1).contains(point))
+ {
+ m_bCanUndo = true;
+
+ if (stack1p == -1) // I.e. it's empty...
+ {
+ // Scoring...
+ if ((m_bDrawThree && (m_nExhaustedDeck == 3))
+ || (!m_bDrawThree && (m_nExhaustedDeck == 1)))
+ {
+ if (!m_bVegasStyle)
+ {
+ m_nExhaustedDeck = 0;
+ m_nScore -= (m_bDrawThree ? 20 : 100);
+
+ if (m_nScore < 0)
+ m_nScore = 0;
+
+ emit UpdateScore(m_nScore);
+ }
+ }
+ if (!m_bVegasStyle || (m_bVegasStyle && ((m_bDrawThree && (m_nExhaustedDeck < 3))
+ || (!m_bDrawThree && (m_nExhaustedDeck < 1)))))
+ {
+ for(; stack2p != -1; stack2p--)
+ {
+ stack1p++;
+ stack1[stack1p] = stack2[stack2p];
+ }
+
+#if HAVE_SOUND
+ if (bSoundOn)
+ PlaySound(IDW_CARDKNOCK);
+#endif
+ }
+ }
+ else
+ {
+ m_nNumToSplay = 0;
+
+ for(int i=0; i<(m_bDrawThree ? 3 : 1); i++)
+ {
+ if (stack1p != -1) // I.e., there are cards left...
+ {
+ stack2[++stack2p] = stack1[stack1p--];
+
+#if HAVE_SOUND
+ if (bSoundOn)
+ {
+ PlaySound(IDW_CARDFLIP);
+ // Pause
+ Pause(55);
+ }
+#endif
+
+ m_nNumToSplay++;
+ }
+ }
+
+ if (stack1p == -1) // This is done here because it's right!
+ {
+ m_nExhaustedDeck++;
+
+ if (m_bVegasStyle && ((m_bDrawThree && (m_nExhaustedDeck == 3))
+ || (!m_bDrawThree && (m_nExhaustedDeck == 1))))
+ m_bShowX = true;
+ }
+ }
+
+ mouseOffset = QPoint(point.x() - 5, point.y() - 7);
+
+ QRect inv1(5, 7, CARD_WIDTH, CARD_HEIGHT),
+ inv2(5 + CARD_WIDTH + 6, 7, (2 * 12) + CARD_WIDTH, (2 * 2) + CARD_HEIGHT);
+ update(inv1);
+ update(inv2);
+ }
+
+ // Check for hit on ace piles
+
+ for(int i=0; i<4; i++)
+ {
+ QRect aceRect(200 + ((CARD_WIDTH + 4) * i), 7, CARD_WIDTH - 1, CARD_HEIGHT - 1);
+
+ if (aceRect.contains(point) && (nAce[i] > -1))
+ {
+ nHitAce = i + 1;
+// mouseOffset = QPoint(point.x() - (200 + ((CARD_WIDTH + 4) * i)), point.y() - 7);
+ mouseOffset = QPoint(point.x() - aceRect.x(), point.y() - aceRect.y());
+ stackPos = QPoint(point.x() - mouseOffset.x(), point.y() - mouseOffset.y());
+ return;
+ }
+ }
+}
+
+
+void GameWidget::OnLButtonUp(QPoint point)
+{
+ if (!allowUserInput)
+ return;
+
+ point -= mouseOffset; // ?? bad form!
+
+ if (hitStack || hitDiscard || (nHitAce != 0))
+ {
+ QRect tabl[7];
+
+ for(int i=0; i<7; i++) // Compute valid rects at bottoms of stacks...
+ {
+ tabl[i].setLeft(10 + (i * (CARD_WIDTH + 8)));
+ tabl[i].setRight(tabl[i].left() + CARD_WIDTH - 1);
+ tabl[i].setTop(130);
+
+ for(int j=0; j<19; j++)
+ {
+ if ((solBoard[i][j] == -1)
+ || (hitStack && (i == stackStart.x()) && (j == stackStart.y())))
+ {
+ if (j > 0)
+ {
+ for(int k=0; k<j-1; k++)
+ {
+ if (!myDeck.IsFaceUp(solBoard[i][k]))
+ tabl[i].setTop(tabl[i].top() + 4);
+ else
+ tabl[i].setTop(tabl[i].top() + 17);
+ }
+ }
+
+ tabl[i].setBottom(tabl[i].top() + CARD_HEIGHT - 1);
+ break;
+ }
+ }
+ }
+
+// stackPos = QPoint(point.x() - mouseOffset.x(), point.y() - mouseOffset.y());
+// QRect c(point.x(), point.y(), CARD_WIDTH - 1, CARD_HEIGHT - 1);
+// QRect c(point.x() - mouseOffset.x(), point.y() - mouseOffset.y(), CARD_WIDTH - 1, CARD_HEIGHT - 1);
+ QRect c(stackPos.x(), stackPos.y(), CARD_WIDTH - 1, CARD_HEIGHT - 1);
+ QRect a[4];
+ a[0] = QRect(200, 7, CARD_WIDTH - 1, CARD_HEIGHT - 1);
+ a[1] = QRect(200 + ((CARD_WIDTH + 4) * 1), 7, CARD_WIDTH - 1, CARD_HEIGHT - 1);
+ a[2] = QRect(200 + ((CARD_WIDTH + 4) * 2), 7, CARD_WIDTH - 1, CARD_HEIGHT - 1);
+ a[3] = QRect(200 + ((CARD_WIDTH + 4) * 3), 7, CARD_WIDTH - 1, CARD_HEIGHT - 1);
+
+ bool bHitAce[4];
+ bHitAce[0] = c.intersects(a[0]);
+ bHitAce[1] = c.intersects(a[1]);
+ bHitAce[2] = c.intersects(a[2]);
+ bHitAce[3] = c.intersects(a[3]);
+
+ // Check to see if hit more than one ace & pick the one that's closer
+ for(int i=0; i<3; i++)
+ {
+ if (bHitAce[i] && bHitAce[i + 1] && (nAce[i] == -1) && (nAce[i + 1] == -1))
+ {
+ if (c.intersected(a[i]).width() > c.intersected(a[i + 1]).width())
+ bHitAce[i + 1] = false;
+ else
+ bHitAce[i] = false;
+
+ break;
+ }
+ }
+
+ bool bMovedToAce = false;
+
+ for(int i=0; i<4; i++)
+ {
+ if (bHitAce[i] && IsValidMoveToAce(nAce[i]))
+ {
+ m_bCanUndo = true;
+
+ if (hitStack)
+ nAce[i] = myDeck.GetCardAtPos(solBoard[stackStart.x()][stackStart.y()]),
+ solBoard[stackStart.x()][stackStart.y()] = -1;
+
+ if (hitDiscard)
+ {
+ nAce[i] = myDeck.GetCardAtPos(stack2[stack2p--]);
+
+ if (m_nNumToSplay != 1)
+ m_nNumToSplay--;
+ }
+
+ if (nHitAce != 0)
+ {
+ nAce[i] = nAce[nHitAce - 1];
+ int nCard = nAce[nHitAce - 1];
+ nAce[nHitAce - 1] = ((nCard - 1) % 13 == 0 ? -1 : nCard - 1);
+ break;
+ }
+
+#if HAVE_SOUND
+ if (bSoundOn)
+ PlaySound(IDW_CARDPLACE);
+#endif
+
+ bMovedToAce = true;
+
+ // Scoring...
+#if 0
+ if (m_bVegasStyle)
+ m_nScore += 5;
+ else
+ m_nScore += 10;
+#else
+ m_nScore += (m_bVegasStyle ? 5 : 10);
+#endif
+
+ emit UpdateScore(m_nScore);
+ break;
+ }
+ }
+
+ if (!bMovedToAce) // No aces, so check for stacks
+ {
+ for(int i=0; i<7; i++)
+ {
+ if (c.intersects(tabl[i]) && IsValidMoveToTableaux(i))
+ {
+ m_bCanUndo = true;
+
+#if HAVE_SOUND
+ if (bSoundOn)
+ PlaySound(IDW_CARDPLACE);
+#endif
+
+ if (hitStack && (i != stackStart.x()))
+ {
+ int cnt = stackStart.y();
+
+ for(int k=0; k<19; k++)
+ {
+ if (solBoard[i][k] == -1)
+ {
+ solBoard[i][k] = solBoard[stackStart.x()][cnt];
+ solBoard[stackStart.x()][cnt] = -1;
+ cnt++;
+ }
+
+ if (solBoard[stackStart.x()][cnt] == -1) // Done copying?
+ break;
+ }
+
+ break;
+ }
+
+ if (hitDiscard)
+ {
+ for(int k=0; k<19; k++)
+ {
+ if (solBoard[i][k] == -1)
+ {
+ solBoard[i][k] = stack2[stack2p--];
+ myDeck.SetCardFaceUp(solBoard[i][k]);
+
+ // Scoring...
+ if (!m_bVegasStyle)
+ {
+ m_nScore += 5;
+ emit UpdateScore(m_nScore);
+ }
+
+ if (m_nNumToSplay != 1)
+ m_nNumToSplay--;
+
+ break;
+ }
+ }
+
+ break;
+ }
+
+ if (nHitAce != 0)
+ {
+ // handle moving to tableaux here...
+ for(int k=0; k<19; k++)
+ {
+ if (solBoard[i][k] == -1)
+ {
+ int nCard = nAce[nHitAce - 1];
+
+ for(int t=0; t<52; t++) // We have to find da damn thing...
+ {
+ if (myDeck.GetCardAtPos(t) == nCard)
+ {
+ solBoard[i][k] = t;
+ break;
+ }
+ }
+
+ nAce[nHitAce - 1] = ((nCard - 1) % 13 == 0 ? -1 : nCard - 1);
+ myDeck.SetCardFaceUp(solBoard[i][k]);
+
+ // Scoring...
+#if 0
+ if (!m_bVegasStyle)
+ m_nScore -= 15;
+ else
+ m_nScore -= 5;
+#else
+ m_nScore -= (m_bVegasStyle ? 5 : 15);
+#endif
+
+ emit UpdateScore(m_nScore);
+ break;
+ }
+ }
+
+ break;
+ }
+ }
+ }
+ }
+
+ update();
+ }
+
+ mouseDown = hitStack = hitDiscard = false;
+ nHitAce = 0;
+
+ if (bAutoRemove)
+ HandleAutoRemove();
+
+ if (PlayerWon())
+ {
+ emit UpdateScore(m_nScore);
+ HandleStatistics();
+ m_bWonLastGame = true;
+ m_bCanUndo = false;
+
+#if HAVE_SOUND
+ if (bSoundOn)
+ {
+ QString id[] = { IDW_WINNER1, IDW_WINNER2, IDW_WINNER3, IDW_WINNER4, IDW_WINNER5 };
+ srand((unsigned)time(NULL));
+ int nWaveNum = rand() % 5;
+ PlaySound(id[nWaveNum]);
+ }
+#endif
+
+ QMessageBox::information(this, "MAC Solitaire", "Congratulations!\nYou won!");
+ allowUserInput = false;
+ }
+}
+
+
+void GameWidget::OnMouseMove(QPoint point)
+{
+ if (mouseDown && (hitStack || hitDiscard || (nHitAce != 0)))
+ {
+ int nHeight = 0;
+
+ if (hitStack)
+ {
+ for(int i=stackStart.y(); i<19; i++)
+ if (solBoard[stackStart.x()][i] != -1)
+ nHeight += 18;
+ }
+ else
+ nHeight = 18;
+
+ nHeight += CARD_HEIGHT - 18;
+
+ QRect rcOld(stackPos.x(), stackPos.y(), CARD_WIDTH,
+ nHeight); // Find old position for repainting...
+
+ stackPos = QPoint(point.x() - mouseOffset.x(), point.y() - mouseOffset.y());
+
+ QRect rcNew(stackPos.x(), stackPos.y(), CARD_WIDTH,
+ nHeight); // Find new position
+ QRect rcUpdate = rcOld.united(rcNew);
+ update(rcUpdate); //wil wok? YESH!
+ }
+}
+
+
+void GameWidget::OnLButtonDblClk(QPoint point)
+{
+ if (dcHitStack || dcHitDiscard)
+ {
+ hitStack = dcHitStack, hitDiscard = dcHitDiscard;
+
+ for(int i=0; i<4; i++)
+ {
+ if (IsValidMoveToAce(nAce[i]))
+ {
+ if (hitStack)
+ {
+ nAce[i] = myDeck.GetCardAtPos(solBoard[stackStart.x()][stackStart.y()]);
+ solBoard[stackStart.x()][stackStart.y()] = -1;
+ }
+ else
+ {
+ nAce[i] = myDeck.GetCardAtPos(stack2[stack2p--]);
+
+ if (m_nNumToSplay != 1)
+ m_nNumToSplay--;
+ }
+
+ update();
+
+#if HAVE_SOUND
+ if (bSoundOn)
+ PlaySound(IDW_ZIP);
+#endif
+
+ // Scoring...
+#if 0
+ if (m_bVegasStyle)
+ m_nScore += 5;
+ else
+ m_nScore += 10;
+#else
+ m_nScore += (m_bVegasStyle ? 5 : 10);
+#endif
+
+ emit UpdateScore(m_nScore);
+ break;
+ }
+ }
+
+ dcHitStack = hitStack = dcHitDiscard = hitDiscard = false;
+ }
+ else
+ OnLButtonDown(point); // Either was on draw pile or somewhere else...
+}
+
+
+// It's behaving strangely, especially with kings in the ace piles...
+// It's becuase of the mod 13 function: kings(13) get whacked to 0 this way...
+void GameWidget::HandleAutoRemove(void)
+{
+ bool bCheck = true;
+
+ while (bCheck)
+ {
+ bCheck = false;
+
+ int nLowestAce = (nAce[0] == -1 ? 0 : ((nAce[0] - 1) % 13) + 1); // Aces are 1-based, cards 1-based
+
+ for(int i=1; i<4; i++)
+ {
+ int nTemp = (nAce[i] == -1 ? 0 : ((nAce[i] - 1) % 13) + 1);
+
+ if (nTemp < nLowestAce)
+ nLowestAce = nTemp;
+ }
+
+ for(int i=0; i<7; i++) // Compare cards that *can* go
+ {
+ for(int j=18; j>=0; j--)
+ {
+ if (solBoard[i][j] != -1)
+ {
+ if (myDeck.IsFaceUp(solBoard[i][j]))
+ {
+ int nCard = myDeck.GetCardAtPos(solBoard[i][j]);
+
+ for(int k=0; k<4; k++)
+ {
+ if (IsValidMoveToAce(nAce[k], nCard))
+ {
+ // Ranking/suiting doesn't work if nAce == -1... FIX!
+ // Should be fixed now...
+ // Figure out some way to simplify this tortuous logic, for cryin' out loud!
+ int nSuit[4], nRank[4];
+
+ for(int t=0; t<4; t++)
+ {
+ if (nAce[t] != -1)
+ nSuit[t] = ((nAce[t] > 13) && (nAce[t] < 40) ? 0 : 1);
+ else
+ nSuit[t] = -1;
+
+ nRank[t] = ((nAce[t] - 1) % 13) + 1;
+ }
+
+ int nCardSuit = ((nCard > 13) && (nCard < 40) ? 0 : 1),
+ nCardRank = ((nCard - 1) % 13) + 1;
+ bool bSpecial = false;
+ int nCR[2], nCnt = 0;
+
+ for(int t=0; t<4; t++)
+ if ((nCardSuit != nSuit[t]) && (t != k) && (nSuit[t] != -1))
+ nCR[nCnt++] = nRank[t];
+
+ if ((nCnt == 2) && (nCR[0] == nCR[1])
+ && (nCR[0] - nLowestAce == 2) && (nCardRank - nLowestAce == 3))
+ bSpecial = true;
+
+ if (((((nCard - 1) % 13) + 1) - nLowestAce) <= 2 || bSpecial)
+ // OR difference is 3 and both opposite color are at 2
+// if (((nCard%13) - nLowestAce) <= 2)
+ {
+ solBoard[i][j] = -1;
+
+ if (m_bAnimationsOn)
+ AnimateCards(nCard, k, i, j);
+
+ nAce[k] = nCard;
+ bCheck = true;
+
+ // Scoring...
+#if 0
+ if (m_bVegasStyle)
+ m_nScore += 5;
+ else
+ m_nScore += 10;
+#else
+ m_nScore += (m_bVegasStyle ? 5 : 10);
+#endif
+ emit UpdateScore(m_nScore);
+ break;
+ }
+ }
+ }
+ }
+
+ break;
+ }
+ }
+ }
+
+ if (stack2p != -1)
+ {
+ int nCard = myDeck.GetCardAtPos(stack2[stack2p]);
+
+ for(int k=0; k<4; k++)
+ {
+ if (IsValidMoveToAce(nAce[k], nCard))
+ {
+ // Ranking/suiting doesn't work if nAce == -1... FIX!
+ // Should be fixed now...
+ // Figure out some way to simplify this tortuous logic, for cryin' out loud!
+ int nSuit[4], nRank[4];
+
+ for(int t=0; t<4; t++)
+ {
+ if (nAce[t] != -1)
+ nSuit[t] = ((nAce[t] > 13) && (nAce[t] < 40) ? 0 : 1);
+ else
+ nSuit[t] = -1;
+
+ nRank[t] = ((nAce[t] - 1) % 13) + 1;
+ }
+
+ int nCardSuit = ((nCard > 13) && (nCard < 40) ? 0 : 1),
+ nCardRank = ((nCard - 1) % 13) + 1;
+ bool bSpecial = false;
+ int nCR[2], nCnt = 0;
+
+ for(int t=0; t<4; t++)
+ {
+ if ((nCardSuit != nSuit[t]) && (t != k) && (nSuit[t] != -1))
+ nCR[nCnt++] = nRank[t];
+ }
+
+ if ((nCnt == 2) && (nCR[0] == nCR[1])
+ && (nCR[0] - nLowestAce == 2) && (nCardRank - nLowestAce == 3))
+ bSpecial = true;
+
+ if (((((nCard - 1) % 13) + 1) - nLowestAce) <= 2 || bSpecial)
+ // OR difference is 3 and both opposite color are at 2 (tortuously checked above)
+ {
+ stack2p--;
+
+ if (m_nNumToSplay != 1)
+ m_nNumToSplay--;
+
+ if (m_bAnimationsOn)
+ AnimateCards(nCard, k, -1, -1);
+
+ nAce[k] = nCard;
+ bCheck = true;
+
+ // Scoring...
+#if 0
+ if (m_bVegasStyle)
+ m_nScore += 5;
+ else
+ m_nScore += 10;
+#else
+ m_nScore += (m_bVegasStyle ? 5 : 10);
+#endif
+
+ emit UpdateScore(m_nScore);
+ break;
+ }
+ }
+ }
+ }
+ }
+}
+
+
+// Have two routines? One to initiate, the other to handle card movements?
+// Good idea! Implement it, you schmendrick!
+void GameWidget::AnimateCards(int nCard, int nAce, int nTabX, int nTabY)
+{
+//no mas--jeff no likee CWaitCursor wc; // Automagically reverts when it goes out of scope
+ int nCX, nCY, nDX, nDY;
+
+ // Step 1: figure out where card started from
+ if (nTabX == -1)
+ {
+// nCX = 5+CARD_WIDTH+6, nCY = 5;
+ nCX = 5 + CARD_WIDTH + 6 + ((m_nNumToSplay - 1) * 12);
+ nCY = 7 + ((m_nNumToSplay - 1) * 2);
+ }
+ else
+ {
+ nCX = 10 + (nTabX * (CARD_WIDTH + 8)), nCY = 130;
+
+ for(int j=0; j<nTabY; j++)
+ {
+ if (solBoard[nTabX][j] != -1)
+ {
+ if (myDeck.IsFaceUp(solBoard[nTabX][j]))
+ nCY += 18;
+ else
+ nCY += 4;
+ }
+ }
+ }
+ // Step 2: figure out where card is going
+ nDX = 200 + ((CARD_WIDTH + 4) * nAce), nDY = 7;
+ // Step 3: animate card flying from start to destination
+ // Use Bresenham's algorithm to figure path...
+ // (ideas for movement: increasing acceleration, curved paths, more than one at a time)
+ m_bFreeCard = true;
+ m_pFirstCard = new SCardInfo(nCard);
+ int nDeltaX = nDX - nCX, nDeltaY = nDY - nCY;
+ int nError = 0;
+ int nUpdate = 0;
+ update(); //will do it??? Seems to...
+//Doing this causes an image of the card to be drawn at (0, 0) :-/
+// repaint();
+ QRect rcOld(nCX, nCY, CARD_WIDTH, CARD_HEIGHT), rcNew, rcUpdate;
+
+ if (abs(nDeltaX) > abs(nDeltaY))
+ {
+ for(int i=0; i<abs(nDeltaX); i++)
+ {
+ // Put card draw stuff into OnDraw? (probably best way to do it...)
+ nError += abs(nDeltaY);
+
+ if (nError > abs(nDeltaX))
+ nCY += (nDeltaY < 0 ? -1 : +1), nError -= abs(nDeltaX);
+
+ m_pFirstCard->nXPos = nCX + (nDeltaX < 0 ? -i : +i), m_pFirstCard->nYPos = nCY;
+ // Draw card
+ nUpdate++;
+
+ if (nUpdate == 10)
+ {
+ rcNew = QRect(m_pFirstCard->nXPos, m_pFirstCard->nYPos,
+ CARD_WIDTH, CARD_HEIGHT);
+ rcUpdate = rcOld.united(rcNew);
+ nUpdate = 0;
+ repaint(rcUpdate);
+ rcOld = rcNew;
+ // Pause
+ Pause(3);
+ }
+ // calc new positions
+ }
+
+ m_pFirstCard->nXPos = nDX, m_pFirstCard->nYPos = nDY;
+ rcNew = QRect(nDX, nDY, CARD_WIDTH, CARD_HEIGHT);
+ rcUpdate = rcOld.united(rcNew);
+ repaint(rcUpdate);
+ }
+ else
+ {
+ for(int i=0; i<abs(nDeltaY); i++)
+ {
+ // Put card draw stuff into OnDraw? (probably best way to do it...)
+ nError += abs(nDeltaX);
+
+ if (nError > abs(nDeltaY))
+ nCX += (nDeltaX < 0 ? -1 : +1), nError -= abs(nDeltaY);
+
+ m_pFirstCard->nXPos = nCX, m_pFirstCard->nYPos = nCY + (nDeltaY < 0 ? -i : +i);
+ // Draw card
+ nUpdate++;
+
+ if (nUpdate == 10)
+ {
+ rcNew = QRect(m_pFirstCard->nXPos, m_pFirstCard->nYPos,
+ CARD_WIDTH, CARD_HEIGHT);
+ rcUpdate = rcOld.united(rcNew);
+ nUpdate = 0;
+ repaint(rcUpdate);//this is crappy. should only update what's needed!
+ rcOld = rcNew;
+ // Pause
+ Pause(3);
+ }
+ // calc new positions
+ }
+
+ m_pFirstCard->nXPos = nDX, m_pFirstCard->nYPos = nDY;
+ rcNew = QRect(nDX, nDY, CARD_WIDTH, CARD_HEIGHT);
+ rcUpdate = rcOld.united(rcNew);
+ repaint(rcUpdate);
+ }
+
+ m_bFreeCard = false;
+ delete m_pFirstCard;
+}
+
+
+bool GameWidget::IsValidMoveToAce(int nAceM)
+{
+ int nCards = 0;
+
+ for(int k=stackStart.y(); k<19; k++)
+ {
+ if (solBoard[stackStart.x()][k] != -1)
+ nCards++;
+ }
+
+ if ((hitStack && (nCards == 1)) || hitDiscard)
+ {
+ int nCardHit = (hitStack ? myDeck.GetCardAtPos(solBoard[stackStart.x()][stackStart.y()])
+ : myDeck.GetCardAtPos(stack2[stack2p]));
+ return IsValidMoveToAce(nAceM, nCardHit);
+ }
+ else if (nHitAce != 0)
+ {
+ return IsValidMoveToAce(nAceM, nAce[nHitAce - 1]);
+ }
+
+ return false;
+}
+
+
+bool GameWidget::IsValidMoveToAce(int nAce, int nCard)
+{
+ if (((nAce == -1) && ((nCard % 13) == 1))
+ || ((nAce == (nCard - 1)) && ((nAce % 13) != 0)))
+ return true;
+
+ return false;
+}
+
+
+bool GameWidget::IsValidMoveToTableaux(int nStack)
+{
+ int nBottomCard = -1, nTopCard;
+
+ for(int i=0; i<19; i++)
+ {
+ if ((solBoard[nStack][i] != -1) && (myDeck.IsFaceUp(solBoard[nStack][i])))
+ nBottomCard = myDeck.GetCardAtPos(solBoard[nStack][i]);
+ }
+
+ if (hitStack)
+ nTopCard = myDeck.GetCardAtPos(solBoard[stackStart.x()][stackStart.y()]);
+ else if (hitDiscard)
+ nTopCard = myDeck.GetCardAtPos(stack2[stack2p]);
+ else if (nHitAce != 0)
+ nTopCard = nAce[nHitAce - 1];
+
+ int colorBC = ((nBottomCard > 13) && (nBottomCard < 40) ? 0 : 1);
+ int colorTC = ((nTopCard > 13) && (nTopCard < 40) ? 0 : 1);
+ int rankBC = (nBottomCard - 1) % 13;
+ int rankTC = (nTopCard - 1) % 13;
+
+ if (((rankBC == (rankTC + 1)) && (colorBC != colorTC))
+ || ((nBottomCard == -1) && (rankTC == 12)))
+ return true;
+
+ return false;
+}
+
+
+bool GameWidget::PlayerWon(void)
+{
+ for(int i=0; i<7; i++)
+ if (solBoard[i][0] != -1)
+ return false;
+
+ if ((stack1p != -1) || (stack2p != -1))
+ return false;
+
+ return true;
+}
+
+
+void GameWidget::HandleStatistics(void)
+{
+ if (PlayerWon())
+ {
+ m_nWins++;
+
+ if (m_bWonLastGame)
+ m_nStreakC++;
+ else
+ m_nStreakC = 1;
+ }
+ else
+ {
+ m_nLosses++;
+
+ if (!m_bWonLastGame)
+ m_nStreakC--;
+ else
+ m_nStreakC = -1;
+ }
+
+ if (m_nStreakC < 0) // Beat largest losing streak?
+ {
+ if (abs(m_nStreakC) > m_nStreakL)
+ m_nStreakL = abs(m_nStreakC);
+ }
+ else // Check for longest winning streak
+ {
+ if (m_nStreakC > m_nStreakW)
+ m_nStreakW = m_nStreakC;
+ }
+
+ if (m_bVegasStyle) // Check for high score
+ {
+ if (m_nScore > m_nVHiScore)
+ m_nVHiScore = m_nScore;
+ }
+ else
+ {
+ if (m_nScore > m_nHiScore)
+ m_nHiScore = m_nScore;
+ }
+}
+
+
+//
+// Halt processing for 'count' milliseconds
+//
+void GameWidget::Pause(int count)
+{
+// DWORD endCount = GetTickCount() + count;
+// while (GetTickCount() < endCount) {} // Still crude, but better control
+#if 1
+ usleep(count * 1000);
+#else
+ // This causes it to lock up randomly. :-/
+ QTime time;
+ time.start();
+
+ while (time.msec() < count)
+ ; // Do nothing...
+#endif
+}
+#endif
+
--- /dev/null
+//
+// mainwin.cpp: Implementation of the MainWin class
+//
+// JLH = James Hammons <jlhamm@acm.org>
+//
+// Who When What
+// --- ---------- ------------------------------------------------------------
+// JLH 03/01/2014 Created this file
+//
+
+// TO DO:
+//
+
+#include "mainwin.h"
+
+#include <stdlib.h> // For rand()
+#include <time.h> // For time()
+#include "gamewidget.h" // Actual mouse/drawing window
+//#include "resource.h"
+//#include "optiondlg.h" // Options dialog class
+//#include "statdlg.h" // Statistics dialog class
+
+
+MainWin::MainWin()
+{
+ gameWidget = new GameWidget(this);
+ setCentralWidget(gameWidget);
+ gameWidget->setFocusPolicy(Qt::StrongFocus); // Without this, it gets no keys
+ setWindowTitle("Warehouse Man Deluxe");
+ setWindowIcon(QIcon(":/wmd-icon.png"));
+
+ newGame = CreateAction(tr("&New"), tr("New Game"), tr("Start a new game of Warehouse Man Deluxe"), QIcon(), QKeySequence(tr("ctrl+n")));
+// connect(newGame, SIGNAL(triggered()), this, SLOT(OnNewGame()));
+
+ gamePlay = CreateAction(tr("&Play"), tr(""), tr(""), QIcon(), QKeySequence(tr("ctrl+a")));
+// connect(gamePlay, SIGNAL(triggered()), this, SLOT(OnGamePlay()));
+
+ helpUndo = CreateAction(tr("&Undo"), tr(""), tr(""), QIcon(), QKeySequence(tr("ctrl+z")));
+// connect(helpUndo, SIGNAL(triggered()), this, SLOT(OnHelpUndo()));
+
+ resetLevel = CreateAction(tr("&Reset Level"), tr("Reset Level"), tr("Start the current level over"), QIcon(), QKeySequence(tr("ctrl+r")));
+ connect(resetLevel, SIGNAL(triggered()), this, SLOT(ResetCurrentLevel()));
+
+ gameOptions = CreateAction(tr("&Options..."), tr("Options"), tr("Configure Warehouse Man Deluxe's options"), QIcon(), QKeySequence(tr("ctrl+o")));
+// connect(gameOptions, SIGNAL(triggered()), this, SLOT(OnGameOptions()));
+
+ gameStats = CreateAction(tr("&Stats..."), tr("Game Stats"), tr("Show game stats"), QIcon(), QKeySequence(tr("ctrl+s")));
+// connect(gameStats, SIGNAL(triggered()), this, SLOT(OnGameStats()));
+
+ appExit = CreateAction(tr("E&xit"), tr("Exit"), tr("Quit playing Warehouse Man Deluxe..."), QIcon(), QKeySequence(tr("ctrl+q")));
+ connect(appExit, SIGNAL(triggered()), this, SLOT(close()));
+
+ appAbout = CreateAction(tr("&About"), tr("About"), tr("Display program information..."), QIcon(), QKeySequence(tr("")));
+ connect(appAbout, SIGNAL(triggered()), this, SLOT(AboutGame()));
+
+ // Get signals from the gameboard to update scores...
+// connect(gameBoard, SIGNAL(UpdateScore(int)), this, SLOT(OnUpdateScore(int)));
+ connect(gameWidget, SIGNAL(GameWasWon()), this, SLOT(WeHaveAWinner()));
+
+ QMenu * menu = menuBar()->addMenu(tr("&Game"));
+ menu->addAction(newGame);
+ menu->addSeparator();
+ menu->addAction(gamePlay);
+ menu->addAction(helpUndo);
+ menu->addAction(resetLevel);
+ menu->addSeparator();
+ menu->addAction(gameOptions);
+ menu->addAction(gameStats);
+ menu->addSeparator();
+ menu->addAction(appExit);
+
+ menu = menuBar()->addMenu(tr("&Help"));
+ menu->addAction(appAbout);
+
+// statusBar()->addPermanentWidget(gameBoard->score);
+ statusBar()->showMessage(tr("Ready"));
+
+ QSettings settings("Underground Software", "Warehouse Man Deluxe");
+ QPoint mainWinPosition = settings.value("pos", QPoint(200, 100)).toPoint();
+ move(mainWinPosition);
+
+/* nCardBack = settings.value("CardBack", BACK4).toInt();
+ m_nBackground = settings.value("Background", 0).toInt();
+ bSoundOn = settings.value("EnableSound", true).toBool();
+ m_bAnimationsOn = settings.value("EnableAnimations", true).toBool();
+ bAutoRemove = settings.value("AutoRemove", true).toBool();
+ scoringOn = settings.value("EnableScoring", false).toBool();
+ m_bCumulativeOn = settings.value("CumulativeScore", false).toBool();
+ m_bVegasStyle = settings.value("VegasScoring", false).toBool();
+ m_bDrawThree = settings.value("DrawThree", false).toBool();
+ m_nWins = settings.value("NumWins", 0).toInt();
+ m_nLosses = settings.value("NumLosses", 0).toInt();
+ m_nHiScore = settings.value("HiScore", 0).toInt();
+ m_nVHiScore = settings.value("VegasHiScore", 0).toInt();
+ m_nStreakW = settings.value("WinStreak", 0).toInt();
+ m_nStreakL = settings.value("LoseStreak", 0).toInt();
+ m_nStreakC = settings.value("CurrentStreak", 0).toInt();
+ m_bWonLastGame = settings.value("WonLastGame", false).toBool();
+ m_nScore = settings.value("LastScore", -52).toInt();*/
+
+// gameBoard->CreateBackground();
+// InitializeAudio();
+
+// mouseDown = false;
+// myDeck.SetCardWidth(CARD_WIDTH);
+// myDeck.SetCardHeight(CARD_HEIGHT);
+//
+// for(int i=0; i<52; i++)
+// myDeck.SetCardPosition(i, QPoint(0, 0));
+
+ ResetGame();
+// allowUserInput = true;
+// m_bFreeCard = false;
+// m_pFirstCard = NULL;
+}
+
+
+MainWin::~MainWin()
+{
+// ShutDownAudio();
+}
+
+
+//
+// Consolidates action creation from a multi-step process to a single-step one.
+//
+QAction * MainWin::CreateAction(QString name, QString tooltip, QString statustip,
+ QIcon icon, QKeySequence key, bool checkable/*= false*/)
+{
+ QAction * action = new QAction(icon, name, this);
+ action->setToolTip(tooltip);
+ action->setStatusTip(statustip);
+ action->setShortcut(key);
+ action->setCheckable(checkable);
+
+ return action;
+}
+
+
+//
+// This is essentially the same as the previous function, but this allows more
+// than one key sequence to be added as key shortcuts.
+//
+QAction * MainWin::CreateAction(QString name, QString tooltip, QString statustip,
+ QIcon icon, QKeySequence key1, QKeySequence key2, bool checkable/*= false*/)
+{
+ QAction * action = new QAction(icon, name, this);
+ action->setToolTip(tooltip);
+ action->setStatusTip(statustip);
+ QList<QKeySequence> keyList;
+ keyList.append(key1);
+ keyList.append(key2);
+ action->setShortcuts(keyList);
+ action->setCheckable(checkable);
+
+ return action;
+}
+
+
+void MainWin::closeEvent(QCloseEvent * event)
+{
+/* if (allowUserInput && m_bTouchedGame)
+ {
+ gameBoard->HandleStatistics();
+ m_bWonLastGame = false;
+ }*/
+
+ QSettings settings("Underground Software", "Warehouse Man Deluxe");
+ settings.setValue("pos", pos());
+
+/*
+ settings.setValue("CardBack", nCardBack);
+ settings.setValue("Background", m_nBackground);
+ settings.setValue("EnableSound", bSoundOn);
+ settings.setValue("EnableAnimations", m_bAnimationsOn);
+ settings.setValue("AutoRemove", bAutoRemove);
+ settings.setValue("EnableScoring", scoringOn);
+ settings.setValue("CumulativeScore", m_bCumulativeOn);
+ settings.setValue("VegasScoring", m_bVegasStyle);
+ settings.setValue("DrawThree", m_bDrawThree);
+ settings.setValue("NumWins", m_nWins);
+ settings.setValue("NumLosses", m_nLosses);
+ settings.setValue("HiScore", m_nHiScore);
+ settings.setValue("VegasHiScore", m_nVHiScore);
+ settings.setValue("WinStreak", m_nStreakW);
+ settings.setValue("LoseStreak", m_nStreakL);
+ settings.setValue("CurrentStreak", m_nStreakC);
+ settings.setValue("WonLastGame", m_bWonLastGame);
+ settings.setValue("LastScore", m_nScore);*/
+
+ event->accept();
+}
+
+
+/*
+void MainWin::OnUpdateScore(int n)
+{
+ if (!scoringOn)
+ return;
+
+ QString s;
+
+ if (m_bVegasStyle)
+ s = QString(tr("Score: $%1")).arg(n);
+ else
+ s = QString(tr("Score: %1")).arg(n);
+
+ gameBoard->score->setText(s);
+printf("OUS: n=%i, s=%s\n", n, s.toAscii().data());
+}
+*/
+
+void MainWin::ResetGame(void)
+{
+ gameWidget->level = 1;
+
+/* myDeck.Shuffle();
+
+ for(int i=0; i<7; i++)
+ for(int j=0; j<20; j++)
+ solBoard[i][j] = -1; // Empty the board...
+
+ int card = 0;
+ myDeck.SetAllFaceDown();
+
+ for(int i=0; i<7; i++) // Fill the tableaux
+ {
+ for(int j=i; j<7; j++)
+ {
+ solBoard[6 - i][6 - j] = card;
+
+ if (i == j)
+ myDeck.SetCardFaceUp(card);
+
+ card++;
+ }
+ }
+
+ for(int i=0; i<24; i++) // Fill the stack
+ stack1[i] = card++;
+
+ stack1p = 23;
+ stack2p = -1;
+ nAce[0] = nAce[1] = nAce[2] = nAce[3] = -1;
+
+ hitStack = hitDiscard = false;
+ nHitAce = 0;
+ m_bTouchedGame = false;
+
+ if (!m_bVegasStyle)
+ m_nScore = 0;
+ else
+ {
+ if (!m_bCumulativeOn)
+ m_nScore = -52;
+ else
+ m_nScore -= 52;
+ }
+
+ m_nExhaustedDeck = 0;
+ m_bShowX = false;
+ m_bCanUndo = false;
+
+ OnUpdateScore(m_nScore);*/
+}
+
+
+void MainWin::AboutGame(void)
+{
+ QMessageBox::about(this, tr("About Warehouse Man Deluxe"), tr("Warehouse Man Deluxe Version 1.0\n\nCopyright © 2014 Underground Software\n\nWritten by James L. Hammons"));
+}
+
+
+void MainWin::WeHaveAWinner(void)
+{
+ QMessageBox::information(this, "Warehouse Man Deluxe", "Congratulations!\nYou beat this level!\nNow try the next level!");
+ gameWidget->NextLevel();
+}
+
+
+void MainWin::ResetCurrentLevel(void)
+{
+ gameWidget->ResetLevel();
+}
+
+
+#if 0
+void MainWin::OnNewGame(void)
+{
+ if (allowUserInput && m_bTouchedGame) // Player didn't win...
+ {
+ gameBoard->HandleStatistics();
+ m_bWonLastGame = false;
+ }
+
+ ResetGame();
+ gameBoard->update();
+ allowUserInput = true;
+
+#if HAVE_SOUND
+ if (bSoundOn)
+ {
+ PlaySound(IDW_CARDKNOCK);
+ gameBoard->Pause(300);
+ PlaySound(IDW_SHUFFLE);
+ }
+#endif
+}
+
+
+void MainWin::OnGameOptions(void)
+{
+ OptionDlg dlg;
+
+ dlg.m_cardBack = nCardBack - BACK1;
+ dlg.m_nBackground = m_nBackground;
+ dlg.m_bCheck1 = bSoundOn;
+ dlg.m_bCheck2 = m_bAnimationsOn;
+ dlg.m_bCheck3 = bAutoRemove;
+ dlg.m_bCheck4 = scoringOn;
+ dlg.m_bCheck5 = m_bCumulativeOn;
+ dlg.m_nRadio1 = m_bVegasStyle;
+ dlg.m_nRadio3 = m_bDrawThree;
+
+ dlg.UpdateUI();
+
+ if (dlg.exec() == QDialog::Rejected)
+ return;
+
+ dlg.UpdateData();
+
+ nCardBack = dlg.m_cardBack + BACK1;
+ m_nBackground = dlg.m_nBackground;
+ bSoundOn = (bool)dlg.m_bCheck1;
+ m_bAnimationsOn = (bool)dlg.m_bCheck2;
+ bAutoRemove = (bool)dlg.m_bCheck3;
+ m_bCumulativeOn = (bool)dlg.m_bCheck5;
+
+ // Reset game if Vegas Style/Draw Three changes at all...
+ bool bChanged = (bool)((m_bVegasStyle != (bool)dlg.m_nRadio1)
+ || (m_bDrawThree != (bool)dlg.m_nRadio3) || (scoringOn != (bool)dlg.m_bCheck4));
+
+ scoringOn = (bool)dlg.m_bCheck4;
+ m_bVegasStyle = (bool)dlg.m_nRadio1;
+ m_bDrawThree = (bool)dlg.m_nRadio3;
+
+ if (bChanged && m_bTouchedGame)
+ OnNewGame(); // Probably should warn of this...
+
+ gameBoard->CreateBackground();
+ gameBoard->update();
+}
+
+
+void MainWin::OnGameStats(void)
+{
+ StatDlg dlg;
+
+/* dlg.m_nWins = m_nWins;
+ dlg.m_nLosses = m_nLosses;
+ dlg.m_nHiScore = m_nHiScore;
+ dlg.m_nVHiScore = m_nVHiScore;
+ dlg.m_nStreakW = m_nStreakW;
+ dlg.m_nStreakL = m_nStreakL;
+ dlg.m_nStreakC = m_nStreakC;*/
+
+ dlg.exec();
+
+ // Since it's possible to reset the stats, we grab the fields back here...
+/* m_nWins = dlg.m_nWins;
+ m_nLosses = dlg.m_nLosses;
+ m_nHiScore = dlg.m_nHiScore;
+ m_nVHiScore = dlg.m_nVHiScore;
+ m_nStreakW = dlg.m_nStreakW;
+ m_nStreakL = dlg.m_nStreakL;
+ m_nStreakC = dlg.m_nStreakC;*/
+}
+
+
+void MainWin::OnHelpUndo(void)
+{
+ if (m_bCanUndo)
+ {
+ for(int i=0; i<7; i++)
+ for(int j=0; j<20; j++)
+ solBoard[i][j] = solBoardUndo[i][j];
+
+ for(int i=0; i<24; i++)
+ stack1[i] = stack1Undo[i], stack2[i] = stack2Undo[i];
+
+ for(int i=0; i<4; i++)
+ nAce[i] = nAceUndo[i];
+
+ stack1p = stack1pUndo, stack2p = stack2pUndo;
+ m_nScore = m_nScoreUndo;
+ m_nExhaustedDeck = m_nExhaustedDeckUndo;
+ m_nNumToSplay = m_nNumToSplayUndo;
+ m_bShowX = m_bShowXUndo;
+
+ OnUpdateScore(m_nScore);
+ }
+
+ m_bCanUndo = false;
+ gameBoard->update(); // wil wok?
+}
+
+
+void MainWin::OnGamePlay(void)
+{
+ // Play a card from discard deck...
+ //NOTE: can reduce size by eliminating duplicate code in OnLButtonDown...
+ m_bCanUndo = true;
+
+ if (stack1p == -1) // I.e. it's empty...
+ {
+ // Scoring...
+ if ((m_bDrawThree && (m_nExhaustedDeck == 3))
+ || (!m_bDrawThree && (m_nExhaustedDeck == 1)))
+ {
+ if (!m_bVegasStyle)
+ {
+ m_nExhaustedDeck = 0;
+ m_nScore -= (m_bDrawThree ? 20 : 100);
+
+ if (m_nScore < 0)
+ m_nScore = 0;
+
+ OnUpdateScore(m_nScore);
+ }
+ }
+
+ if (!m_bVegasStyle || (m_bVegasStyle && ((m_bDrawThree && (m_nExhaustedDeck < 3))
+ || (!m_bDrawThree && (m_nExhaustedDeck < 1)))))
+ {
+ for(; stack2p!=-1; stack2p--)
+ stack1[++stack1p] = stack2[stack2p];
+
+#if HAVE_SOUND
+ if (bSoundOn)
+ PlaySound(IDW_CARDKNOCK);
+#endif
+ }
+ }
+ else
+ {
+ m_nNumToSplay = 0;
+
+ for(int i=0; i<(m_bDrawThree ? 3 : 1); i++)
+ {
+ if (stack1p != -1) // I.e., there are cards left...
+ {
+ stack2[++stack2p] = stack1[stack1p--];
+
+#if HAVE_SOUND
+ if (bSoundOn)
+ {
+ PlaySound(IDW_CARDFLIP);
+ // Pause
+ gameBoard->Pause(55);
+ }
+#endif
+
+ m_nNumToSplay++;
+ }
+ }
+
+ if (stack1p == -1) // This is done here because it's right!
+ {
+ m_nExhaustedDeck++;
+
+ if (m_bVegasStyle && ((m_bDrawThree && (m_nExhaustedDeck == 3))
+ || (!m_bDrawThree && (m_nExhaustedDeck == 1))))
+ m_bShowX = true;
+ }
+ }
+
+ if (bAutoRemove)
+ gameBoard->HandleAutoRemove();
+
+ gameBoard->update();
+}
+
+
+#endif
+