ScummVM API documentation
scopapuzzle.h
1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program. If not, see <http://www.gnu.org/licenses/>.
19  *
20  */
21 
22 #ifndef NANCY_ACTION_SCOPAPUZZLE_H
23 #define NANCY_ACTION_SCOPAPUZZLE_H
24 
25 #include "graphics/font.h"
26 
27 #include "engines/nancy/commontypes.h"
28 #include "engines/nancy/action/puzzlerecord.h"
29 
30 namespace Nancy {
31 namespace Action {
32 
33 // Scopa is the Italian card game Nancy plays against Enrico in Nancy18. Each
34 // player holds three cards and four lie on the table. A card either takes table
35 // cards that add up to its value or is left on the table, and taking the last
36 // cards of the table is a "scopa". Once the deck runs out the round is scored:
37 // most cards, most coins, the seven of coins, the best "primes" and one point
38 // per scopa.
39 //
40 // The record plays one round and then ends, with an event flag telling whether
41 // somebody has won the match. The points are kept under the puzzle's name for
42 // the next round.
43 //
44 // The cards lie in numbered piles, and get from one to another through a queue
45 // of moves. A card doesn't travel: it fades out where it was and in where it
46 // goes, and a pile without places of its own leaves the card where it is.
47 class ScopaPuzzle : public PuzzleRecord {
48 public:
49  ScopaPuzzle() : PuzzleRecord(7) {}
50  virtual ~ScopaPuzzle() {}
51 
52  void init() override;
53 
54  void readData(Common::SeekableReadStream &stream) override;
55  void execute() override;
56  void handleInput(NancyInput &input) override;
57 
58  bool isViewportRelative() const override { return true; }
59 
60 protected:
61  Common::String getRecordTypeName() const override { return "ScopaPuzzle"; }
62 
63  static const uint kNumPlayers = 2;
64 
65  enum { kHuman = 0, kOpponent = 1 };
66 
67  // A player's piles follow each other: hand, taken, trick
68  enum Pile {
69  kHumanHand = 0,
70  kHumanTaken = 1,
71  kHumanTrick = 2, // taken since the last deal
72  kOpponentHand = 3,
73  kOpponentTaken = 4,
74  kOpponentTrick = 5,
75  kDeck = 6,
76  kTable = 7,
77  kLaidOut = 8, // a player's cards, shown for the scoring
78  kPrimes = 9, // the best card of every suit, of both players
79  kNumPiles = 10,
80  kPrimeValues = 10, // only places, for the numbers next to those cards
81  kNumSlotLists = 11
82  };
83 
84  enum CardMode {
85  kFaceUp = 0,
86  kFaceDown = 1,
87  kHidden = 2,
88  kHighlighted = 3
89  };
90 
91  enum Phase {
92  kDeal,
93  kDealing,
94  kPlaying,
95  kTally,
96  kScorePlayers,
97  kScorePrimes
98  };
99 
100  // The cards a line of the scoring is about
101  enum Highlight {
102  kAllCards,
103  kCoinCards,
104  kSevenOfCoinsCard
105  };
106 
107  // Why a play isn't allowed
108  enum PlayError {
109  kPlayAllowed,
110  kWrongSum, // the cards don't add up to the card played
111  kHasToTake, // a card that can take something may not be left on the table
112  kHasToTakeOneCard // a single card of the same value comes before several
113  };
114 
115  // The lines a player has, in the order of the data
116  enum PlayerSound {
117  kSoundScopa,
118  kSoundLastCardsLong,
119  kSoundLastCards,
120  kSoundMostCards,
121  kSoundMostCoins,
122  kSoundSevenOfCoins,
123  kSoundBestPrimes,
124  kSoundNoPoints,
125  kSoundWin,
126  kNumPlayerSounds
127  };
128 
129  // Something that shows up and goes away over a set time
130  struct Fader {
131  uint32 fadeInTime = 0;
132  uint32 fadeOutTime = 0;
133  bool isShown = false;
134  bool isFading = false;
135  float alpha = 0.0f;
136  uint32 lastTime = 0;
137 
138  void show(bool instantly);
139  void hide(bool instantly);
140  float update();
141  bool isVisible() { return update() > 0.0f; }
142  };
143 
144  struct CardState {
145  CardMode mode = kHidden;
146  Common::Rect rect;
147  Fader fader;
148  };
149 
150  // The state a card had before stays on screen until it has faded away
151  struct Card {
152  CardState current;
153  CardState previous;
154 
155  bool isFading();
156  };
157 
158  static const int32 kWaitForCard = -1;
159 
160  struct Move {
161  int srcPile = 0;
162  uint srcIndex = 0;
163  int32 delay = 0; // until the next move, in milliseconds
164  int dstPile = 0;
165  CardMode mode = kFaceUp;
166  };
167 
168  // What holds up the game. A player can get points once it is over.
169  struct Wait {
170  enum Type { kCard, kTime, kSound };
171 
172  Type type = kTime;
173  int card = -1;
174  uint32 endTime = 0;
175  SoundDescription sound;
176  int player = -1;
177  int32 points = 0;
178  };
179 
180  struct Player {
181  // -- File data --
182  uint16 cursor = 0;
183  int16 winFlag = -1;
184  int16 nextStarterFlag = -1; // set after a round the other player started
185  Common::Rect pileSrc;
186  Common::Rect pileDest;
187  Common::Rect pointsRect;
188  int32 fontID = 0;
189  int32 colorID = 0;
190  RandomSoundBlock sounds[kNumPlayerSounds];
191 
192  // -- Runtime --
193  int32 points = 0;
194  int32 numScopas = 0;
195  Fader pileFader;
196 
197  // What the cards taken in the round come to
198  int32 numCards = 0;
199  int32 numCoins = 0;
200  int32 primes = 0;
201  Common::Array<int> bestPrimeCards; // by suit, -1 for none
202  bool hasScoreLine = false;
203  bool scoresMostCards = false;
204  bool scoresMostCoins = false;
205  bool scoresSevenOfCoins = false;
206  bool scoresPrimes = false;
207  };
208 
209  struct Play {
210  int card = -1; // from the hand
211  uint handIndex = 0;
212  Common::Array<uint> taken; // places on the table, in order
213  int worth = 0;
214  };
215 
216  static void readPlayer(Common::SeekableReadStream &stream, Player &player);
217  static void readSlots(Common::SeekableReadStream &stream, Common::Array<Common::Rect> &slots);
218 
219  static int getHandPile(uint playerID) { return playerID * 3; }
220  static int getTakenPile(uint playerID) { return playerID * 3 + 1; }
221  static int getTrickPile(uint playerID) { return playerID * 3 + 2; }
222  static bool hasFixedPlaces(int pile);
223 
224  uint getOtherPlayer(uint playerID) const { return (playerID + 1) % kNumPlayers; }
225  uint countCards(int pile) const;
226 
227  // Card moves and what the game waits for
228  void setCardState(int cardID, CardMode mode, const Common::Rect &rect);
229  void setCardMode(int cardID, CardMode mode);
230  int doMove(const Move &move);
231  void queueMove(int srcPile, uint srcIndex, int32 delay, int dstPile, CardMode mode);
232  bool runMoves();
233  bool updateWaits();
234  void waitForTime(uint32 time, int player = -1, int32 points = 0);
235  void waitForSound(const RandomSoundBlock &sound, int player = -1, int32 points = 0);
236  void startDealSound();
237  void stopDealSound();
238 
239  // The game
240  void runPhase();
241  void dealCards();
242  void startTurn();
243  void switchPlayer();
244  PlayError checkPlay(const Play &play) const;
245  void findPlays(Common::Array<Play> &plays) const;
246  void makePlay(const Play &play);
247  void afterPlay();
248  void moveTricksToTaken();
249  void takeLastCards();
250  void showPilePictures(bool show);
251  void updateButtons();
252 
253  // The scoring
254  void tallyPlayer(Player &player, int takenPile);
255  void tallyRound();
256  void layOutTakenCards(uint playerID);
257  void highlightLaidOutCards(Highlight highlight);
258  void movePrimes(uint playerID);
259  bool scorePlayerStep();
260  bool scorePrimesStep();
261  void finishRound();
262 
263  void findSelectedCards(int pile, Common::Array<uint> &indices) const;
264  int getHoveredCard(int pile, const Common::Point &pos) const;
265  void clickCard(int pile, uint index);
266  void tryPlay(bool sayWhyNotToDiscard);
267 
268  void blendPixel(int x, int y, byte a, byte r, byte g, byte b);
269  void blitFaded(const Graphics::ManagedSurface &image, const Common::Rect &src, const Common::Point &dest, uint32 argb, float alpha);
270  void drawCardState(int cardID, CardState &state);
271  void drawText(const Common::String &text, const Common::Rect &rect, uint fontID, uint colorID, Graphics::TextAlign align);
272  void redraw();
273 
274  // -- File data --
275  Common::String _saveName;
276  int32 _pointsToWin = 0;
277  int16 _roundOverFlag = -1;
278  int16 _redealFlag = -1;
279  int32 _primesFontID = 0;
280  int32 _primesColorID = 0;
281  Player _players[kNumPlayers];
282  Common::Rect _takeSrc;
283  Common::Rect _takeDest;
284  Common::Rect _discardSrc;
285  Common::Rect _discardDest;
286  int32 _thinkTime = 0; // in milliseconds
287  int32 _dealTime = 0;
288  int32 _layOutTime = 0;
289  RandomSoundBlock _dealSound;
290  RandomSoundBlock _discardSound;
291  RandomSoundBlock _takeSound;
292  RandomSoundBlock _wrongSumSound;
293  RandomSoundBlock _hasToTakeSound;
294  RandomSoundBlock _hasToTakeOneCardSound;
295  RandomSoundBlock _noLastScopaSound;
296  RandomSoundBlock _primesSound;
297  RandomSoundBlock _primesTieSound;
298  RandomSoundBlock _scopasSound;
299  Common::Array<Common::Rect> _slots[kNumSlotLists];
300  Common::Path _cardsImageName;
301  int32 _fadeInTime = 0;
302  int32 _fadeOutTime = 0;
303  uint32 _highlightColor = 0; // ARGB
304  Common::Rect _cardBackSrc;
305  Common::Array<Common::Rect> _cardSrcs;
306 
307  // -- Runtime --
308  Graphics::ManagedSurface _cardsImage;
309  Common::Array<Card> _cards;
310  Common::Array<int> _piles[kNumPiles]; // card ids, -1 for a place that got empty
311  Common::Array<Move> _moves;
312  Common::Array<Wait> _waits;
313 
314  Phase _phase = kDeal;
315  bool _isBusy = true;
316  uint _starter = kHuman;
317  uint _currentPlayer = kHuman;
318  int _lastTaker = -1;
319  bool _needsRedeal = false;
320  bool _hasCheckedScopa = false;
321  bool _hasSaidLastCardsLong = false;
322  bool _hasSaidNoLastScopa = false;
323  bool _showsPrimes = false;
324  bool _showsPrimeTotals = false;
325 
326  bool _showsTake = false;
327  bool _showsDiscard = false;
328  Fader _takeFader;
329  Fader _discardFader;
330 
331  SoundDescription _playingDealSound;
332  SoundDescription _errorSound;
333  bool _hasChanged = true;
334  bool _isFading = false;
335 };
336 
337 } // End of namespace Action
338 } // End of namespace Nancy
339 
340 #endif // NANCY_ACTION_SCOPAPUZZLE_H
Definition: managed_surface.h:51
Definition: str.h:59
TextAlign
Definition: font.h:48
Definition: scopapuzzle.h:209
Definition: scopapuzzle.h:160
Definition: scopapuzzle.h:47
Definition: scopapuzzle.h:151
Definition: rect.h:536
Definition: path.h:52
Definition: stream.h:745
Definition: input.h:41
Definition: scopapuzzle.h:180
Definition: scopapuzzle.h:144
Definition: commontypes.h:324
Definition: scopapuzzle.h:169
Definition: rect.h:144
Out move(In first, In last, Out dst)
Definition: algorithm.h:109
Definition: scopapuzzle.h:130
Definition: puzzlerecord.h:37
Definition: commontypes.h:306
Definition: actionmanager.h:32