From 63cafd2799b6e9dcbe34ce63635f1f8a807d895f Mon Sep 17 00:00:00 2001 From: Julian Smart Date: Fri, 24 Jul 1998 19:43:32 +0000 Subject: [PATCH] Added Forty Thieves git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@365 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- samples/forty/Makefile | 1 + samples/forty/Makefile.in | 40 ++ samples/forty/canvas.cpp | 252 ++++++++++ samples/forty/canvas.h | 56 +++ samples/forty/card.cpp | 358 ++++++++++++++ samples/forty/card.h | 65 +++ samples/forty/cards.ico | Bin 0 -> 766 bytes samples/forty/forty.cpp | 258 ++++++++++ samples/forty/forty.h | 31 ++ samples/forty/forty.rc | 6 + samples/forty/game.cpp | 943 +++++++++++++++++++++++++++++++++++++ samples/forty/game.h | 135 ++++++ samples/forty/makefile.nt | 98 ++++ samples/forty/pictures.xpm | 60 +++ samples/forty/pile.cpp | 293 ++++++++++++ samples/forty/pile.h | 80 ++++ samples/forty/playerdg.cpp | 191 ++++++++ samples/forty/playerdg.h | 41 ++ samples/forty/scoredg.cpp | 189 ++++++++ samples/forty/scoredg.h | 32 ++ samples/forty/scorefil.cpp | 189 ++++++++ samples/forty/scorefil.h | 35 ++ samples/forty/symbols.xbm | 37 ++ samples/forty/symbols.xpm | 60 +++ 24 files changed, 3450 insertions(+) create mode 100644 samples/forty/Makefile create mode 100644 samples/forty/Makefile.in create mode 100644 samples/forty/canvas.cpp create mode 100644 samples/forty/canvas.h create mode 100644 samples/forty/card.cpp create mode 100644 samples/forty/card.h create mode 100644 samples/forty/cards.ico create mode 100644 samples/forty/forty.cpp create mode 100644 samples/forty/forty.h create mode 100644 samples/forty/forty.rc create mode 100644 samples/forty/game.cpp create mode 100644 samples/forty/game.h create mode 100644 samples/forty/makefile.nt create mode 100644 samples/forty/pictures.xpm create mode 100644 samples/forty/pile.cpp create mode 100644 samples/forty/pile.h create mode 100644 samples/forty/playerdg.cpp create mode 100644 samples/forty/playerdg.h create mode 100644 samples/forty/scoredg.cpp create mode 100644 samples/forty/scoredg.h create mode 100644 samples/forty/scorefil.cpp create mode 100644 samples/forty/scorefil.h create mode 100644 samples/forty/symbols.xbm create mode 100644 samples/forty/symbols.xpm diff --git a/samples/forty/Makefile b/samples/forty/Makefile new file mode 100644 index 0000000000..027d82ae19 --- /dev/null +++ b/samples/forty/Makefile @@ -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 index 0000000000..d56090e51f --- /dev/null +++ b/samples/forty/Makefile.in @@ -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 index 0000000000..18dec216f2 --- /dev/null +++ b/samples/forty/canvas.cpp @@ -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 index 0000000000..368d6c6b61 --- /dev/null +++ b/samples/forty/canvas.h @@ -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 index 0000000000..5dc266982e --- /dev/null +++ b/samples/forty/card.cpp @@ -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 +#include +#include +#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 index 0000000000..b93ac93dd8 --- /dev/null +++ b/samples/forty/card.h @@ -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 index 0000000000000000000000000000000000000000..35c8379526ed499ff4404fe13da8272e7b84a843 GIT binary patch literal 766 zcmcgqJ9Yyh44jSqUfkiz^_DqCjz-B9sP-xx#idKNRAff5A17N!tbma;Xy7d{am@1_ zveyUj;QB?M>EHATSI$6W?%WE%52f^lGq?1D7$XzSKeVPDokJl_NJj&1N0>xDSV|)8 zc1vLg+?nG=F|tC(H48Vwj&okP3q}#DuQ{^-FhdX~WPvvoR+)FQvMBFK38GK literal 0 HcmV?d00001 diff --git a/samples/forty/forty.cpp b/samples/forty/forty.cpp new file mode 100644 index 0000000000..65a9c463d1 --- /dev/null +++ b/samples/forty/forty.cpp @@ -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 index 0000000000..bdbb7832fd --- /dev/null +++ b/samples/forty/forty.h @@ -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 index 0000000000..911ea25bb9 --- /dev/null +++ b/samples/forty/forty.rc @@ -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 index 0000000000..c121d8dd06 --- /dev/null +++ b/samples/forty/game.cpp @@ -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 +#include +#include +#include +#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 index 0000000000..2360d15f49 --- /dev/null +++ b/samples/forty/game.h @@ -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 index 0000000000..0a70e53963 --- /dev/null +++ b/samples/forty/makefile.nt @@ -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 index 0000000000..31849577c7 --- /dev/null +++ b/samples/forty/pictures.xpm @@ -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 index 0000000000..fd0f60d388 --- /dev/null +++ b/samples/forty/pile.cpp @@ -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 +#include +#include +#include +#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 index 0000000000..49eb8c9b54 --- /dev/null +++ b/samples/forty/pile.h @@ -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 index 0000000000..38160488da --- /dev/null +++ b/samples/forty/playerdg.cpp @@ -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 index 0000000000..995ac57a80 --- /dev/null +++ b/samples/forty/playerdg.h @@ -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 index 0000000000..bd4d9b93b6 --- /dev/null +++ b/samples/forty/scoredg.cpp @@ -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 +#else +#include +#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 index 0000000000..c63cf03547 --- /dev/null +++ b/samples/forty/scoredg.h @@ -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 index 0000000000..9025430eab --- /dev/null +++ b/samples/forty/scorefil.cpp @@ -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 +#include +#include +#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 index 0000000000..d38b050af6 --- /dev/null +++ b/samples/forty/scorefil.h @@ -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 index 0000000000..5dee698c60 --- /dev/null +++ b/samples/forty/symbols.xbm @@ -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 index 0000000000..e5a2b2590f --- /dev/null +++ b/samples/forty/symbols.xpm @@ -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 */ +"...#......*....**.**....#......................................................", +"..###....***..*******..###.....................................................", +".#.#.#..*****.*******.#####....................................................", +"#######**************#######...................................................", +".#.#.#..*****..*****..#####....................................................", +"...#.....***....***.....#......................................................", +"..###.....*......*.....###.....................................................", +"..###.....*......*.....###.....................................................", +"...#.....***....***.....#......................................................", +".#.#.#..*****..*****..#####....................................................", +"#######**************#######...................................................", +".#.#.#..*****.*******.#####....................................................", +"..###....***..*******..###.....................................................", +"...#......*....**.**....#......................................................", +"....###.........*.......**...**.......#........................................", +"...#####.......***.....****.****.....###.......................................", +"...#####.......***....***********...#####......................................", +"....###.......*****...***********..#######.....................................", +".##..#..##...*******..***********.#########....................................", +"####.#.####.*********.***********###########...................................", +"###########..*******...*********.###########...................................", +"####.#.####...*****.....*******..####.#.####...................................", +".##..#..##.....***.......*****....##..#..##....................................", +"....###........***........***........###.......................................", +"..#######.......*..........*.......#######.....................................", +"..#######.......*..........*.......#######.....................................", +"....###........***........***........###.......................................", +".##..#..##.....***.......*****....##..#..##....................................", +"####.#.####...*****.....*******..####.#.####...................................", +"###########..*******...*********.###########...................................", +"####.#.####.*********.***********###########...................................", +".##..#..##...*******..***********.#########....................................", +"....###.......*****...***********..#######.....................................", +"...#####.......***....***********...#####......................................", +"...#####.......***.....****.****.....###.......................................", +"....###.........*.......**...**.......#........................................", +"..##....###..#####....#..#####..###..#####..###...###.#..##..#####..###..#...#.", +".#..#..#...#....#....##..#.....#.........#.#...#.#...##.#..#....#..#...#.#..#..", +"#....#.....#...#....#.#..####..#........#..#...#.#...##.#..#....#..#...#.#.#...", +"#....#...##...###..#..#......#.####....#....###...#####.#..#....#..#...#.##....", +"######..#........#.#####.....#.#...#...#...#...#.....##.#..#....#..#.#.#.#.#...", +"#....#.#.....#...#....#..#...#.#...#...#...#...#....#.#.#..#.#..#..#..#..#..#..", +"#....#.#####..###.....#...###...###....#....###....#..#..##...##....##.#.#...#.", +"#....#.#####..###...#.....###...###....#....###....#...##..#...##..#.##..#...#.", +"#....#.....#.#...#..#....#...#.#...#...#...#...#..#...#..#.#..#..#..#..#..#..#.", +"######....#..#.....#####.#.....#...#...#...#...#.#....#..#.#..#....#.#.#...#.#.", +"#....#..##....###...#..#.#.....#####...#....###..####.#..#.#..#....#...#....##.", +"#....#.#.......#....#.#...####.....#..#....#...#.#...##..#.#..#....#...#...#.#.", +".#..#..#...#..#.....##.......#.....#.#.....#...#.#...##..#.#..#....#...#..#..#.", +"..##....###..#####..#....#####..###..#####..###...###..##..#.#####..###..#...#." +}; -- 2.45.2