1 /*
2  * PROJECT:      Solitaire
3  * LICENSE:      See COPYING in top level directory
4  * FILE:         base/applications/games/solitaire/solundo.cpp
5  * PURPOSE:      Undo module for Solitaire
6  * PROGRAMMER:   Tibor Lajos Füzi
7  */
8 
9 #include "solitaire.h"
10 
11 // source_id and destination_id store the source and destination of the cards
12 // that were moved. These ids are defined in solitaire.h and can be DECK_ID, PILE_ID,
13 // [SUIT_ID..SUIT_ID + 3], [ROW_ID..ROW_ID + NUM_ROW_STACKS - 1].
14 // -1 means that there is no action stored in the undo module.
15 static int source_id = -1;
16 static int destination_id = -1;
17 
18 // Number of cards that were moved.
19 static int number_of_cards = 0;
20 
21 // The score before the action was taken.
22 static int prev_score = 0;
23 
24 // The number of visible pile cards before the action was taken.
25 static int prev_visible_pile_cards = 0;
26 
SetUndo(int set_source_id,int set_destination_id,int set_number_of_cards,int set_prev_score,int set_prev_visible_pile_cards)27 void SetUndo(
28     int set_source_id,
29     int set_destination_id,
30     int set_number_of_cards,
31     int set_prev_score,
32     int set_prev_visible_pile_cards)
33 {
34     if ((set_source_id == set_destination_id) || (set_number_of_cards == 0))
35         return;
36 
37     source_id = set_source_id;
38     destination_id = set_destination_id;
39     number_of_cards = set_number_of_cards;
40     prev_score = set_prev_score;
41     prev_visible_pile_cards = set_prev_visible_pile_cards;
42     SetUndoMenuState(true);
43 }
44 
ClearUndo(void)45 void ClearUndo(void)
46 {
47     source_id = -1;
48     destination_id = -1;
49     number_of_cards = 0;
50     SetUndoMenuState(false);
51 }
52 
Undo(void)53 void Undo(void)
54 {
55     CardRegion *source = NULL;
56     CardRegion *destination = NULL;
57 
58     if ((source_id < 1)                                  ||
59         (source_id > (ROW_ID + NUM_ROW_STACKS - 1))      ||
60         (destination_id < 1)                             ||
61         (destination_id > (ROW_ID + NUM_ROW_STACKS - 1)) ||
62         (number_of_cards < 1))
63     {
64         ClearUndo();
65         return;
66     }
67 
68     if (source_id >= ROW_ID)
69         source = pRowStack[source_id - ROW_ID];
70     else if ((source_id >= SUIT_ID) && (source_id < SUIT_ID + 4))
71         source = pSuitStack[source_id - SUIT_ID];
72     else if (source_id == PILE_ID)
73         source = pPile;
74     else if (source_id == DECK_ID)
75         source = pDeck;
76 
77     if (destination_id >= ROW_ID)
78         destination = pRowStack[destination_id - ROW_ID];
79     else if ((destination_id >= SUIT_ID) && (destination_id < SUIT_ID + 4))
80         destination = pSuitStack[destination_id - SUIT_ID];
81     else if (destination_id == PILE_ID)
82         destination = pPile;
83     else if (destination_id == DECK_ID)
84         destination = pDeck;
85 
86     if (destination == NULL || source == NULL)
87     {
88         ClearUndo();
89         return;
90     }
91 
92     // If the player clicked on the deck.
93     if (destination == pPile && source == pDeck)
94     {
95         // Put back the cards on the deck in reversed order.
96         CardStack tmp = activepile.Pop(number_of_cards);
97         tmp.Reverse();
98         source->Push(tmp);
99         // Restore the pile to be the top cards in the active pile.
100         destination->Clear();
101         if (prev_visible_pile_cards <= 1)
102         {
103             destination->SetOffsets(0,0);
104             destination->SetCardStack(activepile);
105         }
106         else
107         {
108             tmp = activepile.Top(prev_visible_pile_cards);
109             destination->SetOffsets(CS_DEFXOFF, 1);
110             destination->Push(tmp);
111         }
112         VisiblePileCards = prev_visible_pile_cards;
113     }
114 
115     // If the player clicked on the empty deck.
116     else if (source == pPile && destination == pDeck)
117     {
118         // Put back all the cards from the deck to the active pile in reversed order.
119         destination->Reverse();
120         activepile.Push(destination->GetCardStack());
121         destination->Clear();
122         if (prev_visible_pile_cards <= 1)
123         {
124             source->SetOffsets(0,0);
125             source->SetCardStack(activepile);
126         }
127         else
128         {
129             CardStack tmp = activepile.Top(prev_visible_pile_cards);
130             source->SetOffsets(CS_DEFXOFF, 1);
131             source->Push(tmp);
132         }
133         VisiblePileCards = prev_visible_pile_cards;
134     }
135 
136     // If the player moved one card from the pile.
137     else if (source == pPile)
138     {
139         CardStack tmp = destination->Pop(1);
140         activepile.Push(tmp);
141         if (prev_visible_pile_cards <= 1)
142         {
143             source->Push(tmp);
144         }
145         else
146         {
147             source->Clear();
148             tmp = activepile.Top(prev_visible_pile_cards);
149             source->Push(tmp);
150             source->SetOffsets(CS_DEFXOFF, 1);
151         }
152         VisiblePileCards = prev_visible_pile_cards;
153     }
154 
155     // If the player moved cards between row stacks / suit stacks.
156     else
157     {
158         destination->MoveCard(source, number_of_cards, false);
159     }
160 
161     lScore = prev_score;
162 
163     // -2 points for the undo in standard score mode.
164     if (GetScoreMode() == SCORE_STD)
165         lScore = lScore >= 2 ? lScore - 2 : 0;
166 
167     UpdateStatusBar();
168 
169     SolWnd.Redraw();
170     ClearUndo();
171 }
172