]> Shamusworld >> Repos - warehouse-man-deluxe/commitdiff
Initial commit.
authorShamus Hammons <jlhamm@acm.org>
Wed, 5 Mar 2014 18:42:27 +0000 (12:42 -0600)
committerShamus Hammons <jlhamm@acm.org>
Wed, 5 Mar 2014 18:42:27 +0000 (12:42 -0600)
14 files changed:
.gitignore [new file with mode: 0644]
res/resources.qrc [new file with mode: 0644]
res/wmd-icon.png [new file with mode: 0644]
src/app.cpp [new file with mode: 0644]
src/app.h [new file with mode: 0644]
src/boards.cpp [new file with mode: 0644]
src/boards.h [new file with mode: 0644]
src/gameboard.cpp [new file with mode: 0644]
src/gameboard.h [new file with mode: 0644]
src/gamewidget.cpp [new file with mode: 0644]
src/gamewidget.h [new file with mode: 0644]
src/mainwin.cpp [new file with mode: 0644]
src/mainwin.h [new file with mode: 0644]
warehousemandeluxe.pro [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..c465c5f
--- /dev/null
@@ -0,0 +1,4 @@
+obj/
+Makefile
+warehousemandeluxe
+res/*.xcf
diff --git a/res/resources.qrc b/res/resources.qrc
new file mode 100644 (file)
index 0000000..c527ba4
--- /dev/null
@@ -0,0 +1,6 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource>
+       <file>wmd-icon.png</file>
+</qresource>
+</RCC>
+
diff --git a/res/wmd-icon.png b/res/wmd-icon.png
new file mode 100644 (file)
index 0000000..2de59c9
Binary files /dev/null and b/res/wmd-icon.png differ
diff --git a/src/app.cpp b/src/app.cpp
new file mode 100644 (file)
index 0000000..e6fa79f
--- /dev/null
@@ -0,0 +1,39 @@
+//
+// app.cpp: Implementation of the application
+//
+// Part of the Warehouse Man Deluxe Project
+// (C) 2014 Underground Software
+// See the README and GPLv3 files for licensing and warranty information
+//
+// JLH = James Hammons <jlhamm@acm.org>
+//
+// Who  When        What
+// ---  ----------  -------------------------------------------------------------
+// JLH  03/01/2014  Created this file
+//
+
+#include "app.h"
+
+#include <QApplication>
+#include "mainwin.h"
+
+// Main app constructor--we stick globally accessible stuff here...
+
+App::App(int & argc, char * argv[]): QApplication(argc, argv)
+{
+       mainWindow = new MainWin;
+       mainWindow->show();
+}
+
+
+// Here's the main application loop--short and simple...
+int main(int argc, char * argv[])
+{
+       // This must the same name as the .qrc filename
+       Q_INIT_RESOURCE(resources);
+
+       App app(argc, argv);
+
+       return app.exec();
+}
+
diff --git a/src/app.h b/src/app.h
new file mode 100644 (file)
index 0000000..d0105a0
--- /dev/null
+++ b/src/app.h
@@ -0,0 +1,19 @@
+#ifndef __APP_H__
+#define __APP_H__
+
+#include <QtGui>
+
+// Forward declarations
+class MainWin;
+
+class App: public QApplication
+{
+       public:
+               App(int & argc, char * argv[]);
+
+       public:
+               MainWin * mainWindow;
+};
+
+#endif // __APP_H__
+
diff --git a/src/boards.cpp b/src/boards.cpp
new file mode 100644 (file)
index 0000000..df1ee50
--- /dev/null
@@ -0,0 +1,181 @@
+//
+// boards.cpp: Actual playable (we hope!) game boards
+//
+// by James Hammons
+// © 2014 Underground Software
+//
+// JLH = James Hammons <jlhamm@acm.org>
+//
+// Who  When        What
+// ---  ----------  ------------------------------------------------------------
+// JLH  03/03/2014  Created this file
+//
+
+//
+// We use anonymous structs to create these, to keep things simple. :-)
+//
+// Legend:
+//   @ = Wall
+//     = Space
+//   X = Box
+//   . = Spot to move box to
+//   + = Spot to move box to, that already has a box on it
+//   o = Player initial position
+//
+
+static const struct {
+       unsigned int width, height;
+       unsigned char state[5 * 5 + 1]; } board001 = { 5, 5,
+       "@@@@@"
+       "@o  @"
+       "@ X @"
+       "@ . @"
+       "@@@@@"
+};
+
+
+static const struct {
+       unsigned int width, height;
+       unsigned char state[7 * 7 + 1]; } board002 = { 7, 7,
+       "@@@@@@@"
+       "@     @"
+       "@ X.X @"
+       "@ .@. @"
+       "@ X.X @"
+       "@o    @"
+       "@@@@@@@"
+};
+
+
+static const struct {
+       unsigned int width, height;
+       unsigned char state[7 * 5 + 1]; } board003 = { 7, 5,
+       "@@@@@@@"
+       "@. X .@"
+       "@ XoX @"
+       "@. X .@"
+       "@@@@@@@"
+};
+
+
+static const struct {
+       unsigned int width, height;
+       unsigned char state[8 * 5 + 1]; } board004 = { 8, 5,
+       "@@@@@@@@"
+       "@  ..X @"
+       "@ Xo X @"
+       "@ X..  @"
+       "@@@@@@@@"
+};
+
+
+static const struct {
+       unsigned int width, height;
+       unsigned char state[8 * 7 + 1]; } board005 = { 8, 7,
+       " @@@@@@@"
+       " @     @"
+       "@@ .X. @"
+       "@o X X @"
+       "@  .X. @"
+       "@@     @"
+       " @@@@@@@"
+};
+
+
+static const struct {
+       unsigned int width, height;
+       unsigned char state[8 * 8 + 1]; } board006 = { 8, 8,
+       " @@@@@  "
+       "@@   @@@"
+       "@  @   @"
+       "@ @  @ @"
+       "@ X X@ @"
+       "@.@    @"
+       "@. o@@@@"
+       "@@@@@   "
+};
+
+
+static const struct {
+       unsigned int width, height;
+       unsigned char state[8 * 6 + 1]; } board007 = { 8, 6,
+       "@@@@@@@@"
+       "@ X. X.@"
+       "@o.X X.@"
+       "@ X. X.@"
+       "@ .X X.@"
+       "@@@@@@@@"
+};
+
+
+static const struct {
+       unsigned int width, height;
+       unsigned char state[10 * 8 + 1]; } board008 = { 10, 8,
+       "   @@@@@@@"
+       "  @@  @ o@"
+       "  @   @  @"
+       "  @X X X @"
+       "  @ X@@  @"
+       "@@@ X @ @@"
+       "@.....  @ "
+       "@@@@@@@@@ "
+};
+
+
+static const struct {
+       unsigned int width, height;
+       unsigned char state[9 * 7 + 1]; } board009 = { 9, 7,
+       "@@@@@@@@@"
+       "@   +   @"
+       "@ X.@.X @"
+       "@  X.X  @"
+       "@@@.X.@@@"
+       "  @@o@@  "
+       "   @@@   "
+};
+
+
+static const struct {
+       unsigned int width, height;
+       unsigned char state[7 * 7 + 1]; } board010 = { 7, 7,
+       "  @@@@@"
+       "@@@   @"
+       "@o .X.@"
+       "@  X X@"
+       "@@@.X.@"
+       "  @   @"
+       "  @@@@@"
+};
+
+
+static const struct {
+       unsigned int width, height;
+       unsigned char state[10 * 8 + 1]; } board011 = { 10, 8,
+       "  @@@@    "
+       "  @  @    "
+       "@@@  @@@@@"
+       "@  ..X   @"
+       "@oX.. X  @"
+       "@@@ X@@@@@"
+       "  @  @    "
+       "  @@@@    "
+};
+
+
+static const struct {
+       unsigned int width, height;
+       unsigned char state[10 * 6 + 1]; } board012 = { 10, 6,
+       " @@@@@@@@@"
+       "@@       @"
+       "@   @X@X @"
+       "@ XX  .X.@"
+       "@ o@@@...@"
+       "@@@@ @@@@@"
+};
+
+
+const void * boards[] = {
+       &board001, &board002, &board003, &board004, &board005, &board006, &board007, &board008,
+       &board009, &board010, &board011, &board012, //&board013, &board014, &board015, &board016,
+};
+
diff --git a/src/boards.h b/src/boards.h
new file mode 100644 (file)
index 0000000..6264de4
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef __BOARDS_H__
+#define __BOARDS_H__
+
+// Okay, this is ugly but works and I can't think of any better way to handle
+// this. So what we do when we pass the anonymous structs into a function is
+// pass them as a (void *) and then cast them as type (Board *) in order to
+// use them. Yes, it's ugly. Come up with something better!
+
+struct Board {
+       unsigned int width;             // Width of the board
+       unsigned int height;    // Height of the board
+//     unsigned int x;                 // Initial X position of player
+//     unsigned int y;                 // Initial Y position of player
+       unsigned char state[];  // Board data
+};
+
+#define NUMBER_OF_BOARDS       12
+extern const void * boards[];
+
+#endif // __BOARDS_H__
+
diff --git a/src/gameboard.cpp b/src/gameboard.cpp
new file mode 100644 (file)
index 0000000..0c4a89e
--- /dev/null
@@ -0,0 +1,168 @@
+//
+// gameboard.cpp: Game board class implementation
+//
+// by James Hammons
+// © 2014 Underground Software
+//
+// JLH = James Hammons <jlhamm@acm.org>
+//
+// Who  When        What
+// ---  ----------  ------------------------------------------------------------
+// JLH  03/01/2014  Created this file
+//
+
+#include "gameboard.h"
+#include <string.h>
+//#include <stdio.h>   // for printf()
+#include "boards.h"
+
+
+GameBoard::GameBoard(int boardNumber)
+{
+       // Sanity check
+       if (boardNumber > NUMBER_OF_BOARDS)
+               boardNumber = NUMBER_OF_BOARDS;
+
+       // boardNumber is 1-based
+       Board * boardToUse = (Board *)boards[boardNumber - 1];
+
+       width = boardToUse->width;
+       height = boardToUse->height;
+       boardLength = width * height;
+       board = new char[boardLength];
+       initialBoard = new char[boardLength];
+//     initialX = boardToUse->x;
+//     initialY = boardToUse->y;
+
+       for(int i=0; i<boardLength; i++)
+       {
+               char c = boardToUse->state[i];
+
+               if (c == '@')
+                       initialBoard[i] = GTWall;
+               else if (c == ' ')
+                       initialBoard[i] = GTSpace;
+               else if (c == 'X')
+                       initialBoard[i] = GTBox;
+               else if (c == '.')
+                       initialBoard[i] = GTBoxSpot;
+               else if (c == '+')
+                       initialBoard[i] = GTBox | GTBoxSpot;
+               else if (c == 'o')
+               {
+                       initialBoard[i] = GTSpace;
+                       initialX = i % width, initialY = i / width;
+               }
+       }
+
+       ResetGame();
+}
+
+
+GameBoard::~GameBoard()
+{
+       if (board)
+               delete[] board;
+
+       if (initialBoard)
+               delete[] initialBoard;
+}
+
+
+bool GameBoard::GameHasBeenWon(void)
+{
+       // Check to see if all boxes are on their spots
+       for(int i=0; i<boardLength; i++)
+       {
+               char cell = board[i] & ~GTBoxSpot;
+
+               if ((cell == GTBox) && !(board[i] & GTBoxSpot))
+                       return false;
+       }
+
+       return true;
+}
+
+
+void GameBoard::ResetGame(void)
+{
+       memcpy(board, initialBoard, boardLength);
+       playerX = initialX, playerY = initialY;
+}
+
+
+int GameBoard::MovePlayerN(void)
+{
+       // Sanity check (player trying to move into wall)
+       if (playerY == 1)
+               return PMInvalid;
+
+       char cell1 = board[playerX + ((playerY - 1) * width)] & ~GTBoxSpot;
+       char cell2 = board[playerX + ((playerY - 2) * width)] & ~GTBoxSpot;
+
+       return Move(playerY, -1, cell1, cell2);
+}
+
+
+int GameBoard::MovePlayerS(void)
+{
+       // Sanity check (player trying to move into wall)
+       if (playerY == (height - 2))
+               return PMInvalid;
+
+       char cell1 = board[playerX + ((playerY + 1) * width)] & ~GTBoxSpot;
+       char cell2 = board[playerX + ((playerY + 2) * width)] & ~GTBoxSpot;
+
+       return Move(playerY, +1, cell1, cell2);
+}
+
+
+int GameBoard::MovePlayerE(void)
+{
+       // Sanity check (player trying to move into wall)
+       if (playerX == (width - 2))
+               return PMInvalid;
+
+       char cell1 = board[(playerX + 1) + (playerY * width)] & ~GTBoxSpot;
+       char cell2 = board[(playerX + 2) + (playerY * width)] & ~GTBoxSpot;
+
+       return Move(playerX, +1, cell1, cell2);
+}
+
+
+int GameBoard::MovePlayerW(void)
+{
+       // Sanity check (player trying to move into wall)
+       if (playerX == 1)
+               return PMInvalid;
+
+       char cell1 = board[(playerX - 1) + (playerY * width)] & ~GTBoxSpot;
+       char cell2 = board[(playerX - 2) + (playerY * width)] & ~GTBoxSpot;
+
+       return Move(playerX, -1, cell1, cell2);
+}
+
+
+int GameBoard::Move(int & var, int direction, char cell1, char cell2)
+{
+       // Player is moving into an unoccupied space...
+       if (cell1 == GTSpace)
+       {
+               var += direction;
+               return PMWalk;
+       }
+       // Player is pushing a box into an unoccupied space...
+       else if ((cell1 == GTBox) && (cell2 == GTSpace))
+       {
+               var += direction;
+               board[playerX + (playerY * width)] &= GTBoxSpot;
+               var += direction;
+               board[playerX + (playerY * width)] |= GTBox;
+               var -= direction;
+               return PMPush;
+       }
+
+       // All other combinations are no good
+       return PMInvalid;
+}
+
diff --git a/src/gameboard.h b/src/gameboard.h
new file mode 100644 (file)
index 0000000..b32dc88
--- /dev/null
@@ -0,0 +1,38 @@
+#ifndef __GAMEBOARD_H__
+#define __GAMEBOARD_H__
+
+enum { GTSpace=0x00, GTWall=0x01, GTBox=0x02, GTBoxSpot=0x04 };
+enum { PMInvalid, PMWalk, PMPush };
+
+class GameBoard
+{
+       public:
+               GameBoard(int);//, int, int, int);
+               ~GameBoard();
+
+       protected:
+
+       public:
+               bool GameHasBeenWon(void);
+               void ResetGame(void);
+               int MovePlayerN(void);
+               int MovePlayerS(void);
+               int MovePlayerE(void);
+               int MovePlayerW(void);
+
+       private:
+               int Move(int & var, int direction, char, char);
+
+       public:
+               int playerX, playerY;           // Player X/Y are zero-based
+               int width, height;
+               char * board;
+
+       private:
+               char * initialBoard;
+               int initialX, initialY;
+               int boardLength;
+};
+
+#endif // __GAMEBOARD_H__
+
diff --git a/src/gamewidget.cpp b/src/gamewidget.cpp
new file mode 100644 (file)
index 0000000..837edd8
--- /dev/null
@@ -0,0 +1,1340 @@
+//
+// 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
+
diff --git a/src/gamewidget.h b/src/gamewidget.h
new file mode 100644 (file)
index 0000000..c587e08
--- /dev/null
@@ -0,0 +1,54 @@
+#ifndef __GAMEWIDGET_H__
+#define __GAMEWIDGET_H__
+
+#include <QtGui>
+
+class GameBoard;
+
+class GameWidget: public QWidget
+{
+       Q_OBJECT
+
+       public:
+               GameWidget(QWidget * parent = 0);
+               ~GameWidget();
+
+       protected:
+               void paintEvent(QPaintEvent * event);
+               void mousePressEvent(QMouseEvent * event);
+               void mouseMoveEvent(QMouseEvent * event);
+               void mouseReleaseEvent(QMouseEvent * event);
+               void mouseDoubleClickEvent(QMouseEvent * event);
+               void keyPressEvent(QKeyEvent * event);
+               void keyReleaseEvent(QKeyEvent * event);
+
+       signals:
+               void UpdateScore(int);
+               void GameWasWon(void);
+
+       public:
+               void NextLevel(void);
+               void ResetLevel(void);
+/*
+               void DrawBoard(QPainter * painter, QRect r);
+               bool CreateBackground(void);
+               void OnLButtonDown(QPoint point);
+               void OnLButtonUp(QPoint point);
+               void OnMouseMove(QPoint point);
+               void OnLButtonDblClk(QPoint point);
+               void HandleAutoRemove(void);
+               void AnimateCards(int nCard, int nAce, int nTabX, int nTabY);
+               bool IsValidMoveToAce(int nAceM);
+               bool IsValidMoveToAce(int nAce, int nCard);
+               bool IsValidMoveToTableaux(int nStack);
+               bool PlayerWon(void);
+               void HandleStatistics(void);
+               void Pause(int);*/
+
+       public:
+               GameBoard * gameBoard;
+               int level;
+};
+
+#endif // __GAMEWIDGET_H__
+
diff --git a/src/mainwin.cpp b/src/mainwin.cpp
new file mode 100644 (file)
index 0000000..8ba6ded
--- /dev/null
@@ -0,0 +1,485 @@
+//
+// 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
+
diff --git a/src/mainwin.h b/src/mainwin.h
new file mode 100644 (file)
index 0000000..854e58a
--- /dev/null
@@ -0,0 +1,53 @@
+#ifndef __MAINWIN_H__
+#define __MAINWIN_H__
+
+#include <QtGui>
+
+class GameWidget;
+
+class MainWin: public QMainWindow
+{
+       Q_OBJECT
+
+       public:
+               MainWin();
+               ~MainWin();
+
+       private:
+               void ResetGame(void);
+
+       protected:
+               QAction * CreateAction(QString name, QString tooltip, QString statustip,
+                       QIcon icon, QKeySequence key, bool checkable = false);
+               QAction * CreateAction(QString name, QString tooltip, QString statustip,
+                       QIcon icon, QKeySequence key1, QKeySequence key2, bool checkable = false);
+
+       protected slots:
+               void closeEvent(QCloseEvent * event);
+
+//             void QuitGame(void);
+               void AboutGame(void);
+               void WeHaveAWinner(void);
+               void ResetCurrentLevel(void);
+/*             void OnNewGame(void);
+               void OnGameOptions(void);
+               void OnGameStats(void);
+               void OnHelpUndo(void);
+               void OnUpdateScore(int);
+               void OnGamePlay(void);
+               void OnAppAbout(void);*/
+
+       private:
+               GameWidget * gameWidget;
+               QAction * newGame;
+               QAction * gamePlay;
+               QAction * helpUndo;
+               QAction * gameOptions;
+               QAction * gameStats;
+               QAction * appExit;
+               QAction * appAbout;
+               QAction * resetLevel;
+};
+
+#endif // __MAINWIN_H__
+
diff --git a/warehousemandeluxe.pro b/warehousemandeluxe.pro
new file mode 100644 (file)
index 0000000..a68a1e5
--- /dev/null
@@ -0,0 +1,33 @@
+# Use 'qmake -o Makefile warehouse-man-deluxe.pro'
+
+CONFIG    += qt warn_on release debug
+RESOURCES += res/resources.qrc
+#LIBS      += -Ldxflib/lib -ldxf
+#LIBS      += -lao
+
+# We stuff all the intermediate crap into obj/ so it won't confuse us mere mortals ;-)
+OBJECTS_DIR = obj
+MOC_DIR     = obj
+RCC_DIR     = obj
+UI_DIR      = obj
+
+INCLUDEPATH += \
+       src
+
+DEPENDPATH = \
+       src
+
+HEADERS = \
+       app.h \
+       boards.h \
+       gameboard.h \
+       gamewidget.h \
+       mainwin.h
+
+SOURCES = \
+       app.cpp \
+       boards.cpp \
+       gameboard.cpp \
+       gamewidget.cpp \
+       mainwin.cpp
+