ScummVM API documentation
conversation.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_CONVERSATION_H
23 #define NANCY_ACTION_CONVERSATION_H
24 
25 #include "engines/nancy/action/actionrecord.h"
26 #include "engines/nancy/movieplayer.h"
27 
28 namespace Nancy {
29 namespace Action {
30 
31 // The base class for conversations, with no video data. Contains the following:
32 // - a base sound for the NPC's speech and its caption (mandatory)
33 // - a list of possible player responses, also with sounds and captions (optional)
34 // Captions are displayed in the Textbox, and player responses are also selectable there.
35 // Captions are hypertext; meaning, they contain extra data related to the text (see misc/hypertext.h)
36 // A conversation will auto-advance to a next scene when no responses are available; the next scene
37 // can either be described within the Conversation data, or can be whatever's pushed onto the scene "stack".
38 // Also supports branching scenes depending on a condition, though that is only used in older games.
39 // Player responses can also be conditional. Up to Nancy11 the condition data comes from nancy.dat
40 // (see devtools/create_nancy); from Nancy12 on it lives in per-character data scenes (S<800 + charID> / S<900 + charID>).
42 public:
44  virtual ~ConversationSound();
45 
46  void init() override;
47  void readData(Common::SeekableReadStream &stream) override;
48  void execute() override;
49 
50  virtual bool isVideoDonePlaying() { return true; }
51  // Called when the line gets skipped, so the character stops animating with it
52  virtual void skipVideo() {}
53  bool isViewportRelative() const override { return true; }
54 
55  // Enhancement: cut the currently playing line short, as if its sound and
56  // video had just finished. Any available responses still get shown.
57  void skipLine();
58 
59 protected:
61  byte type;
62  FlagDescription flag;
63  byte orFlag;
64 
65  void read(Common::SeekableReadStream &stream);
66  bool isSatisfied() const;
67  void set() const;
68  };
69 
71  Common::Array<ConversationFlag> conditionFlags;
72 
73  void read(Common::SeekableReadStream &stream);
74  bool isSatisfied() const;
75  };
76 
77  struct ResponseStruct {
78  enum AddRule { kAddIfNotFound, kRemoveAndAddToEnd, kRemove };
79 
80  ConversationFlags conditionFlags;
81  Common::String text;
82  Common::String soundName;
83  byte addRule = kAddIfNotFound;
84  SceneChangeDescription sceneChange;
85  FlagDescription flagDesc;
86 
87  bool isOnScreen = false;
88  };
89 
90  struct FlagsStruct {
91  ConversationFlags conditions;
92  ConversationFlag flagToSet;
93  };
94 
96  ConversationFlags conditions;
97  SceneChangeDescription sceneChange;
98  };
99 
100  static const byte kDefaultNextSceneEnabled = 1;
101  static const byte kDefaultNextSceneDisabled = 2;
102 
103  static const byte kPopNextScene = 1;
104  static const byte kNoPopNextScene = 2;
105 
106  Common::String getRecordTypeName() const override { return "ConversationSound"; }
107 
108  // Functions for reading captions are virtual to allow easier support for the terse Conversation variants
109  virtual void readCaptionText(Common::SeekableReadStream &stream);
110  virtual void readResponseText(Common::SeekableReadStream &stream, ResponseStruct &response);
111 
112  // Used in subclasses
113  void readTerseData(Common::SeekableReadStream &stream);
114  void readTerseCaptionText(Common::SeekableReadStream &stream);
115  void readTerseResponseText(Common::SeekableReadStream &stream, ResponseStruct &response);
116 
117  // Nancy13 compact conversation format. readCelDataNancy13 is the only
118  // per-class difference: the base skips the cel-only frame fields, while
119  // ConversationCel reads them plus the XSheet.
120  void readDataNancy13(Common::SeekableReadStream &stream);
121  virtual void readCelDataNancy13(Common::SeekableReadStream &stream);
122 
123  // Add conditional/goodbye responses: from nancy.dat up to Nancy11, from data scenes for Nancy12+
124  void addConditionalDialogue();
125  void addGoodbye();
126  void addConditionalDialogueNancy12();
127  void addGoodbyeNancy12();
128 
129  Common::String _text;
130 
131  SoundDescription _sound;
132  SoundDescription _responseGenericSound;
133 
134  // Nancy14 added concatenated lines: several sound files that play back to
135  // back as a single line of dialogue. Empty for an ordinary single-sound line.
136  Common::Array<Common::String> _concatSounds;
137  uint _curConcatSound = 0;
138 
139  byte _conditionalResponseCharacterID;
140  byte _goodbyeResponseCharacterID;
141  // Nancy16 names the conditional dialogue and goodbye scenes directly
142  Common::String _conditionalResponseScene;
143  Common::String _goodbyeResponseScene;
144  byte _defaultNextScene = kDefaultNextSceneEnabled;
145  byte _popNextScene = kNoPopNextScene;
146  SceneChangeDescription _sceneChange;
147 
149  Common::Array<FlagsStruct> _flagsStructs;
150  Common::Array<SceneBranchStruct> _sceneBranchStructs;
151 
152  bool _hasDrawnTextbox;
153  bool _isDialogOpen = false; // in the Nancy16 UI
154  int16 _pickedResponse;
155  bool _isSkipped = false;
156 
157  const byte _noResponse;
158 };
159 
160 // Conversation with an AVF video. Originally called PlayPrimaryVideoChan0
162 public:
163  void init() override;
164  void updateGraphics() override;
165  void onPause(bool pause) override;
166 
167  void readData(Common::SeekableReadStream &stream) override;
168 
169  bool isVideoDonePlaying() override;
170 
171 protected:
172  Common::String getRecordTypeName() const override;
173 
174  Common::String _videoName;
175  Common::Path _paletteName;
176  uint _videoFormat = kLargeVideoFormat;
177  uint16 _firstFrame = 0;
178  int16 _lastFrame = 0;
179  MoviePlayer _decoder;
180 };
181 
182 class ConversationCelLoader;
183 
184 // Conversation with separate cels for the body and head of the character.
185 // Cels are separate images bundled inside a .cal file
187 public:
188  ConversationCel() {}
189  virtual ~ConversationCel();
190 
191  void init() override;
192  void registerGraphics() override;
193  void updateGraphics() override;
194  void onPause(bool pause) override;
195 
196  void readData(Common::SeekableReadStream &stream) override;
197 
198  bool load();
199  uint getCurFrame() const { return _curFrame; }
200 
201 protected:
202  Common::String getRecordTypeName() const override { return "ConversationCel"; }
203 
204  struct Cel {
206  Common::Rect src;
207  Common::Rect dest;
208  };
209 
210  class RenderedCel : public RenderObject {
211  public:
212  RenderedCel() : RenderObject(9) {}
213  bool isViewportRelative() const override { return true; }
214 
215  // Nancy15 head movies: show a decoded movie frame instead of a cel
216  void setMovieFrame(const Graphics::Surface &frame);
217  };
218 
219  static const byte kCelOverrideTreeRectsOff = 1;
220  static const byte kCelOverrideTreeRectsOn = 2;
221 
222  bool isVideoDonePlaying() override;
223  void skipVideo() override;
224  Cel &loadCel(const Common::Path &name, const Common::String &treeName);
225 
226  void readXSheet(Common::SeekableReadStream &stream, const Common::String &xsheetName);
227  void readCelDataNancy13(Common::SeekableReadStream &stream) override;
228 
231 
232  uint32 _frameTime = 0;
233  uint _videoFormat = kLargeVideoFormat;
234  uint16 _firstFrame = 0;
235  uint16 _lastFrame = 0;
236 
237  Common::Array<byte> _drawingOrder;
238  Common::Array<byte> _overrideTreeRects;
239 
240  Common::Array<Common::Rect> _overrideRectSrcs;
241  Common::Array<Common::Rect> _overrideRectDests;
242 
243  // Nancy15 gave every cel tree a destination rect inside the XSheet. A tree that
244  // names a movie instead of a loaded cel archive (the character's head) is played
245  // into that rect; _treeMovies holds one player per such tree, null for cel trees.
246  Common::Array<Common::Rect> _treeRects;
248 
249  // Nancy16 has no cels left: every tree is a movie, and each XSheet frame holds
250  // the movie frame to show per tree. kMovieFrameFreeRunning leaves the tree
251  // playing on the movie's own clock (the lip-synced head); the body movie is a
252  // library of fidgets the XSheet picks frames from.
253  static const int32 kMovieFrameFreeRunning = -1;
254  Common::Array<Common::Array<int32>> _treeMovieFrames;
255  Common::Array<int32> _treeShownFrames;
256 
257  bool isTreeFreeRunning(uint tree) const;
258  void showMovieFrame(uint tree, uint xsheetFrame);
259 
260  uint _curFrame = 0;
261  uint32 _nextFrameTime = 0;
262 
263  Common::Array<RenderedCel> _celRObjects;
264 
267 };
268 
269 // A ConversationSound without embedded text; uses the CONVO chunk instead
271 protected:
272  Common::String getRecordTypeName() const override { return "ConversationSoundT"; }
273 
274  void readCaptionText(Common::SeekableReadStream &stream) override { readTerseCaptionText(stream); }
275  void readResponseText(Common::SeekableReadStream &stream, ResponseStruct &response) override { readTerseResponseText(stream, response); }
276 };
277 
278 // A ConversationCel without embedded text; uses the CONVO chunk instead
280 protected:
281  Common::String getRecordTypeName() const override { return "ConversationCelT"; }
282 
283  void readCaptionText(Common::SeekableReadStream &stream) override { readTerseCaptionText(stream); }
284  void readResponseText(Common::SeekableReadStream &stream, ResponseStruct &response) override { readTerseResponseText(stream, response); }
285 };
286 
287 // A ConversationSound with a much smaller data footprint
289 public:
290  void readData(Common::SeekableReadStream &stream) override;
291 
292 protected:
293  Common::String getRecordTypeName() const override { return "ConversationSoundTerse"; }
294 };
295 
296 // A ConversationCel with a much smaller data footprint
298 public:
299  void readData(Common::SeekableReadStream &stream) override;
300 
301 protected:
302  Common::String getRecordTypeName() const override { return "ConversationCelTerse"; }
303 };
304 
305 // Nancy12+ conditional dialogue record (type 35), one per response, stored in scene S<800 + charID>
307 public:
308  void readData(Common::SeekableReadStream &stream) override;
309  Common::String getRecordTypeName() const override { return "ConversationInfoCheck"; }
310 
311  Common::String _soundID; // Doubles as the CONVO text key
312  uint16 _sceneID = 0;
313 };
314 
315 // Nancy12+ goodbye record (type 36), stored in scene S<900 + charID>; one sound and scene are picked at random
317 public:
318  void readData(Common::SeekableReadStream &stream) override;
319  Common::String getRecordTypeName() const override { return "ConversationGoodbye"; }
320 
322  Common::Array<uint16> _sceneIDs;
323 };
324 
325 } // End of namespace Action
326 } // End of namespace Nancy
327 
328 #endif // NANCY_ACTION_CONVERSATION_H
Definition: managed_surface.h:51
Definition: str.h:59
Definition: surface.h:67
Definition: conversation.h:204
Definition: commontypes.h:186
Definition: movieplayer.h:56
Definition: array.h:52
Definition: conversation.h:161
Definition: rect.h:536
Definition: path.h:52
Definition: stream.h:745
Definition: conversation.h:41
Definition: actionrecord.h:169
Definition: renderobject.h:36
Definition: conversation.h:306
Definition: conversation.h:316
Definition: conversation.h:288
Definition: hashmap.h:85
Definition: actionrecord.h:107
Definition: conversation.h:297
Definition: conversation.h:186
Definition: conversation.h:210
Definition: commontypes.h:306
Definition: conversation.h:270
Definition: conversation.h:279
Definition: commontypes.h:201
Definition: actionmanager.h:32