ScummVM API documentation
puzzledata.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 #include "common/serializer.h"
23 #include "common/array.h"
24 #include "common/hashmap.h"
25 
26 #include "engines/nancy/commontypes.h"
27 #include "engines/nancy/enginedata.h"
28 
29 #ifndef NANCY_PUZZLEDATA_H
30 #define NANCY_PUZZLEDATA_H
31 
32 namespace Nancy {
33 
34 // The following structs contain persistent data for specific
35 // puzzle types, which is to be stored in savefiles
36 
37 struct PuzzleData {
38  PuzzleData() {}
39  virtual ~PuzzleData() {}
40 
41  virtual void synchronize(Common::Serializer &ser) = 0;
42 };
43 
44 struct SliderPuzzleData : public PuzzleData {
46  virtual ~SliderPuzzleData() {}
47 
48  static constexpr uint32 getTag() { return MKTAG('S', 'L', 'I', 'D'); }
49  virtual void synchronize(Common::Serializer &ser);
50 
51  Common::Array<Common::Array<int16>> playerTileOrder;
52  bool playerHasTriedPuzzle;
53 };
54 
57  virtual ~RippedLetterPuzzleData() {}
58 
59  static constexpr uint32 getTag() { return MKTAG('R', 'I', 'P', 'L'); }
60  virtual void synchronize(Common::Serializer &ser);
61 
62  Common::Array<int8> order;
63  Common::Array<byte> rotations;
64  bool playerHasTriedPuzzle;
65  // Some games (e.g. Nancy7) have multiple instances of the same puzzle in
66  // different scenes, so we need to key the puzzle data by scene ID.
67  uint16 sceneId;
68 
69  // Temporary values, do not save to file
70  int8 pickedUpPieceID = -1;
71  byte pickedUpPieceRot = 0;
72  int pickedUpPieceLastPos = -1;
73 };
74 
75 struct TowerPuzzleData : public PuzzleData {
77  virtual ~TowerPuzzleData() {}
78 
79  static constexpr uint32 getTag() { return MKTAG('T', 'O', 'W', 'R'); }
80  virtual void synchronize(Common::Serializer &ser);
81 
83  bool playerHasTriedPuzzle;
84 };
85 
86 struct RiddlePuzzleData : public PuzzleData {
88  virtual ~RiddlePuzzleData() {}
89 
90  static constexpr uint32 getTag() { return MKTAG('R', 'I', 'D', 'L'); }
91  virtual void synchronize(Common::Serializer &ser);
92 
93  Common::Array<byte> solvedRiddleIDs;
94  int8 incorrectRiddleID;
95 };
96 
99  virtual ~SoundEqualizerPuzzleData() {}
100 
101  static constexpr uint32 getTag() { return MKTAG('S', 'E', 'Q', 'L'); }
102  virtual void synchronize(Common::Serializer &ser);
103 
104  Common::Array<byte> sliderValues;
105 };
106 
107 // Contains a single bool indicating whether the puzzle was solved
108 struct SimplePuzzleData : public PuzzleData {
110  virtual ~SimplePuzzleData() {}
111 
112  virtual void synchronize(Common::Serializer &ser);
113 
114  bool solvedPuzzle;
115 };
116 
118  static constexpr uint32 getTag() { return MKTAG('A', 'S', 'M', 'B'); }
119 };
120 
121 // Placed bead-type ids on the thread.
122 struct BeadPuzzleData : public PuzzleData {
123  BeadPuzzleData() {}
124  virtual ~BeadPuzzleData() {}
125 
126  static constexpr uint32 getTag() { return MKTAG('B', 'E', 'A', 'D'); }
127  virtual void synchronize(Common::Serializer &ser);
128 
129  Common::Array<int16> placedBeads;
130 };
131 
132 // Cached current/solved tile layouts for a SortPuzzle. Each cell is encoded as
133 // 4 consecutive int16s: srcRow, srcCol, value, isEmpty. The first two int16s
134 // of each array are the grid rows and cols.
135 struct SortPuzzleData : public PuzzleData {
136  SortPuzzleData() {}
137  virtual ~SortPuzzleData() {}
138 
139  static constexpr uint32 getTag() { return MKTAG('S', 'O', 'R', 'T'); }
140  virtual void synchronize(Common::Serializer &ser);
141 
142  Common::Array<int16> currentState;
143  Common::Array<int16> solvedState;
144 };
145 
146 // Per-magnet (left, top, right, bottom, locked) packed as 5 int16s. The
147 // puzzle's two scenes (3280, 3281) are the same puzzle with the same data,
148 // so a single flat array suffices.
151  virtual ~MagnetMazePuzzleData() {}
152 
153  static constexpr uint32 getTag() { return MKTAG('M', 'M', 'A', 'Z'); }
154  virtual void synchronize(Common::Serializer &ser);
155 
156  Common::Array<int16> magnetState;
157 };
158 
159 // Nancy10 GridMapPuzzle: per-item (inMap, inItems, mapRow, mapCol, itemsRow,
160 // itemsCol) packed as 6 int16s.
161 // Nancy14 LetterGridPuzzle: the marked column of each row, -1 = unmarked.
162 struct GridMapPuzzleData : public PuzzleData {
163  GridMapPuzzleData() {}
164  virtual ~GridMapPuzzleData() {}
165 
166  static constexpr uint32 getTag() { return MKTAG('G', 'M', 'A', 'P'); }
167  virtual void synchronize(Common::Serializer &ser);
168 
169  Common::Array<int16> itemState;
170 };
171 
172 struct QuizPuzzleData : public PuzzleData {
173  QuizPuzzleData() {}
174  virtual ~QuizPuzzleData() {}
175 
176  static constexpr uint32 getTag() { return MKTAG('Q', 'U', 'I', 'Z'); }
177  virtual void synchronize(Common::Serializer &ser);
178 
179  // Keyed by solve-scene ID so that multiple QuizPuzzle instances
180  // (e.g. a two-page Nancy 9 puzzle) each maintain their own state.
183 };
184 
185 struct JournalData : public PuzzleData {
186  JournalData() {}
187  virtual ~JournalData() {}
188 
189  struct Entry {
190  Entry(const Common::String &s = Common::String(), uint16 m = 0, uint16 sc = kNoScene) : stringID(s), mark(m), sceneID(sc) {}
191 
192  Common::String stringID;
193  uint16 mark = 0;
194  uint16 sceneID = kNoScene;
195  };
196 
197  static constexpr uint32 getTag() { return MKTAG('J', 'O', 'U', 'R'); }
198  virtual void synchronize(Common::Serializer &ser);
199 
200  // From Nancy15 every protagonist keeps their own journal, so entries are
201  // always reached through the active player character's slot. Earlier games
202  // have a single character and only ever touch slot 0.
203  Common::Array<Entry> &entries(uint16 surfaceID);
204  bool hasEntries(uint16 surfaceID) const;
205 
206  // Hands the journal of one character to another. Nancy15 seeds a Hardy
207  // boy's journal from his brother's the first time he is played.
208  void inheritEntries(uint from, uint to);
209 
210  Common::HashMap<uint16, Common::Array<Entry>> journalEntries[kMaxPlayerCharacters];
211 
212 private:
213  static void syncOneJournal(Common::Serializer &ser, Common::HashMap<uint16, Common::Array<Entry>> &journal);
214 };
215 
216 // Contains variables that can be read and modified through action records.
217 // Mixes two separate things:
218 // - the exhibit data table in nancy6
219 // - the general variable storage in nancy8 and up
220 // The exhibit data was only ever used in nancy6, so mixing these should be ok.
221 struct TableData : public PuzzleData {
222  TableData();
223  virtual ~TableData() {}
224 
225  static constexpr uint32 getTag() { return MKTAG('T', 'A', 'B', 'L'); }
226  virtual void synchronize(Common::Serializer &ser);
227 
228  void setSingleValue(uint16 index, int16 value);
229  int16 getSingleValue(uint16 index) const;
230 
231  void setComboValue(uint16 index, float value);
232  float getComboValue(uint16 index) const;
233 
234  // The number of single (non-combo) values, i.e. the boundary between the
235  // single-value and combo-value index ranges.
236  uint getNumSingleValues() const;
237  uint getNumComboValues() const;
238 
239  // Index markers used inside SetValueCombo and ValueTest records: an entry
240  // to skip, and an entry whose payload is used as a literal number.
241  byte getNoIndex() const;
242  byte getLiteralIndex() const;
243 
244  // Reads a value by its combined index (single values come first, then combos).
245  // Combo (float) values are rounded to the nearest integer.
246  int16 getValue(uint16 index) const;
247  void setValue(uint16 index, int16 value);
248 
249  Common::Array<int16> singleValues;
250  Common::Array<float> comboValues;
251 };
252 
253 // Nancy 10+ cellphone state mutated by the ChangeCellPhoneInfo,
254 // SetCellPhoneBatteryAndSignal and AddSearchLink action records,
255 // persisted between saves.
256 struct CellPhoneData : public PuzzleData {
257  CellPhoneData() {}
258  virtual ~CellPhoneData() {}
259 
260  static constexpr uint32 getTag() { return MKTAG('C', 'E', 'L', 'L'); }
261  virtual void synchronize(Common::Serializer &ser);
262 
263  bool noSignal = false;
264  bool batteryLow = false;
265  // Loaded set to true once the popup has seeded the contact list from
266  // the UICL chunk; we then own it as runtime data.
267  bool seeded = false;
269 
270  // Populated by AR 131 (AddSearchLink). Mode 0 → emailMessages (each
271  // with a body-text CVTX key + read flag); any non-zero mode →
272  // searchLinks (web search topics).
273  Common::Array<SearchLink> emailMessages;
274  Common::Array<SearchLink> searchLinks;
275 
276 private:
277  void syncLinkArray(Common::Serializer &ser, Common::Array<SearchLink> &arr);
278 };
279 
280 // A cell-phone camera snapshot (Nancy 13). Stored as raw BGRA32 pixels so it
281 // survives save/load independently of the scene it was taken from.
283  uint16 width = 0;
284  uint16 height = 0;
285  Common::Array<byte> pixels; // width * height * 4, BGRA32
286  bool sent = false; // true once the player has "sent" it
287 
288  // Indices into UICL::cameraSubjects that were inside the viewfinder.
289  Common::Array<int16> subjects;
290 };
291 
292 // Nancy 13 camera snapshots. Kept in its own lazily-created PuzzleData chunk so
293 // existing saves and the CELL chunk are untouched (no save-version bump).
296  virtual ~CellPhonePictureData() {}
297 
298  static constexpr uint32 getTag() { return MKTAG('C', 'P', 'I', 'C'); }
299  virtual void synchronize(Common::Serializer &ser);
300 
302 };
303 
304 // Nancy 11+ AR 69 (TimerControl). 10 software timers, each counting up from
305 // zero. In Nancy 11 a "configured" timer (state 5/6) fires a set of event flags,
306 // plays an optional sound and shows an optional caption once its target duration
307 // elapses. From Nancy 12 a running timer instead carries up to kNumTriggers
308 // independent triggers (see ResetAndStartTimer), each firing its own flags and
309 // sound. Started/stopped via ResetAndStartTimer (104) and StopTimer (105), which
310 // in Nancy 11 carry a timer-slot index.
311 struct TimerData : public PuzzleData {
312  // Nancy 12+ per-timer trigger: fires its flags and sound once its target
313  // duration is reached. A one-shot trigger clears the whole timer when it
314  // fires; a repeating one leaves the timer counting.
315  struct Trigger {
316  enum Type { kOneShot = 1, kRepeating = 2 };
317 
318  int32 type = kOneShot;
319  uint32 durationMs = 0;
320  bool hasFired = false;
321  SoundDescription sound;
322  FlagDescription flags[10];
323  };
324 
325  struct Timer {
326  enum State { kIdle = 0, kRunning = 1, kPaused = 2, kOneShot = 5, kRepeating = 6 };
327 
328  int32 state = kIdle;
329  uint32 currentTimeMs = 0;
330  uint32 durationMs = 0;
331  bool hasFired = false;
332  SoundDescription sound;
333  Common::String autotextKey;
334  Common::String caption;
335  FlagDescription flags[10];
336  Common::Array<Trigger> triggers; // Nancy 12+
337 
338  void reset() { *this = Timer(); }
339  };
340 
341  // Nancy11-13 have 10 timers, and Nancy14+ have 20. However, only Nancy15+
342  // save all 20: Nancy14 has 20 timers, but its scripts never use any past
343  // the first 10, so its saves keep storing 10 timers. Since the TimerData chunk isn't
344  // length-prefixed, storing more timers for Nancy14 would break existing
345  // saves unless the savegame version is bumped.
346  static const uint kNumTimers = 20;
347  static const uint kNumSavedTimers = 10; // Timers stored in saves before Nancy15
348  static const uint kNumTriggers = 20;
349 
350  TimerData() {}
351  virtual ~TimerData() {}
352 
353  static constexpr uint32 getTag() { return MKTAG('T', 'M', 'R', 'S'); }
354  virtual void synchronize(Common::Serializer &ser);
355 
356  Timer timers[kNumTimers];
357 };
358 
359 // Nancy 12+ UI resource values (from the UIRC boot chunk), e.g. resource 0 is
360 // the coin purse amount in cents. Seeded from UIRC on first use, mutated by AR
361 // 132 (ResourceUse), and persisted between saves.
362 struct UIResourceData : public PuzzleData {
363  UIResourceData() {}
364  virtual ~UIResourceData() {}
365 
366  static constexpr uint32 getTag() { return MKTAG('U', 'R', 'E', 'S'); }
367  virtual void synchronize(Common::Serializer &ser);
368 
369  // Set true once seeded from UIRC, so a loaded save isn't re-seeded.
370  bool seeded = false;
371  Common::Array<int32> values;
372 
373  // Nancy15+ gives every protagonist their own resources, seeded from their
374  // own UIRC. `values` holds the active character's; these are the others'.
375  // An empty entry means that character has never been played.
376  Common::Array<Common::Array<int32>> characterValues;
377 
378  // Grows the array as needed
379  Common::Array<int32> &getCharacterValues(uint character);
380 };
381 
382 // Nancy 10+ taskbar button-disable overrides, set by AR 29 (ControlUIItems).
383 // A disable can span a range of scenes set from an earlier scene's AR, so the
384 // override has to persist across saves for the button to stay disabled after a
385 // load into a scene that doesn't itself re-run the AR.
386 struct TaskbarData : public PuzzleData {
387  static const uint kNumButtons = 6;
388  static const uint kNumNotificationSubCategories = 3;
389 
390  struct Override {
391  bool active = false;
392  int16 startScene = -1;
393  int16 endScene = -1;
394  uint16 clickSoundMode = 0;
395  };
396 
397  TaskbarData() {}
398  virtual ~TaskbarData() {}
399 
400  static constexpr uint32 getTag() { return MKTAG('T', 'S', 'K', 'B'); }
401  virtual void synchronize(Common::Serializer &ser);
402 
403  Override overrides[kNumButtons];
404  // Notification badge flags, mirrored from the Taskbar so they survive a
405  // load. Set by AR triggers (inventory add, ModifyListEntryAdd, etc.) that
406  // won't re-run when loading into a later scene.
407  bool notifications[kNumButtons][kNumNotificationSubCategories] = {};
408 };
409 
410 // Nancy15+ active player character (Nancy / Frank / Joe), selected by AR 134.
411 // The whole popup UI is rebuilt from the character's own data files, so the
412 // selection has to survive a save/load for the right UI to come back.
413 // Every character also carries their own inventory: the active character's is
414 // the live one inside Scene, while the other characters' are parked here.
416  struct Inventory {
417  bool isValid = false; // False until the character has been played
418  int16 heldItem = -1;
419  Common::Array<byte> items;
420  Common::Array<byte> disabledItems;
421  Common::Array<int16> order; // Display order of the inventory popup
422  };
423 
425  virtual ~PlayerCharacterData() {}
426 
427  static constexpr uint32 getTag() { return MKTAG('P', 'C', 'H', 'R'); }
428  virtual void synchronize(Common::Serializer &ser);
429 
430  // Grows the array as needed, so a character that has never been played
431  // still gets an (empty) inventory
432  Inventory &getInventory(uint character);
433 
434  uint16 characterIndex = 0;
435  Common::Array<Inventory> inventories;
436  // The look each character wears, chosen on the Design Select screen.
437  // Empty means their PCUI default.
438  Common::String designs[kMaxPlayerCharacters];
439 };
440 
441 // Nancy13+ WordFindPuzzle (AR 170). The puzzle is solved one word at a time across
442 // several scene visits; this remembers which word is currently active so progress
443 // survives leaving and re-entering the scene (and saving/loading).
445  WordFindPuzzleData() {}
446  virtual ~WordFindPuzzleData() {}
447 
448  static constexpr uint32 getTag() { return MKTAG('W', 'F', 'N', 'D'); }
449  virtual void synchronize(Common::Serializer &ser);
450 
451  int16 currentWord = 0;
452 };
453 
454 // Nancy14+ HangmanPuzzle (AR 177). Remembers which words have already been used
455 // so a fresh visit picks a new one; once every word has been used the set is
456 // cleared and words become available again (matching the original's word-reuse
457 // bitmap). Persisted so progress survives leaving the scene and saving.
458 struct HangmanData : public PuzzleData {
459  HangmanData() {}
460  virtual ~HangmanData() {}
461 
462  static constexpr uint32 getTag() { return MKTAG('H', 'A', 'N', 'G'); }
463  virtual void synchronize(Common::Serializer &ser);
464 
466 };
467 
468 // Nancy14+ DecoderPuzzle (AR 182). The decoded line typed so far, plus the scene
469 // it belongs to. A scene's two records (with and without the substitution table)
470 // hand the line to each other through here; other scenes start empty.
471 struct DecoderData : public PuzzleData {
472  DecoderData() {}
473  virtual ~DecoderData() {}
474 
475  static constexpr uint32 getTag() { return MKTAG('D', 'C', 'D', 'R'); }
476  virtual void synchronize(Common::Serializer &ser);
477 
478  uint16 sceneID = kNoScene;
479  Common::String text;
480 };
481 
482 // Nancy12 DrivingPuzzle (AR 160). The car's position, heading and tire state persist
483 // across visits to the driving map (driving into a location, then coming back), matching
484 // the original's retainState mechanism, which saves the car to globals every frame and
485 // restores it on setup. `valid` is false until the car has been driven, so the first
486 // visit starts from the header's start position.
487 struct DrivingData : public PuzzleData {
488  DrivingData() {}
489  virtual ~DrivingData() {}
490 
491  static constexpr uint32 getTag() { return MKTAG('D', 'R', 'V', 'G'); }
492  virtual void synchronize(Common::Serializer &ser);
493 
494  bool valid = false;
495  int32 carX = 0;
496  int32 carY = 0;
497  double heading = 0.0;
498  int32 tireDamage = 0;
499  bool flatTire = false;
500  double fuelBurnAccum = 0.0; // fractional fuel drained but not yet a whole unit
501  bool infiniteFuel = false; // cheat toggle, kept across building visits
502 };
503 
504 // Nancy12 MirrorLightPuzzle (AR 163). The angle of each mirror, so a mirror stays
505 // where the player turned it when the puzzle scene is left and re-entered.
506 // An angle of -1 marks a mirror that was never saved, which keeps its initial angle.
507 struct MirrorLightData : public PuzzleData {
508  MirrorLightData() {}
509  virtual ~MirrorLightData() {}
510 
511  static constexpr uint32 getTag() { return MKTAG('M', 'I', 'R', 'L'); }
512  virtual void synchronize(Common::Serializer &ser);
513 
514  Common::Array<double> angles; // radians, indexed by mirror
515 };
516 
517 // Nancy14 BuildPuzzle (AR 166). The board as it was after the last drop. A puzzle
518 // scene that re-runs picks it back up, as long as it is still the last build
519 // puzzle entered and its resume flag is set; otherwise the puzzle starts over.
520 struct BuildPuzzleData : public PuzzleData {
521  BuildPuzzleData() {}
522  virtual ~BuildPuzzleData() {}
523 
524  static constexpr uint32 getTag() { return MKTAG('B', 'L', 'D', 'P'); }
525  virtual void synchronize(Common::Serializer &ser);
526 
527  uint16 sceneID = kNoScene;
528  int16 placedCount = 0;
529  bool solved = false;
530  bool wrongIngredient = false;
531  Common::Array<int16> pieces; // 6 per piece: sourceID, assignedZone, left, top, right, bottom
532  Common::Array<int16> zones; // per zone: numWrong, then one count per ingredient
533 };
534 
535 PuzzleData *makePuzzleData(const uint32 tag);
536 
537 } // End of namespace Nancy
538 
539 #endif // NANCY_PUZZLEDATA_H
Definition: puzzledata.h:117
Definition: str.h:59
Definition: puzzledata.h:55
Definition: puzzledata.h:362
Definition: array.h:52
Definition: puzzledata.h:507
Definition: puzzledata.h:37
Definition: puzzledata.h:108
Definition: puzzledata.h:415
Definition: puzzledata.h:390
Definition: puzzledata.h:172
Definition: puzzledata.h:487
Definition: serializer.h:80
Definition: puzzledata.h:444
Definition: puzzledata.h:44
Definition: puzzledata.h:311
Definition: puzzledata.h:221
Definition: hashmap.h:85
Definition: puzzledata.h:97
Definition: puzzledata.h:294
Definition: puzzledata.h:520
Definition: puzzledata.h:256
Definition: puzzledata.h:86
Definition: puzzledata.h:162
Definition: puzzledata.h:458
Definition: puzzledata.h:386
Definition: puzzledata.h:416
#define MKTAG(a0, a1, a2, a3)
Definition: endian.h:188
Definition: puzzledata.h:189
Definition: commontypes.h:296
Definition: puzzledata.h:75
Definition: puzzledata.h:325
Definition: puzzledata.h:315
Definition: puzzledata.h:135
Definition: puzzledata.h:149
Definition: puzzledata.h:122
Definition: commontypes.h:194
Definition: puzzledata.h:185
Definition: puzzledata.h:282
Definition: puzzledata.h:471
Definition: actionmanager.h:32