--- /dev/null
+include ../../src/gtk/setup/general/makeapp
--- /dev/null
+# WXXT base directory
+WXBASEDIR=@WXBASEDIR@
+
+# set the OS type for compilation
+OS=@OS@
+# compile a library only
+RULE=bin
+
+# define library name
+BIN_TARGET=forty
+# define library sources
+BIN_SRC=\
+canvas.cpp \
+card.cpp \
+forty.cpp \
+game.cpp \
+pile.cpp \
+playerdg.cpp \
+scoredg.cpp \
+scorefil.cpp
+
+#define library objects
+BIN_OBJ=\
+canvas.o \
+card.o \
+forty.o \
+game.o \
+pile.o \
+playerdg.o \
+scoredg.o \
+scorefil.o
+
+# additional things needed to link
+BIN_LINK=
+
+# additional things needed to compile
+ADD_COMPILE=
+
+# include the definitions now
+include ../../../template.mak
--- /dev/null
+/////////////////////////////////////////////////////////////////////////////
+// Name: canvas.cpp
+// Purpose: Forty Thieves patience game
+// Author: Chris Breeze
+// Modified by:
+// Created: 21/07/97
+// RCS-ID: $Id$
+// Copyright: (c) 1993-1998 Chris Breeze
+// Licence: wxWindows licence
+//---------------------------------------------------------------------------
+// Last modified: 22nd July 1998 - ported to wxWindows 2.0
+/////////////////////////////////////////////////////////////////////////////
+
+#ifdef __GNUG__
+#pragma implementation
+#pragma interface
+#endif
+
+// For compilers that support precompilation, includes "wx/wx.h".
+#include "wx/wxprec.h"
+
+#ifdef __BORLANDC__
+#pragma hdrstop
+#endif
+
+#ifndef WX_PRECOMP
+#include "wx/wx.h"
+#endif
+
+#include "forty.h"
+#include "card.h"
+#include "game.h"
+#include "scorefil.h"
+#include "playerdg.h"
+#include "canvas.h"
+
+BEGIN_EVENT_TABLE(FortyCanvas, wxScrolledWindow)
+ EVT_MOUSE_EVENTS(FortyCanvas::OnMouseEvent)
+END_EVENT_TABLE()
+
+FortyCanvas::FortyCanvas(wxWindow* parent, int x, int y, int w, int h) :
+ wxScrolledWindow(parent, -1, wxPoint(x, y), wxSize(w, h)),
+ m_helpingHand(TRUE),
+ m_rightBtnUndo(TRUE),
+ m_playerDialog(0),
+ m_leftBtnDown(FALSE)
+{
+#ifdef __WXGTK__
+ m_font = wxTheFontList->FindOrCreateFont(12, wxROMAN, wxNORMAL, wxNORMAL);
+#else
+ m_font = wxTheFontList->FindOrCreateFont(10, wxSWISS, wxNORMAL, wxNORMAL);
+#endif
+ SetBackgroundColour(*FortyApp::BackgroundColour());
+ AllowDoubleClick(true);
+
+ m_handCursor = new wxCursor(wxCURSOR_HAND);
+ m_arrowCursor = new wxCursor(wxCURSOR_ARROW);
+
+ wxString name = wxTheApp->GetAppName();
+ if (name.Length() <= 0) name = "forty";
+ m_scoreFile = new ScoreFile(name);
+ m_game = new Game(0, 0, 0);
+ m_game->Deal();
+}
+
+
+FortyCanvas::~FortyCanvas()
+{
+ UpdateScores();
+ delete m_game;
+ delete m_scoreFile;
+}
+
+
+/*
+Write the current player's score back to the score file
+*/
+void FortyCanvas::UpdateScores()
+{
+ if (m_player.Length() > 0 && m_scoreFile && m_game)
+ {
+ m_scoreFile->WritePlayersScore(
+ m_player,
+ m_game->GetNumWins(),
+ m_game->GetNumGames(),
+ m_game->GetScore()
+ );
+ }
+}
+
+
+void FortyCanvas::OnDraw(wxDC& dc)
+{
+ dc.SetFont(m_font);
+ m_game->Redraw(dc);
+
+ // if player name not set (and selection dialog is not displayed)
+ // then ask the player for their name
+ if (m_player.Length() == 0 && !m_playerDialog)
+ {
+ m_playerDialog = new PlayerSelectionDialog(this, m_scoreFile);
+ m_player = m_playerDialog->GetPlayersName();
+ if (m_player.Length() > 0)
+ {
+ // user entered a name - lookup their score
+ int wins, games, score;
+ m_scoreFile->ReadPlayersScore(m_player, wins, games, score);
+ m_game->NewPlayer(wins, games, score);
+ m_game->DisplayScore(dc);
+ delete m_playerDialog;
+ m_playerDialog = 0;
+ }
+ else
+ {
+ // user cancelled the dialog - exit the app
+ ((wxFrame*)GetParent())->Close(TRUE);
+ }
+ }
+}
+
+/*
+Called when the main frame is closed
+*/
+bool FortyCanvas::OnClose()
+{
+ if (m_game->InPlay() &&
+ wxMessageBox("Are you sure you want to\nabandon the current game?",
+ "Warning", wxYES_NO | wxICON_QUESTION) == wxNO)
+ {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+void FortyCanvas::OnMouseEvent(wxMouseEvent& event)
+{
+ int mouseX = (int)event.GetX();
+ int mouseY = (int)event.GetY();
+
+ wxClientDC dc(this);
+ PrepareDC(dc);
+ dc.SetFont(m_font);
+
+ if (event.LeftDClick())
+ {
+ if (m_leftBtnDown)
+ {
+ m_leftBtnDown = FALSE;
+ ReleaseMouse();
+ m_game->LButtonUp(dc, mouseX, mouseY);
+ }
+ m_game->LButtonDblClk(dc, mouseX, mouseY);
+ }
+ else if (event.LeftDown())
+ {
+ if (!m_leftBtnDown)
+ {
+ m_leftBtnDown = TRUE;
+ CaptureMouse();
+ m_game->LButtonDown(dc, mouseX, mouseY);
+ }
+ }
+ else if (event.LeftUp())
+ {
+ if (m_leftBtnDown)
+ {
+ m_leftBtnDown = FALSE;
+ ReleaseMouse();
+ m_game->LButtonUp(dc, mouseX, mouseY);
+ }
+ }
+ else if (event.RightDown() && !event.LeftIsDown())
+ {
+ // only allow right button undo if m_rightBtnUndo is TRUE
+ if (m_rightBtnUndo)
+ {
+ if (event.ControlDown() || event.ShiftDown())
+ {
+ m_game->Redo(dc);
+ }
+ else
+ {
+ m_game->Undo(dc);
+ }
+ }
+ }
+ else if (event.Dragging())
+ {
+ m_game->MouseMove(dc, mouseX, mouseY);
+ }
+
+ if (!event.LeftIsDown())
+ {
+ SetCursorStyle(mouseX, mouseY);
+ }
+}
+
+void FortyCanvas::SetCursorStyle(int x, int y)
+{
+ if (m_game->HaveYouWon())
+ {
+ if (wxMessageBox("Do you wish to play again?",
+ "Well Done, You have won!", wxYES_NO | wxICON_QUESTION) == wxYES)
+ {
+ m_game->Deal();
+
+ wxClientDC dc(this);
+ PrepareDC(dc);
+ dc.SetFont(m_font);
+ m_game->Redraw(dc);
+ }
+ else
+ {
+ // user cancelled the dialog - exit the app
+ ((wxFrame*)GetParent())->Close(TRUE);
+ }
+ }
+
+ // Only set cursor to a hand if 'helping hand' is enabled and
+ // the card under the cursor can go somewhere
+ if (m_game->CanYouGo(x, y) && m_helpingHand)
+ {
+ SetCursor(m_handCursor);
+ }
+ else
+ {
+ SetCursor(m_arrowCursor);
+ }
+
+}
+
+void FortyCanvas::NewGame()
+{
+ m_game->Deal();
+ Refresh();
+}
+
+void FortyCanvas::Undo()
+{
+ wxClientDC dc(this);
+ PrepareDC(dc);
+ dc.SetFont(m_font);
+ m_game->Undo(dc);
+}
+
+void FortyCanvas::Redo()
+{
+ wxClientDC dc(this);
+ PrepareDC(dc);
+ dc.SetFont(m_font);
+ m_game->Redo(dc);
+}
--- /dev/null
+/////////////////////////////////////////////////////////////////////////////
+// Name: canvas.h
+// Purpose: Forty Thieves patience game
+// Author: Chris Breeze
+// Modified by:
+// Created: 21/07/97
+// RCS-ID: $Id$
+// Copyright: (c) 1993-1998 Chris Breeze
+// Licence: wxWindows licence
+//---------------------------------------------------------------------------
+// Last modified: 22nd July 1998 - ported to wxWindows 2.0
+/////////////////////////////////////////////////////////////////////////////
+#ifndef _CANVAS_H_
+#define _CANVAS_H_
+
+class Card;
+class Game;
+class ScoreFile;
+class PlayerSelectionDialog;
+
+class FortyCanvas: public wxScrolledWindow
+{
+public:
+ FortyCanvas(wxWindow* parent, int x, int y, int w, int h);
+ virtual ~FortyCanvas();
+
+ virtual void OnDraw(wxDC& dc);
+ bool OnClose();
+ void OnMouseEvent(wxMouseEvent& event);
+ void SetCursorStyle(int x, int y);
+
+ void NewGame();
+ void Undo();
+ void Redo();
+
+ ScoreFile* GetScoreFile() const { return m_scoreFile; }
+ void UpdateScores();
+ void EnableHelpingHand(bool enable) { m_helpingHand = enable; }
+ void EnableRightButtonUndo(bool enable) { m_rightBtnUndo = enable; }
+
+ DECLARE_EVENT_TABLE()
+
+private:
+ wxFont* m_font;
+ Game* m_game;
+ ScoreFile* m_scoreFile;
+ wxCursor* m_arrowCursor;
+ wxCursor* m_handCursor;
+ bool m_helpingHand;
+ bool m_rightBtnUndo;
+ wxString m_player;
+ PlayerSelectionDialog* m_playerDialog;
+ bool m_leftBtnDown;
+};
+
+#endif
--- /dev/null
+/////////////////////////////////////////////////////////////////////////////
+// Name: card.cpp
+// Purpose: Forty Thieves patience game
+// Author: Chris Breeze
+// Modified by:
+// Created: 21/07/97
+// RCS-ID: $Id$
+// Copyright: (c) 1993-1998 Chris Breeze
+// Licence: wxWindows licence
+//---------------------------------------------------------------------------
+// Last modified: 22nd July 1998 - ported to wxWindows 2.0
+/////////////////////////////////////////////////////////////////////////////
+//+-------------------------------------------------------------+
+//| Description: |
+//| A class for drawing playing cards. |
+//| Currently assumes that the card symbols have been |
+//| loaded into hbmap_symbols and the pictures for the |
+//| Jack, Queen and King have been loaded into |
+//| hbmap_pictures. |
+//+-------------------------------------------------------------+
+
+#ifdef __GNUG__
+#pragma implementation
+#pragma interface
+#endif
+
+// For compilers that support precompilation, includes "wx/wx.h".
+#include "wx/wxprec.h"
+
+#ifdef __BORLANDC__
+#pragma hdrstop
+#endif
+
+#ifndef WX_PRECOMP
+#include "wx/wx.h"
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "forty.h"
+#include "card.h"
+
+#ifdef __WXGTK__
+#include "pictures.xpm"
+#include "symbols.xbm"
+#endif
+
+wxBitmap* Card::m_pictureBmap = 0;
+wxBitmap* Card::m_symbolBmap = 0;
+
+
+//+-------------------------------------------------------------+
+//| Card::Card() |
+//+-------------------------------------------------------------+
+//| Description: |
+//| Constructor for a playing card. |
+//| Checks that the value is in the range 1..52 and then |
+//| initialises the suit, colour, pipValue and wayUp. |
+//+-------------------------------------------------------------+
+Card::Card(int value, WayUp way_up) :
+ m_wayUp(way_up)
+{
+ if (!m_symbolBmap)
+ {
+#ifdef __WXMSW__
+ m_symbolBmap = new wxBitmap("CardSymbols", wxBITMAP_TYPE_BMP_RESOURCE);
+#else
+ m_symbolBmap = new wxBitmap(Symbols_bits, Symbols_width, Symbols_height);
+#endif
+ if (!m_symbolBmap->Ok())
+ {
+ ::wxMessageBox("Failed to load bitmap CardSymbols", "Error");
+ }
+ }
+ if (!m_pictureBmap)
+ {
+#ifdef __WXMSW__
+ m_pictureBmap = new wxBitmap("CardPictures", wxBITMAP_TYPE_BMP_RESOURCE);
+#else
+ m_pictureBmap = new wxBitmap(Pictures);
+#endif
+ if (!m_pictureBmap->Ok())
+ {
+ ::wxMessageBox("Failed to load bitmap CardPictures", "Error");
+ }
+ }
+
+ if (value >= 1 && value <= PackSize)
+ {
+ switch ((value - 1) / 13)
+ {
+ case 0:
+ m_suit = clubs;
+ m_colour = black;
+ break;
+ case 1:
+ m_suit = diamonds;
+ m_colour = red;
+ break;
+ case 2:
+ m_suit = hearts;
+ m_colour = red;
+ break;
+ case 3:
+ m_suit = spades;
+ m_colour = black;
+ break;
+ }
+ m_pipValue = 1 + (value - 1) % 13;
+ m_status = TRUE;
+ }
+ else
+ {
+ m_status = FALSE;
+ }
+} // Card::Card()
+
+
+//+-------------------------------------------------------------+
+//| Card::~Card() |
+//+-------------------------------------------------------------+
+//| Description: |
+//| Destructor - nothing to do at present. |
+//+-------------------------------------------------------------+
+Card::~Card()
+{
+}
+
+
+//+-------------------------------------------------------------+
+//| Card::Erase() |
+//+-------------------------------------------------------------+
+//| Description: |
+//| Erase the card at (x, y) by drawing a rectangle in the |
+//| background colour. |
+//+-------------------------------------------------------------+
+void Card::Erase(wxDC& dc, int x, int y)
+{
+ wxPen* pen = wxThePenList->FindOrCreatePen(
+ *FortyApp::BackgroundColour(),
+ 1,
+ wxSOLID
+ );
+ dc.SetPen(pen);
+ dc.SetBrush(FortyApp::BackgroundBrush());
+ dc.DrawRectangle(x, y, CardWidth, CardHeight);
+} // Card::Erase()
+
+
+//+-------------------------------------------------------------+
+//| Card::Draw() |
+//+-------------------------------------------------------------+
+//| Description: |
+//| Draw the card at (x, y). |
+//| If the card is facedown draw the back of the card. |
+//| If the card is faceup draw the front of the card. |
+//| Cards are not held in bitmaps, instead they are drawn |
+//| from their constituent parts when required. |
+//| hbmap_symbols contains large and small suit symbols and |
+//| pip values. These are copied to the appropriate part of |
+//| the card. Picture cards use the pictures defined in |
+//| hbmap_pictures. Note that only one picture is defined |
+//| for the Jack, Queen and King, unlike a real pack where |
+//| each suit is different. |
+//| |
+//| WARNING: |
+//| The locations of these symbols is 'hard-wired' into the |
+//| code. Editing the bitmaps or the numbers below will |
+//| result in the wrong symbols being displayed. |
+//+-------------------------------------------------------------+
+void Card::Draw(wxDC& dc, int x, int y)
+{
+ wxBrush* backgroundBrush = dc.GetBackground();
+ dc.SetBrush(wxWHITE_BRUSH);
+ dc.SetPen(wxBLACK_PEN);
+ dc.DrawRoundedRectangle(x, y, CardWidth, CardHeight, 4);
+ if (m_wayUp == facedown)
+ {
+ dc.SetBackground(wxRED_BRUSH);
+ dc.SetBackgroundMode(wxSOLID);
+ wxBrush* brush = wxTheBrushList->FindOrCreateBrush(
+ "BLACK", wxCROSSDIAG_HATCH
+ );
+ dc.SetBrush(brush);
+
+ dc.DrawRoundedRectangle(
+ x + 4, y + 4,
+ CardWidth - 8, CardHeight - 8,
+ 2
+ );
+ }
+ else
+ {
+ wxMemoryDC memoryDC;
+ memoryDC.SelectObject(m_symbolBmap);
+
+// dc.SetBackgroundMode(wxTRANSPARENT);
+
+ dc.SetTextBackground(*wxWHITE);
+ switch (m_suit)
+ {
+ case spades:
+ case clubs:
+ dc.SetTextForeground(*wxBLACK);
+ break;
+ case diamonds:
+ case hearts:
+ dc.SetTextForeground(*wxRED);
+ break;
+ }
+ // Draw the value
+ dc.Blit(x + 3, y + 3, 6, 7,
+ &memoryDC, 6 * (m_pipValue - 1), 36, wxCOPY);
+ dc.Blit(x + CardWidth - 9, y + CardHeight - 11, 6, 7,
+ &memoryDC, 6 * (m_pipValue - 1), 43, wxCOPY);
+
+ // Draw the pips
+ dc.Blit(x + 11, y + 3, 7, 7,
+ &memoryDC, 7 * m_suit, 0, wxCOPY);
+ dc.Blit(x + CardWidth - 17, y + CardHeight - 11, 7, 7,
+ &memoryDC, 7 * m_suit, 7, wxCOPY);
+
+ switch (m_pipValue)
+ {
+ case 1:
+ dc.Blit(x - 5 + CardWidth / 2, y - 5 + CardHeight / 2, 11, 11,
+ &memoryDC, 11 * m_suit, 14, wxCOPY);
+ break;
+
+ case 3:
+ dc.Blit(x - 5 + CardWidth / 2, y - 5 + CardHeight / 2, 11, 11,
+ &memoryDC, 11 * m_suit, 14, wxCOPY);
+ case 2:
+ dc.Blit(x - 5 + CardWidth / 2,
+ y - 5 + CardHeight / 4, 11, 11,
+ &memoryDC, 11 * m_suit, 14, wxCOPY);
+ dc.Blit(x - 5 + CardWidth / 2,
+ y - 5 + 3 * CardHeight / 4, 11, 11,
+ &memoryDC, 11 * m_suit, 25, wxCOPY);
+ break;
+
+ case 5:
+ dc.Blit(x - 5 + CardWidth / 2, y - 5 + CardHeight / 2, 11, 11,
+ &memoryDC, 11 * m_suit, 14, wxCOPY);
+ case 4:
+ dc.Blit(x - 5 + CardWidth / 4,
+ y - 5 + CardHeight / 4, 11, 11,
+ &memoryDC, 11 * m_suit, 14, wxCOPY);
+ dc.Blit(x - 5 + CardWidth / 4,
+ y - 5 + 3 * CardHeight / 4, 11, 11,
+ &memoryDC, 11 * m_suit, 25, wxCOPY);
+ dc.Blit(x - 5 + 3 * CardWidth / 4,
+ y - 5 + CardHeight / 4, 11, 11,
+ &memoryDC, 11 * m_suit, 14, wxCOPY);
+ dc.Blit(x - 5 + 3 * CardWidth / 4,
+ y - 5 + 3 * CardHeight / 4, 11, 11,
+ &memoryDC, 11 * m_suit, 25, wxCOPY);
+ break;
+
+ case 8:
+ dc.Blit(x - 5 + 5 * CardWidth / 10,
+ y - 5 + 5 * CardHeight / 8, 11, 11,
+ &memoryDC, 11 * m_suit, 25, wxCOPY);
+ case 7:
+ dc.Blit(x - 5 + 5 * CardWidth / 10,
+ y - 5 + 3 * CardHeight / 8, 11, 11,
+ &memoryDC, 11 * m_suit, 14, wxCOPY);
+ case 6:
+ dc.Blit(x - 5 + CardWidth / 4,
+ y - 5 + CardHeight / 4, 11, 11,
+ &memoryDC, 11 * m_suit, 14, wxCOPY);
+ dc.Blit(x - 5 + CardWidth / 4,
+ y - 5 + CardHeight / 2, 11, 11,
+ &memoryDC, 11 * m_suit, 14, wxCOPY);
+ dc.Blit(x - 5 + CardWidth / 4,
+ y - 5 + 3 * CardHeight / 4, 11, 11,
+ &memoryDC, 11 * m_suit, 25, wxCOPY);
+ dc.Blit(x - 5 + 3 * CardWidth / 4,
+ y - 5 + CardHeight / 4, 11, 11,
+ &memoryDC, 11 * m_suit, 14, wxCOPY);
+ dc.Blit(x - 5 + 3 * CardWidth / 4,
+ y - 5 + CardHeight / 2, 11, 11,
+ &memoryDC, 11 * m_suit, 14, wxCOPY);
+ dc.Blit(x - 5 + 3 * CardWidth / 4,
+ y - 5 + 3 * CardHeight / 4, 11, 11,
+ &memoryDC, 11 * m_suit, 25, wxCOPY);
+ break;
+
+ case 10:
+ dc.Blit(x - 5 + CardWidth / 2,
+ y - 5 + 2 * CardHeight / 3, 11, 11,
+ &memoryDC, 11 * m_suit, 25, wxCOPY);
+ case 9:
+ dc.Blit(x - 5 + CardWidth / 4,
+ y - 6 + CardHeight / 4, 11, 11,
+ &memoryDC, 11 * m_suit, 14, wxCOPY);
+ dc.Blit(x - 5 + CardWidth / 4,
+ y - 6 + 5 * CardHeight / 12, 11, 11,
+ &memoryDC, 11 * m_suit, 14, wxCOPY);
+ dc.Blit(x - 5 + CardWidth / 4,
+ y - 5 + 7 * CardHeight / 12, 11, 11,
+ &memoryDC, 11 * m_suit, 25, wxCOPY);
+ dc.Blit(x - 5 + CardWidth / 4,
+ y - 5 + 3 * CardHeight / 4, 11, 11,
+ &memoryDC, 11 * m_suit, 25, wxCOPY);
+
+ dc.Blit(x - 5 + 3 * CardWidth / 4,
+ y - 6 + CardHeight / 4, 11, 11,
+ &memoryDC, 11 * m_suit, 14, wxCOPY);
+ dc.Blit(x - 5 + 3 * CardWidth / 4,
+ y - 6 + 5 * CardHeight / 12, 11, 11,
+ &memoryDC, 11 * m_suit, 14, wxCOPY);
+ dc.Blit(x - 5 + 3 * CardWidth / 4,
+ y - 5 + 7 * CardHeight / 12, 11, 11,
+ &memoryDC, 11 * m_suit, 25, wxCOPY);
+ dc.Blit(x - 5 + 3 * CardWidth / 4,
+ y - 5 + 3 * CardHeight / 4, 11, 11,
+ &memoryDC, 11 * m_suit, 25, wxCOPY);
+ dc.Blit(x - 5 + CardWidth / 2,
+ y - 5 + CardHeight / 3, 11, 11,
+ &memoryDC, 11 * m_suit, 14, wxCOPY);
+ break;
+ case 11:
+ case 12:
+ case 13:
+ memoryDC.SelectObject(m_pictureBmap);
+ dc.Blit(x + 5, y - 5 + CardHeight / 4, 40, 45,
+ &memoryDC, 40 * (m_pipValue - 11), 0, wxCOPY);
+ memoryDC.SelectObject(m_symbolBmap);
+ dc.Blit(x + 32, y - 3 + CardHeight / 4, 11, 11,
+ &memoryDC, 11 * m_suit, 14, wxCOPY);
+ dc.Blit(x + 7, y + 27 + CardHeight / 4, 11, 11,
+ &memoryDC, 11 * m_suit, 25, wxCOPY);
+ break;
+ }
+
+ }
+ dc.SetBackground(backgroundBrush);
+} // Card:Draw()
+
+
+//+-------------------------------------------------------------+
+//| Card::DrawNullCard() |
+//+-------------------------------------------------------------+
+//| Description: |
+//| Draws the outline of a card at (x, y). |
+//| Used to draw place holders for empty piles of cards. |
+//+-------------------------------------------------------------+
+void Card::DrawNullCard(wxDC& dc, int x, int y)
+{
+ wxPen* pen = wxThePenList->FindOrCreatePen(*FortyApp::TextColour(), 1, wxSOLID);
+ dc.SetBrush(FortyApp::BackgroundBrush());
+ dc.SetPen(pen);
+ dc.DrawRoundedRectangle(x, y, CardWidth, CardHeight, 4);
+} // Card::DrawNullCard()
+
+
--- /dev/null
+/////////////////////////////////////////////////////////////////////////////
+// Name: card.h
+// Purpose: Forty Thieves patience game
+// Author: Chris Breeze
+// Modified by:
+// Created: 21/07/97
+// RCS-ID: $Id$
+// Copyright: (c) 1993-1998 Chris Breeze
+// Licence: wxWindows licence
+//---------------------------------------------------------------------------
+// Last modified: 22nd July 1998 - ported to wxWindows 2.0
+/////////////////////////////////////////////////////////////////////////////
+//+-------------------------------------------------------------+
+//| Description: |
+//| A class for drawing playing cards. |
+//| InitCards() must be called before using the Card class, |
+//| otherwise the card bitmaps will not be loaded. |
+//| CloseCards() must be called before terminating the |
+//| program so that the bitmaps are deleted and the memory |
+//| given back to Windows. |
+//+-------------------------------------------------------------+
+#ifndef _CARD_H_
+#define _CARD_H_
+
+ // Constants
+const int PackSize = 52;
+const int CardWidth = 50;
+const int CardHeight = 70;
+
+ // Data types
+enum Suit { clubs = 0, diamonds = 1, hearts = 2, spades = 3 };
+enum SuitColour { red = 0, black = 1 };
+enum WayUp { faceup, facedown };
+
+
+//--------------------------------//
+// A class defining a single card //
+//--------------------------------//
+class Card {
+public:
+ Card(int value, WayUp way_up = facedown);
+ virtual ~Card();
+
+ void Draw(wxDC& pDC, int x, int y);
+ static void DrawNullCard(wxDC& pDC, int x, int y); // Draw card place-holder
+ void Erase(wxDC& pDC, int x, int y);
+
+ void TurnCard(WayUp way_up = faceup) { m_wayUp = way_up; }
+ WayUp GetWayUp() const { return m_wayUp; }
+ int GetPipValue() const { return m_pipValue; }
+ Suit GetSuit() const { return m_suit; }
+ SuitColour GetColour() const { return m_colour; }
+
+private:
+ Suit m_suit;
+ int m_pipValue; // in the range 1 (Ace) to 13 (King)
+ SuitColour m_colour; // red or black
+ bool m_status;
+ WayUp m_wayUp;
+
+ static wxBitmap* m_symbolBmap;
+ static wxBitmap* m_pictureBmap;
+};
+
+#endif // _CARD_H_
--- /dev/null
+/////////////////////////////////////////////////////////////////////////////
+// Name: forty.cpp
+// Purpose: Forty Thieves patience game
+// Author: Chris Breeze
+// Modified by:
+// Created: 21/07/97
+// RCS-ID: $Id$
+// Copyright: (c) 1993-1998 Chris Breeze
+// Licence: wxWindows licence
+//---------------------------------------------------------------------------
+// Last modified: 22nd July 1998 - ported to wxWindows 2.0
+/////////////////////////////////////////////////////////////////////////////
+
+#ifdef __GNUG__
+#pragma implementation
+#pragma interface
+#endif
+
+// For compilers that support precompilation, includes "wx/wx.h".
+#include "wx/wxprec.h"
+
+#ifdef __BORLANDC__
+#pragma hdrstop
+#endif
+
+#ifndef WX_PRECOMP
+#include "wx/wx.h"
+#endif
+
+#include "canvas.h"
+#include "forty.h"
+#include "scoredg.h"
+#ifdef wx_x
+#include "cards.xbm"
+#endif
+
+class FortyFrame: public wxFrame
+{
+public:
+ FortyFrame(wxFrame* frame, char* title, int x, int y, int w, int h);
+ virtual ~FortyFrame();
+
+ bool OnClose();
+
+ // Menu callbacks
+ void NewGame(wxCommandEvent& event);
+ void Exit(wxCommandEvent& event);
+ void About(wxCommandEvent& event);
+ void Undo(wxCommandEvent& event);
+ void Redo(wxCommandEvent& event);
+ void Scores(wxCommandEvent& event);
+ void ToggleRightButtonUndo(wxCommandEvent& event);
+ void ToggleHelpingHand(wxCommandEvent& event);
+
+ DECLARE_EVENT_TABLE()
+
+private:
+ enum MenuCommands { NEW_GAME = 10, SCORES, EXIT,
+ UNDO, REDO,
+ RIGHT_BUTTON_UNDO, HELPING_HAND,
+ ABOUT };
+
+ wxMenuBar* m_menuBar;
+ FortyCanvas* m_canvas;
+};
+
+BEGIN_EVENT_TABLE(FortyFrame, wxFrame)
+ EVT_MENU(NEW_GAME, FortyFrame::NewGame)
+ EVT_MENU(EXIT, FortyFrame::Exit)
+ EVT_MENU(ABOUT, FortyFrame::About)
+ EVT_MENU(UNDO, FortyFrame::Undo)
+ EVT_MENU(REDO, FortyFrame::Redo)
+ EVT_MENU(SCORES, FortyFrame::Scores)
+ EVT_MENU(RIGHT_BUTTON_UNDO, FortyFrame::ToggleRightButtonUndo)
+ EVT_MENU(HELPING_HAND, FortyFrame::ToggleHelpingHand)
+END_EVENT_TABLE()
+
+// Create a new application object
+IMPLEMENT_APP (FortyApp)
+
+wxColour* FortyApp::m_backgroundColour = 0;
+wxColour* FortyApp::m_textColour = 0;
+wxBrush* FortyApp::m_backgroundBrush = 0;
+
+bool FortyApp::OnInit()
+{
+ FortyFrame* frame = new FortyFrame(
+ 0,
+ "Forty Thieves",
+ -1, -1, 668, 510
+ );
+
+ // Show the frame
+ frame->Show(TRUE);
+
+ return true;
+}
+
+wxColour* FortyApp::BackgroundColour()
+{
+ if (!m_backgroundColour)
+ {
+ m_backgroundColour = new wxColour(0, 128, 0);
+ }
+ return m_backgroundColour;
+}
+
+wxBrush* FortyApp::BackgroundBrush()
+{
+ if (!m_backgroundBrush)
+ {
+ m_backgroundBrush = new wxBrush(*BackgroundColour(), wxSOLID);
+ }
+ return m_backgroundBrush;
+}
+
+wxColour* FortyApp::TextColour()
+{
+ if (!m_textColour)
+ {
+ m_textColour = new wxColour("BLACK");
+ }
+ return m_textColour;
+}
+
+// My frame constructor
+FortyFrame::FortyFrame(wxFrame* frame, char* title, int x, int y, int w, int h):
+ wxFrame(frame, -1, title, wxPoint(x, y), wxSize(w, h))
+{
+ // set the icon
+#ifdef __WXMSW__
+ SetIcon(new wxIcon("CardsIcon"));
+#else
+#ifdef GTK_TBD
+ SetIcon(new wxIcon(Cards_bits, Cards_width, Cards_height));
+#endif
+#endif
+
+ // Make a menu bar
+ wxMenu* gameMenu = new wxMenu;
+ gameMenu->Append(NEW_GAME, "&New", "Start a new game");
+ gameMenu->Append(SCORES, "&Scores...", "Displays scores");
+ gameMenu->Append(EXIT, "E&xit", "Exits Forty Thieves");
+
+ wxMenu* editMenu = new wxMenu;
+ editMenu->Append(UNDO, "&Undo", "Undo the last move");
+ editMenu->Append(REDO, "&Redo", "Redo a move that has been undone");
+
+ wxMenu* optionsMenu = new wxMenu;
+ optionsMenu->Append(RIGHT_BUTTON_UNDO,
+ "&Right button undo",
+ "Enables/disables right mouse button undo and redo",
+ TRUE
+ );
+ optionsMenu->Append(HELPING_HAND,
+ "&Helping hand",
+ "Enables/disables hand cursor when a card can be moved",
+ TRUE
+ );
+ optionsMenu->Check(HELPING_HAND, TRUE);
+ optionsMenu->Check(RIGHT_BUTTON_UNDO, TRUE);
+
+ wxMenu* helpMenu = new wxMenu;
+ helpMenu->Append(ABOUT, "&About", "Displays program version information");
+
+ m_menuBar = new wxMenuBar;
+ m_menuBar->Append(gameMenu, "&Game");
+ m_menuBar->Append(editMenu, "&Edit");
+ m_menuBar->Append(optionsMenu, "&Options");
+ m_menuBar->Append(helpMenu, "&Help");
+
+ SetMenuBar(m_menuBar);
+
+ m_canvas = new FortyCanvas(this, 0, 0, 400, 400);
+ wxLayoutConstraints* constr = new wxLayoutConstraints;
+ constr->left.SameAs(this, wxLeft);
+ constr->top.SameAs(this, wxTop);
+ constr->right.SameAs(this, wxRight);
+ constr->height.SameAs(this, wxHeight);
+ m_canvas->SetConstraints(constr);
+
+ CreateStatusBar();
+}
+
+FortyFrame::~FortyFrame()
+{
+}
+
+bool FortyFrame::OnClose()
+{
+ return m_canvas->OnClose();
+}
+
+void
+FortyFrame::NewGame(wxCommandEvent&)
+{
+ m_canvas->NewGame();
+}
+
+void
+FortyFrame::Exit(wxCommandEvent&)
+{
+#ifdef __WXGTK__
+ // wxGTK doesn't call OnClose() so we do it here
+ if (OnClose())
+#endif
+ Close(TRUE);
+}
+
+void
+FortyFrame::About(wxCommandEvent&)
+{
+ wxMessageBox(
+ "Forty Thieves\n\n"
+ "A freeware program using the wxWindows\n"
+ "portable C++ GUI toolkit.\n"
+ "http://web.ukonline.co.uk/julian.smart/wxwin\n"
+ "http://www.freiburg.linux.de/~wxxt\n\n"
+ "Author: Chris Breeze (c) 1992-1998\n"
+ "email: chris.breeze@iname.com",
+ "About Forty Thieves",
+ wxOK, this
+ );
+}
+
+void
+FortyFrame::Undo(wxCommandEvent&)
+{
+ m_canvas->Undo();
+}
+
+void
+FortyFrame::Redo(wxCommandEvent&)
+{
+ m_canvas->Redo();
+}
+
+void
+FortyFrame::Scores(wxCommandEvent&)
+{
+ m_canvas->UpdateScores();
+ ScoreDialog scores(this, m_canvas->GetScoreFile());
+ scores.Display();
+}
+
+void
+FortyFrame::ToggleRightButtonUndo(wxCommandEvent& event)
+{
+ bool checked = m_menuBar->IsChecked(event.GetId());
+ m_canvas->EnableRightButtonUndo(checked);
+}
+
+void
+FortyFrame::ToggleHelpingHand(wxCommandEvent& event)
+{
+ bool checked = m_menuBar->IsChecked(event.GetId());
+ m_canvas->EnableHelpingHand(checked);
+}
--- /dev/null
+/////////////////////////////////////////////////////////////////////////////
+// Name: forty.h
+// Purpose: Forty Thieves patience game
+// Author: Chris Breeze
+// Modified by:
+// Created: 21/07/97
+// RCS-ID: $Id$
+// Copyright: (c) 1993-1998 Chris Breeze
+// Licence: wxWindows licence
+//---------------------------------------------------------------------------
+// Last modified: 22nd July 1998 - ported to wxWindows 2.0
+/////////////////////////////////////////////////////////////////////////////
+#ifndef _FORTY_H_
+#define _FORTY_H_
+
+class FortyApp: public wxApp
+{
+public:
+ bool OnInit();
+
+ static wxColour* BackgroundColour();
+ static wxColour* TextColour();
+ static wxBrush* BackgroundBrush();
+
+private:
+ static wxColour* m_backgroundColour;
+ static wxColour* m_textColour;
+ static wxBrush* m_backgroundBrush;
+};
+
+#endif
--- /dev/null
+#include "wx/msw/wx.rc"
+
+CardsIcon ICON "cards.ico"
+CardPictures BITMAP "pictures.bmp"
+CardSymbols BITMAP "symbols.bmp"
+
--- /dev/null
+/////////////////////////////////////////////////////////////////////////////
+// Name: game.cpp
+// Purpose: Forty Thieves patience game
+// Author: Chris Breeze
+// Modified by:
+// Created: 21/07/97
+// RCS-ID: $Id$
+// Copyright: (c) 1993-1998 Chris Breeze
+// Licence: wxWindows licence
+//---------------------------------------------------------------------------
+// Last modified: 22nd July 1998 - ported to wxWindows 2.0
+/////////////////////////////////////////////////////////////////////////////
+
+#ifdef __GNUG__
+#pragma implementation
+#pragma interface
+#endif
+
+// For compilers that support precompilation, includes "wx/wx.h".
+#include "wx/wxprec.h"
+
+#ifdef __BORLANDC__
+#pragma hdrstop
+#endif
+
+#ifndef WX_PRECOMP
+#include "wx/wx.h"
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include <string.h>
+#include "forty.h"
+#include "game.h"
+
+Game::Game(int wins, int games, int score) :
+ m_inPlay(FALSE),
+ m_moveIndex(0),
+ m_redoIndex(0),
+ m_bmap(0),
+ m_bmapCard(0)
+{
+ int i;
+
+ m_pack = new Pack(2, 2 + 4 * (CardHeight + 2));
+ srand(time(0));
+
+ for (i = 0; i < 5; i++) m_pack->Shuffle();
+
+ m_discard = new Discard(2, 2 + 5 * (CardHeight + 2));
+
+ for (i = 0; i < 8; i++)
+ {
+ m_foundations[i] = new Foundation(2 + (i / 4) * (CardWidth + 2),
+ 2 + (i % 4) * (CardHeight + 2));
+ }
+
+ for (i = 0; i < 10; i++)
+ {
+ m_bases[i] = new Base(8 + (i + 2) * (CardWidth + 2), 2);
+ }
+ Deal();
+ m_srcPile = 0;
+ m_liftedCard = 0;
+
+ // copy the input parameters for future reference
+ m_numWins = wins;
+ m_numGames = games;
+ m_totalScore = score;
+ m_currentScore = 0;
+}
+
+
+// Make sure we delete all objects created by the game object
+Game::~Game()
+{
+ int i;
+
+ delete m_pack;
+ delete m_discard;
+ for (i = 0; i < 8; i++)
+ {
+ delete m_foundations[i];
+ }
+ for (i = 0; i < 10; i++)
+ {
+ delete m_bases[i];
+ }
+ delete m_bmap;
+ delete m_bmapCard;
+}
+
+/*
+Set the score for a new player.
+NB: call Deal() first if the new player is to start
+a new game
+*/
+void Game::NewPlayer(int wins, int games, int score)
+{
+ m_numWins = wins;
+ m_numGames = games;
+ m_totalScore = score;
+ m_currentScore = 0;
+}
+
+// Undo the last move
+void Game::Undo(wxDC& dc)
+{
+ if (m_moveIndex > 0)
+ {
+ m_moveIndex--;
+ Card* card = m_moves[m_moveIndex].dest->RemoveTopCard(dc);
+ m_moves[m_moveIndex].src->AddCard(dc, card);
+ DisplayScore(dc);
+ }
+}
+
+// Redo the last move
+void Game::Redo(wxDC& dc)
+{
+ if (m_moveIndex < m_redoIndex)
+ {
+ Card* card = m_moves[m_moveIndex].src->RemoveTopCard(dc);
+ if (m_moves[m_moveIndex].src == m_pack)
+ {
+ m_pack->Redraw(dc);
+ card->TurnCard(faceup);
+ }
+ m_moves[m_moveIndex].dest->AddCard(dc, card);
+ DisplayScore(dc);
+ m_moveIndex++;
+ }
+}
+
+void Game::DoMove(wxDC& dc, Pile* src, Pile* dest)
+{
+ if (m_moveIndex < MaxMoves)
+ {
+ if (src == dest)
+ {
+ wxMessageBox("Game::DoMove() src == dest", "Debug message",
+ wxOK | wxICON_EXCLAMATION);
+ }
+ m_moves[m_moveIndex].src = src;
+ m_moves[m_moveIndex].dest = dest;
+ m_moveIndex++;
+
+ // when we do a move any moves in redo buffer are discarded
+ m_redoIndex = m_moveIndex;
+ }
+ else
+ {
+ wxMessageBox("Game::DoMove() Undo buffer full", "Debug message",
+ wxOK | wxICON_EXCLAMATION);
+ }
+
+ if (!m_inPlay)
+ {
+ m_inPlay = TRUE;
+ m_numGames++;
+ }
+ DisplayScore(dc);
+}
+
+
+void Game::DisplayScore(wxDC& dc)
+{
+ wxColour* bgColour = FortyApp::BackgroundColour();
+ wxPen* pen = wxThePenList->FindOrCreatePen(*bgColour, 1, wxSOLID);
+ dc.SetTextBackground(*bgColour);
+ dc.SetTextForeground(*FortyApp::TextColour());
+ dc.SetBrush(FortyApp::BackgroundBrush());
+ dc.SetPen(pen);
+
+ // count the number of cards in foundations
+ m_currentScore = 0;
+ for (int i = 0; i < 8; i++)
+ {
+ m_currentScore += m_foundations[i]->GetNumCards();
+ }
+
+ int x, y;
+ m_pack->GetTopCardPos(x, y);
+ x += 12 * CardWidth - 105;
+
+ int w, h;
+ {
+ long width, height;
+ dc.GetTextExtent("Average score:m_x", &width, &height);
+ w = width;
+ h = height;
+ }
+ dc.DrawRectangle(x + w, y, 20, 4 * h);
+
+ char str[80];
+ sprintf(str, "%d", m_currentScore);
+ dc.DrawText("Score:", x, y);
+ dc.DrawText(str, x + w, y);
+ y += h;
+
+ sprintf(str, "%d", m_numGames);
+ dc.DrawText("Games played:", x, y);
+ dc.DrawText(str, x + w, y);
+ y += h;
+
+ sprintf(str, "%d", m_numWins);
+ dc.DrawText("Games won:", x, y);
+ dc.DrawText(str, x + w, y);
+ y += h;
+
+ int average = 0;
+ if (m_numGames > 0)
+ {
+ average = (2 * (m_currentScore + m_totalScore) + m_numGames ) / (2 * m_numGames);
+ }
+ sprintf(str, "%d", average);
+ dc.DrawText("Average score:", x, y);
+ dc.DrawText(str, x + w, y);
+}
+
+
+// Shuffle the m_pack and deal the cards
+void Game::Deal()
+{
+ int i, j;
+ Card* card;
+
+ // Reset all the piles, the undo buffer and shuffle the m_pack
+ m_moveIndex = 0;
+ m_pack->ResetPile();
+ for (i = 0; i < 5; i++)
+ {
+ m_pack->Shuffle();
+ }
+ m_discard->ResetPile();
+ for (i = 0; i < 10; i++)
+ {
+ m_bases[i]->ResetPile();
+ }
+ for (i = 0; i < 8; i++)
+ {
+ m_foundations[i]->ResetPile();
+ }
+
+ // Deal the initial 40 cards onto the bases
+ for (i = 0; i < 10; i++)
+ {
+ for (j = 1; j <= 4; j++)
+ {
+ card = m_pack->RemoveTopCard();
+ card->TurnCard(faceup);
+ m_bases[i]->AddCard(card);
+ }
+ }
+
+ if (m_inPlay)
+ {
+ // player has started the game and then redealt
+ // and so we must add the score for this game to the total score
+ m_totalScore += m_currentScore;
+ }
+ m_currentScore = 0;
+ m_inPlay = FALSE;
+}
+
+
+// Redraw the m_pack, discard pile, the bases and the foundations
+void Game::Redraw(wxDC& dc)
+{
+ int i;
+ m_pack->Redraw(dc);
+ m_discard->Redraw(dc);
+ for (i = 0; i < 8; i++)
+ {
+ m_foundations[i]->Redraw(dc);
+ }
+ for (i = 0; i < 10; i++)
+ {
+ m_bases[i]->Redraw(dc);
+ }
+ DisplayScore(dc);
+
+ if (m_bmap == 0)
+ {
+ m_bmap = new wxBitmap(CardWidth, CardHeight);
+ m_bmapCard = new wxBitmap(CardWidth, CardHeight);
+
+ // Initialise the card bitmap to the background colour
+ wxMemoryDC memoryDC;
+ memoryDC.SelectObject(m_bmapCard);
+ memoryDC.SetBrush(FortyApp::BackgroundBrush());
+ memoryDC.DrawRectangle(0, 0, CardWidth, CardHeight);
+ memoryDC.SelectObject(m_bmap);
+ memoryDC.DrawRectangle(0, 0, CardWidth, CardHeight);
+ }
+}
+
+
+// Test to see if the point (x, y) is over the top card of one of the piles
+// Returns pointer to the pile, or 0 if (x, y) is not over a pile
+// or the pile is empty
+Pile* Game::WhichPile(int x, int y)
+{
+ if (m_pack->GetCard(x, y) &&
+ m_pack->GetCard(x, y) == m_pack->GetTopCard())
+ {
+ return m_pack;
+ }
+
+ if (m_discard->GetCard(x, y) &&
+ m_discard->GetCard(x, y) == m_discard->GetTopCard())
+ {
+ return m_discard;
+ }
+
+ int i;
+ for (i = 0; i < 8; i++)
+ {
+ if (m_foundations[i]->GetCard(x, y) &&
+ m_foundations[i]->GetCard(x, y) == m_foundations[i]->GetTopCard())
+ {
+ return m_foundations[i];
+ }
+ }
+
+ for (i = 0; i < 10; i++)
+ {
+ if (m_bases[i]->GetCard(x, y) &&
+ m_bases[i]->GetCard(x, y) == m_bases[i]->GetTopCard())
+ {
+ return m_bases[i];
+ }
+ }
+ return 0;
+}
+
+
+// Left button is pressed - if cursor is over the m_pack then deal a card
+// otherwise if it is over a card pick it up ready to be dragged - see MouseMove()
+bool Game::LButtonDown(wxDC& dc, int x, int y)
+{
+ m_srcPile = WhichPile(x, y);
+ if (m_srcPile == m_pack)
+ {
+ Card* card = m_pack->RemoveTopCard();
+ if (card)
+ {
+ m_pack->Redraw(dc);
+ card->TurnCard(faceup);
+ m_discard->AddCard(dc, card);
+ DoMove(dc, m_pack, m_discard);
+ }
+ m_srcPile = 0;
+ }
+ else if (m_srcPile)
+ {
+ m_srcPile->GetTopCardPos(m_xPos, m_yPos);
+ m_xOffset = m_xPos - x;
+ m_yOffset = m_yPos - y;
+
+ // Copy the area under the card
+ // Initialise the card bitmap to the background colour
+ {
+ wxMemoryDC memoryDC;
+ memoryDC.SelectObject(m_bmap);
+ m_liftedCard = m_srcPile->RemoveTopCard(memoryDC, m_xPos, m_yPos);
+ }
+
+ // Draw the card in card bitmap ready for blitting onto
+ // the screen
+ {
+ wxMemoryDC memoryDC;
+ memoryDC.SelectObject(m_bmapCard);
+ m_liftedCard->Draw(memoryDC, 0, 0);
+ }
+ }
+ return m_srcPile != 0;
+}
+
+// Called when the left button is double clicked
+// If a card is under the pointer and it can move elsewhere then move it.
+// Move onto a foundation as first choice, a populated base as second and
+// an empty base as third choice.
+// NB Cards in the m_pack cannot be moved in this way - they aren't in play
+// yet
+void Game::LButtonDblClk(wxDC& dc, int x, int y)
+{
+ Pile* pile = WhichPile(x, y);
+ if (!pile) return;
+
+ // Double click on m_pack is the same as left button down
+ if (pile == m_pack)
+ {
+ LButtonDown(dc, x, y);
+ }
+ else
+ {
+ Card* card = pile->GetTopCard();
+
+ if (card)
+ {
+ int i;
+
+ // if the card is an ace then try to place it next
+ // to an ace of the same suit
+ if (card->GetPipValue() == 1)
+ {
+ for(i = 0; i < 4; i++)
+ {
+ Card* m_topCard;
+ if ((m_topCard = m_foundations[i]->GetTopCard()))
+ {
+ if (m_topCard->GetSuit() == card->GetSuit() &&
+ m_foundations[i + 4] != pile &&
+ m_foundations[i + 4]->GetTopCard() == 0)
+ {
+ pile->RemoveTopCard(dc);
+ m_foundations[i + 4]->AddCard(dc, card);
+ DoMove(dc, pile, m_foundations[i + 4]);
+ return;
+ }
+ }
+ }
+ }
+
+ // try to place the card on a foundation
+ for(i = 0; i < 8; i++)
+ {
+ if (m_foundations[i]->AcceptCard(card) && m_foundations[i] != pile)
+ {
+ pile->RemoveTopCard(dc);
+ m_foundations[i]->AddCard(dc, card);
+ DoMove(dc, pile, m_foundations[i]);
+ return;
+ }
+ }
+ // try to place the card on a populated base
+ for(i = 0; i < 10; i++)
+ {
+ if (m_bases[i]->AcceptCard(card) &&
+ m_bases[i] != pile &&
+ m_bases[i]->GetTopCard())
+ {
+ pile->RemoveTopCard(dc);
+ m_bases[i]->AddCard(dc, card);
+ DoMove(dc, pile, m_bases[i]);
+ return;
+ }
+ }
+ // try to place the card on any base
+ for(i = 0; i < 10; i++)
+ {
+ if (m_bases[i]->AcceptCard(card) && m_bases[i] != pile)
+ {
+ pile->RemoveTopCard(dc);
+ m_bases[i]->AddCard(dc, card);
+ DoMove(dc, pile, m_bases[i]);
+ return;
+ }
+ }
+ }
+ }
+}
+
+
+// Test to see whether the game has been won:
+// i.e. m_pack, discard and bases are empty
+bool Game::HaveYouWon()
+{
+ if (m_pack->GetTopCard()) return FALSE;
+ if (m_discard->GetTopCard()) return FALSE;
+ for(int i = 0; i < 10; i++)
+ {
+ if (m_bases[i]->GetTopCard()) return FALSE;
+ }
+ m_numWins++;
+ m_totalScore += m_currentScore;
+ m_currentScore = 0;
+ return TRUE;
+}
+
+
+// See whether the card under the cursor can be moved somewhere else
+// Returns TRUE if it can be moved, FALSE otherwise
+bool Game::CanYouGo(int x, int y)
+{
+ Pile* pile = WhichPile(x, y);
+ if (pile && pile != m_pack)
+ {
+ Card* card = pile->GetTopCard();
+
+ if (card)
+ {
+ int i;
+ for(i = 0; i < 8; i++)
+ {
+ if (m_foundations[i]->AcceptCard(card) && m_foundations[i] != pile)
+ {
+ return TRUE;
+ }
+ }
+ for(i = 0; i < 10; i++)
+ {
+ if (m_bases[i]->GetTopCard() &&
+ m_bases[i]->AcceptCard(card) &&
+ m_bases[i] != pile)
+ {
+ return TRUE;
+ }
+ }
+ }
+ }
+ return FALSE;
+}
+
+
+// Called when the left button is released after dragging a card
+// Scan the piles to see if this card overlaps a pile and can be added
+// to the pile. If the card overlaps more than one pile on which it can be placed
+// then put it on the nearest pile.
+void Game::LButtonUp(wxDC& dc, int x, int y)
+{
+ if (m_srcPile)
+ {
+ // work out the position of the dragged card
+ x += m_xOffset;
+ y += m_yOffset;
+
+ Pile* nearestPile = 0;
+ int distance = (CardHeight + CardWidth) * (CardHeight + CardWidth);
+
+ // find the nearest pile which will accept the card
+ int i;
+ for (i = 0; i < 8; i++)
+ {
+ if (DropCard(x, y, m_foundations[i], m_liftedCard))
+ {
+ if (m_foundations[i]->CalcDistance(x, y) < distance)
+ {
+ nearestPile = m_foundations[i];
+ distance = nearestPile->CalcDistance(x, y);
+ }
+ }
+ }
+ for (i = 0; i < 10; i++)
+ {
+ if (DropCard(x, y, m_bases[i], m_liftedCard))
+ {
+ if (m_bases[i]->CalcDistance(x, y) < distance)
+ {
+ nearestPile = m_bases[i];
+ distance = nearestPile->CalcDistance(x, y);
+ }
+ }
+ }
+
+ // Restore the area under the card
+ wxMemoryDC memoryDC;
+ memoryDC.SelectObject(m_bmap);
+ dc.Blit(m_xPos, m_yPos, CardWidth, CardHeight,
+ &memoryDC, 0, 0, wxCOPY);
+
+ // Draw the card in its new position
+ if (nearestPile)
+ {
+ // Add to new pile
+ nearestPile->AddCard(dc, m_liftedCard);
+ if (nearestPile != m_srcPile)
+ {
+ DoMove(dc, m_srcPile, nearestPile);
+ }
+ }
+ else
+ {
+ // Return card to src pile
+ m_srcPile->AddCard(dc, m_liftedCard);
+ }
+ m_srcPile = 0;
+ m_liftedCard = 0;
+ }
+}
+
+
+
+
+bool Game::DropCard(int x, int y, Pile* pile, Card* card)
+{
+ bool retval = FALSE;
+ if (pile->Overlap(x, y))
+ {
+ if (pile->AcceptCard(card))
+ {
+ retval = TRUE;
+ }
+ }
+ return retval;
+}
+
+
+void Game::MouseMove(wxDC& dc, int mx, int my)
+{
+ if (m_liftedCard)
+ {
+ wxMemoryDC memoryDC;
+ memoryDC.SelectObject(m_bmap);
+
+ int dx = mx + m_xOffset - m_xPos;
+ int dy = my + m_yOffset - m_yPos;
+
+ if (abs(dx) >= CardWidth || abs(dy) >= CardHeight)
+ {
+ // Restore the area under the card
+ dc.Blit(m_xPos, m_yPos, CardWidth, CardHeight,
+ &memoryDC, 0, 0, wxCOPY);
+
+ // Copy the area under the card in the new position
+ memoryDC.Blit(0, 0, CardWidth, CardHeight,
+ &dc, m_xPos + dx, m_yPos + dy, wxCOPY);
+ }
+ else if (dx >= 0)
+ {
+ // dx >= 0
+ dc.Blit(m_xPos, m_yPos, dx, CardHeight, &memoryDC, 0, 0, wxCOPY);
+ if (dy >= 0)
+ {
+ // dy >= 0
+ dc.Blit(m_xPos + dx, m_yPos, CardWidth - dx, dy, &memoryDC, dx, 0, wxCOPY);
+ memoryDC.Blit(0, 0, CardWidth - dx, CardHeight - dy,
+ &memoryDC, dx, dy, wxCOPY);
+ memoryDC.Blit(0, CardHeight - dy, CardWidth - dx, dy,
+ &dc, m_xPos + dx, m_yPos + CardHeight, wxCOPY);
+ }
+ else
+ {
+ // dy < 0
+ dc.Blit(m_xPos + dx, m_yPos + dy + CardHeight, CardWidth - dx, -dy,
+ &memoryDC, dx, CardHeight + dy, wxCOPY);
+ memoryDC.Blit(0, -dy, CardWidth - dx, CardHeight + dy,
+ &memoryDC, dx, 0, wxCOPY);
+ memoryDC.Blit(0, 0, CardWidth - dx, -dy,
+ &dc, m_xPos + dx, m_yPos + dy, wxCOPY);
+ }
+ memoryDC.Blit(CardWidth - dx, 0, dx, CardHeight,
+ &dc, m_xPos + CardWidth, m_yPos + dy, wxCOPY);
+ }
+ else
+ {
+ // dx < 0
+ dc.Blit(m_xPos + CardWidth + dx, m_yPos, -dx, CardHeight,
+ &memoryDC, CardWidth + dx, 0, wxCOPY);
+ if (dy >= 0)
+ {
+ dc.Blit(m_xPos, m_yPos, CardWidth + dx, dy, &memoryDC, 0, 0, wxCOPY);
+ memoryDC.Blit(-dx, 0, CardWidth + dx, CardHeight - dy,
+ &memoryDC, 0, dy, wxCOPY);
+ memoryDC.Blit(-dx, CardHeight - dy, CardWidth + dx, dy,
+ &dc, m_xPos, m_yPos + CardHeight, wxCOPY);
+ }
+ else
+ {
+ // dy < 0
+ dc.Blit(m_xPos, m_yPos + CardHeight + dy, CardWidth + dx, -dy,
+ &memoryDC, 0, CardHeight + dy, wxCOPY);
+ memoryDC.Blit(-dx, -dy, CardWidth + dx, CardHeight + dy,
+ &memoryDC, 0, 0, wxCOPY);
+ memoryDC.Blit(-dx, 0, CardWidth + dx, -dy,
+ &dc, m_xPos, m_yPos + dy, wxCOPY);
+ }
+ memoryDC.Blit(0, 0, -dx, CardHeight,
+ &dc, m_xPos + dx, m_yPos + dy, wxCOPY);
+ }
+ m_xPos += dx;
+ m_yPos += dy;
+
+ // draw the card in its new position
+ memoryDC.SelectObject(m_bmapCard);
+ dc.Blit(m_xPos, m_yPos, CardWidth, CardHeight,
+ &memoryDC, 0, 0, wxCOPY);
+ }
+}
+
+
+
+//----------------------------------------------//
+// The Pack class: holds the two decks of cards //
+//----------------------------------------------//
+Pack::Pack(int x, int y) : Pile(x, y, 0, 0)
+{
+ for (m_topCard = 0; m_topCard < NumCards; m_topCard++)
+ {
+ m_cards[m_topCard] = new Card(1 + m_topCard / 2, facedown);
+ }
+ m_topCard = NumCards - 1;
+}
+
+
+void Pack::Shuffle()
+{
+ Card* temp[NumCards];
+ int i;
+
+ // Don't try to shuffle an empty m_pack!
+ if (m_topCard < 0) return;
+
+ // Copy the cards into a temporary array. Start by clearing
+ // the array and then copy the card into a random position.
+ // If the position is occupied then find the next lower position.
+ for (i = 0; i <= m_topCard; i++)
+ {
+ temp[i] = 0;
+ }
+ for (i = 0; i <= m_topCard; i++)
+ {
+ int pos = rand() % (m_topCard + 1);
+ while (temp[pos])
+ {
+ pos--;
+ if (pos < 0) pos = m_topCard;
+ }
+ m_cards[i]->TurnCard(facedown);
+ temp[pos] = m_cards[i];
+ m_cards[i] = 0;
+ }
+
+ // Copy each card back into the m_pack in a random
+ // position. If position is occupied then find nearest
+ // unoccupied position after the random position.
+ for (i = 0; i <= m_topCard; i++)
+ {
+ int pos = rand() % (m_topCard + 1);
+ while (m_cards[pos])
+ {
+ pos++;
+ if (pos > m_topCard) pos = 0;
+ }
+ m_cards[pos] = temp[i];
+ }
+}
+
+void Pack::Redraw(wxDC& dc)
+{
+ Pile::Redraw(dc);
+
+ char str[10];
+ sprintf(str, "%d ", m_topCard + 1);
+
+ dc.SetTextBackground(*FortyApp::BackgroundColour());
+ dc.SetTextForeground(*FortyApp::TextColour());
+ dc.DrawText(str, m_x + CardWidth + 5, m_y + CardHeight / 2);
+
+}
+
+void Pack::AddCard(Card* card)
+{
+ if (card == m_cards[m_topCard + 1])
+ {
+ m_topCard++;
+ }
+ else
+ {
+ wxMessageBox("Pack::AddCard() Undo error", "Forty Thieves: Warning",
+ wxOK | wxICON_EXCLAMATION);
+ }
+ card->TurnCard(facedown);
+}
+
+
+Pack::~Pack()
+{
+ for (m_topCard = 0; m_topCard < NumCards; m_topCard++)
+ {
+ delete m_cards[m_topCard];
+ }
+};
+
+
+//------------------------------------------------------//
+// The Base class: holds the initial pile of four cards //
+//------------------------------------------------------//
+Base::Base(int x, int y) : Pile(x, y, 0, 12)
+{
+ m_topCard = -1;
+}
+
+
+bool Base::AcceptCard(Card* card)
+{
+ bool retval = FALSE;
+
+ if (m_topCard >= 0)
+ {
+ if (m_cards[m_topCard]->GetSuit() == card->GetSuit() &&
+ m_cards[m_topCard]->GetPipValue() - 1 == card->GetPipValue())
+ {
+ retval = TRUE;
+ }
+ }
+ else
+ {
+ // pile is empty - ACCEPT
+ retval = TRUE;
+ }
+ return retval;
+}
+
+Base::~Base()
+{
+// nothing special at the moment
+};
+
+
+//----------------------------------------------------------------//
+// The Foundation class: holds the cards built up from the ace... //
+//----------------------------------------------------------------//
+Foundation::Foundation(int x, int y) : Pile(x, y, 0, 0)
+{
+ m_topCard = -1;
+}
+
+bool Foundation::AcceptCard(Card* card)
+{
+ bool retval = FALSE;
+
+ if (m_topCard >= 0)
+ {
+ if (m_cards[m_topCard]->GetSuit() == card->GetSuit() &&
+ m_cards[m_topCard]->GetPipValue() + 1 == card->GetPipValue())
+ {
+ retval = TRUE;
+ }
+ }
+ else if (card->GetPipValue() == 1)
+ {
+ // It's an ace and the pile is empty - ACCEPT
+ retval = TRUE;
+ }
+ return retval;
+}
+
+Foundation::~Foundation()
+{
+// nothing special at the moment
+};
+
+
+//----------------------------------------------------//
+// The Discard class: holds cards dealt from the m_pack //
+//----------------------------------------------------//
+Discard::Discard(int x, int y) : Pile(x, y, 19, 0)
+{
+ m_topCard = -1;
+}
+
+void Discard::Redraw(wxDC& dc)
+{
+ if (m_topCard >= 0)
+ {
+ if (m_dx == 0 && m_dy == 0)
+ {
+ m_cards[m_topCard]->Draw(dc, m_x, m_y);
+ }
+ else
+ {
+ int x = m_x;
+ int y = m_y;
+ for (int i = 0; i <= m_topCard; i++)
+ {
+ m_cards[i]->Draw(dc, x, y);
+ x += m_dx;
+ y += m_dy;
+ if (i == 31)
+ {
+ x = m_x;
+ y = m_y + CardHeight / 3;
+ }
+ }
+ }
+ }
+ else
+ {
+ Card::DrawNullCard(dc, m_x, m_y);
+ }
+}
+
+
+void Discard::GetTopCardPos(int& x, int& y)
+{
+ if (m_topCard < 0)
+ {
+ x = m_x;
+ y = m_y;
+ }
+ else if (m_topCard > 31)
+ {
+ x = m_x + m_dx * (m_topCard - 32);
+ y = m_y + CardHeight / 3;
+ }
+ else
+ {
+ x = m_x + m_dx * m_topCard;
+ y = m_y;
+ }
+}
+
+
+Card* Discard::RemoveTopCard(wxDC& dc, int m_xOffset, int m_yOffset)
+{
+ Card* card;
+
+ if (m_topCard <= 31)
+ {
+ card = Pile::RemoveTopCard(dc, m_xOffset, m_yOffset);
+ }
+ else
+ {
+ int topX, topY, x, y;
+ GetTopCardPos(topX, topY);
+ card = Pile::RemoveTopCard();
+ card->Erase(dc, topX - m_xOffset, topY - m_yOffset);
+ GetTopCardPos(x, y);
+ dc.SetClippingRegion(topX - m_xOffset, topY - m_yOffset,
+ CardWidth, CardHeight);
+
+ for (int i = m_topCard - 31; i <= m_topCard - 31 + CardWidth / m_dx; i++)
+ {
+ m_cards[i]->Draw(dc, m_x - m_xOffset + i * m_dx, m_y - m_yOffset);
+ }
+ if (m_topCard > 31)
+ {
+ m_cards[m_topCard]->Draw(dc, topX - m_xOffset - m_dx, topY - m_yOffset);
+ }
+ dc.DestroyClippingRegion();
+ }
+
+ return card;
+}
+
+
+Discard::~Discard()
+{
+// nothing special at the moment
+};
--- /dev/null
+/////////////////////////////////////////////////////////////////////////////
+// Name: game.h
+// Purpose: Forty Thieves patience game
+// Author: Chris Breeze
+// Modified by:
+// Created: 21/07/97
+// RCS-ID: $Id$
+// Copyright: (c) 1993-1998 Chris Breeze
+// Licence: wxWindows licence
+//---------------------------------------------------------------------------
+// Last modified: 22nd July 1998 - ported to wxWindows 2.0
+/////////////////////////////////////////////////////////////////////////////
+#ifndef _GAME_H_
+#define _GAME_H_
+#include "card.h"
+#include "pile.h"
+
+const int MaxMoves = 800;
+
+
+//---------------------------------------//
+// A class which holds the pack of cards //
+//---------------------------------------//
+class Pack : public Pile {
+public:
+ Pack(int x, int y);
+ ~Pack();
+ void Redraw(wxDC& dc);
+ void ResetPile() { m_topCard = NumCards - 1; }
+ void Shuffle();
+ void AddCard(Card* card); // Add card
+ void AddCard(wxDC& dc, Card* card) { AddCard(card); Redraw(dc); }
+};
+
+
+//----------------------------------------------------------//
+// A class which holds a base i.e. the initial 10 x 4 cards //
+//----------------------------------------------------------//
+class Base : public Pile {
+public:
+ Base(int x, int y);
+ ~Base();
+ bool AcceptCard(Card* card);
+};
+
+
+//----------------------------------------------------//
+// A class which holds a foundation i.e. Ace, 2, 3... //
+//----------------------------------------------------//
+class Foundation : public Pile {
+public:
+ Foundation(int x, int y);
+ ~Foundation();
+ bool AcceptCard(Card* card);
+};
+
+
+//--------------------------------------//
+// A class which holds the discard pile //
+//--------------------------------------//
+class Discard : public Pile {
+public:
+ Discard(int x, int y);
+ ~Discard();
+ void Redraw(wxDC& dc);
+ void GetTopCardPos(int& x, int& y);
+ Card* RemoveTopCard(wxDC& dc, int m_xOffset, int m_yOffset);
+};
+
+
+class Game {
+public:
+ Game(int wins, int games, int score);
+ virtual ~Game();
+
+ void NewPlayer(int wins, int games, int score);
+ void Deal(); // Shuffle and deal a new game
+ bool CanYouGo(int x, int y); // can card under (x,y) go somewhere?
+ bool HaveYouWon(); // have you won the game?
+
+ void Undo(wxDC& dc); // Undo the last go
+ void Redo(wxDC& dc); // Redo the last go
+
+ void Redraw(wxDC& dc);
+ void DisplayScore(wxDC& dc);
+ bool LButtonDown(wxDC& dc, int mx, int my); //
+ void LButtonUp(wxDC& dc, int mx, int my);
+ void LButtonDblClk(wxDC& dc, int mx, int my);
+ void MouseMove(wxDC& dc, int mx, int my);
+
+ int GetNumWins() const { return m_numWins; }
+ int GetNumGames() const { return m_numGames; }
+ int GetScore() const { return m_currentScore + m_totalScore; }
+
+ bool InPlay() const { return m_inPlay; }
+
+private:
+ bool DropCard(int x, int y, Pile* pile, Card* card);
+ // can the card at (x, y) be dropped on the pile?
+ Pile* WhichPile(int x, int y); // which pile is (x, y) over?
+ void DoMove(wxDC& dc, Pile* src, Pile* dest);
+
+ bool m_inPlay; // flag indicating that the game has started
+
+ // undo buffer
+ struct {
+ Pile* src;
+ Pile* dest;
+ } m_moves[MaxMoves];
+ int m_moveIndex; // current position in undo/redo buffer
+ int m_redoIndex; // max move index available for redo
+
+ // the various piles of cards
+ Pack* m_pack;
+ Discard* m_discard;
+ Base* m_bases[10];
+ Foundation* m_foundations[8];
+
+ // variables to do with dragging cards
+ Pile* m_srcPile;
+ Card* m_liftedCard;
+ int m_xPos, m_yPos; // current coords of card being dragged
+ int m_xOffset, m_yOffset; // card/mouse offset when dragging a card
+
+ wxBitmap* m_bmap;
+ wxBitmap* m_bmapCard;
+
+ // variables to do with scoring
+ int m_numGames;
+ int m_numWins;
+ int m_totalScore;
+ int m_currentScore;
+};
+
+#endif // _GAME_H_
--- /dev/null
+#
+# File: makefile.nt
+# Author: Julian Smart
+# Created: 1997
+# Updated:
+# Copyright:
+#
+# "%W% %G%"
+#
+# Makefile : Builds Forty Thieves example (MS VC++).
+# Use FINAL=1 argument to nmake to build final version with no debugging
+# info
+
+# Set WXDIR for your system
+WXDIR = $(WXWIN)
+
+!include $(WXDIR)\src\ntwxwin.mak
+
+THISDIR = $(WXDIR)\samples\forty
+PROGRAM=forty
+
+OBJECTS = $(PROGRAM).obj canvas.obj card.obj game.obj pile.obj playerdg.obj scoredg.obj scorefil.obj
+
+$(PROGRAM): $(PROGRAM).exe
+
+all: wx $(PROGRAM).exe
+
+wx:
+ cd $(WXDIR)\src\msw
+ nmake -f makefile.nt FINAL=$(FINAL)
+ cd $(THISDIR)
+
+wxclean:
+ cd $(WXDIR)\src\msw
+ nmake -f makefile.nt clean
+ cd $(THISDIR)
+
+$(PROGRAM).exe: $(DUMMYOBJ) $(WXLIB) $(OBJECTS) $(PROGRAM).res
+ $(link) @<<
+-out:$(PROGRAM).exe
+$(LINKFLAGS)
+$(DUMMYOBJ) $(OBJECTS) $(PROGRAM).res
+$(LIBS)
+<<
+
+
+$(PROGRAM).obj: $(PROGRAM).h $(PROGRAM).$(SRCSUFF) $(DUMMYOBJ)
+ $(cc) @<<
+$(CPPFLAGS) /c /Tp $*.$(SRCSUFF)
+<<
+
+canvas.obj: forty.h canvas.h canvas.$(SRCSUFF) $(DUMMYOBJ)
+ $(cc) @<<
+$(CPPFLAGS) /c /Tp $*.$(SRCSUFF)
+<<
+
+card.obj: forty.h card.h card.$(SRCSUFF) $(DUMMYOBJ)
+ $(cc) @<<
+$(CPPFLAGS) /c /Tp $*.$(SRCSUFF)
+<<
+
+pile.obj: forty.h pile.h pile.$(SRCSUFF) $(DUMMYOBJ)
+ $(cc) @<<
+$(CPPFLAGS) /c /Tp $*.$(SRCSUFF)
+<<
+
+game.obj: forty.h game.h game.$(SRCSUFF) $(DUMMYOBJ)
+ $(cc) @<<
+$(CPPFLAGS) /c /Tp $*.$(SRCSUFF)
+<<
+
+playerdg.obj: forty.h playerdg.h playerdg.$(SRCSUFF) $(DUMMYOBJ)
+ $(cc) @<<
+$(CPPFLAGS) /c /Tp $*.$(SRCSUFF)
+<<
+
+scoredg.obj: forty.h scoredg.h scoredg.$(SRCSUFF) $(DUMMYOBJ)
+ $(cc) @<<
+$(CPPFLAGS) /c /Tp $*.$(SRCSUFF)
+<<
+
+scorefil.obj: forty.h scorefil.h scorefil.$(SRCSUFF) $(DUMMYOBJ)
+ $(cc) @<<
+$(CPPFLAGS) /c /Tp $*.$(SRCSUFF)
+<<
+
+$(PROGRAM).res : $(PROGRAM).rc $(WXDIR)\include\wx\msw\wx.rc
+ $(rc) -r /i$(WXDIR)\include /i$(WXDIR)\contrib\fafa -fo$@ $(PROGRAM).rc
+
+
+clean:
+ -erase *.obj
+ -erase *.sbr
+ -erase *.exe
+ -erase *.res
+ -erase *.map
+ -erase *.pdb
+
--- /dev/null
+/* XPM */
+static char *Pictures[] = {
+/* width height num_colors chars_per_pixel */
+" 120 45 8 1",
+/* colors */
+". c #000000",
+"# c #c0c0c0",
+"a c #808080",
+"b c #ff0000",
+"c c #ffff00",
+"d c #0000ff",
+"e c #00ffff",
+"f c #ffffff",
+/* pixels */
+"........................................................................................................................",
+".fff.fffffff.bb.bb.bb.b.fffffffffffffff..fffffffffff..f..bbc.cc..ffffffffffffff..fff.ffffff.bbccccbcccccbb.ffffffffffff.",
+".ff.c.fffffff.bbbbbbbb.ffffffffffffffff..fff.ffffff..f.ff.bbc..c.ffffffffffffff..ff.a.ffffff.bbccbbbcccbb.fffffffffffff.",
+".f.cbc.fffffff........fffffffffffffffff..ff.b.fffff.f.ffff.bb..c..fffffffffffff..f.#af.ffffff.bbbbbbbbbb.ffffffffffffff.",
+".f.cbc.ffffff.fff.c.c.fffffffffffffffff..ff.b.fffff..f.ff.f.bbc.c.fffffffffffff..f.#af.ffffff............ffffffffffffff.",
+".ff.c.fffffff.f..f.c.c.ffffffffffffffff..fff.ffffff.f..ff..f.bb..ffffffffffffff..f.#af.ffffff.a..f.fff.f.ffffffffffffff.",
+".f.cbc.ffffff.f.ff.c.c.ffffffffffffffff..ff.c.fffff.fff.ffff..b.fffffffffffffff..f.#af.ffffff.a.f..fff..f.fffffffffffff.",
+".f.cbc.fffff.fffff.c.c.ffffffffffffffff..ff.c.fffff.fff.ffff....fffffffffffffff..f.#af.ffffff.a.ffff.ffff.fffffffffffff.",
+".ff.c.fffff.ffffff.c.c.ffffffffffffffff..ff.c.fffff.fff..fff.b..fffffffffffffff..f.#af.ffffff.a.fffff.fff.fffffffffffff.",
+".f.cbc.ffff..###ff.c.c.ffffffffffffffff..ff.c.fffff.ffffffff..b.fffffffffffffff..f.#af.ffffff.a.ffff..fff.fffffffffffff.",
+".f.cbc.ffffff...ff.c.c.ffffffffffffffff..fff.ffffff.ffbbbbff.f...ffffffffffffff..f.#af.fff..f.a..ffffffff.fffffffffffff.",
+".ff....ffffff.ffff.c.c.ffffffffffffffff..ff....fffff.ffffff.f.f...fffffffffffff..f.#af.fff....a...f....f..fffffffffffff.",
+".f.ffff.fffff.fffff.c.c.fffffffffffffff..f.ffff.ffff..ffff.f.f.f..fffffffffffff..f.#af.ffff.aaa.a..f.f.f...ffffffffffff.",
+".f....ff.f.................ffffffffffff..f....ff.f.................ffffffffffff..f.#af.fff...................ffffffffff.",
+".ff.fff....eddddddddddddddd.....fffffff..f.fffff...ffffffffff.cdbb......fffffff..f.#af.....c.cc..bbbbbb..c......fffffff.",
+".ff....bbbd.dbcbbbbbbbbbcbdedbbb....fff..f....f.bc.fdddddddf.cdbb.d..f.....ffff..f.#af..cbbcc.cc..bbbb..c......b....fff.",
+"...bbbb...deedbbcbbcbbcbbbd.dbb.bbbb.....f.fff.fbbc.fffffff.cdbb.d..f..dd.c..ff..........cbbcc.cc......c.....bbbdfff....",
+".bb....c.ccdeedbbbcccbbbbdedbb.bbb..cc...ff...c.fbbc.fdddf.cdbb.d..f..dd.cccd.f...ffff...dcbbcc.cc....cc...ddbbbdfddddf.",
+"...cc.c....bd.dbcbbcbbcbbd.db.bb..cbc.b..ff.dccc.bbc.ffff.cdbb.dd..ff...cdcdfd.........f.dcbbacc.cccccc..fdcbdbbdffddff.",
+"..c....bbbbbdeddddddddddddedbb..cccc.bb..f..fdcdc.bbc.ff.cdbb.dddd..ff.cccdffdc...ffff.f.dcbbcacc.c...c.fdccccdbdffddff.",
+"...bb.bb....bbbbbbbbbbbbbbbb..ccbbc.bb....ffdfdccc.bbc..cdbb..........cccdfdfbc........f.dcbbccacc.ccb.fdddbdbdbddffffd.",
+".bbb.b..ccc.d.d.d.d.dd.d.d.d.cccbb.bb.b..cbdfffdccc.fdfdfdfdfdfdfdfd.cccdfffbbc...ffff.f.dcbbacca.bcdcc.caddddcddff..ff.",
+".bb.bb.ccbcd.d.d.d.ff.d.d.d.dcbcc.bb.bb..cbbddddcdc.dbdbdbdbdbdbdbdb.cdcddddbbc.........ddcddaacc.cdddc.ccaddcdd........",
+".b.bb.bbccc.d.d.d.dd.d.d.d.d.ccc.bb.bbb..cbbfffdccc.fdfdfdfdfdfdfdfd.cccdfffdbc..ff..ffddcddddaac.ccdcb.accbbcd.f.ffff..",
+"..bb.cbbcc..bbbbbbbbbbbbbbbb....b..bb....cbfdfdccc..........bbdc..cbb.cccdfdff...dffffddcdbdbddaac.bcc.ccacbbcd.f.......",
+".bb.cccc..bbdeddddddddddddedbbbbb....c...cdffdccc.ff..dddd.bbdc.ff.cbb.cdcdff.f..ffddffdbdccccdfa.c...c.ccabbcd.f.ffff..",
+".b.cbc..bb.bd.dbbcbbcbbcbd.db....c.cc.....dfdcdc...ff..dd.bbdc.ffff.cbb.cccd.ff..ffddffdbbdbcdff..cccccc.ccbbcd.f.......",
+"..cc..bbb.bbdedbbbbcccbbbdeedcc.c....bb..f.dccc.dd..f..d.bbdc.fdddf.cbbf.c...ff..fddddfdbbbddf...cc....cc.cbbcd...ffff..",
+"....bbbb.bbd.dbbbcbbcbbcbbdeed...bbbb....ff..c.dd..f..d.bbdc.fffffff.cbbf.fff.f.....fffdbbb......c......cc.cbbc.........",
+".fff....bbbdedbcbbbbbbbbbcbd.dbbb....ff..ffff.....f..d.bbdc.fdddddddf.cb.f....f..fff....bb......c..bbbb..cc.cbbc..fa#.f.",
+".fffffff.....ddddddddddddddde....fff.ff..fffffff......bbdc.ffffffffff...fffff.f..fffffff.......c..bbbbbb..cc......fa#.f.",
+".ffffffffffff.................f.ff....f..ffffffffffff.................f.ff....f..ffffffffff...................fff.fa#.f.",
+".fffffffffffffff.c.c.fffff.fffff.ffff.f..fffffffffffff..f.f.f.ffff..ffff.ffff.f..ffffffffffff...f.f.f..a.aaa.ffff.fa#.f.",
+".ffffffffffffffff.c.c.ffff.ffffff....ff..fffffffffffff...f.f.ffffff.fffff....ff..fffffffffffff..f....f...a....fff.fa#.f.",
+".ffffffffffffffff.c.c.ff...ffffff.cbc.f..ffffffffffffff...f.ffbbbbff.ffffff.fff..fffffffffffff.ffffffff..a.f..fff.fa#.f.",
+".ffffffffffffffff.c.c.ff###..ffff.cbc.f..fffffffffffffff.b..ffffffff.fffff.c.ff..fffffffffffff.fff..ffff.a.ffffff.fa#.f.",
+".ffffffffffffffff.c.c.ffffff.fffff.c.ff..fffffffffffffff..b.fff..fff.fffff.c.ff..fffffffffffff.fff.fffff.a.ffffff.fa#.f.",
+".ffffffffffffffff.c.c.fffff.fffff.cbc.f..fffffffffffffff....ffff.fff.fffff.c.ff..fffffffffffff.ffff.ffff.a.ffffff.fa#.f.",
+".ffffffffffffffff.c.c.ff.f.ffffff.cbc.f..fffffffffffffff.b..ffff.fff.fffff.c.ff..fffffffffffff.f..fff..f.a.ffffff.fa#.f.",
+".ffffffffffffffff.c.c.f..f.fffffff.c.ff..ffffffffffffff..bb.f..ff..f.ffffff.fff..ffffffffffffff.f.fff.ff.a.ffffff.fa#.f.",
+".fffffffffffffffff.c.c.fff.ffffff.cbc.f..fffffffffffff.c.cbb.f.ff.f..fffff.b.ff..ffffffffffffff............ffffff.fa#.f.",
+".fffffffffffffffff........fffffff.cbc.f..fffffffffffff..c..bb.ffff.f.fffff.b.ff..ffffffffffffff.bbbbbbbbbb.ffffff.fa#.f.",
+".ffffffffffffffff.bbbbbbbb.fffffff.c.ff..ffffffffffffff.c..cbb.ff.f..ffffff.fff..fffffffffffff.bbcccbbbccbb.ffffff.a.ff.",
+".fffffffffffffff.b.bb.bb.bb.fffffff.fff..ffffffffffffff..cc.cbb..f..fffffffffff..ffffffffffff.bbcccccbccccbb.ffffff.fff.",
+"........................................................................................................................"
+};
--- /dev/null
+/////////////////////////////////////////////////////////////////////////////
+// Name: pile.cpp
+// Purpose: Forty Thieves patience game
+// Author: Chris Breeze
+// Modified by:
+// Created: 21/07/97
+// RCS-ID: $Id$
+// Copyright: (c) 1993-1998 Chris Breeze
+// Licence: wxWindows licence
+//---------------------------------------------------------------------------
+// Last modified: 22nd July 1998 - ported to wxWindows 2.0
+/////////////////////////////////////////////////////////////////////////////
+//+-------------------------------------------------------------+
+//| Description: |
+//| The base class for holding piles of playing cards. |
+//+-------------------------------------------------------------+
+
+#ifdef __GNUG__
+#pragma implementation
+#pragma interface
+#endif
+
+// For compilers that support precompilation, includes "wx/wx.h".
+#include "wx/wxprec.h"
+
+#ifdef __BORLANDC__
+#pragma hdrstop
+#endif
+
+#ifndef WX_PRECOMP
+#include "wx/wx.h"
+#endif
+#ifdef __GNUG__
+#pragma implementation
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include <string.h>
+#include "card.h"
+#include "pile.h"
+
+
+//+-------------------------------------------------------------+
+//| Pile::Pile() |
+//+-------------------------------------------------------------+
+//| Description: |
+//| Initialise the pile to be empty of cards. |
+//+-------------------------------------------------------------+
+Pile::Pile(int x, int y, int dx, int dy)
+{
+ m_x = x;
+ m_y = y;
+ m_dx = dx;
+ m_dy = dy;
+ for (m_topCard = 0; m_topCard < NumCards; m_topCard++)
+ {
+ m_cards[m_topCard] = 0;
+ }
+ m_topCard = -1; // i.e. empty
+}
+
+
+//+-------------------------------------------------------------+
+//| Pile::Redraw() |
+//+-------------------------------------------------------------+
+//| Description: |
+//| Redraw the pile on the screen. If the pile is empty |
+//| just draw a NULL card as a place holder for the pile. |
+//| Otherwise draw the pile from the bottom up, starting |
+//| at the origin of the pile, shifting each subsequent |
+//| card by the pile's x and y offsets. |
+//+-------------------------------------------------------------+
+void Pile::Redraw(wxDC& dc)
+{
+ if (m_topCard >= 0)
+ {
+ if (m_dx == 0 && m_dy == 0)
+ {
+ m_cards[m_topCard]->Draw(dc, m_x, m_y);
+ }
+ else
+ {
+ int x = m_x;
+ int y = m_y;
+ for (int i = 0; i <= m_topCard; i++)
+ {
+ m_cards[i]->Draw(dc, x, y);
+ x += m_dx;
+ y += m_dy;
+ }
+ }
+ }
+ else
+ {
+ Card::DrawNullCard(dc, m_x, m_y);
+ }
+}
+
+
+//+-------------------------------------------------------------+
+//| Pile::GetTopCard() |
+//+-------------------------------------------------------------+
+//| Description: |
+//| Return a pointer to the top card in the pile or NULL |
+//| if the pile is empty. |
+//| NB: Gets a copy of the card without removing it from the |
+//| pile. |
+//+-------------------------------------------------------------+
+Card* Pile::GetTopCard()
+{
+ Card* card = 0;
+
+ if (m_topCard >= 0)
+ {
+ card = m_cards[m_topCard];
+ }
+ return card;
+}
+
+
+//+-------------------------------------------------------------+
+//| Pile::RemoveTopCard() |
+//+-------------------------------------------------------------+
+//| Description: |
+//| If the pile is not empty, remove the top card from the |
+//| pile and return the pointer to the removed card. |
+//| If the pile is empty return a NULL pointer. |
+//+-------------------------------------------------------------+
+Card* Pile::RemoveTopCard()
+{
+ Card* card = 0;
+
+ if (m_topCard >= 0)
+ {
+ card = m_cards[m_topCard--];
+ }
+ return card;
+}
+
+
+//+-------------------------------------------------------------+
+//| Pile::RemoveTopCard() |
+//+-------------------------------------------------------------+
+//| Description: |
+//| As RemoveTopCard() but also redraw the top of the pile |
+//| after the card has been removed. |
+//| NB: the offset allows for the redrawn area to be in a |
+//| bitmap ready for 'dragging' cards acrosss the screen. |
+//+-------------------------------------------------------------+
+Card* Pile::RemoveTopCard(wxDC& dc, int xOffset, int yOffset)
+{
+ int topX, topY, x, y;
+
+ GetTopCardPos(topX, topY);
+ Card* card = RemoveTopCard();
+
+ if (card)
+ {
+ card->Erase(dc, topX - xOffset, topY - yOffset);
+ GetTopCardPos(x, y);
+ if (m_topCard < 0)
+ {
+ Card::DrawNullCard(dc, x - xOffset, y - yOffset);
+ }
+ else
+ {
+ m_cards[m_topCard]->Draw(dc, x - xOffset, y - yOffset);
+ }
+ }
+
+ return card;
+}
+
+
+void Pile::GetTopCardPos(int& x, int& y)
+{
+ if (m_topCard < 0)
+ {
+ x = m_x;
+ y = m_y;
+ }
+ else
+ {
+ x = m_x + m_dx * m_topCard;
+ y = m_y + m_dy * m_topCard;
+ }
+}
+
+void Pile::AddCard(Card* card)
+{
+ if (m_topCard < -1) m_topCard = -1;
+
+ m_cards[++m_topCard] = card;
+}
+
+void Pile::AddCard(wxDC& dc, Card* card)
+{
+ AddCard(card);
+ int x, y;
+ GetTopCardPos(x, y);
+ card->Draw(dc, x, y);
+}
+
+// Can the card leave this pile.
+// If it is a member of the pile then the answer is yes.
+// Derived classes may override this behaviour to incorporate
+// the rules of the game
+bool Pile::CanCardLeave(Card* card)
+{
+ for (int i = 0; i <= m_topCard; i++)
+ {
+ if (card == m_cards[i]) return TRUE;
+ }
+ return FALSE;
+}
+
+// Calculate how far x, y is from top card in the pile
+// Returns the square of the distance
+int Pile::CalcDistance(int x, int y)
+{
+ int cx, cy;
+ GetTopCardPos(cx, cy);
+ return ((cx - x) * (cx - x) + (cy - y) * (cy - y));
+}
+
+
+// Return the card at x, y. Check the top card first, then
+// work down the pile. If a card is found then return a pointer
+// to the card, otherwise return NULL
+Card* Pile::GetCard(int x, int y)
+{
+ int cardX;
+ int cardY;
+ GetTopCardPos(cardX, cardY);
+
+ for (int i = m_topCard; i >= 0; i--)
+ {
+ if (x >= cardX && x <= cardX + CardWidth &&
+ y >= cardY && y <= cardY + CardHeight)
+ {
+ return m_cards[i];
+ }
+ cardX -= m_dx;
+ cardY -= m_dy;
+ }
+ return 0;
+}
+
+
+// Return the position of the given card. If it is not a member of this pile
+// return the origin of the pile.
+void Pile::GetCardPos(Card* card, int& x, int& y)
+{
+ x = m_x;
+ y = m_y;
+
+ for (int i = 0; i <= m_topCard; i++)
+ {
+ if (card == m_cards[i])
+ {
+ return;
+ }
+ x += m_dx;
+ y += m_dy;
+ }
+
+ // card not found in pile, return origin of pile
+ x = m_x;
+ y = m_y;
+}
+
+
+bool Pile::Overlap(int x, int y)
+{
+ int cardX;
+ int cardY;
+ GetTopCardPos(cardX, cardY);
+
+ if (x >= cardX - CardWidth && x <= cardX + CardWidth &&
+ y >= cardY - CardHeight && y <= cardY + CardHeight)
+ {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+Pile::~Pile()
+{
+// nothing special at the moment
+}
--- /dev/null
+/////////////////////////////////////////////////////////////////////////////
+// Name: pile.h
+// Purpose: Forty Thieves patience game
+// Author: Chris Breeze
+// Modified by:
+// Created: 21/07/97
+// RCS-ID: $Id$
+// Copyright: (c) 1993-1998 Chris Breeze
+// Licence: wxWindows licence
+//---------------------------------------------------------------------------
+// Last modified: 22nd July 1998 - ported to wxWindows 2.0
+/////////////////////////////////////////////////////////////////////////////
+//+-------------------------------------------------------------+
+//| Description: |
+//| The base class for holding piles of playing cards. |
+//| This is the basic building block for card games. A pile |
+//| has a position on the screen and an offset for each |
+//| card placed on it e.g. a pack has no offset, but the |
+//| discard pile may be fanned out across the screen. |
+//| |
+//| The pile knows how to draw itself, though this may be |
+//| overridden if the default layout needs to be changed. |
+//| One or more cards can be removed from the top of a pile, |
+//| and single cards can be added to the top of a pile. |
+//| Functions are provided which redraw the screen when |
+//| cards are added or removed. |
+//| |
+//| Cards know which way up they are and how to draw |
+//| themselves. Piles are lists of cards. Piles know which |
+//| cards they contain and where they are to be drawn. |
+//+-------------------------------------------------------------+
+#ifndef _PILE_H_
+#define _PILE_H_
+#include "card.h"
+
+const int NumCards = 2 * PackSize;
+
+
+//----------------------------------------------------------------//
+// A class defining a pile of cards with a position on the screen //
+//----------------------------------------------------------------//
+class Pile {
+public:
+ Pile(int x, int y, int dx = 0, int dy = 0);
+ virtual ~Pile();
+
+ // General functions
+ virtual void ResetPile() { m_topCard = -1; }
+ virtual void Redraw(wxDC& pDC);
+
+ // Card query functions
+ virtual Card* GetCard(int x, int y); // Get pointer to card at x, y
+ Card* GetTopCard(); // Get pointer to top card
+ virtual void GetCardPos(Card* card, int& x, int& y);
+ // Get position of a card
+ virtual void GetTopCardPos(int& x, int& y);
+ // Get position of the top card
+ int GetNumCards() { return m_topCard + 1; } // Number of cards in pile
+ bool Overlap(int x, int y); // does card at x,y overlap the pile?
+ int CalcDistance(int x, int y); // calculates the square of the distance
+ // of a card at (x,y) from the top of the pile
+
+ // Functions removing one or more cards from the top of a pile
+ virtual bool CanCardLeave(Card* card);
+ Card* RemoveTopCard();
+ virtual Card* RemoveTopCard(wxDC& pDC, int xOffset = 0, int yOffset = 0);
+
+ // Functions to add a card to the top of a pile
+ virtual bool AcceptCard(Card*) { return FALSE; }
+ virtual void AddCard(Card* card); // Add card to top of pile
+ virtual void AddCard(wxDC& pDC, Card* card); // Add card + redraw it
+
+protected:
+ int m_x, m_y; // Position of the pile on the screen
+ int m_dx, m_dy; // Offset when drawing the pile
+ Card* m_cards[NumCards]; // Array of cards in this pile
+ int m_topCard; // Array index of the top card
+};
+
+#endif // _PILE_H_
--- /dev/null
+/////////////////////////////////////////////////////////////////////////////
+// Name: playerdg.cpp
+// Purpose: Forty Thieves patience game
+// Author: Chris Breeze
+// Modified by:
+// Created: 21/07/97
+// RCS-ID: $Id$
+// Copyright: (c) 1993-1998 Chris Breeze
+// Licence: wxWindows licence
+//---------------------------------------------------------------------------
+// Last modified: 22nd July 1998 - ported to wxWindows 2.0
+/////////////////////////////////////////////////////////////////////////////
+
+#ifdef __GNUG__
+#pragma implementation
+#pragma interface
+#endif
+
+// For compilers that support precompilation, includes "wx/wx.h".
+#include "wx/wxprec.h"
+
+#ifdef __BORLANDC__
+#pragma hdrstop
+#endif
+
+#ifndef WX_PRECOMP
+#include "wx/wx.h"
+#endif
+
+#include "scorefil.h"
+#include "playerdg.h"
+
+const int ID_LISTBOX = 101;
+
+BEGIN_EVENT_TABLE(PlayerSelectionDialog, wxDialog)
+ EVT_SIZE(PlayerSelectionDialog::OnSize)
+ EVT_BUTTON(wxID_OK, PlayerSelectionDialog::ButtonCallback)
+ EVT_BUTTON(wxID_CANCEL, PlayerSelectionDialog::ButtonCallback)
+ EVT_LISTBOX(ID_LISTBOX, PlayerSelectionDialog::SelectCallback)
+END_EVENT_TABLE()
+
+PlayerSelectionDialog::PlayerSelectionDialog(
+ wxWindow* parent,
+ ScoreFile* file
+ ) :
+ wxDialog(parent, -1, "Player Selection",
+ wxDefaultPosition, wxSize(250, 200),
+ wxDIALOG_MODAL | wxDEFAULT_DIALOG_STYLE),
+ m_scoreFile(file)
+{
+ // enable constraints
+ SetAutoLayout (TRUE);
+
+ wxStaticText* msg = new wxStaticText(this, -1, "Please select a name from the list");
+
+ wxListBox* list = new wxListBox(
+ this, ID_LISTBOX,
+ wxDefaultPosition, wxDefaultSize,
+ 0, 0,
+ wxLB_SINGLE
+ );
+ int numPlayers = 0;
+ wxString* players = 0;
+ m_scoreFile->GetPlayerList(&players, numPlayers);
+ for (int i = 0; i < numPlayers; i++)
+ {
+ list->Append(players[i]);
+ }
+ delete players;
+
+ m_textField = new wxTextCtrl(this, -1, "", wxDefaultPosition, wxDefaultSize, 0);
+
+ m_OK = new wxButton(this, wxID_OK, "OK");
+ m_cancel = new wxButton(this, wxID_CANCEL, "Cancel");
+
+ wxLayoutConstraints* layout;
+
+ // Constrain the msg at the top of the window
+ layout = new wxLayoutConstraints;
+ layout->left.SameAs (this, wxLeft, 10);
+ layout->top.SameAs (this, wxTop, 10);
+ layout->height.AsIs();
+ layout->width.AsIs();
+ msg->SetConstraints(layout);
+
+ // Constrain the OK button
+ layout = new wxLayoutConstraints;
+ layout->left.SameAs (this, wxLeft, 10);
+ layout->bottom.SameAs (this, wxBottom, 10);
+ layout->height.AsIs();
+ layout->width.AsIs();
+ m_OK->SetConstraints(layout);
+
+ // Constrain the OK button
+ layout = new wxLayoutConstraints;
+ layout->left.RightOf (m_OK, 10);
+ layout->bottom.SameAs (this, wxBottom, 10);
+ layout->height.AsIs();
+ layout->width.AsIs();
+ m_cancel->SetConstraints(layout);
+
+ // Constrain the Name text entry field
+ layout = new wxLayoutConstraints;
+ layout->left.SameAs (this, wxLeft, 10);
+ layout->right.SameAs (this, wxRight, 10);
+ layout->bottom.SameAs (m_OK, wxTop, 10);
+ layout->height.AsIs();
+ m_textField->SetConstraints(layout);
+
+ // Constrain the list of players
+ layout = new wxLayoutConstraints;
+ layout->left.SameAs (this, wxLeft, 10);
+ layout->right.SameAs (this, wxRight, 10);
+ layout->top.Below (msg, 10);
+ layout->bottom.SameAs (m_textField, wxTop, 10);
+ list->SetConstraints(layout);
+
+ wxString prevPlayer = m_scoreFile->GetPreviousPlayer();
+ if (prevPlayer.Length() > 0)
+ {
+ list->SetStringSelection(prevPlayer);
+ m_textField->SetValue(prevPlayer);
+ }
+
+ Layout();
+}
+
+PlayerSelectionDialog::~PlayerSelectionDialog()
+{
+}
+
+void PlayerSelectionDialog::OnSize(wxSizeEvent& event)
+{
+ Layout();
+}
+
+const wxString& PlayerSelectionDialog::GetPlayersName()
+{
+ m_player = "";
+ Show(TRUE);
+ return m_player;
+}
+
+bool PlayerSelectionDialog::OnClose()
+{
+ // hide the dialog
+ // NB don't return TRUE otherwise delete is called
+ m_player = "";
+ Show(FALSE);
+ return FALSE;
+}
+
+void PlayerSelectionDialog::SelectCallback(wxCommandEvent& event)
+{
+ if (event.GetEventType() == wxEVT_COMMAND_LISTBOX_SELECTED)
+ {
+#ifdef __WXGTK__
+ if (event.IsSelection())
+#endif
+ m_textField->SetValue(event.GetString());
+ }
+}
+
+void PlayerSelectionDialog::ButtonCallback(wxCommandEvent& event)
+{
+ if (event.GetId() == wxID_OK)
+ {
+ wxString name = m_textField->GetValue();
+ if (!name.IsNull() && name.Length() > 0)
+ {
+ if (name.Contains('@'))
+ {
+ wxMessageBox("Names should not contain the '@' character", "Forty Thieves");
+ }
+ else
+ {
+ m_player = name;
+ Show(FALSE);
+ }
+ }
+ else
+ {
+ wxMessageBox("Please enter your name", "Forty Thieves");
+ }
+ }
+ else
+ {
+ m_player = "";
+ Show(FALSE);
+ }
+}
--- /dev/null
+/////////////////////////////////////////////////////////////////////////////
+// Name: playerdg.h
+// Purpose: Forty Thieves patience game
+// Author: Chris Breeze
+// Modified by:
+// Created: 21/07/97
+// RCS-ID: $Id$
+// Copyright: (c) 1993-1998 Chris Breeze
+// Licence: wxWindows licence
+//---------------------------------------------------------------------------
+// Last modified: 22nd July 1998 - ported to wxWindows 2.0
+/////////////////////////////////////////////////////////////////////////////
+#ifndef _PLAYERDG_H_
+#define _PLAYERDG_H_
+
+class PlayerSelectionDialog : public wxDialog
+{
+public:
+ PlayerSelectionDialog(wxWindow* parent, ScoreFile* file);
+ virtual ~PlayerSelectionDialog();
+
+ const wxString& GetPlayersName();
+ void ButtonCallback(wxCommandEvent& event);
+ void SelectCallback(wxCommandEvent& event);
+ void OnSize(wxSizeEvent& event);
+
+ DECLARE_EVENT_TABLE()
+
+protected:
+ friend void SelectCallback(wxListBox&, wxCommandEvent&);
+ bool OnClose();
+
+private:
+ ScoreFile* m_scoreFile;
+ wxString m_player;
+ wxButton* m_OK;
+ wxButton* m_cancel;
+ wxTextCtrl* m_textField;
+};
+
+#endif
--- /dev/null
+/////////////////////////////////////////////////////////////////////////////
+// Name: scoredg.cpp
+// Purpose: Forty Thieves patience game
+// Author: Chris Breeze
+// Modified by:
+// Created: 21/07/97
+// RCS-ID: $Id$
+// Copyright: (c) 1993-1998 Chris Breeze
+// Licence: wxWindows licence
+//---------------------------------------------------------------------------
+// Last modified: 22nd July 1998 - ported to wxWindows 2.0
+/////////////////////////////////////////////////////////////////////////////
+
+#ifdef __GNUG__
+#pragma implementation
+#pragma interface
+#endif
+
+// For compilers that support precompilation, includes "wx/wx.h".
+#include "wx/wxprec.h"
+
+#ifdef __BORLANDC__
+#pragma hdrstop
+#endif
+
+#ifndef WX_PRECOMP
+#include "wx/wx.h"
+#endif
+
+#if defined(__WXMSW__) && !defined(GNUWIN32)
+#include <strstrea.h>
+#else
+#include <strstream.h>
+#endif
+#include "scorefil.h"
+#include "scoredg.h"
+
+class ScoreCanvas : public wxScrolledWindow
+{
+public:
+ ScoreCanvas(wxWindow* parent, ScoreFile* scoreFile);
+ virtual ~ScoreCanvas();
+
+ void OnDraw(wxDC& dc);
+
+private:
+ wxFont* m_font;
+ wxString m_text;
+};
+
+
+ScoreCanvas::ScoreCanvas(wxWindow* parent, ScoreFile* scoreFile) :
+ wxScrolledWindow(parent)
+{
+#ifdef __WXGTK__
+ m_font = wxTheFontList->FindOrCreateFont(12, wxROMAN, wxNORMAL, wxNORMAL);
+#else
+ m_font = wxTheFontList->FindOrCreateFont(10, wxSWISS, wxNORMAL, wxNORMAL);
+#endif
+
+ wxString* players = 0;
+ int length = 0;
+ scoreFile->GetPlayerList(&players, length);
+
+ ostrstream os;
+
+ os << "Player\tWins\tGames\tScore\n";
+ for (int i = 0; i < length; i++)
+ {
+ int wins, games, score;
+ scoreFile->ReadPlayersScore(players[i], wins, games, score);
+ int average = 0;
+ if (games > 0)
+ {
+ average = (2 * score + games) / (2 * games);
+ }
+
+ os << players[i] << '\t'
+ << wins << '\t'
+ << games << '\t'
+ << average << '\n';
+ }
+ os << '\0';
+ char* str = os.str();
+ m_text = str;
+ delete str;
+ delete players;
+}
+
+ScoreCanvas::~ScoreCanvas()
+{
+}
+
+void ScoreCanvas::OnDraw(wxDC& dc)
+{
+ dc.SetFont(m_font);
+
+ const char* str = m_text;
+ unsigned int tab = 0;
+ unsigned int tabstops[] = { 5, 100, 150, 200 };
+
+ // get the line spacing for the current font
+ int lineSpacing;
+ {
+ long w, h;
+ dc.GetTextExtent("Testing", &w, &h);
+ lineSpacing = (int)h;
+ }
+
+ int y = 0;
+ while (*str)
+ {
+ char text[256];
+ char* dest = text;
+
+ while (*str && *str >= ' ') *dest++ = *str++;
+ *dest = '\0';
+
+ dc.DrawText(text, tabstops[tab], y);
+
+ if (*str == '\t')
+ {
+ if (tab < sizeof(tabstops) / sizeof(tabstops[0]) - 1)
+ {
+ tab++;
+ }
+ }
+ else if (*str == '\n')
+ {
+ tab = 0;
+ y += lineSpacing;
+ }
+ if (*str) str++;
+ }
+}
+
+
+ScoreDialog::ScoreDialog(
+ wxWindow* parent,
+ ScoreFile* file
+ ) :
+ wxDialog(parent, -1, "Scores",
+ wxDefaultPosition, wxSize(310, 200),
+ wxDIALOG_MODAL | wxDEFAULT_DIALOG_STYLE),
+ m_scoreFile(file)
+{
+ // enable constraints
+ SetAutoLayout (TRUE);
+
+ ScoreCanvas* list = new ScoreCanvas(this, m_scoreFile);
+ m_OK = new wxButton(this, wxID_OK, "OK");
+
+ wxLayoutConstraints* layout;
+
+ // Constrain the OK button
+ layout = new wxLayoutConstraints;
+ layout->left.SameAs (this, wxLeft, 10);
+ layout->bottom.SameAs (this, wxBottom, 10);
+ layout->height.AsIs();
+ layout->width.AsIs();
+ m_OK->SetConstraints(layout);
+
+ // Constrain the list of players
+ layout = new wxLayoutConstraints;
+ layout->left.SameAs (this, wxLeft, 10);
+ layout->right.SameAs (this, wxRight, 10);
+ layout->top.SameAs (this, wxTop, 10);
+ layout->bottom.SameAs (m_OK, wxTop, 10);
+ list->SetConstraints(layout);
+
+ Layout();
+}
+
+ScoreDialog::~ScoreDialog()
+{
+}
+
+void ScoreDialog::Display()
+{
+ Show(TRUE);
+}
+
+bool ScoreDialog::OnClose()
+{
+ // hide the dialog
+ // NB don't return TRUE otherwise delete is called
+ Show(FALSE);
+ return FALSE;
+}
--- /dev/null
+/////////////////////////////////////////////////////////////////////////////
+// Name: scoredg.h
+// Purpose: Forty Thieves patience game
+// Author: Chris Breeze
+// Modified by:
+// Created: 21/07/97
+// RCS-ID: $Id$
+// Copyright: (c) 1993-1998 Chris Breeze
+// Licence: wxWindows licence
+//---------------------------------------------------------------------------
+// Last modified: 22nd July 1998 - ported to wxWindows 2.0
+/////////////////////////////////////////////////////////////////////////////
+#ifndef _SCOREDG_H_
+#define _SCOREDG_H_
+
+class ScoreDialog : public wxDialog
+{
+public:
+ ScoreDialog(wxWindow* parent, ScoreFile* file);
+ virtual ~ScoreDialog();
+
+ void Display();
+
+protected:
+ bool OnClose();
+
+private:
+ ScoreFile* m_scoreFile;
+ wxButton* m_OK;
+};
+
+#endif
--- /dev/null
+/////////////////////////////////////////////////////////////////////////////
+// Name: scorefil.cpp
+// Purpose: Forty Thieves patience game
+// Author: Chris Breeze
+// Modified by:
+// Created: 21/07/97
+// RCS-ID: $Id$
+// Copyright: (c) 1993-1998 Chris Breeze
+// Licence: wxWindows licence
+//---------------------------------------------------------------------------
+// Last modified: 14th May 1998 - ported to wxWindows 2.0
+/////////////////////////////////////////////////////////////////////////////
+
+#ifdef __GNUG__
+#pragma implementation
+#pragma interface
+#endif
+
+// For compilers that support precompilation, includes "wx/wx.h".
+#include "wx/wxprec.h"
+
+#ifdef __BORLANDC__
+#pragma hdrstop
+#endif
+
+#ifndef WX_PRECOMP
+#include "wx/wx.h"
+#endif
+
+#ifdef __WXGTK__
+#include <unistd.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#endif
+#include "wx/textfile.h"
+#include "wx/config.h"
+#include "wx/fileconf.h"
+
+#include "scorefil.h"
+
+
+ScoreFile::ScoreFile(const char* appName)
+{
+ wxString filename;
+#ifdef __WXGTK__
+ m_configFilename << "/usr/local/share/" << appName << ".scores";
+ if (access(m_configFilename, F_OK) == 0)
+ {
+ if (access(m_configFilename, R_OK | W_OK) != 0)
+ {
+ // file is not r/w - use local file instead
+ m_configFilename = wxFileConfig::GetLocalFileName(appName);
+ }
+ }
+ else
+ {
+ int fd = creat(m_configFilename, 0666);
+
+ if (fd < 0)
+ {
+ // failed to create file - use local file instead
+ m_configFilename = wxFileConfig::GetLocalFileName(appName);
+ }
+ else
+ {
+ // ensure created file has rw-rw-rw permissions
+ close(fd);
+ }
+ }
+#else
+ // Windows
+ m_configFilename = wxFileConfig::GetGlobalFileName(appName);
+#endif
+ m_config = new wxFileConfig(m_configFilename);
+}
+
+ScoreFile::~ScoreFile()
+{
+ delete m_config;
+#ifdef __WXGTK__
+ // ensure score file has rw-rw-rw permissions
+ // (wxFileConfig sets them to rw-------)
+ chmod(m_configFilename, 0666);
+#endif
+}
+
+
+void ScoreFile::GetPlayerList(wxString** list, int& length)
+{
+ m_config->SetPath("/Players");
+ length = m_config->GetNumberOfGroups();
+
+ if (length <= 0)
+ {
+ *list = 0;
+ return;
+ }
+
+ *list = new wxString[length];
+
+ wxString player;
+ long index, i = 0;
+ if (m_config->GetFirstGroup(player, index))
+ {
+ (*list)[i++] = player;
+ while (m_config->GetNextGroup(player, index))
+ {
+ (*list)[i++] = player;
+ }
+ }
+}
+
+
+// Calculate an encrypted check number to prevent tampering with
+// score file
+long ScoreFile::CalcCheck(const char* name, int p1, int p2, int p3)
+{
+ long check = 0;
+ while (*name)
+ {
+ check = (check << 1) ^ (long)*name++;
+ check = ((check >> 23) ^ check) & 0xFFFFFF;
+ }
+ check = (check << 1) ^ (long)p1;
+ check = ((check >> 23) ^ check) & 0xFFFFFF;
+ check = (check << 1) ^ (long)p2;
+ check = ((check >> 23) ^ check) & 0xFFFFFF;
+ check = (check << 1) ^ (long)p3;
+ check = ((check >> 23) ^ check) & 0xFFFFFF;
+ return check;
+}
+
+wxString ScoreFile::GetPreviousPlayer() const
+{
+ wxString result;
+ m_config->SetPath("/General");
+ m_config->Read(&result, "LastPlayer");
+ return result;
+}
+
+void ScoreFile::ReadPlayersScore(
+ const char* player,
+ int& wins,
+ int& games,
+ int& score)
+{
+ long check;
+ long myWins, myGames, myScore;
+
+ games = wins = score = 0;
+
+ m_config->SetPath("/Players");
+ m_config->SetPath(player);
+ if (m_config->Read(&myScore, "Score") &&
+ m_config->Read(&myGames, "Games") &&
+ m_config->Read(&myWins, "Wins") &&
+ m_config->Read(&check, "Check"))
+ {
+ if (check != CalcCheck(player, myGames, myWins, myScore))
+ {
+ wxMessageBox("Score file corrupted", "Warning",
+ wxOK | wxICON_EXCLAMATION);
+ }
+ else
+ {
+ games = myGames;
+ wins = myWins;
+ score = myScore;
+ }
+ }
+ WritePlayersScore(player, wins, games, score);
+}
+
+
+void ScoreFile::WritePlayersScore(const char* player, int wins, int games, int score)
+{
+ if (player)
+ {
+ m_config->SetPath("/General");
+ m_config->Write("LastPlayer", player);
+
+ m_config->SetPath("/Players");
+ m_config->SetPath(player);
+ m_config->Write("Score", score);
+ m_config->Write("Games", games);
+ m_config->Write("Wins", wins);
+ m_config->Write("Check", CalcCheck(player, games, wins, score));
+ }
+}
--- /dev/null
+/////////////////////////////////////////////////////////////////////////////
+// Name: scorefil.h
+// Purpose: Forty Thieves patience game
+// Author: Chris Breeze
+// Modified by:
+// Created: 21/07/97
+// RCS-ID: $Id$
+// Copyright: (c) 1993-1998 Chris Breeze
+// Licence: wxWindows licence
+//---------------------------------------------------------------------------
+// Last modified: 22nd July 1998 - ported to wxWindows 2.0
+/////////////////////////////////////////////////////////////////////////////
+#ifndef _SCOREFILE_H_
+#define _SCOREFILE_H_
+
+class wxConfig;
+
+class ScoreFile {
+public:
+ ScoreFile(const char* appName);
+ virtual ~ScoreFile();
+
+ void GetPlayerList(wxString** list, int& number);
+ wxString GetPreviousPlayer() const;
+
+ void ReadPlayersScore(const char* player, int& wins, int& games, int &score);
+ void WritePlayersScore(const char* player, int wins, int games, int score);
+
+private:
+ long CalcCheck(const char* name, int p1, int p2, int p3);
+ wxString m_configFilename;
+ wxConfig* m_config;
+};
+
+#endif
--- /dev/null
+#define Symbols_width 79
+#define Symbols_height 50
+static char Symbols_bits[] = {
+ 0x08,0x84,0x0d,0x01,0x00,0x00,0x00,0x00,0x00,0x80,0x1c,0xce,0x9f,0x03,0x00,
+ 0x00,0x00,0x00,0x00,0x80,0x2a,0xdf,0xdf,0x07,0x00,0x00,0x00,0x00,0x00,0x80,
+ 0xff,0xff,0xff,0x0f,0x00,0x00,0x00,0x00,0x00,0x80,0x2a,0x9f,0xcf,0x07,0x00,
+ 0x00,0x00,0x00,0x00,0x80,0x08,0x0e,0x07,0x01,0x00,0x00,0x00,0x00,0x00,0x80,
+ 0x1c,0x04,0x82,0x03,0x00,0x00,0x00,0x00,0x00,0x80,0x1c,0x04,0x82,0x03,0x00,
+ 0x00,0x00,0x00,0x00,0x80,0x08,0x0e,0x07,0x01,0x00,0x00,0x00,0x00,0x00,0x80,
+ 0x2a,0x9f,0xcf,0x07,0x00,0x00,0x00,0x00,0x00,0x80,0xff,0xff,0xff,0x0f,0x00,
+ 0x00,0x00,0x00,0x00,0x80,0x2a,0xdf,0xdf,0x07,0x00,0x00,0x00,0x00,0x00,0x80,
+ 0x1c,0xce,0x9f,0x03,0x00,0x00,0x00,0x00,0x00,0x80,0x08,0x84,0x0d,0x01,0x00,
+ 0x00,0x00,0x00,0x00,0x80,0x70,0x00,0x01,0x63,0x40,0x00,0x00,0x00,0x00,0x80,
+ 0xf8,0x80,0x83,0xf7,0xe0,0x00,0x00,0x00,0x00,0x80,0xf8,0x80,0xc3,0xff,0xf1,
+ 0x01,0x00,0x00,0x00,0x80,0x70,0xc0,0xc7,0xff,0xf9,0x03,0x00,0x00,0x00,0x80,
+ 0x26,0xe3,0xcf,0xff,0xfd,0x07,0x00,0x00,0x00,0x80,0xaf,0xf7,0xdf,0xff,0xff,
+ 0x0f,0x00,0x00,0x00,0x80,0xff,0xe7,0x8f,0xff,0xfe,0x0f,0x00,0x00,0x00,0x80,
+ 0xaf,0xc7,0x07,0x7f,0x5e,0x0f,0x00,0x00,0x00,0x80,0x26,0x83,0x03,0x3e,0x4c,
+ 0x06,0x00,0x00,0x00,0x80,0x70,0x80,0x03,0x1c,0xe0,0x00,0x00,0x00,0x00,0x80,
+ 0xfc,0x01,0x01,0x08,0xf8,0x03,0x00,0x00,0x00,0x80,0xfc,0x01,0x01,0x08,0xf8,
+ 0x03,0x00,0x00,0x00,0x80,0x70,0x80,0x03,0x1c,0xe0,0x00,0x00,0x00,0x00,0x80,
+ 0x26,0x83,0x03,0x3e,0x4c,0x06,0x00,0x00,0x00,0x80,0xaf,0xc7,0x07,0x7f,0x5e,
+ 0x0f,0x00,0x00,0x00,0x80,0xff,0xe7,0x8f,0xff,0xfe,0x0f,0x00,0x00,0x00,0x80,
+ 0xaf,0xf7,0xdf,0xff,0xff,0x0f,0x00,0x00,0x00,0x80,0x26,0xe3,0xcf,0xff,0xfd,
+ 0x07,0x00,0x00,0x00,0x80,0x70,0xc0,0xc7,0xff,0xf9,0x03,0x00,0x00,0x00,0x80,
+ 0xf8,0x80,0xc3,0xff,0xf1,0x01,0x00,0x00,0x00,0x80,0xf8,0x80,0x83,0xf7,0xe0,
+ 0x00,0x00,0x00,0x00,0x80,0x70,0x00,0x01,0x63,0x40,0x00,0x00,0x00,0x00,0x80,
+ 0x0c,0xe7,0x43,0x3e,0xe7,0x73,0x5c,0xe6,0x73,0xa2,0x92,0x08,0x61,0x82,0x00,
+ 0x8a,0x62,0x09,0x89,0x92,0x21,0x88,0x50,0x9e,0x00,0x89,0x62,0x09,0x89,0x8a,
+ 0x21,0xc6,0x49,0xa0,0x87,0x70,0x7c,0x09,0x89,0x86,0x3f,0x01,0xfa,0xa0,0x88,
+ 0x88,0x60,0x09,0xa9,0x8a,0xa1,0x20,0x42,0xa2,0x88,0x88,0x50,0x29,0x49,0x92,
+ 0xa1,0xcf,0x41,0x1c,0x87,0x70,0x48,0xc6,0xb0,0xa2,0xa1,0xcf,0x11,0x1c,0x87,
+ 0x70,0x88,0x89,0x69,0xa2,0x21,0x28,0x12,0xa2,0x88,0x88,0x44,0x4a,0x92,0xa4,
+ 0x3f,0x24,0xf8,0x82,0x88,0x88,0x42,0x4a,0xa8,0xa8,0x21,0xc3,0x91,0x82,0x8f,
+ 0x70,0x5e,0x4a,0x88,0xb0,0xa1,0x80,0x50,0x3c,0x48,0x88,0x62,0x4a,0x88,0xa8,
+ 0x92,0x48,0x30,0x20,0x28,0x88,0x62,0x4a,0x88,0xa4,0x0c,0xe7,0x13,0x3e,0xe7,
+ 0x73,0x9c,0xe9,0x73,0xa2};
--- /dev/null
+/* XPM */
+static char *symbols[] = {
+/* width height num_colors chars_per_pixel */
+" 79 50 3 1",
+/* colors */
+". c #ffffff",
+"* c #ff0000",
+"# c #000000",
+/* pixels */
+"...#......*....**.**....#......................................................",
+"..###....***..*******..###.....................................................",
+".#.#.#..*****.*******.#####....................................................",
+"#######**************#######...................................................",
+".#.#.#..*****..*****..#####....................................................",
+"...#.....***....***.....#......................................................",
+"..###.....*......*.....###.....................................................",
+"..###.....*......*.....###.....................................................",
+"...#.....***....***.....#......................................................",
+".#.#.#..*****..*****..#####....................................................",
+"#######**************#######...................................................",
+".#.#.#..*****.*******.#####....................................................",
+"..###....***..*******..###.....................................................",
+"...#......*....**.**....#......................................................",
+"....###.........*.......**...**.......#........................................",
+"...#####.......***.....****.****.....###.......................................",
+"...#####.......***....***********...#####......................................",
+"....###.......*****...***********..#######.....................................",
+".##..#..##...*******..***********.#########....................................",
+"####.#.####.*********.***********###########...................................",
+"###########..*******...*********.###########...................................",
+"####.#.####...*****.....*******..####.#.####...................................",
+".##..#..##.....***.......*****....##..#..##....................................",
+"....###........***........***........###.......................................",
+"..#######.......*..........*.......#######.....................................",
+"..#######.......*..........*.......#######.....................................",
+"....###........***........***........###.......................................",
+".##..#..##.....***.......*****....##..#..##....................................",
+"####.#.####...*****.....*******..####.#.####...................................",
+"###########..*******...*********.###########...................................",
+"####.#.####.*********.***********###########...................................",
+".##..#..##...*******..***********.#########....................................",
+"....###.......*****...***********..#######.....................................",
+"...#####.......***....***********...#####......................................",
+"...#####.......***.....****.****.....###.......................................",
+"....###.........*.......**...**.......#........................................",
+"..##....###..#####....#..#####..###..#####..###...###.#..##..#####..###..#...#.",
+".#..#..#...#....#....##..#.....#.........#.#...#.#...##.#..#....#..#...#.#..#..",
+"#....#.....#...#....#.#..####..#........#..#...#.#...##.#..#....#..#...#.#.#...",
+"#....#...##...###..#..#......#.####....#....###...#####.#..#....#..#...#.##....",
+"######..#........#.#####.....#.#...#...#...#...#.....##.#..#....#..#.#.#.#.#...",
+"#....#.#.....#...#....#..#...#.#...#...#...#...#....#.#.#..#.#..#..#..#..#..#..",
+"#....#.#####..###.....#...###...###....#....###....#..#..##...##....##.#.#...#.",
+"#....#.#####..###...#.....###...###....#....###....#...##..#...##..#.##..#...#.",
+"#....#.....#.#...#..#....#...#.#...#...#...#...#..#...#..#.#..#..#..#..#..#..#.",
+"######....#..#.....#####.#.....#...#...#...#...#.#....#..#.#..#....#.#.#...#.#.",
+"#....#..##....###...#..#.#.....#####...#....###..####.#..#.#..#....#...#....##.",
+"#....#.#.......#....#.#...####.....#..#....#...#.#...##..#.#..#....#...#...#.#.",
+".#..#..#...#..#.....##.......#.....#.#.....#...#.#...##..#.#..#....#...#..#..#.",
+"..##....###..#####..#....#####..###..#####..###...###..##..#.#####..###..#...#."
+};