ScummVM API documentation
scene.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_STATE_SCENE_H
23 #define NANCY_STATE_SCENE_H
24 
25 #include "common/singleton.h"
26 #include "common/queue.h"
27 
28 #include "engines/nancy/commontypes.h"
29 #include "engines/nancy/puzzledata.h"
30 
31 #include "engines/nancy/action/actionmanager.h"
32 
33 #include "engines/nancy/state/state.h"
34 
35 #include "engines/nancy/ui/fullscreenimage.h"
36 #include "engines/nancy/ui/viewport.h"
37 #include "engines/nancy/ui/textbox.h"
38 #include "engines/nancy/ui/inventorybox.h"
39 #include "engines/nancy/ui/inventorypopup.h"
40 #include "engines/nancy/ui/notebookpopup.h"
41 #include "engines/nancy/ui/cellphonepopup.h"
42 #include "engines/nancy/ui/conversationpopup.h"
43 
44 namespace Common {
45 class SeekableReadStream;
46 class Serializer;
47 }
48 
49 namespace Nancy {
50 
51 class NancyEngine;
52 class NancyConsole;
53 struct SceneChangeDescription;
54 
55 namespace Action {
56 class ConversationSound;
57 class PlaySecondaryMovie;
58 }
59 
60 namespace Misc {
61 class Lightning;
62 class SpecialEffect;
63 }
64 
65 namespace UI {
66 class Button;
67 class Taskbar;
68 class ViewportOrnaments;
69 class TextboxOrnaments;
70 class InventoryBoxOrnaments;
71 class Clock;
72 }
73 
74 namespace State {
75 
76 // The game state that handles all of the gameplay
77 class Scene : public State, public Common::Singleton<Scene> {
78 public:
79  struct SceneSummary {
80  // SSUM and TSUM
81  // Default values set to match those applied when loading from a TSUM chunk
82  Common::String description;
83  Common::Path videoFile;
84 
85  uint16 videoFormat = kLargeVideoFormat;
87  SoundDescription sound;
88 
89  byte panningType = kPan360;
90  uint16 numberOfVideoFrames = 0;
91  uint16 degreesPerRotation = 18;
92  uint16 totalViewAngle = 0;
93  uint16 horizontalScrollDelta = 1;
94  uint16 verticalScrollDelta = 10;
95  uint16 horizontalEdgeSize = 15;
96  uint16 verticalEdgeSize = 15;
97  Time slowMoveTimeDelta = 400;
98  Time fastMoveTimeDelta = 66;
99 
100  // Sound start vectors, used in nancy3 and up
101  Math::Vector3d listenerPosition;
102 
103  void read(Common::SeekableReadStream &stream);
104  void readTerse(Common::SeekableReadStream &stream);
105  };
106 
107  Scene();
108  virtual ~Scene();
109 
110  // State API
111  void process() override;
112  void onStateEnter(const NancyState::NancyState prevState) override;
113  bool onStateExit(const NancyState::NancyState nextState) override;
114 
115  // Used when winning/losing game
116  void setDestroyOnExit() { _destroyOnExit = true; }
117 
118  bool isRunningAd() const { return _isRunningAd; }
119 
120  void changeScene(const SceneChangeDescription &sceneDescription);
121  void pushScene(int16 itemID = -1);
122  void popScene(bool inventory = false);
123 
124  // Nancy 11+ "UI prep scenes": opening a taskbar popup first runs a hidden,
125  // videoless scene whose event-flag-gated ARs populate the popup's content;
126  // a UIPopupPrepScene AR (32) then calls finishUIPrepScene to restore the
127  // prior scene and open the (now populated) popup. startUIPrepScene saves
128  // the current scene and jumps to prepSceneID; uiType (a UIType) selects
129  // which popup finishUIPrepScene opens. No-op if a prep is already running
130  // or prepSceneID is kNoScene.
131  void startUIPrepScene(int16 uiType, int16 prepSceneID);
132  void finishUIPrepScene();
133  bool isUIPrepActive() const { return _uiPrep.active; }
134  uint16 getSceneCounts(int16 hours) const {
135  return _flags.sceneCounts.contains(hours) ? _flags.sceneCounts[hours] : 0;
136  }
137 
138  void setPlayerTime(Time time, byte relative);
139  Time getPlayerTime() const { return _timers.playerTime; }
140  Time getTimerTime() const { return _timers.timerIsActive ? _timers.timerTime : 0; }
141  byte getPlayerTOD() const;
142 
143  void addItemToInventory(int16 id);
144  void removeItemFromInventory(int16 id, bool pickUp = true);
145  int16 getHeldItem() const { return _flags.heldItem; }
146  void setHeldItem(int16 id);
147  void setNoHeldItem();
148  byte hasItem(int16 id) const;
149  byte getItemDisabledState(int16 id) const { return _flags.disabledItems[id]; }
150  void setItemDisabledState(int16 id, byte state) {
151  if ((uint16)id < _flags.disabledItems.size())
152  _flags.disabledItems[id] = state;
153  }
154 
155  void installInventorySoundOverride(byte command, const SoundDescription &sound, const Common::String &caption, uint16 itemID);
156  void playItemCantSound(int16 itemID = -1, bool notHoldingSound = false);
157 
158  void setEventFlag(int16 label, byte flag);
159  void setEventFlag(FlagDescription eventFlag);
160  bool getEventFlag(int16 label, byte flag) const;
161  bool getEventFlag(FlagDescription eventFlag) const;
162 
163  // Nancy 11+ software-timer queries used by timer dependencies.
164  bool isSoftwareTimerActive(uint16 index) const;
165  uint32 getSoftwareTimerElapsed(uint16 index) const;
166 
167  // Nancy 12+ UI resource values (the UIRC boot chunk). Resource 0 is the
168  // coin purse amount in cents. Backed by the lazily-created, saved
169  // UIResourceData puzzle chunk, seeded from UIRC on first use and mutated by
170  // AR 132 (ResourceUse). Non-const because the first access creates/seeds it.
171  int32 getUIResource(uint index);
172  void setUIResource(uint index, int32 value);
173 
174  void setLogicCondition(int16 label, byte flag);
175  bool getLogicCondition(int16 label, byte flag) const;
176  void clearLogicConditions();
177  Time getLogicConditionTimestamp(int16 label) const {
178  return _flags.logicConditions[label].timestamp;
179  }
180 
181  void setDifficulty(uint difficulty) { _difficulty = difficulty; }
182  uint16 getDifficulty() const { return _difficulty; }
183 
184  byte getHintsRemaining() const { return _hintsRemaining[_difficulty]; }
185  void useHint(uint16 characterID, uint16 hintID);
186 
187  void requestStateChange(NancyState::NancyState state) { _gameStateRequested = state; }
188  void resetStateToInit() { _state = kInit; }
189 
190  void resetAndStartTimer() { _timers.timerIsActive = true; _timers.timerTime = 0; }
191  void stopTimer() { _timers.timerIsActive = false; _timers.timerTime = 0; }
192 
193  Time getMovementTimeDelta(bool fast) const { return fast ? _sceneState.summary.fastMoveTimeDelta : _sceneState.summary.slowMoveTimeDelta; }
194 
195  // Nancy 11+ AR 30/31. Toggles whether the player may scroll/pan the viewport.
196  // Backed by a reserved event flag (so it persists across scene changes and
197  // is saved/restored with the rest of the event flags).
198  void setPlayerScrolling(bool enabled);
199  bool getPlayerScrolling() const;
200 
201  void registerGraphics();
202 
203  void synchronize(Common::Serializer &serializer);
204 
205  UI::FullScreenImage &getFrame() { return _frame; }
206  UI::Viewport &getViewport() { return _viewport; }
207  UI::Textbox &getTextbox() { return _textbox; }
208  UI::InventoryBox &getInventoryBox() { return _inventoryBox; }
209  UI::InventoryPopup &getInventoryPopup() { return _inventoryPopup; }
210  UI::NotebookPopup &getNotebookPopup() { return _notebookPopup; }
211  UI::CellPhonePopup &getCellPhonePopup() { return _cellPhonePopup; }
212  UI::ConversationPopup &getConversationPopup() { return _conversationPopup; }
213  UI::Clock *getClock();
214  UI::Taskbar *getTaskbar() { return _taskbar; }
215 
216  Action::ActionManager &getActionManager() { return _actionManager; }
217 
218  SceneChangeDescription &getSceneInfo() { return _sceneState.currentScene; }
219  SceneChangeDescription &getNextSceneInfo() { return _sceneState.nextScene; }
220  const SceneSummary &getSceneSummary() const { return _sceneState.summary; }
221 
222  void setActiveMovie(Action::PlaySecondaryMovie *activeMovie);
223  Action::PlaySecondaryMovie *getActiveMovie();
224 
225  // Called when a PSM(isRandom) AR is loaded — drives stale-chain cleanup.
226  void notifyRandomMovieARLoaded() { _hadRandomMovieARThisScene = true; }
227  void setActiveConversation(Action::ConversationSound *activeConversation);
228  Action::ConversationSound *getActiveConversation();
229 
230  Graphics::ManagedSurface &getLastScreenshot() { return _lastScreenshot; }
231 
232  // The Vampire Diaries only;
233  void beginLightning(int16 distance, uint16 pulseTime, int16 rgbPercent);
234 
235  // Used from nancy2 onwards
236  void specialEffect(byte type, uint16 fadeToBlackTime, uint16 frameTime);
237  void specialEffect(byte type, uint16 totalTime, uint16 fadeToBlackTime, Common::Rect rect);
238 
239  // Get the persistent data for a given puzzle type
240  PuzzleData *getPuzzleData(const uint32 tag);
241 
242  enum State {
243  kInit,
244  kLoad,
245  kStartSound,
246  kRun
247  };
248 
249  State getState() const { return _state; }
250  void setState(State state) { _state = state; }
251 
252  // Close every open Nancy 10+ popup. Used before a script auto-opens one
253  // (e.g. the incoming game-over call) so two popups can't stack.
254  void closeActivePopups();
255 
256  struct Timers {
257  Time pushedPlayTime;
258  Time lastTotalTime;
259  Time sceneTime;
260  Time timerTime;
261  bool timerIsActive = false;
262  Time playerTime; // In-game time of day, adds a minute every 5 seconds
263  Time playerTimeNextMinute; // Stores the next tick count until we add a minute to playerTime
264  };
265 
266  Timers _timers;
267 
268  RenderObject _hotspotDebug;
269 
270 private:
271  void init();
272  void load(bool fromSaveFile = false);
273  void run();
274  void handleInput();
275 
276  // Nancy 11+ AR 69. Advances all running software timers (stored as TimerData
277  // puzzle data) and fires any whose configured duration has just elapsed.
278  void tickSoftwareTimers(uint32 deltaMs);
279  void fireSoftwareTimer(TimerData::Timer &timer);
280  void fireTimerTrigger(TimerData::Trigger &trigger);
281 
282  // Rect of the open Nancy 10+ taskbar popup, or empty if none.
283  Common::Rect activePopupConfinement() const;
284 
285  void initStaticData();
286 
287  void clearSceneData(bool nextIsNoArt = false);
288  void clearPuzzleData();
289 
290  // Maps an event flag label to its index in the eventFlags array
291  int16 eventFlagToIndex(int16 label) const;
292 
293  struct SceneState {
294  SceneSummary summary;
295  SceneChangeDescription currentScene;
296  SceneChangeDescription nextScene;
297  SceneChangeDescription pushedScene;
298  bool isScenePushed = false;
299  SceneChangeDescription pushedInvScene;
300  int16 pushedInvItemID = -1;
301  bool isInvScenePushed = false;
302  };
303 
304  struct PlayFlags {
305  struct LogicCondition {
306  LogicCondition();
307  byte flag;
308  Time timestamp;
309  };
310 
311  LogicCondition logicConditions[30];
312  Common::Array<byte> eventFlags;
314  Common::Array<byte> items;
315  Common::Array<byte> disabledItems;
316  int16 heldItem = -1;
317  int16 primaryVideoResponsePicked = -1;
318  };
319 
320  struct InventorySoundOverride {
321  bool isDefault = false; // When true, other fields are ignored
322  SoundDescription sound;
323  Common::String caption;
324  };
325 
326  // UI
327  UI::FullScreenImage _frame;
328  UI::Viewport _viewport;
329  UI::Textbox _textbox;
330  UI::InventoryBox _inventoryBox;
331  UI::InventoryPopup _inventoryPopup;
332  UI::NotebookPopup _notebookPopup;
333  UI::CellPhonePopup _cellPhonePopup;
334  UI::ConversationPopup _conversationPopup;
335 
336  UI::Button *_menuButton;
337  UI::Button *_helpButton;
338  UI::Taskbar *_taskbar;
339  Time _buttonPressActivationTime;
340 
341  // A clicked MENU/HELP taskbar button whose state change is deferred until
342  // its click sound finishes playing (see handleInput). -1 = none pending.
343  int _pendingTaskbarButton;
344 
345  UI::ViewportOrnaments *_viewportOrnaments;
346  UI::TextboxOrnaments *_textboxOrnaments;
347  UI::InventoryBoxOrnaments *_inventoryBoxOrnaments;
348  RenderObject *_clock;
349 
350  Common::Rect _mapHotspot;
351 
352  // General data
353  SceneState _sceneState;
354  PlayFlags _flags;
355  uint16 _difficulty;
356  Common::Array<uint16> _hintsRemaining;
357  int16 _lastHintCharacter;
358  int16 _lastHintID;
359  NancyState::NancyState _gameStateRequested;
360  Common::HashMap<uint16, InventorySoundOverride> _inventorySoundOverrides;
361 
362  Misc::Lightning *_lightning;
363  Common::Queue<Misc::SpecialEffect> _specialEffects;
364 
366 
367  Action::ActionManager _actionManager;
368  Action::PlaySecondaryMovie *_activeMovie;
369  Action::ConversationSound *_activeConversation;
370 
371  // Set by notifyRandomMovieARLoaded; checked in clearSceneData to wind
372  // down a persistent random-movie whose scene chain is over.
373  bool _hadRandomMovieARThisScene = false;
374 
375  // Whether esc was already down last frame, so a held key only skips once
376  bool _escHeld = false;
377 
378  // Contains a screenshot of the Scene state from the last time it was exited
379  Graphics::ManagedSurface _lastScreenshot;
380 
381  bool _destroyOnExit;
382  bool _isRunningAd;
383 
384  // State for a running UI prep scene (see startUIPrepScene).
385  struct UIPrepState {
386  bool active = false;
387  int16 uiType = 0; // UIType of the popup that requested the prep
388  SceneChangeDescription returnScene;
389  uint32 startMillis = 0;
390  } _uiPrep;
391 
392  State _state;
393 };
394 
395 #define NancySceneState Nancy::State::Scene::instance()
396 
397 } // End of namespace State
398 } // End of namespace Nancy
399 
400 #endif // NANCY_STATE_SCENE_H
Definition: managed_surface.h:51
Definition: conversationpopup.h:41
Definition: str.h:59
Definition: inventorypopup.h:43
Definition: viewport.h:42
Definition: time.h:30
Definition: taskbar.h:36
Definition: commontypes.h:165
Definition: puzzledata.h:37
Definition: inventorybox.h:42
Definition: rect.h:536
Definition: path.h:52
Definition: textbox.h:39
Definition: stream.h:745
Definition: secondarymovie.h:46
Definition: conversation.h:41
Definition: queue.h:42
Definition: serializer.h:80
Definition: actionmanager.h:48
Definition: soundequalizerpuzzle.h:27
Definition: renderobject.h:36
Definition: scene.h:79
Definition: scene.h:256
Definition: ornaments.h:30
Definition: lightning.h:32
Definition: clock.h:37
Definition: button.h:33
Definition: algorithm.h:29
Definition: cellphonepopup.h:38
Definition: notebookpopup.h:38
Definition: commontypes.h:282
Definition: puzzledata.h:298
Definition: puzzledata.h:288
Definition: ornaments.h:38
Definition: fullscreenimage.h:30
Definition: ornaments.h:46
Definition: scene.h:77
Definition: input.h:69
Definition: commontypes.h:180
Definition: actionmanager.h:32
Definition: singleton.h:42