From 9dff498b21da9e6b60bd12d1d14de5f411382ff4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tibor=20Lajos=20F=C3=BCzi?= Date: Sun, 28 Feb 2021 22:31:19 +0100 Subject: [PATCH] [SOLITAIRE] Add undo feature & fix occasionally invisible cards (#3422) Two issues are addressed: CORE-2189: missing undo feature Works the same way as solitaire in windows xp: - only 1 action can be undone; - the player gets -2 points in standard score mode; - the undo action resets when the player clicks on a row stack to turn the top card. CORE-11148: invisible cards This happens in 3-card mode, when only 1 card left in the deck. The fix for this is to modify the pile stack to contain all the face-up cards. It was actually already in the code somewhere else, so I turned it into a separate function. --- .../games/solitaire/CMakeLists.txt | 1 + .../games/solitaire/lang/bg-BG.rc | 1 + .../games/solitaire/lang/ca-ES.rc | 1 + .../games/solitaire/lang/cs-CZ.rc | 1 + .../games/solitaire/lang/de-DE.rc | 1 + .../games/solitaire/lang/el-GR.rc | 1 + .../games/solitaire/lang/en-US.rc | 1 + .../games/solitaire/lang/es-ES.rc | 1 + .../games/solitaire/lang/eu-ES.rc | 1 + .../games/solitaire/lang/fr-FR.rc | 1 + .../games/solitaire/lang/he-IL.rc | 1 + .../games/solitaire/lang/hu-HU.rc | 1 + .../games/solitaire/lang/id-ID.rc | 1 + .../games/solitaire/lang/it-IT.rc | 1 + .../games/solitaire/lang/ja-JP.rc | 1 + .../games/solitaire/lang/ko-KR.rc | 1 + .../games/solitaire/lang/lt-LT.rc | 1 + .../games/solitaire/lang/nl-NL.rc | 1 + .../games/solitaire/lang/no-NO.rc | 1 + .../games/solitaire/lang/pl-PL.rc | 1 + .../games/solitaire/lang/pt-BR.rc | 1 + .../games/solitaire/lang/ro-RO.rc | 1 + .../games/solitaire/lang/ru-RU.rc | 1 + .../games/solitaire/lang/sk-SK.rc | 1 + .../games/solitaire/lang/sq-AL.rc | 1 + .../games/solitaire/lang/sv-SE.rc | 1 + .../games/solitaire/lang/th-TH.rc | 1 + .../games/solitaire/lang/tr-TR.rc | 1 + .../games/solitaire/lang/uk-UA.rc | 1 + .../games/solitaire/lang/zh-CN.rc | 1 + .../games/solitaire/lang/zh-TW.rc | 1 + base/applications/games/solitaire/resource.h | 11 +- .../games/solitaire/solcreate.cpp | 2 - base/applications/games/solitaire/solgame.cpp | 50 ++++- .../games/solitaire/solitaire.cpp | 20 +- base/applications/games/solitaire/solitaire.h | 7 + base/applications/games/solitaire/solundo.cpp | 171 ++++++++++++++++++ 37 files changed, 276 insertions(+), 16 deletions(-) create mode 100644 base/applications/games/solitaire/solundo.cpp diff --git a/base/applications/games/solitaire/CMakeLists.txt b/base/applications/games/solitaire/CMakeLists.txt index a0f083774ad..a229418320a 100644 --- a/base/applications/games/solitaire/CMakeLists.txt +++ b/base/applications/games/solitaire/CMakeLists.txt @@ -2,6 +2,7 @@ list(APPEND SOURCE solcreate.cpp solgame.cpp + solundo.cpp solitaire.cpp solitaire.h) diff --git a/base/applications/games/solitaire/lang/bg-BG.rc b/base/applications/games/solitaire/lang/bg-BG.rc index a19f9edf2cf..2b8a79bf8b5 100644 --- a/base/applications/games/solitaire/lang/bg-BG.rc +++ b/base/applications/games/solitaire/lang/bg-BG.rc @@ -71,6 +71,7 @@ BEGIN BEGIN MENUITEM "&Раздаване\tF2", IDM_GAME_NEW MENUITEM SEPARATOR + MENUITEM "&Undo", IDM_GAME_UNDO, GRAYED MENUITEM "&Тесте...", IDM_GAME_DECK MENUITEM "&Настройки...", IDM_GAME_OPTIONS MENUITEM SEPARATOR diff --git a/base/applications/games/solitaire/lang/ca-ES.rc b/base/applications/games/solitaire/lang/ca-ES.rc index 1a8a0d1f68f..231eb5589b3 100644 --- a/base/applications/games/solitaire/lang/ca-ES.rc +++ b/base/applications/games/solitaire/lang/ca-ES.rc @@ -71,6 +71,7 @@ BEGIN BEGIN MENUITEM "R&eparteix\tF2", IDM_GAME_NEW MENUITEM SEPARATOR + MENUITEM "&Undo", IDM_GAME_UNDO, GRAYED MENUITEM "&Barallar...", IDM_GAME_DECK MENUITEM "&Opcions...", IDM_GAME_OPTIONS MENUITEM SEPARATOR diff --git a/base/applications/games/solitaire/lang/cs-CZ.rc b/base/applications/games/solitaire/lang/cs-CZ.rc index 58060af83ad..bb61acd6295 100644 --- a/base/applications/games/solitaire/lang/cs-CZ.rc +++ b/base/applications/games/solitaire/lang/cs-CZ.rc @@ -69,6 +69,7 @@ BEGIN BEGIN MENUITEM "&Rozdat\tF2", IDM_GAME_NEW MENUITEM SEPARATOR + MENUITEM "&Undo", IDM_GAME_UNDO, GRAYED MENUITEM "Rub& karet...", IDM_GAME_DECK MENUITEM "&Možnosti...", IDM_GAME_OPTIONS MENUITEM SEPARATOR diff --git a/base/applications/games/solitaire/lang/de-DE.rc b/base/applications/games/solitaire/lang/de-DE.rc index 331096f604a..3211c65648b 100644 --- a/base/applications/games/solitaire/lang/de-DE.rc +++ b/base/applications/games/solitaire/lang/de-DE.rc @@ -71,6 +71,7 @@ BEGIN BEGIN MENUITEM "&Karten geben\t F2", IDM_GAME_NEW MENUITEM SEPARATOR + MENUITEM "&Undo", IDM_GAME_UNDO, GRAYED MENUITEM "&Deckblatt...", IDM_GAME_DECK MENUITEM "&Optionen...", IDM_GAME_OPTIONS MENUITEM SEPARATOR diff --git a/base/applications/games/solitaire/lang/el-GR.rc b/base/applications/games/solitaire/lang/el-GR.rc index 7dbaa6e8450..08707ffce52 100644 --- a/base/applications/games/solitaire/lang/el-GR.rc +++ b/base/applications/games/solitaire/lang/el-GR.rc @@ -71,6 +71,7 @@ BEGIN BEGIN MENUITEM "&Deal\tF2", IDM_GAME_NEW MENUITEM SEPARATOR + MENUITEM "&Undo", IDM_GAME_UNDO, GRAYED MENUITEM "De&ck...", IDM_GAME_DECK MENUITEM "&Επιλογές...", IDM_GAME_OPTIONS MENUITEM SEPARATOR diff --git a/base/applications/games/solitaire/lang/en-US.rc b/base/applications/games/solitaire/lang/en-US.rc index 46abfe30d90..b8111ee7e2b 100644 --- a/base/applications/games/solitaire/lang/en-US.rc +++ b/base/applications/games/solitaire/lang/en-US.rc @@ -71,6 +71,7 @@ BEGIN BEGIN MENUITEM "&Deal\tF2", IDM_GAME_NEW MENUITEM SEPARATOR + MENUITEM "&Undo", IDM_GAME_UNDO, GRAYED MENUITEM "De&ck...", IDM_GAME_DECK MENUITEM "&Options...", IDM_GAME_OPTIONS MENUITEM SEPARATOR diff --git a/base/applications/games/solitaire/lang/es-ES.rc b/base/applications/games/solitaire/lang/es-ES.rc index 3a3222a558f..16d1944faa8 100644 --- a/base/applications/games/solitaire/lang/es-ES.rc +++ b/base/applications/games/solitaire/lang/es-ES.rc @@ -73,6 +73,7 @@ BEGIN BEGIN MENUITEM "&Repartir\tF2", IDM_GAME_NEW MENUITEM SEPARATOR + MENUITEM "&Undo", IDM_GAME_UNDO, GRAYED MENUITEM "&Barajas...", IDM_GAME_DECK MENUITEM "&Opciones...", IDM_GAME_OPTIONS MENUITEM SEPARATOR diff --git a/base/applications/games/solitaire/lang/eu-ES.rc b/base/applications/games/solitaire/lang/eu-ES.rc index 8a3c97956b4..064f283d75e 100644 --- a/base/applications/games/solitaire/lang/eu-ES.rc +++ b/base/applications/games/solitaire/lang/eu-ES.rc @@ -71,6 +71,7 @@ BEGIN BEGIN MENUITEM "&Banatu\tF2", IDM_GAME_NEW MENUITEM SEPARATOR + MENUITEM "&Undo", IDM_GAME_UNDO, GRAYED MENUITEM "&Barajak...", IDM_GAME_DECK MENUITEM "&Aukerak...", IDM_GAME_OPTIONS MENUITEM SEPARATOR diff --git a/base/applications/games/solitaire/lang/fr-FR.rc b/base/applications/games/solitaire/lang/fr-FR.rc index f1f874719cd..2f81611d373 100644 --- a/base/applications/games/solitaire/lang/fr-FR.rc +++ b/base/applications/games/solitaire/lang/fr-FR.rc @@ -71,6 +71,7 @@ BEGIN BEGIN MENUITEM "&Donne\tF2", IDM_GAME_NEW MENUITEM SEPARATOR + MENUITEM "&Undo", IDM_GAME_UNDO, GRAYED MENUITEM "&Jeux...", IDM_GAME_DECK MENUITEM "&Options...", IDM_GAME_OPTIONS MENUITEM SEPARATOR diff --git a/base/applications/games/solitaire/lang/he-IL.rc b/base/applications/games/solitaire/lang/he-IL.rc index 49129736df4..dda42542783 100644 --- a/base/applications/games/solitaire/lang/he-IL.rc +++ b/base/applications/games/solitaire/lang/he-IL.rc @@ -73,6 +73,7 @@ BEGIN BEGIN MENUITEM "&חלק\tF2", IDM_GAME_NEW MENUITEM SEPARATOR + MENUITEM "&Undo", IDM_GAME_UNDO, GRAYED MENUITEM "ח&פיסה...", IDM_GAME_DECK MENUITEM "&אפשרויות", IDM_GAME_OPTIONS MENUITEM SEPARATOR diff --git a/base/applications/games/solitaire/lang/hu-HU.rc b/base/applications/games/solitaire/lang/hu-HU.rc index 2dad6759ef1..13633305d71 100644 --- a/base/applications/games/solitaire/lang/hu-HU.rc +++ b/base/applications/games/solitaire/lang/hu-HU.rc @@ -71,6 +71,7 @@ BEGIN BEGIN MENUITEM "&Osztás\tF2", IDM_GAME_NEW MENUITEM SEPARATOR + MENUITEM "&Visszavonás", IDM_GAME_UNDO, GRAYED MENUITEM "&Hátlap...", IDM_GAME_DECK MENUITEM "&Beállítások...", IDM_GAME_OPTIONS MENUITEM SEPARATOR diff --git a/base/applications/games/solitaire/lang/id-ID.rc b/base/applications/games/solitaire/lang/id-ID.rc index a2af672ed89..b877e5ae7a1 100644 --- a/base/applications/games/solitaire/lang/id-ID.rc +++ b/base/applications/games/solitaire/lang/id-ID.rc @@ -71,6 +71,7 @@ BEGIN BEGIN MENUITEM "&Main Baru\tF2", IDM_GAME_NEW MENUITEM SEPARATOR + MENUITEM "&Undo", IDM_GAME_UNDO, GRAYED MENUITEM "&Dek...", IDM_GAME_DECK MENUITEM "&Pilihan...", IDM_GAME_OPTIONS MENUITEM SEPARATOR diff --git a/base/applications/games/solitaire/lang/it-IT.rc b/base/applications/games/solitaire/lang/it-IT.rc index c767ebff5ea..845f574e154 100644 --- a/base/applications/games/solitaire/lang/it-IT.rc +++ b/base/applications/games/solitaire/lang/it-IT.rc @@ -72,6 +72,7 @@ BEGIN BEGIN MENUITEM "&Dai carte\tF2", IDM_GAME_NEW MENUITEM SEPARATOR + MENUITEM "&Undo", IDM_GAME_UNDO, GRAYED MENUITEM "Maz&zo...", IDM_GAME_DECK MENUITEM "O&pzioni...", IDM_GAME_OPTIONS MENUITEM SEPARATOR diff --git a/base/applications/games/solitaire/lang/ja-JP.rc b/base/applications/games/solitaire/lang/ja-JP.rc index cba2e976ac1..fc8bd2fa945 100644 --- a/base/applications/games/solitaire/lang/ja-JP.rc +++ b/base/applications/games/solitaire/lang/ja-JP.rc @@ -70,6 +70,7 @@ BEGIN BEGIN MENUITEM "カードを配る(&D)\tF2", IDM_GAME_NEW MENUITEM SEPARATOR + MENUITEM "&Undo", IDM_GAME_UNDO, GRAYED MENUITEM "カードの装飾(&C)...", IDM_GAME_DECK MENUITEM "オプション(&O)...", IDM_GAME_OPTIONS MENUITEM SEPARATOR diff --git a/base/applications/games/solitaire/lang/ko-KR.rc b/base/applications/games/solitaire/lang/ko-KR.rc index b59f7841038..5c16be49a6b 100644 --- a/base/applications/games/solitaire/lang/ko-KR.rc +++ b/base/applications/games/solitaire/lang/ko-KR.rc @@ -65,6 +65,7 @@ BEGIN BEGIN MENUITEM "새 게임(&D)\tF2", IDM_GAME_NEW MENUITEM SEPARATOR + MENUITEM "&Undo", IDM_GAME_UNDO, GRAYED MENUITEM "덱(&C)...", IDM_GAME_DECK /* FIXME: is 덱 correct? */ MENUITEM "옵션(&O)...", IDM_GAME_OPTIONS MENUITEM SEPARATOR diff --git a/base/applications/games/solitaire/lang/lt-LT.rc b/base/applications/games/solitaire/lang/lt-LT.rc index 38b9219d929..dbb674c3857 100644 --- a/base/applications/games/solitaire/lang/lt-LT.rc +++ b/base/applications/games/solitaire/lang/lt-LT.rc @@ -71,6 +71,7 @@ BEGIN BEGIN MENUITEM "&Dalinti\tF2", IDM_GAME_NEW MENUITEM SEPARATOR + MENUITEM "&Undo", IDM_GAME_UNDO, GRAYED MENUITEM "&Malka...", IDM_GAME_DECK MENUITEM "&Nuostatos...", IDM_GAME_OPTIONS MENUITEM SEPARATOR diff --git a/base/applications/games/solitaire/lang/nl-NL.rc b/base/applications/games/solitaire/lang/nl-NL.rc index d8bed184acd..6e71cd9fc59 100644 --- a/base/applications/games/solitaire/lang/nl-NL.rc +++ b/base/applications/games/solitaire/lang/nl-NL.rc @@ -71,6 +71,7 @@ BEGIN BEGIN MENUITEM "&Delen\tF2", IDM_GAME_NEW MENUITEM SEPARATOR + MENUITEM "&Undo", IDM_GAME_UNDO, GRAYED MENUITEM "&Kaarten...", IDM_GAME_DECK MENUITEM "&Opties...", IDM_GAME_OPTIONS MENUITEM SEPARATOR diff --git a/base/applications/games/solitaire/lang/no-NO.rc b/base/applications/games/solitaire/lang/no-NO.rc index c9c9e259436..79600a528cb 100644 --- a/base/applications/games/solitaire/lang/no-NO.rc +++ b/base/applications/games/solitaire/lang/no-NO.rc @@ -63,6 +63,7 @@ BEGIN BEGIN MENUITEM "&Del ut\tF2", IDM_GAME_NEW MENUITEM SEPARATOR + MENUITEM "&Undo", IDM_GAME_UNDO, GRAYED MENUITEM "Kort&stokk...", IDM_GAME_DECK MENUITEM "&Valg...", IDM_GAME_OPTIONS MENUITEM SEPARATOR diff --git a/base/applications/games/solitaire/lang/pl-PL.rc b/base/applications/games/solitaire/lang/pl-PL.rc index bb046fb80e4..af7615ff881 100644 --- a/base/applications/games/solitaire/lang/pl-PL.rc +++ b/base/applications/games/solitaire/lang/pl-PL.rc @@ -73,6 +73,7 @@ BEGIN BEGIN MENUITEM "&Rozdaj\tF2", IDM_GAME_NEW MENUITEM SEPARATOR + MENUITEM "&Undo", IDM_GAME_UNDO, GRAYED MENUITEM "&Talia...", IDM_GAME_DECK MENUITEM "&Opcje...", IDM_GAME_OPTIONS MENUITEM SEPARATOR diff --git a/base/applications/games/solitaire/lang/pt-BR.rc b/base/applications/games/solitaire/lang/pt-BR.rc index b51054578cb..6f8563bc8a2 100644 --- a/base/applications/games/solitaire/lang/pt-BR.rc +++ b/base/applications/games/solitaire/lang/pt-BR.rc @@ -65,6 +65,7 @@ BEGIN BEGIN MENUITEM "&Novo Jogo\tF2", IDM_GAME_NEW MENUITEM SEPARATOR + MENUITEM "&Undo", IDM_GAME_UNDO, GRAYED MENUITEM "Baralho...", IDM_GAME_DECK MENUITEM "&Opções...", IDM_GAME_OPTIONS MENUITEM SEPARATOR diff --git a/base/applications/games/solitaire/lang/ro-RO.rc b/base/applications/games/solitaire/lang/ro-RO.rc index fdffea90cae..4e14430b7a2 100644 --- a/base/applications/games/solitaire/lang/ro-RO.rc +++ b/base/applications/games/solitaire/lang/ro-RO.rc @@ -73,6 +73,7 @@ BEGIN BEGIN MENUITEM "Rundă &nouă\tF2", IDM_GAME_NEW MENUITEM SEPARATOR + MENUITEM "&Undo", IDM_GAME_UNDO, GRAYED MENUITEM "Culoare &dorsală…", IDM_GAME_DECK MENUITEM "&Opțiuni…", IDM_GAME_OPTIONS MENUITEM SEPARATOR diff --git a/base/applications/games/solitaire/lang/ru-RU.rc b/base/applications/games/solitaire/lang/ru-RU.rc index 3e97b0c859e..047ce7487f8 100644 --- a/base/applications/games/solitaire/lang/ru-RU.rc +++ b/base/applications/games/solitaire/lang/ru-RU.rc @@ -65,6 +65,7 @@ BEGIN BEGIN MENUITEM "Н&овая игра\tF2", IDM_GAME_NEW MENUITEM SEPARATOR + MENUITEM "&Undo", IDM_GAME_UNDO, GRAYED MENUITEM "&Обложки...", IDM_GAME_DECK MENUITEM "&Настройки...", IDM_GAME_OPTIONS MENUITEM SEPARATOR diff --git a/base/applications/games/solitaire/lang/sk-SK.rc b/base/applications/games/solitaire/lang/sk-SK.rc index 69f57b46f90..11a33849c43 100644 --- a/base/applications/games/solitaire/lang/sk-SK.rc +++ b/base/applications/games/solitaire/lang/sk-SK.rc @@ -72,6 +72,7 @@ BEGIN BEGIN MENUITEM "&Rozdať\tF2", IDM_GAME_NEW MENUITEM SEPARATOR + MENUITEM "&Undo", IDM_GAME_UNDO, GRAYED MENUITEM "&Balíček...", IDM_GAME_DECK MENUITEM "&Možnosti...", IDM_GAME_OPTIONS MENUITEM SEPARATOR diff --git a/base/applications/games/solitaire/lang/sq-AL.rc b/base/applications/games/solitaire/lang/sq-AL.rc index 1e2f3b00af7..02400e87f51 100644 --- a/base/applications/games/solitaire/lang/sq-AL.rc +++ b/base/applications/games/solitaire/lang/sq-AL.rc @@ -72,6 +72,7 @@ BEGIN BEGIN MENUITEM "&Ndaj Letrat\tF2", IDM_GAME_NEW MENUITEM SEPARATOR + MENUITEM "&Undo", IDM_GAME_UNDO, GRAYED MENUITEM "Pa&ko...", IDM_GAME_DECK MENUITEM "&Opsione...", IDM_GAME_OPTIONS MENUITEM SEPARATOR diff --git a/base/applications/games/solitaire/lang/sv-SE.rc b/base/applications/games/solitaire/lang/sv-SE.rc index c1d15301f1d..d548ee8670f 100644 --- a/base/applications/games/solitaire/lang/sv-SE.rc +++ b/base/applications/games/solitaire/lang/sv-SE.rc @@ -63,6 +63,7 @@ BEGIN BEGIN MENUITEM "&Ge\tF2", IDM_GAME_NEW MENUITEM SEPARATOR + MENUITEM "&Undo", IDM_GAME_UNDO, GRAYED MENUITEM "&Kortlek...", IDM_GAME_DECK MENUITEM "&Alternativ...", IDM_GAME_OPTIONS MENUITEM SEPARATOR diff --git a/base/applications/games/solitaire/lang/th-TH.rc b/base/applications/games/solitaire/lang/th-TH.rc index ebabeab9946..c5e8486224e 100644 --- a/base/applications/games/solitaire/lang/th-TH.rc +++ b/base/applications/games/solitaire/lang/th-TH.rc @@ -71,6 +71,7 @@ BEGIN BEGIN MENUITEM "แ&จกไพ่\tF2", IDM_GAME_NEW MENUITEM SEPARATOR + MENUITEM "&Undo", IDM_GAME_UNDO, GRAYED MENUITEM "แ&ต่งไพ่...", IDM_GAME_DECK MENUITEM "&ตัวเลือก...", IDM_GAME_OPTIONS MENUITEM SEPARATOR diff --git a/base/applications/games/solitaire/lang/tr-TR.rc b/base/applications/games/solitaire/lang/tr-TR.rc index e53de0d0f4f..57ce217bffd 100644 --- a/base/applications/games/solitaire/lang/tr-TR.rc +++ b/base/applications/games/solitaire/lang/tr-TR.rc @@ -72,6 +72,7 @@ BEGIN BEGIN MENUITEM "&Dağıt\tF2", IDM_GAME_NEW MENUITEM SEPARATOR + MENUITEM "&Undo", IDM_GAME_UNDO, GRAYED MENUITEM "D&esteler...", IDM_GAME_DECK MENUITEM "&Seçenekler...", IDM_GAME_OPTIONS MENUITEM SEPARATOR diff --git a/base/applications/games/solitaire/lang/uk-UA.rc b/base/applications/games/solitaire/lang/uk-UA.rc index 299492e8022..c65482340e7 100644 --- a/base/applications/games/solitaire/lang/uk-UA.rc +++ b/base/applications/games/solitaire/lang/uk-UA.rc @@ -71,6 +71,7 @@ BEGIN BEGIN MENUITEM "&Роздати карти\tF2", IDM_GAME_NEW MENUITEM SEPARATOR + MENUITEM "&Undo", IDM_GAME_UNDO, GRAYED MENUITEM "&Колода...", IDM_GAME_DECK MENUITEM "Па&раметри...", IDM_GAME_OPTIONS MENUITEM SEPARATOR diff --git a/base/applications/games/solitaire/lang/zh-CN.rc b/base/applications/games/solitaire/lang/zh-CN.rc index 5487ba8b1ca..18e8a067444 100644 --- a/base/applications/games/solitaire/lang/zh-CN.rc +++ b/base/applications/games/solitaire/lang/zh-CN.rc @@ -71,6 +71,7 @@ BEGIN BEGIN MENUITEM "发牌(&D)\tF2", IDM_GAME_NEW MENUITEM SEPARATOR + MENUITEM "&Undo", IDM_GAME_UNDO, GRAYED MENUITEM "背面图案(&C)...", IDM_GAME_DECK MENUITEM "选项(&O)...", IDM_GAME_OPTIONS MENUITEM SEPARATOR diff --git a/base/applications/games/solitaire/lang/zh-TW.rc b/base/applications/games/solitaire/lang/zh-TW.rc index ff8c2410ed8..8cc1aa8225b 100644 --- a/base/applications/games/solitaire/lang/zh-TW.rc +++ b/base/applications/games/solitaire/lang/zh-TW.rc @@ -71,6 +71,7 @@ BEGIN BEGIN MENUITEM "發牌(&D)\tF2", IDM_GAME_NEW MENUITEM SEPARATOR + MENUITEM "&Undo", IDM_GAME_UNDO, GRAYED MENUITEM "背面圖案(&C)...", IDM_GAME_DECK MENUITEM "選項(&O)...", IDM_GAME_OPTIONS MENUITEM SEPARATOR diff --git a/base/applications/games/solitaire/resource.h b/base/applications/games/solitaire/resource.h index 0b221bc4f9c..680ec9fbb51 100644 --- a/base/applications/games/solitaire/resource.h +++ b/base/applications/games/solitaire/resource.h @@ -8,11 +8,12 @@ /* Menu */ #define IDM_GAME_NEW 1001 -#define IDM_GAME_DECK 1002 -#define IDM_GAME_OPTIONS 1003 -#define IDM_GAME_EXIT 1004 -#define IDM_HELP_CONTENTS 1005 -#define IDM_HELP_ABOUT 1006 +#define IDM_GAME_UNDO 1002 +#define IDM_GAME_DECK 1003 +#define IDM_GAME_OPTIONS 1004 +#define IDM_GAME_EXIT 1005 +#define IDM_HELP_CONTENTS 1006 +#define IDM_HELP_ABOUT 1007 /* Dialogs */ #define IDD_OPTIONS 1200 diff --git a/base/applications/games/solitaire/solcreate.cpp b/base/applications/games/solitaire/solcreate.cpp index 00d29d856d6..64af9b11ba6 100644 --- a/base/applications/games/solitaire/solcreate.cpp +++ b/base/applications/games/solitaire/solcreate.cpp @@ -5,8 +5,6 @@ CardRegion *pPile; CardRegion *pSuitStack[4]; CardRegion *pRowStack[NUM_ROW_STACKS]; -extern CardStack activepile; - HBITMAP hbmBitmap; HDC hdcBitmap; int yRowStackCardOffset; diff --git a/base/applications/games/solitaire/solgame.cpp b/base/applications/games/solitaire/solgame.cpp index f1322647dba..19219b8f9f4 100644 --- a/base/applications/games/solitaire/solgame.cpp +++ b/base/applications/games/solitaire/solgame.cpp @@ -10,6 +10,7 @@ extern TCHAR MsgWin[128]; extern TCHAR MsgDeal[128]; CardStack activepile; +int VisiblePileCards; int LastId; bool fGameStarted = false; bool bAutoroute = false; @@ -53,6 +54,7 @@ void NewGame(void) deck.NewDeck(); deck.Shuffle(); activepile.Clear(); + VisiblePileCards = 0; //deal to each row stack.. for(i = 0; i < NUM_ROW_STACKS; i++) @@ -85,6 +87,7 @@ void NewGame(void) dwPrevMode = GetScoreMode(); UpdateStatusBar(); + ClearUndo(); TRACE("EXIT NewGame()\n"); @@ -160,6 +163,8 @@ bool CARDLIBPROC RowStackDropProc(CardRegion &stackobj, CardStack &dragcards) fGameStarted = true; + SetUndo(LastId, stackobj.Id(), dragcards.NumCards(), lScore, VisiblePileCards); + if (LastId == PILE_ID) { if (GetScoreMode() == SCORE_STD) @@ -245,6 +250,8 @@ bool CARDLIBPROC SuitStackDropProc(CardRegion &stackobj, CardStack &dragcards) if (b) { + SetUndo(LastId, stackobj.Id(), 1, lScore, VisiblePileCards); + if ((LastId == PILE_ID) || (LastId >= ROW_ID)) { if (GetScoreMode() == SCORE_VEGAS) @@ -300,6 +307,7 @@ void CARDLIBPROC RowStackClickProc(CardRegion &stackobj, int iNumClicked) lScore = lScore + 5; UpdateStatusBar(); } + ClearUndo(); } LastId = stackobj.Id(); @@ -363,6 +371,7 @@ void CARDLIBPROC SuitStackAddProc(CardRegion &stackobj, const CardStack &added) } UpdateStatusBar(); + ClearUndo(); MessageBox(SolWnd, MsgWin, szAppName, MB_OK | MB_ICONINFORMATION); @@ -450,6 +459,22 @@ void CARDLIBPROC PileDblClickProc(CardRegion &stackobj, int iNumClicked) TRACE("EXIT PileDblClickProc()\n"); } +// +// Fix for the 3-card play when only 1 card left on the pile. +// +void FixIfOneCardLeft(void) +{ + // If there is just 1 card left, then modify the + // stack to contain ALL the face-up cards. The effect + // will be, the next time a card is dragged, all the + // previous card-triplets will be available underneath. + if ((dwOptions & OPTION_THREE_CARDS) && pPile->NumCards() == 1) + { + pPile->SetOffsets(0, 0); + pPile->SetCardStack(activepile); + } +} + // // What happens when a card is removed from face-up pile? // @@ -462,16 +487,13 @@ void CARDLIBPROC PileRemoveProc(CardRegion &stackobj, int iItems) //modify our "virtual" pile by removing the same card //that was removed from the physical card stack activepile.Pop(iItems); - - //if there is just 1 card left, then modify the - //stack to contain ALL the face-up cards..the effect - //will be, the next time a card is dragged, all the - //previous card-triplets will be available underneath - if(stackobj.NumCards() == 1) + if ((dwOptions & OPTION_THREE_CARDS) && (VisiblePileCards > 1)) { - stackobj.SetOffsets(0,0); - stackobj.SetCardStack(activepile); + --VisiblePileCards; } + + FixIfOneCardLeft(); + TRACE("EXIT PileRemoveProc()\n"); } @@ -506,10 +528,13 @@ void CARDLIBPROC DeckClickProc(CardRegion &stackobj, int iNumClicked) activepile.Reverse(); cardstack.Push(activepile); activepile.Clear(); + SetUndo(PILE_ID, DECK_ID, cardstack.NumCards(), lScore, VisiblePileCards); + VisiblePileCards = 0; } } else if (GetScoreMode() == SCORE_STD) { + SetUndo(PILE_ID, DECK_ID, activepile.NumCards(), lScore, VisiblePileCards); if ((dwWasteCount >= dwWasteTreshold) && (activepile.NumCards() != 0)) { if (dwOptions & OPTION_THREE_CARDS) @@ -523,6 +548,7 @@ void CARDLIBPROC DeckClickProc(CardRegion &stackobj, int iNumClicked) activepile.Reverse(); cardstack.Push(activepile); activepile.Clear(); + VisiblePileCards = 0; UpdateStatusBar(); } @@ -533,6 +559,8 @@ void CARDLIBPROC DeckClickProc(CardRegion &stackobj, int iNumClicked) activepile.Reverse(); cardstack.Push(activepile); activepile.Clear(); + SetUndo(PILE_ID, DECK_ID, cardstack.NumCards(), lScore, VisiblePileCards); + VisiblePileCards = 0; } dwWasteCount++; @@ -541,6 +569,8 @@ void CARDLIBPROC DeckClickProc(CardRegion &stackobj, int iNumClicked) { int numcards = min((dwOptions & OPTION_THREE_CARDS) ? 3 : 1, cardstack.NumCards()); + SetUndo(DECK_ID, PILE_ID, numcards, lScore, VisiblePileCards); + //make a "visible" copy of these cards CardStack temp; temp = cardstack.Pop(numcards); @@ -553,6 +583,8 @@ void CARDLIBPROC DeckClickProc(CardRegion &stackobj, int iNumClicked) //remove the top 3 from deck activepile.Push(temp); + + VisiblePileCards = numcards; } activepile.Print(); @@ -560,6 +592,8 @@ void CARDLIBPROC DeckClickProc(CardRegion &stackobj, int iNumClicked) pDeck->SetCardStack(cardstack); pPile->SetCardStack(pile); + FixIfOneCardLeft(); + SolWnd.Redraw(); TRACE("EXIT DeckClickProc()\n"); } diff --git a/base/applications/games/solitaire/solitaire.cpp b/base/applications/games/solitaire/solitaire.cpp index 84895cb5701..529f6ba56e9 100644 --- a/base/applications/games/solitaire/solitaire.cpp +++ b/base/applications/games/solitaire/solitaire.cpp @@ -12,6 +12,7 @@ DWORD dwAppStartTime; HWND hwndMain; HWND hwndStatus; HINSTANCE hInstance; +HMENU hGameMenu; TCHAR szAppName[128]; TCHAR szScore[64]; @@ -178,6 +179,18 @@ void SetPlayTimer(void) } } +void SetUndoMenuState(bool enable) +{ + if (enable) + { + EnableMenuItem(hGameMenu, IDM_GAME_UNDO, MF_BYCOMMAND | MF_ENABLED); + } + else + { + EnableMenuItem(hGameMenu, IDM_GAME_UNDO, MF_BYCOMMAND | MF_GRAYED); + } +} + // // Main entry point // @@ -248,6 +261,8 @@ int WINAPI _tWinMain(HINSTANCE hInst, HINSTANCE hPrev, LPTSTR szCmdLine, int iCm hwndMain = hwnd; + hGameMenu = GetSubMenu(GetMenu(hwndMain), 0); + UpdateStatusBar(); ShowWindow(hwnd, iCmdShow); @@ -706,6 +721,10 @@ LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) NewGame(); return 0; + case IDM_GAME_UNDO: + Undo(); + return 0; + case IDM_GAME_DECK: ShowDeckOptionsDlg(hwnd); return 0; @@ -753,4 +772,3 @@ LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) } - diff --git a/base/applications/games/solitaire/solitaire.h b/base/applications/games/solitaire/solitaire.h index 9905ec51a9a..2254b7abb58 100644 --- a/base/applications/games/solitaire/solitaire.h +++ b/base/applications/games/solitaire/solitaire.h @@ -54,15 +54,18 @@ void NewGame(void); #define Y_BORDERWITHFRAME 20 #define Y_ROWSTACK_BORDER 32 extern int yRowStackCardOffset; +extern int VisiblePileCards; extern CardRegion *pDeck; extern CardRegion *pPile; extern CardRegion *pSuitStack[]; extern CardRegion *pRowStack[]; +extern CardStack activepile; extern void UpdateStatusBar(void); extern void SetPlayTimer(void); extern int GetScoreMode(void); +extern void SetUndoMenuState(bool enable); bool CARDLIBPROC RowStackDragProc(CardRegion &stackobj, int iNumCards); bool CARDLIBPROC RowStackDropProc(CardRegion &stackobj, CardStack &dragcards); @@ -80,5 +83,9 @@ void CARDLIBPROC PileClickProc(CardRegion &stackobj, int iNumClicked); void CARDLIBPROC PileRemoveProc(CardRegion &stackobj, int iRemoved); +void SetUndo(int set_source_id, int set_destination_id, int set_number_of_cards, int set_prev_score, int set_prev_visible_pile_cards); +void ClearUndo(void); +void Undo(void); + #endif /* _SOL_PCH_ */ diff --git a/base/applications/games/solitaire/solundo.cpp b/base/applications/games/solitaire/solundo.cpp new file mode 100644 index 00000000000..ef509255889 --- /dev/null +++ b/base/applications/games/solitaire/solundo.cpp @@ -0,0 +1,171 @@ +/* + * PROJECT: Solitaire + * LICENSE: See COPYING in top level directory + * FILE: base/applications/games/solitaire/solundo.cpp + * PURPOSE: Undo module for Solitaire + * PROGRAMMER: Tibor Lajos Füzi + */ + +#include "solitaire.h" + +// source_id and destination_id store the source and destination of the cards +// that were moved. These ids are defined in solitaire.h and can be DECK_ID, PILE_ID, +// [SUIT_ID..SUIT_ID + 3], [ROW_ID..ROW_ID + NUM_ROW_STACKS - 1]. +// -1 means that there is no action stored in the undo module. +static int source_id = -1; +static int destination_id = -1; + +// Number of cards that were moved. +static int number_of_cards = 0; + +// The score before the action was taken. +static int prev_score = 0; + +// The number of visible pile cards before the action was taken. +static int prev_visible_pile_cards = 0; + +void SetUndo( + int set_source_id, + int set_destination_id, + int set_number_of_cards, + int set_prev_score, + int set_prev_visible_pile_cards) +{ + if ((set_source_id == set_destination_id) || (set_number_of_cards == 0)) + return; + + source_id = set_source_id; + destination_id = set_destination_id; + number_of_cards = set_number_of_cards; + prev_score = set_prev_score; + prev_visible_pile_cards = set_prev_visible_pile_cards; + SetUndoMenuState(true); +} + +void ClearUndo(void) +{ + source_id = -1; + destination_id = -1; + number_of_cards = 0; + SetUndoMenuState(false); +} + +void Undo(void) +{ + CardRegion *source = NULL; + CardRegion *destination = NULL; + + if ((source_id < 1) || + (source_id > (ROW_ID + NUM_ROW_STACKS - 1)) || + (destination_id < 1) || + (destination_id > (ROW_ID + NUM_ROW_STACKS - 1)) || + (number_of_cards < 1)) + { + ClearUndo(); + return; + } + + if (source_id >= ROW_ID) + source = pRowStack[source_id - ROW_ID]; + else if ((source_id >= SUIT_ID) && (source_id < SUIT_ID + 4)) + source = pSuitStack[source_id - SUIT_ID]; + else if (source_id == PILE_ID) + source = pPile; + else if (source_id == DECK_ID) + source = pDeck; + + if (destination_id >= ROW_ID) + destination = pRowStack[destination_id - ROW_ID]; + else if ((destination_id >= SUIT_ID) && (destination_id < SUIT_ID + 4)) + destination = pSuitStack[destination_id - SUIT_ID]; + else if (destination_id == PILE_ID) + destination = pPile; + else if (destination_id == DECK_ID) + destination = pDeck; + + if (destination == NULL || source == NULL) + { + ClearUndo(); + return; + } + + // If the player clicked on the deck. + if (destination == pPile && source == pDeck) + { + // Put back the cards on the deck in reversed order. + CardStack tmp = activepile.Pop(number_of_cards); + tmp.Reverse(); + source->Push(tmp); + // Restore the pile to be the top cards in the active pile. + destination->Clear(); + if (prev_visible_pile_cards <= 1) + { + destination->SetOffsets(0,0); + destination->SetCardStack(activepile); + } + else + { + tmp = activepile.Top(prev_visible_pile_cards); + destination->SetOffsets(CS_DEFXOFF, 1); + destination->Push(tmp); + } + VisiblePileCards = prev_visible_pile_cards; + } + + // If the player clicked on the empty deck. + else if (source == pPile && destination == pDeck) + { + // Put back all the cards from the deck to the active pile in reversed order. + destination->Reverse(); + activepile.Push(destination->GetCardStack()); + destination->Clear(); + if (prev_visible_pile_cards <= 1) + { + source->SetOffsets(0,0); + source->SetCardStack(activepile); + } + else + { + CardStack tmp = activepile.Top(prev_visible_pile_cards); + source->SetOffsets(CS_DEFXOFF, 1); + source->Push(tmp); + } + VisiblePileCards = prev_visible_pile_cards; + } + + // If the player moved one card from the pile. + else if (source == pPile) + { + CardStack tmp = destination->Pop(1); + activepile.Push(tmp); + if (prev_visible_pile_cards <= 1) + { + source->Push(tmp); + } + else + { + source->Clear(); + tmp = activepile.Top(prev_visible_pile_cards); + source->Push(tmp); + source->SetOffsets(CS_DEFXOFF, 1); + } + VisiblePileCards = prev_visible_pile_cards; + } + + // If the player moved cards between row stacks / suit stacks. + else + { + destination->MoveCard(source, number_of_cards, false); + } + + lScore = prev_score; + + // -2 points for the undo in standard score mode. + if (GetScoreMode() == SCORE_STD) + lScore = lScore >= 2 ? lScore - 2 : 0; + + UpdateStatusBar(); + + SolWnd.Redraw(); + ClearUndo(); +}