From e7d9b2c4e813ba0da239484b1f5d609e4844caf0 Mon Sep 17 00:00:00 2001 From: Shamus Hammons Date: Wed, 5 Mar 2014 12:42:27 -0600 Subject: [PATCH] Initial commit. --- .gitignore | 4 + res/resources.qrc | 6 + res/wmd-icon.png | Bin 0 -> 1230 bytes src/app.cpp | 39 ++ src/app.h | 19 + src/boards.cpp | 181 ++++++ src/boards.h | 21 + src/gameboard.cpp | 168 +++++ src/gameboard.h | 38 ++ src/gamewidget.cpp | 1340 ++++++++++++++++++++++++++++++++++++++++ src/gamewidget.h | 54 ++ src/mainwin.cpp | 485 +++++++++++++++ src/mainwin.h | 53 ++ warehousemandeluxe.pro | 33 + 14 files changed, 2441 insertions(+) create mode 100644 .gitignore create mode 100644 res/resources.qrc create mode 100644 res/wmd-icon.png create mode 100644 src/app.cpp create mode 100644 src/app.h create mode 100644 src/boards.cpp create mode 100644 src/boards.h create mode 100644 src/gameboard.cpp create mode 100644 src/gameboard.h create mode 100644 src/gamewidget.cpp create mode 100644 src/gamewidget.h create mode 100644 src/mainwin.cpp create mode 100644 src/mainwin.h create mode 100644 warehousemandeluxe.pro diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c465c5f --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +obj/ +Makefile +warehousemandeluxe +res/*.xcf diff --git a/res/resources.qrc b/res/resources.qrc new file mode 100644 index 0000000..c527ba4 --- /dev/null +++ b/res/resources.qrc @@ -0,0 +1,6 @@ + + + wmd-icon.png + + + diff --git a/res/wmd-icon.png b/res/wmd-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..2de59c9cc88eebfa5e3d45ce8502b16851562747 GIT binary patch literal 1230 zcmV;<1Tp)GP)GXaM1g2ey;03B&m zSad^gZEa<4bN~PV002XBWnpw>WFU8GbZ8()Nlj2>E@cM*00c5gL_t(|+U=duj^!W> zLx+n0|K;w}NUPDkZ7C!;$?@Y#JGaG-W1ubVJkK9c7Y9Rt000622ml}efB*mj00;n- zL63Ujtu?t7tn)luxN(fO5~xUgWFdBlrv;=X-rC(-YY0HG+E)|5n&?m0_vAO;{=YB+ z*iF0_(Qkgof_xbPcoVNobg33_NBr-=UJc|G`B{jzs{Snkcv9`7#789hn{faBh9&u~ z0$4@-%0bvk^jq@7wSd*cXCQh;(5uI&?;`&1fMu-c8S<^I-$Vc-)jo4mQHfst+vj;| ztOKkj{w~>PA$p|mTjhhUR`C|CL4jzczCSI1(f&SL_0fq|zV^Pl;@>KEmC7S;(CoN& zo(L)q1W+8WLm=-I=4cBz04)H}0um={fCB&o01yB`000311ON~K7+VKmZ2$)V2msIm z{=<{qz;A7$(oW*+7=+#pym~Y&dxp5WN2LNVe=+3hrH|HHIydlm?lEKrsNe?C$aiso z3T_aQ_^q>mOm1-1=OYMu+cfZMfFg(>O2{)4fb|A zH^^4?CK({B8)PMZS^(B0?RJCRAqJ&MgTKzz=BQ^0gSqVGVxK!mlVJgH&C9}M|(&_`sC1& z0}-hDgaUYC`JRKG@nzQ$0c^R;%Dvv>;SgyDAmNL)fSspuSMBvH4v3O>0F^<%8|X~0 zwRgyW*K=3xV3rqvdez^ZQ5@Y3`pT+^7_deJX#G4x83%|Q^0Iy8qN|Xv(&uN7ZH?vz zovMF-4H?{^S0LW{IwHHlQK9Oe%uAOjWPu1|wR4qk^gF@Z1d#m@hDdI3Q1$+9U{OSG zs{eHev`}&OvxHUemE+@+XbJ%Uzjc6&{W@@~Xfu4^0L6g-f}6yw8zTT500hkgZABJC z05|}s*!vLxKmgUN9{~UaP`UbleuQ=d0S*A1s~-V?p%&2C1#~L)4=vVe>~R1x08ode s^A61dNdGthNL2j@0Fdly0iZPg0VY7K=EU +// +// Who When What +// --- ---------- ------------------------------------------------------------- +// JLH 03/01/2014 Created this file +// + +#include "app.h" + +#include +#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 index 0000000..d0105a0 --- /dev/null +++ b/src/app.h @@ -0,0 +1,19 @@ +#ifndef __APP_H__ +#define __APP_H__ + +#include + +// 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 index 0000000..df1ee50 --- /dev/null +++ b/src/boards.cpp @@ -0,0 +1,181 @@ +// +// boards.cpp: Actual playable (we hope!) game boards +// +// by James Hammons +// © 2014 Underground Software +// +// JLH = James Hammons +// +// 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 index 0000000..6264de4 --- /dev/null +++ b/src/boards.h @@ -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 index 0000000..0c4a89e --- /dev/null +++ b/src/gameboard.cpp @@ -0,0 +1,168 @@ +// +// gameboard.cpp: Game board class implementation +// +// by James Hammons +// © 2014 Underground Software +// +// JLH = James Hammons +// +// Who When What +// --- ---------- ------------------------------------------------------------ +// JLH 03/01/2014 Created this file +// + +#include "gameboard.h" +#include +//#include // 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; istate[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 +// +// Who When What +// --- ---------- ------------------------------------------------------------ +// JLH 03/01/2014 Created this file +// + +#include "gamewidget.h" +#include // 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; yheight; y++) + { + for(int x=0; xwidth; 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 -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 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 abs(nDeltaY)) + { + for(int i=0; i 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)) + 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 index 0000000..c587e08 --- /dev/null +++ b/src/gamewidget.h @@ -0,0 +1,54 @@ +#ifndef __GAMEWIDGET_H__ +#define __GAMEWIDGET_H__ + +#include + +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 index 0000000..8ba6ded --- /dev/null +++ b/src/mainwin.cpp @@ -0,0 +1,485 @@ +// +// mainwin.cpp: Implementation of the MainWin class +// +// JLH = James Hammons +// +// Who When What +// --- ---------- ------------------------------------------------------------ +// JLH 03/01/2014 Created this file +// + +// TO DO: +// + +#include "mainwin.h" + +#include // For rand() +#include // 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 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 index 0000000..854e58a --- /dev/null +++ b/src/mainwin.h @@ -0,0 +1,53 @@ +#ifndef __MAINWIN_H__ +#define __MAINWIN_H__ + +#include + +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 index 0000000..a68a1e5 --- /dev/null +++ b/warehousemandeluxe.pro @@ -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 + -- 2.37.2