]> git.saurik.com Git - wxWidgets.git/commitdiff
Added Forty Thieves
authorJulian Smart <julian@anthemion.co.uk>
Fri, 24 Jul 1998 19:43:32 +0000 (19:43 +0000)
committerJulian Smart <julian@anthemion.co.uk>
Fri, 24 Jul 1998 19:43:32 +0000 (19:43 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@365 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

24 files changed:
samples/forty/Makefile [new file with mode: 0644]
samples/forty/Makefile.in [new file with mode: 0644]
samples/forty/canvas.cpp [new file with mode: 0644]
samples/forty/canvas.h [new file with mode: 0644]
samples/forty/card.cpp [new file with mode: 0644]
samples/forty/card.h [new file with mode: 0644]
samples/forty/cards.ico [new file with mode: 0644]
samples/forty/forty.cpp [new file with mode: 0644]
samples/forty/forty.h [new file with mode: 0644]
samples/forty/forty.rc [new file with mode: 0644]
samples/forty/game.cpp [new file with mode: 0644]
samples/forty/game.h [new file with mode: 0644]
samples/forty/makefile.nt [new file with mode: 0644]
samples/forty/pictures.xpm [new file with mode: 0644]
samples/forty/pile.cpp [new file with mode: 0644]
samples/forty/pile.h [new file with mode: 0644]
samples/forty/playerdg.cpp [new file with mode: 0644]
samples/forty/playerdg.h [new file with mode: 0644]
samples/forty/scoredg.cpp [new file with mode: 0644]
samples/forty/scoredg.h [new file with mode: 0644]
samples/forty/scorefil.cpp [new file with mode: 0644]
samples/forty/scorefil.h [new file with mode: 0644]
samples/forty/symbols.xbm [new file with mode: 0644]
samples/forty/symbols.xpm [new file with mode: 0644]

diff --git a/samples/forty/Makefile b/samples/forty/Makefile
new file mode 100644 (file)
index 0000000..027d82a
--- /dev/null
@@ -0,0 +1 @@
+include ../../src/gtk/setup/general/makeapp
diff --git a/samples/forty/Makefile.in b/samples/forty/Makefile.in
new file mode 100644 (file)
index 0000000..d56090e
--- /dev/null
@@ -0,0 +1,40 @@
+# 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
diff --git a/samples/forty/canvas.cpp b/samples/forty/canvas.cpp
new file mode 100644 (file)
index 0000000..18dec21
--- /dev/null
@@ -0,0 +1,252 @@
+/////////////////////////////////////////////////////////////////////////////
+// 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);
+}
diff --git a/samples/forty/canvas.h b/samples/forty/canvas.h
new file mode 100644 (file)
index 0000000..368d6c6
--- /dev/null
@@ -0,0 +1,56 @@
+/////////////////////////////////////////////////////////////////////////////
+// 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
diff --git a/samples/forty/card.cpp b/samples/forty/card.cpp
new file mode 100644 (file)
index 0000000..5dc2669
--- /dev/null
@@ -0,0 +1,358 @@
+/////////////////////////////////////////////////////////////////////////////
+// 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()
+
+
diff --git a/samples/forty/card.h b/samples/forty/card.h
new file mode 100644 (file)
index 0000000..b93ac93
--- /dev/null
@@ -0,0 +1,65 @@
+/////////////////////////////////////////////////////////////////////////////
+// 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_
diff --git a/samples/forty/cards.ico b/samples/forty/cards.ico
new file mode 100644 (file)
index 0000000..35c8379
Binary files /dev/null and b/samples/forty/cards.ico differ
diff --git a/samples/forty/forty.cpp b/samples/forty/forty.cpp
new file mode 100644 (file)
index 0000000..65a9c46
--- /dev/null
@@ -0,0 +1,258 @@
+/////////////////////////////////////////////////////////////////////////////
+// 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);
+}
diff --git a/samples/forty/forty.h b/samples/forty/forty.h
new file mode 100644 (file)
index 0000000..bdbb783
--- /dev/null
@@ -0,0 +1,31 @@
+/////////////////////////////////////////////////////////////////////////////
+// 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
diff --git a/samples/forty/forty.rc b/samples/forty/forty.rc
new file mode 100644 (file)
index 0000000..911ea25
--- /dev/null
@@ -0,0 +1,6 @@
+#include "wx/msw/wx.rc"
+
+CardsIcon    ICON   "cards.ico"
+CardPictures BITMAP "pictures.bmp"
+CardSymbols  BITMAP "symbols.bmp"
+
diff --git a/samples/forty/game.cpp b/samples/forty/game.cpp
new file mode 100644 (file)
index 0000000..c121d8d
--- /dev/null
@@ -0,0 +1,943 @@
+/////////////////////////////////////////////////////////////////////////////
+// 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
+};
diff --git a/samples/forty/game.h b/samples/forty/game.h
new file mode 100644 (file)
index 0000000..2360d15
--- /dev/null
@@ -0,0 +1,135 @@
+/////////////////////////////////////////////////////////////////////////////
+// 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_
diff --git a/samples/forty/makefile.nt b/samples/forty/makefile.nt
new file mode 100644 (file)
index 0000000..0a70e53
--- /dev/null
@@ -0,0 +1,98 @@
+#
+# 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
+
diff --git a/samples/forty/pictures.xpm b/samples/forty/pictures.xpm
new file mode 100644 (file)
index 0000000..3184957
--- /dev/null
@@ -0,0 +1,60 @@
+/* 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.",
+"........................................................................................................................"
+};
diff --git a/samples/forty/pile.cpp b/samples/forty/pile.cpp
new file mode 100644 (file)
index 0000000..fd0f60d
--- /dev/null
@@ -0,0 +1,293 @@
+/////////////////////////////////////////////////////////////////////////////
+// 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
+}
diff --git a/samples/forty/pile.h b/samples/forty/pile.h
new file mode 100644 (file)
index 0000000..49eb8c9
--- /dev/null
@@ -0,0 +1,80 @@
+/////////////////////////////////////////////////////////////////////////////
+// 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_
diff --git a/samples/forty/playerdg.cpp b/samples/forty/playerdg.cpp
new file mode 100644 (file)
index 0000000..3816048
--- /dev/null
@@ -0,0 +1,191 @@
+/////////////////////////////////////////////////////////////////////////////
+// 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);
+       }
+}
diff --git a/samples/forty/playerdg.h b/samples/forty/playerdg.h
new file mode 100644 (file)
index 0000000..995ac57
--- /dev/null
@@ -0,0 +1,41 @@
+/////////////////////////////////////////////////////////////////////////////
+// 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
diff --git a/samples/forty/scoredg.cpp b/samples/forty/scoredg.cpp
new file mode 100644 (file)
index 0000000..bd4d9b9
--- /dev/null
@@ -0,0 +1,189 @@
+/////////////////////////////////////////////////////////////////////////////
+// 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;
+}
diff --git a/samples/forty/scoredg.h b/samples/forty/scoredg.h
new file mode 100644 (file)
index 0000000..c63cf03
--- /dev/null
@@ -0,0 +1,32 @@
+/////////////////////////////////////////////////////////////////////////////
+// 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
diff --git a/samples/forty/scorefil.cpp b/samples/forty/scorefil.cpp
new file mode 100644 (file)
index 0000000..9025430
--- /dev/null
@@ -0,0 +1,189 @@
+/////////////////////////////////////////////////////////////////////////////
+// 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));
+       }
+}
diff --git a/samples/forty/scorefil.h b/samples/forty/scorefil.h
new file mode 100644 (file)
index 0000000..d38b050
--- /dev/null
@@ -0,0 +1,35 @@
+/////////////////////////////////////////////////////////////////////////////
+// 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
diff --git a/samples/forty/symbols.xbm b/samples/forty/symbols.xbm
new file mode 100644 (file)
index 0000000..5dee698
--- /dev/null
@@ -0,0 +1,37 @@
+#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};
diff --git a/samples/forty/symbols.xpm b/samples/forty/symbols.xpm
new file mode 100644 (file)
index 0000000..e5a2b25
--- /dev/null
@@ -0,0 +1,60 @@
+/* XPM */
+static char *symbols[] = {
+/* width height num_colors chars_per_pixel */
+"    79    50        3            1",
+/* colors */
+". c #ffffff",
+"* c #ff0000",
+"# c #000000",
+/* pixels */
+"...#......*....**.**....#......................................................",
+"..###....***..*******..###.....................................................",
+".#.#.#..*****.*******.#####....................................................",
+"#######**************#######...................................................",
+".#.#.#..*****..*****..#####....................................................",
+"...#.....***....***.....#......................................................",
+"..###.....*......*.....###.....................................................",
+"..###.....*......*.....###.....................................................",
+"...#.....***....***.....#......................................................",
+".#.#.#..*****..*****..#####....................................................",
+"#######**************#######...................................................",
+".#.#.#..*****.*******.#####....................................................",
+"..###....***..*******..###.....................................................",
+"...#......*....**.**....#......................................................",
+"....###.........*.......**...**.......#........................................",
+"...#####.......***.....****.****.....###.......................................",
+"...#####.......***....***********...#####......................................",
+"....###.......*****...***********..#######.....................................",
+".##..#..##...*******..***********.#########....................................",
+"####.#.####.*********.***********###########...................................",
+"###########..*******...*********.###########...................................",
+"####.#.####...*****.....*******..####.#.####...................................",
+".##..#..##.....***.......*****....##..#..##....................................",
+"....###........***........***........###.......................................",
+"..#######.......*..........*.......#######.....................................",
+"..#######.......*..........*.......#######.....................................",
+"....###........***........***........###.......................................",
+".##..#..##.....***.......*****....##..#..##....................................",
+"####.#.####...*****.....*******..####.#.####...................................",
+"###########..*******...*********.###########...................................",
+"####.#.####.*********.***********###########...................................",
+".##..#..##...*******..***********.#########....................................",
+"....###.......*****...***********..#######.....................................",
+"...#####.......***....***********...#####......................................",
+"...#####.......***.....****.****.....###.......................................",
+"....###.........*.......**...**.......#........................................",
+"..##....###..#####....#..#####..###..#####..###...###.#..##..#####..###..#...#.",
+".#..#..#...#....#....##..#.....#.........#.#...#.#...##.#..#....#..#...#.#..#..",
+"#....#.....#...#....#.#..####..#........#..#...#.#...##.#..#....#..#...#.#.#...",
+"#....#...##...###..#..#......#.####....#....###...#####.#..#....#..#...#.##....",
+"######..#........#.#####.....#.#...#...#...#...#.....##.#..#....#..#.#.#.#.#...",
+"#....#.#.....#...#....#..#...#.#...#...#...#...#....#.#.#..#.#..#..#..#..#..#..",
+"#....#.#####..###.....#...###...###....#....###....#..#..##...##....##.#.#...#.",
+"#....#.#####..###...#.....###...###....#....###....#...##..#...##..#.##..#...#.",
+"#....#.....#.#...#..#....#...#.#...#...#...#...#..#...#..#.#..#..#..#..#..#..#.",
+"######....#..#.....#####.#.....#...#...#...#...#.#....#..#.#..#....#.#.#...#.#.",
+"#....#..##....###...#..#.#.....#####...#....###..####.#..#.#..#....#...#....##.",
+"#....#.#.......#....#.#...####.....#..#....#...#.#...##..#.#..#....#...#...#.#.",
+".#..#..#...#..#.....##.......#.....#.#.....#...#.#...##..#.#..#....#...#..#..#.",
+"..##....###..#####..#....#####..###..#####..###...###..##..#.#####..###..#...#."
+};