ScummVM API documentation
view1.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 MACS2_VIEW1_H
23 #define MACS2_VIEW1_H
24 
25 #include "macs2/character.h"
26 #include "macs2/events.h"
27 #include "macs2/gameobjects.h"
28 #include "macs2/macs2.h"
29 
30 namespace Macs2 {
31 
32 class ActionBar;
33 class GameObject;
34 
35 enum class ViewMode {
36  VM_GAME,
37  VM_HELP
38 };
39 
40 enum class FadeMode {
41  None,
42  FromBlack,
43  ToBlack
44 };
45 
46 struct SpeechActData {
47  Character *speaker = nullptr;
49  Common::Point position;
50  bool onRightSide = false;
51  bool mouthAnimActive = false;
52  // Mouth animation counter from handleTimerCallback (1008:d38b).
53  // Decremented each frame. Controls which portrait frame is drawn:
54  // >1: draw frame 2 from primary portrait blob (+0x14C)
55  // ==0: draw frame 1 from alternate portrait blob (+0x15C) (mouth open)
56  // <0: draw frame 2 from alternate portrait blob (+0x15C) (mouth closed)
57  int16 mouthAnimCounter = 0;
58 };
59 
60 struct ScalingValues {
61  uint16 characterY;
62  uint16 scalingFactor;
63 };
64 
65 class View1 : public UIElement {
66  friend class ActionBar;
67 
68 private:
69  // Set by action bar map button on press; enterMapMode() runs on panel release.
70  bool _pendingMapOpen = false;
71 
72  ActionBar *_actionBar = nullptr;
73 
74  // Saved scene visuals for help screen restore (avoids changeScene on exit)
76  Graphics::ManagedSurface _savedDepthMap;
77 
78  // Tick counter gating the mode-dependent palette brighten effect
79  // (updateBackgroundAnimationPalette). Matches g_wBgAnimTickCounter in the
80  // binary gameTick (1008:e556).
81  uint32 _bgAnimTickCounter = 0;
82 
83  // Save/Load panel from handleSaveLoadPanelClick (1008:86a4).
84  // Opened by right-click during script execution or action bar button 8.
85  //
86  // Sub-mode 1 (Load): clicking a slot loads the game from that file
87  // Sub-mode 2 (Save): clicking a slot opens text input for save name
88  //
89  // Button bar (7 buttons):
90  // Button 1 = Enter load mode (sub-mode=1)
91  // Button 2 = Enter save mode (sub-mode=2)
92  // Button 3 = Toggle music on/off
93  // Button 4 = Page scroll (cycles 0->1->2->0)
94  // Button 5 = Confirm save (double-click pattern)
95  // Button 6 = Confirm load (double-click pattern)
96  // Button 7 = Play music / close panel
97  enum class SaveLoadSubMode {
98  None = 0,
99  Load = 1,
100  Save = 2
101  };
102  SaveLoadSubMode _saveLoadSubMode = SaveLoadSubMode::None;
103  uint16 _saveLoadPageIndex = 0;
104  bool _saveConfirmArmed = false;
105  bool _loadConfirmArmed = false;
106  bool _helpButtonDisabled = false; // g_wMapDisabledFlag (1020:23b4): disables action bar help button AND save/load panel buttons 1-2
107  uint16 _clickedButtonIndex = 0; // g_wClickedButtonIndex: last clicked button (0=none)
108  Common::String _saveSlotNames[30]; // 3 pages x 10 slots
109 
110  int _currentFadeValue = -1;
111  FadeMode _fadeMode = FadeMode::None;
112  bool _cursorSuppressedForFade = false;
113  bool _cursorWasVisibleBeforeFade = false;
114 
115  // Save/Load panel geometry (binary globals: g_wUiPanelX/Y/Width/Height, g_wActionBarButtonWidth/Height)
116  Common::Rect _saveLoadPanelRect;
117  Common::Rect _saveLoadButtonRects[7];
118  uint16 _saveLoadButtonWidth = 0; // g_wActionBarButtonWidth (after +6)
119  uint16 _saveLoadButtonHeight = 0; // g_wActionBarButtonHeight (after +6)
120 
121  Common::Array<Common::Rect> _mainMenuButtonLocations;
122  Common::Rect _mainMenuRect;
123  Common::Point _inventoryGridUpperLeft;
124  Common::Point _inventorySlotSize;
125  Common::Array<Common::Rect> _inventoryButtonLocations;
126  uint16 _inventoryScrollOffset = 0;
127 
128  static const uint16 kMaxSceneObjects = 0x200;
129  mutable uint16 _sortedObjectCount = 0;
130  mutable uint16 _sortedObjectIndices[kMaxSceneObjects + 1];
131  mutable Character *_characterByObjectIndex[kMaxSceneObjects + 1] = {};
132 
133  void openOriginalSaveLoadPanel();
134  void drawOriginalSaveLoadPanel(Graphics::ManagedSurface &s);
135  void handleOriginalSaveLoadClick(const Common::Point &pos);
136  void closeOriginalSaveLoadPanel();
137 
138  void drawDarkRectangle(uint16 x, uint16 y, uint16 width, uint16 height);
139  void drawBackgroundAnimations(Graphics::ManagedSurface &s);
140  void drawCurrentSpeaker(Graphics::ManagedSurface &s);
141 
142  void beginFadeCursorSuppression();
143  void endFadeCursorSuppression(const Graphics::Palette &palette);
144 
145  bool handleInventoryClick(const MouseDownMessage &msg);
146  bool handleContainerInventoryClick(const MouseDownMessage &msg);
147  // Binary handleInven uiBackgroundRestorePending=1; flip; runScriptExecutor; pending=0.
148  void runInventoryPanelScriptIfPending(bool excludeCloseButton);
149  bool handleActionBarClick(const MouseDownMessage &msg);
150  void walkToScreenPosition(const Common::Point &pos);
151 
152  // Input state machine from handleInput (1008:e8bf).
153  // The original game's input handler has two major branches:
154  //
155  // 1. NORMAL MODE (scene data offset 0x61db == 0):
156  // Two sub-modes based on whether a script is executing (0f88):
157  // a) Script NOT executing: Full interaction
158  // - Left click + Walk mode (0x16): pathfind to click position
159  // - Left click + other modes: hit-test hotspots/characters, run script
160  // - Right click: open action bar popup (g_wUiPanelState=1)
161  // - Button flag 8 (skip): fast-forward script to opcode 0x1D
162  // b) Script IS executing: Limited interaction
163  // - Left click: dismiss text boxes, dialogue choices, timer clicks
164  // - Right click: open map/save panel (state=4) if no UI is blocking
165  //
166  // 2. MAP MODE (scene data offset 0x61db != 0):
167  // - Left click: getDepthAtPoint() at click position
168  // depth 1..0xF9: preview that scene image
169  // depth 0xFF: full scene change back to main scene
170  //
171  // UI Panel States (g_wUiPanelState):
172  // 0 = Normal gameplay
173  // 1 = Action bar (right-click popup)
174  // 2 = Inventory panel
175  // 3 = Dialogue/save panel
176  // 4 = Map panel
177  //
178  // Panel dismissal uses keyboard scancode in PTR_LOOP_1020_0fe8:
179  // 6 = close inventory/dialogue panels
180  // 7 = close map panel
181  bool handleInput(const MouseDownMessage &msg);
182  bool handlePanelRelease(const MouseUpMessage &msg);
183  bool handleHelpClick(const MouseDownMessage &msg);
184 
185  void showStringBox(const Common::StringArray &sa);
186 
187  void renderString(uint16 x, uint16 y, const Common::String &s);
188  void renderString(const Common::Point &pos, const Common::String &s);
189  void renderStringTo(uint16 x, uint16 y, const Common::String &s, Graphics::ManagedSurface &surf);
190  void renderStringWithFont(uint16 x, uint16 y, const Common::String &s, const GlyphData *glyphs, uint16 numGlyphs);
191  void renderStringWithFontTo(uint16 x, uint16 y, const Common::String &s, const GlyphData *glyphs,
192  uint16 numGlyphs, Graphics::ManagedSurface &surf);
193  int measureStringWithFont(const Common::String &s, const GlyphData *glyphs, uint16 numGlyphs);
194  void drawSpriteTransparent(int shadingTableOffset, uint8 depthThreshold, uint16 scalingFactor,
195  int16 drawX, int16 drawY, uint16 srcWidth, uint16 srcHeight,
196  const byte *srcPixels, Graphics::ManagedSurface &s, bool useMaskedShading = false);
197  void drawSpriteScaled(int shadingTableOffset, uint8 depthThreshold, int16 drawX, int16 drawY,
198  uint16 srcWidth, uint16 srcHeight, const byte *srcPixels,
199  Graphics::ManagedSurface &s, bool useMaskedShading = false);
200 
201  void drawSprite(int16 x, int16 y, uint16 width, uint16 height, byte *data, Graphics::ManagedSurface &s, bool mirrored, bool useDepth = false, uint8 depth = 0, bool clipToGameArea = false);
202  void drawSprite(int16 x, int16 y, const Sprite &sprite, Graphics::ManagedSurface &s, bool mirrored, bool useDepth = false, uint8 depth = 0, bool clipToGameArea = false);
203  void drawSprite(int16 x, int16 y, const GlyphData &glyph, Graphics::ManagedSurface &s, bool mirrored, bool useDepth = false, uint8 depth = 0, bool clipToGameArea = false);
204  void drawSprite(const Common::Point &pos, uint16 width, uint16 height, byte *data, Graphics::ManagedSurface &s, bool mirrored, bool useDepth = false, uint8 depth = 0, bool clipToGameArea = false);
205 
206  void drawSpriteClipped(uint16 x, uint16 y, const Common::Rect &clippingRect, uint16 width, uint16 height, const byte *const data, Graphics::ManagedSurface &s);
207  void drawSpriteClipped(uint16 x, uint16 y, const Common::Rect &clippingRect, const Sprite &sprite, Graphics::ManagedSurface &s);
208  void drawSpriteFitted(const Common::Rect &bounds, const Sprite &sprite, Graphics::ManagedSurface &s, uint16 inset = 6);
209 
210  void sortObjectListByY() const;
211  void buildSortedObjectList(int low, int high) const;
212 
213  void drawAllCharacters(Graphics::ManagedSurface *surface = nullptr, bool fullUpdate = true);
214 
215  int findInventoryItem(const GameObject *item);
216  void setViewPaletteSafely(const Graphics::Palette &colors);
217  void applyPaletteWithFade(const Graphics::Palette &sourcePalette, int fadeValue);
218 
219 public:
220  View1();
221  virtual ~View1();
222 
223  ScalingValues _scalingValues;
224  ViewMode _currentMode = ViewMode::VM_GAME;
225  bool _paletteDirty = true;
226  bool _isShowingTextBox = false;
227  bool _isShowingDialoguePanel = false;
228  bool _continueScriptAfterUI = false;
229  Common::StringArray _drawnStringBox;
230  uint16 _dialogueChoiceCount = 0;
231  Common::Array<uint16> _dialogueChoiceLineCounts;
232  SpeechActData _currentSpeechActData;
233  Graphics::ManagedSurface _backgroundSurface;
234 
235  bool _started = false;
236  // As long as this debug bool is active, apply any click possible whenever it makes sense
237  bool _autoclickActive = false;
238 
239  Common::Array<Character *> _characters;
240  Common::Array<Character *> _pendingCharacterDeletes;
241 
242  // If this is the protagonist, we have our normal inventory
243  // If this is another object, it is the inventory of a storage container
244  GameObject *_inventorySource = nullptr;
245 
246  // TODO: Find a better place for those
247  // The inventory items for the currently opened inventory
248  Common::Array<GameObject *> _inventoryItems;
249 
250  // If this is not null, we are using this object
251  GameObject *_activeInventoryItem = nullptr;
252 
253  Common::Point _stringBoxPosition;
254 
255  // Binary g_wUiPanelState: 0=none, 1=action bar, 2=protagonist inv, 3=container inv, 4=save/load
256  enum UiPanelState : uint16 {
257  kUiPanelNone = 0,
258  kUiPanelActionBar = 1,
259  kUiPanelInventory = 2,
260  kUiPanelContainerInventory = 3,
261  kUiPanelSaveLoad = 4
262  };
263  UiPanelState _uiPanelState = kUiPanelNone;
264 
265  // Binary g_wPendingPanelRequest (1020:1034): deferred panel open request.
266  // Set while action bar is active; processed by gameTick when _uiPanelState returns to kUiPanelNone.
267  // Values: 0=none, 1=protagonist inventory, 2=container inventory, 3=save/load
268  enum PendingPanelRequest : uint16 {
269  kPanelRequestNone = 0,
270  kPanelRequestInventory = 1,
271  kPanelRequestContainerInventory = 2,
272  kPanelRequestSaveLoad = 3,
273  kPanelRequestSaveLoadActive = 4 // Set by handleSaveLoadPanelClick to keep panel alive
274  };
275  PendingPanelRequest _pendingPanelRequest = kPanelRequestNone;
276 
277  bool _uiBackgroundRestorePending = false;
278  bool _isDialogueChoiceInputActive = false;
279  Script::MouseMode _savedCursorMode = Script::MouseMode::Walk;
280 
281  enum class InventoryButtonIndex {
282  Look = 0,
283  Hand = 1,
284  Up = 2,
285  Down = 3,
286  Drop = 4,
287  Close = 5
288  };
289 
290  // Action bar button layout from handleActionBarClick (1008:42dc).
291  // The action bar is a 3x3 grid of buttons, centered on the right-click
292  // position. Each button is sized to fit the largest cursor icon + 6px padding.
293  // The panel is clamped to screen bounds (320x200).
294  enum class MainMenuButtonIndex {
295  Talk = 0, // Sets cursor mode to 0x13 (Talk)
296  Look = 1, // Sets cursor mode to 0x14 (Look)
297  Use = 2, // Sets cursor mode to 0x15 (Use)
298  Walk = 3, // Sets cursor mode to 0x16 (Walk)
299  Inventory = 4, // Opens inventory panel (g_wHasSavedUiBackground=1)
300  InventoryUse = 5, // Uses selected inventory item (cursor 0x17), only if item selected
301  Map = 6, // Opens help/info screen (sets scene+0x61db=1 for map panel mode)
302  SaveLoad = 7, // Opens dialogue/save panel (g_wHasSavedUiBackground=3)
303  Close = 8 // Implicit close (clicking outside any button)
304  };
305 
306  // Debug: last hovered area/hotspot (updated every mouse move for ImGui)
307  uint16 _hoverAreaId = 0;
308  uint16 _hoverHotspotId = 0;
309 
310  struct BorderStyle {
311  uint32 outerEdge; // sprite for outer frame (0x1010 = black)
312  uint32 topLeft; // sprite for top/left edge
313  uint32 bottomRight; // sprite for bottom/right edge
314  };
315  static const BorderStyle kBorderRaised;
316  static const BorderStyle kBorderPressed;
317 
319  Common::Point position;
320  uint8 alignment = 0;
321  Common::String text;
322  };
323 
324  Common::Array<OverlayTextEntry> _overlayTextEntries;
325 
326  bool hasPersistentActionBar() const;
327  bool shouldShowActionBar() const;
328  void ensureActionBar();
330  int actionBarTopY() const;
331 
332  // g_wHelpButtonDisabled (1020:23B4): when non-zero, help/map button is disabled
333  // and script scene changes use applyScenePaletteEffect instead of palette fades.
334  // Map overlay mode is scene+0x61db (_currentMode == VM_HELP), not this flag.
335  bool isHelpButtonDisabled() const { return _helpButtonDisabled; }
336 
337  void restoreUiPaletteEntries();
338 
339  void clearClickedButtonIndex() { _clickedButtonIndex = 0; }
340 
341  AnimFrame *getInventoryIcon(GameObject *gameObject);
342 
343  void flushPendingCharacterDeletes();
344  void transferPickupTarget(GameObject *targetObject);
345  void finishPanelCloseAfterRelease(UiPanelState closedFromState);
346 
347  // debug tools
348  void drawPathfindingPoints(Graphics::ManagedSurface &s);
349  void drawDebugOutput(Graphics::ManagedSurface &s);
350  void drawPath(Graphics::ManagedSurface &s);
351 
352  // Sets the source for the to-be-opened inventory and updats the array of inventory objects
353  void setInventorySource(GameObject *newInventorySource);
354  void refreshProtagonistInventoryAfterLoad(uint16 actorIndex);
355  void openInventory(GameObject *newInventorySource);
356  // Binary handleInput (1008:e8bf) close path for the inventory panels.
357  void closeInventory();
358 
359  bool isInventorySourceProtagonist() const;
360 
361  void transferInventoryItem(GameObject *item, GameObject *targetContainer);
362 
363  Character *getCharacterByIndex(uint16 index) const;
364  void rebuildCharacterLookupTable() const;
365 
366  int getCharacterArrayIndex(const Character *c) const;
367 
368  // Updates the cursor from the mode set in the engine - TODO: Clean up, this should not
369  // be so separated
370  void updateCursor(const Graphics::Palette *palette = nullptr);
371 
372  bool msgFocus(const FocusMessage &msg) override;
373  bool msgKeypress(const KeypressMessage &msg) override;
374  bool msgAction(const ActionMessage &msg) override;
375 
376  bool msgMouseDown(const MouseDownMessage &msg) override;
377  bool msgMouseUp(const MouseUpMessage &msg) override;
378  bool msgMouseMove(const MouseMoveMessage &msg) override;
379  void draw() override;
380  bool tick() override;
381 
382  void drawInventory(Graphics::ManagedSurface &s);
383  GameObject *getClickedInventoryItem(const Common::Point &p);
384 
385  void openMainMenu(Common::Point clickedPosition);
387  void openScriptActionBar(const Common::Point &position, Script::MouseMode restoreCursorMode);
389  void closeScriptActionBar(Script::MouseMode &outSavedCursorMode);
390  void enterMapMode();
391 
392  void layoutActionBarButtons();
393  void drawMainMenu(Graphics::ManagedSurface &s);
394  void drawSceneUpdate();
395  void drawSceneFrame(bool fullUpdate);
396 
397  void handleTextBoxInput();
398  void dismissDialoguePanel();
399  bool handleDialogueChoiceClick(int clickY, int clickX);
400 
401  void startFading(uint16 speed = 4);
402  void fadePaletteToBlack(uint16 speed, const Graphics::Palette &sourcePalette);
403  void startFadeToBlack(uint16 speed = 4);
404  void startFadingWithSpeed(uint16 speed);
405  // Mode-1 scene transition: clearScreen + full palette (1008:ad6e local_6==1).
406  void instantSceneCut();
407  // Draw the current scene and push pixels to the physical screen immediately.
408  void presentFrame();
409 
410  void showSpeechAct(uint16 characterIndex, const Common::Array<Common::String> &strings, const Common::Point &position, bool onRightSide = false);
411 
412  void drawNinePatchBorder(const Common::Point &pos, const Common::Point &size,
413  const BorderStyle &style, bool fillCenter, bool fillSides,
415  void drawBorder(const Common::Point &pos, const Common::Point &size, Graphics::ManagedSurface &s);
416  void drawBorderSide(const Common::Point &pos, const Common::Point &size, Graphics::ManagedSurface &s);
417 
418  Macs2::AnimFrame *getUISprite(uint32 offset);
419 
420  void drawHorizontalBorderHighlight(const Common::Point &pos, int16 width, uint32 spriteAddress, Graphics::ManagedSurface &s);
421  void drawVerticalBorderHighlight(const Common::Point &pos, int16 height, uint32 spriteAddress, Graphics::ManagedSurface &s);
422 
423  void drawImageResources(Graphics::ManagedSurface &s);
424 
425  void showDialogueChoice(uint16 speakerObjectID, const Common::Array<Common::StringArray> &choices, const Common::Point &position, bool onRightSide = false);
426 
427  void triggerDialogueChoice(uint8 index);
428 
429  void addOverlayTextEntry(const OverlayTextEntry &entry);
430  void clearOverlayTextEntries();
431  void drawOverlayTextEntries();
432 
433  uint16 getHitObjectID(const Common::Point &pos) const;
434 };
435 
436 } // namespace Macs2
437 
438 #endif
Definition: managed_surface.h:51
Definition: str.h:59
Definition: messages.h:58
Definition: gameobjects.h:107
Definition: events.h:54
Definition: view1.h:46
Definition: messages.h:75
Definition: messages.h:69
Definition: rect.h:536
Definition: view1.h:318
Definition: view1.h:310
Definition: messages.h:63
Definition: character.h:33
constexpr int PALETTE_COUNT
Definition: palette.h:42
Definition: view1.h:65
Definition: text.h:33
Definition: rect.h:144
Definition: messages.h:42
Definition: messages.h:33
Definition: sprite.h:30
Definition: macs2.h:104
Simple class for handling a palette data.
Definition: palette.h:61
Definition: actionbar.h:31
Definition: actionbar.h:43
Definition: view1.h:60