ScummVM API documentation
eem.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 
23 #ifndef EEM_EEM_H
24 #define EEM_EEM_H
25 
26 #include "common/array.h"
27 #include "common/events.h"
28 #include "common/keyboard.h"
29 #include "common/language.h"
30 #include "common/platform.h"
31 #include "common/random.h"
32 #include "common/rect.h"
33 #include "common/scummsys.h"
34 
35 #include "common/serializer.h"
36 
37 #include "engines/advancedDetector.h"
38 #include "engines/engine.h"
39 #include "engines/savestate.h"
40 
41 #include "eem/animation.h"
42 #include "eem/font.h"
43 #include "eem/mystery.h"
44 #include "eem/resource.h"
45 
46 namespace EEM {
47 
48 class AudioPlayer;
49 class MusicPlayer;
50 
52 const uint kPalSize = 768;
53 
54 void fadeCurrentPaletteToBlack(uint delayMs = 8);
55 void fadePaletteFromBlack(const byte *target, uint delayMs = 8);
56 
81 enum ScreenId {
82  kScreenInvalid = 0xFFFF,
83  kScreenInitClues = 0x00,
84  kScreenMap = 0x01,
85  kScreenMapAlt = 0x02,
86  kScreenSite = 0x03,
87  kScreenNotebook = 0x04,
88  kScreenGallery = 0x05,
89  kScreenSetup = 0x06,
90  kScreenAccuse = 0x07,
91  kScreenProfile = 0x08,
92  kScreenChoosePartner = 0x09,
93  kScreenChooseMystery = 0x0A,
94  kScreenTitle = 0x0B,
95  kScreenAction = 0x0C
96 };
97 
100 enum Variant {
101  kVariantCD = 0,
102  kVariantFloppy = 1,
103  kVariantLondonCD = 2,
104  kVariantMac = 3,
105 };
106 
109 enum Partner {
110  kPartnerJake = 0,
111  kPartnerJenny = 1,
112 };
113 
114 constexpr int kScreenWidth = 320;
115 constexpr int kScreenHeight = 200;
116 constexpr int kMacScreenWidth = 512;
117 constexpr int kMacScreenHeight = 384;
118 
119 constexpr Common::Rect kPdaSiteRect (Common::Point(35, 111), 21, 25);
120 constexpr Common::Rect kPdaPartnerFootMapRect (Common::Point( 7, 177), 50, 23);
121 constexpr Common::Rect kPdaPartnerHeadHintRect (Common::Point( 5, 80), 39, 30);
122 
123 class EEMEngine : public Engine {
124 public:
125  EEMEngine(OSystem *syst, const ADGameDescription *gameDesc);
126  ~EEMEngine() override;
127 
128  Common::Error run() override;
129 
130  const char *getGameId() const;
131  Common::Platform getPlatform() const;
132  Variant getVariant() const { return _variant; }
133  bool isFloppy() const { return _variant == kVariantFloppy || isDemo(); }
134  bool isLondon() const { return _variant == kVariantLondonCD; }
135  // London (game) and Macintosh (platform) are orthogonal -- the London CD
136  // shipped for both DOS and Mac -- so derive Mac-ness from the platform
137  // rather than the single-valued `_variant` (which can only hold one of
138  // them at a time). This lets EEM2 Mac be both London and Macintosh.
139  bool isMacintosh() const { return getPlatform() == Common::kPlatformMacintosh; }
140  bool isDemo() const {
141  return _gameDescription && (_gameDescription->flags & ADGF_DEMO);
142  }
143  int screenWidth() const { return isMacintosh() ? kMacScreenWidth : kScreenWidth; }
144  int screenHeight() const { return isMacintosh() ? kMacScreenHeight : kScreenHeight; }
145  int scaleX(int x) const {
146  return isMacintosh() ? scaleCoord(x, kMacScreenWidth, kScreenWidth) : x;
147  }
148  int scaleY(int y) const {
149  return isMacintosh() ? scaleCoord(y, kMacScreenHeight, kScreenHeight) : y;
150  }
151  int unscaleX(int x) const {
152  return isMacintosh() ? scaleCoord(x, kScreenWidth, kMacScreenWidth) : x;
153  }
154  int unscaleY(int y) const {
155  return isMacintosh() ? scaleCoord(y, kScreenHeight, kMacScreenHeight) : y;
156  }
157  Common::Point scalePoint(int x, int y) const {
158  return Common::Point(scaleX(x), scaleY(y));
159  }
160  Common::Rect scaleRect(const Common::Rect &r) const {
161  return Common::Rect(scaleX(r.left), scaleY(r.top),
162  scaleX(r.right), scaleY(r.bottom));
163  }
164 
165  bool hasFeature(EngineFeature f) const override;
166  bool canLoadGameStateCurrently(Common::U32String *msg = nullptr) override;
167  bool canSaveGameStateCurrently(Common::U32String *msg = nullptr) override;
168 
169  int getAutosaveSlot() const override { return -1; }
170 
172  bool isAutosave = false) override;
174 
175  Common::Error saveProfile(const Common::String &name);
176 
177  bool loadProfile(const Common::String &name);
178 
179  SaveStateList listProfiles() const;
180 
181  const ADGameDescription *_gameDescription;
182  Variant _variant = kVariantCD;
183  Common::Language _language = Common::EN_ANY;
184 
186  bool isSpanish() const { return _language == Common::ES_ESP; }
187 
188  DBDArchive &getPics() { return _picsArchive; }
189  DBDArchive &getAni() { return _aniArchive; }
190  DBDArchive &getSites() { return _sitesArchive; }
191  DBDArchive &getBalloons() { return _balloonArchive; }
192  DBDArchive &getButtons() { return _buttonArchive; }
193  Mystery &getMystery() { return _mystery; }
194  const EEMFont &getFont() const { return _font; }
195  uint8 getPartnerIndex() const { return _partner; }
196 
199  void setInteractiveMouseCursor(bool active);
200 
202  void setHotspotMouseCursor(bool active);
203 
207  void setSiteHotspotCursorId(int cursorId);
208 
210  void displayClue(const byte *clueBlock);
211 
214  bool doPuzzle(uint puzzleId);
215 
216  void displayFloppyHotspotDialog(uint siteNum, uint hotIdx);
217 
218  bool floppyHotspotSearched(uint siteNum, uint hotspotIdx) const;
219 
221  const Common::String &playerName() const { return _playerName; }
222 
224  void applyClueSideEffects(const byte *entry);
225 
226  void doNotebook();
227  void doGallery();
228  bool moreInfo(const byte *gd, uint suspectIdx,
229  const Picture &galBg, bool haveBg);
230  void doBigMap();
231 
233  void doAccuse();
234  void doAccuseFloppy();
235 
238  bool doAccuseNotes();
239 
240  void drawKDBalloonOverCurrentScreen(Common::String text);
241 
243  void doHelp();
244 
246  void doInterfaceHelp(uint num = 0);
247 
249  uint16 getKDTextBalloon(byte firstChar) const;
250 
252  uint16 fitBalloonToText(uint16 bubNum, const Common::String &text);
253 
256  uint getBalloonLineCapacity(uint16 balloonId, int lineH) const;
257 
260  const Common::String &playerName,
261  uint partner) const;
262 
265  bool loadKdAnim(uint16 num, Animation &anim, int &px, int &py,
266  uint16 &animId);
267 
268  void setPartnerEraseBg(const Graphics::ManagedSurface *bg);
269 
272  void setPartnerIdleAnim(bool has, uint16 animId, int x, int y) {
273  _hasPartnerIdle = has;
274  _partnerIdleAnimId = animId;
275  _partnerIdleX = x;
276  _partnerIdleY = y;
277  }
278 
285  bool getBalloonInsets(uint16 bubNum, uint16 &xInset, uint16 &yInset,
286  uint16 &textW) const;
287  bool getBalloonIndicatorPos(uint16 bubNum, uint16 &dx,
288  uint16 &dy) const;
289 
290  void drawFloppyBubbleIndicator(Graphics::ManagedSurface &dst,
291  uint16 bubNum, int ballX, int ballY,
292  bool endIndicator);
293 
294  bool areYouSure();
295 
296 private:
297  void applyStartupTestOverrides();
298  bool areMysteriesSolved(uint lo, uint hi) const;
299 
302  bool anyMysterySolved(uint lo, uint hi) const;
303 
307  uint mysteryTierCount() const { return isLondon() ? 2 : 3; }
308 
311  bool mysteryTierRange(uint stage, uint &lo, uint &hi) const;
312 
313  void advanceChainStageAfterSolve(uint mysteryNum);
314  void applySkipRepeatedCasesOption();
315 
316  void screenDriver();
317 
319  void drawNotebookFrame(int &page);
320 
323  Common::String notebookNoteText(uint clueId, const byte *ni,
324  uint16 niCount, bool floppyNb,
325  const byte *bufBase,
326  uint32 mysSz) const;
327 
330  struct AccuseNotesCtx {
331  const byte *ni;
332  uint16 niCount;
333  bool floppyNote;
334  const byte *bufBaseNotes;
335  const Common::Array<uint> *found;
336  int rectX, rectY, rectW, rectH;
337  uint expected;
338  bool haveBg;
339  const Picture *accuseBg;
340  Common::Array<Common::Rect> *slotRects;
341  Common::Array<uint> *slotClues;
342  int *pageBreaks;
343  int pageBreaksCap;
344  int *numPages;
345  int *page;
346  };
347 
349  Common::String accuseNoteText(uint clueId, const AccuseNotesCtx &ctx) const;
350 
352  void accuseRebuildPagination(const AccuseNotesCtx &ctx);
353 
355  void accuseDrawScreen(const AccuseNotesCtx &ctx);
356 
360  void floppyKDHint(uint kdSlot, const byte *kdIdx,
361  const byte *bufBase, uint32 mysSize);
362  void displayScrapbookExtra(uint mysteryNum);
363  void accuseDrawGallery(int highlighted,
365  Common::Array<int> &suspects, uint8 num,
366  bool haveAccuseBg, const Picture &accuseBg);
367  void drawGalleryFrame(const byte *gd, uint8 numSuspects,
368  Common::Array<Common::Rect> &slotRects,
369  Common::Array<int> &slotSuspect);
370 
371  struct BigMapOverviewState {
372  Common::Rect window;
373  int zoomX = 0;
374  int zoomY = 0;
375  };
376 
377  struct BigMapDetailState {
378  const Common::Array<byte> *mapPixels = nullptr;
379  uint16 mapW = 0;
380  uint16 mapH = 0;
381 
382  int scrollX = 0;
383  int scrollY = 0;
384  int maxScrollX = 0;
385  int maxScrollY = 0;
386 
387  int mapWinX = 0;
388  int mapWinY = 0;
389  int mapWinW = 0;
390  int mapWinH = 0;
391 
392  Common::Rect returnRect;
393  Common::Rect setupRect;
394  Common::Rect arrowYUp;
395  Common::Rect arrowYDown;
396  Common::Rect arrowXLeft;
397  Common::Rect arrowXRight;
398  Common::Rect xSlider;
399  Common::Rect ySlider;
400 
401  int arrowStepX = 0;
402  int arrowStepY = 0;
403 
404  uint32 startTick = 0;
405  uint32 lastDrawTick = 0;
406  uint32 lastCycleTick = 0;
407  };
408 
409  bool bigMapRunOverview(BigMapOverviewState &state);
410  bool bigMapLoadDetailPixels(Common::Array<byte> &mapPixels,
411  uint16 &mapW, uint16 &mapH);
412  void bigMapInitDetailState(BigMapDetailState &state,
413  const Common::Array<byte> &mapPixels,
414  uint16 mapW, uint16 mapH,
415  const BigMapOverviewState &overview);
416  bool bigMapRunDetail(BigMapDetailState &state);
417  bool bigMapHandleDetailEvent(const Common::Event &ev,
418  BigMapDetailState &state,
419  bool &returnToOverview, bool &dirty);
420  void bigMapHandleDetailKey(const Common::Event &ev,
421  BigMapDetailState &state, bool &dirty);
422  bool bigMapHandleDetailMouseDown(const Common::Event &ev,
423  BigMapDetailState &state,
424  bool &returnToOverview, bool &dirty);
425  bool bigMapTrySelectDetailSite(int mouseX, int mouseY,
426  const BigMapDetailState &state);
427  void bigMapCycleOverviewPalette(bool mac);
428  void bigMapCycleDetailPalette(bool mac);
429  void drawBigMapOverview(uint32 elapsedMs);
430  void drawBigMapDetail(int scrollX, int scrollY,
431  const Common::Array<byte> &mapPixels,
432  uint16 mapW, uint16 mapH,
433  uint32 elapsedMs);
434  void drawAccuseGallery(uint8 numSuspects, const byte *gd,
435  int highlighted,
436  Common::Array<Common::Rect> &slotRects,
437  Common::Array<int> &slotSuspect);
438 
440  bool openArchives();
441 
443  bool loadSitePalettes();
444 
447  void setSitePalette(uint num);
448 
451  bool getSitePalette(uint num, byte *out) const;
452 
455  bool setAnmPalette(const Common::Path &anmPath);
456 
457 public:
459  void setSitePaletteForSite(uint siteNum) { setSitePalette(siteNum + 1); }
460 private:
461 
462  void blitAt(const Picture &pic, int x, int y);
463 
468  void blitAtScaled(const Picture &pic, int x, int y, int scale);
469 
470 public:
471  void waitForInput(uint32 maxMs);
472 
479  void playAnm(const Common::Path &path, uint frameDelayMs = 120,
480  bool holdLastFrame = false, bool fadeIn = false,
481  bool setSkipIntroOnEsc = true);
482 
487  void playFlc(const Common::Path &path, bool fadeIn = false,
488  bool holdLastFrame = false);
489 
490 private:
491  void interruptAudio(bool stopMusicToo = true);
492 
493  void showEAKidsLogo();
494  void showHighScoreLogo();
495  void showFloppyStormLogo();
496 
497  bool waitIntroDelay(uint32 maxMs);
498  void runMacStartup();
499  void showMacEAKidsLogo();
500  void showMacStillLogo(uint picId, uint palId, uint holdMs,
501  bool playThunder);
502  void showMacTitleIntro();
503 
504  void runLondonStartup();
506  bool startLondonTrainingMystery();
507  void showLondonEAKidsLogo();
508  void showLondonLogo(uint picId, uint palId, uint holdMs,
509  bool playThunder = false);
510  void showLondonCharSelect();
511  void playLondonInitCluesAnim(uint16 caseType, const Picture &bg,
512  bool haveBriefingBg);
513  void playCdFloppyInitCluesAnim(uint16 caseType, bool floppy,
514  const Picture &bg, bool haveBriefingBg);
515 
516  void doProfilePicker();
517  void doNewPlayer();
518  void doChoosePartner();
519 
529  int doShowEnding(uint num, bool firstPage = true);
530 
534  void doShowScrapbook(uint stage);
535 
536  void doActionScreen();
537  void doCaseSelection();
538  void doSiteLoop();
539 
540  void doSetup();
541 
542  void setupDrawScreen();
543  Common::KeyCode setupShowFullscreenPic(uint16 picId, bool transparent);
544  void setupLeave();
545 
546  void doSetupLondon();
547  void setupDrawScreenLondon();
550  void setupShowSavedConfirm();
551 
553  void doInitClues();
554 
561  void displayFloppyBriefing(const byte *initBlock);
562 
566  void displayFloppyDialogRecords(const byte *rec, uint count,
567  uint lastIndicator = 0);
568 
572  bool floppyDialogWaitForClick();
573 
574 public:
577  void startTravelMusic();
578 
580  void waitForMusicDone(uint32 maxMs = 60000);
581 
583  void stopMusic();
584 
587  bool doLondonApproach(uint16 approachId);
588 
591  void syncSoundSettings() override;
592 
595  void startLondonTravelMusic(uint8 travelKind);
596 private:
597  static int scaleCoord(int value, int target, int source) {
598  const bool negative = value < 0;
599  const int magnitude = negative ? -value : value;
600  const int scaled = (magnitude * target + source / 2) / source;
601  return negative ? -scaled : scaled;
602  }
603 
604  Common::String _playerName;
605 
610  bool _playerFemale = false;
611 
613  uint8 _mysteriesSolved[55] = {};
614  uint8 _chainStage = 1;
615 
616  bool _voiceOn = true;
617  bool _musicOn = true;
618 
621  bool _profileCreatedThisSession = false;
622 
624 
625  DBDArchive _picsArchive;
626  DBDArchive _aniArchive;
627  DBDArchive _sitesArchive;
628  DBDArchive _balloonArchive;
629  DBDArchive _buttonArchive;
630  Mystery _mystery;
631  EEMFont _font;
632  EEMFont _dialogFont;
633 
634  Common::Array<byte> _sitePals;
635 
636  uint16 _lastScreen;
637  uint16 _nextScreen;
638  uint8 _partner;
639 
641  bool _skipIntro = false;
642 
644  Graphics::ManagedSurface _partnerEraseBg;
645 
647  bool _hasPartnerIdle = false;
648  uint16 _partnerIdleAnimId = 0;
649  int _partnerIdleX = 0;
650  int _partnerIdleY = 0;
651 
652  bool _interactiveMouseCursor = false;
655  int _siteCursorId = 0;
656 
659  int _lastSiteArrivalAnim = -1;
660 
661  bool _restoredContentDataLoaded = false;
662 
665  MusicPlayer *_music = nullptr;
666 
667 public:
668  AudioPlayer *_audio = nullptr;
669 
671  void setNextScreen(ScreenId s) { _nextScreen = s; }
672  bool shouldPlaySiteArrival(uint siteNum) const {
673  return _lastSiteArrivalAnim != (int)siteNum;
674  }
675  void markSiteArrivalPlayed(uint siteNum) {
676  _lastSiteArrivalAnim = (int)siteNum;
677  }
678  void resetSiteArrivalState() {
679  _lastSiteArrivalAnim = -1;
680  }
681  void setSiteArrivalState(uint siteNum) {
682  _lastSiteArrivalAnim = (int)siteNum;
683  }
684 };
685 
686 Common::Rect pdaControlRect(const EEMEngine *vm, const Common::Rect &rect);
687 
688 } // End of namespace EEM
689 
690 #endif
Definition: managed_surface.h:51
void waitForMusicDone(uint32 maxMs=60000)
_IsMIDIPlaying spin + _StopMIDI cleanup in _DoSiteLoop.
void stopMusic()
_StopMIDI @ 20a2:0512.
uint16 fitBalloonToText(uint16 bubNum, const Common::String &text)
Pick a shorter balloon sibling when wrapped text leaves empty lines.
void applyClueSideEffects(const byte *entry)
Apply a ClueEntry&#39;s side effects (notebook, gallery, site flags).
Definition: str.h:59
void setNextScreen(ScreenId s)
_NextScreen @ 2d5d:3f26 writer for site loop / inline screens.
Definition: eem.h:671
EngineFeature
Definition: engine.h:258
bool doAccuseNotes()
void setInteractiveMouseCursor(bool active)
Definition: stream.h:77
Definition: error.h:81
T left
Definition: rect.h:170
void setSiteHotspotCursorId(int cursorId)
Common::Error run() override
int getAutosaveSlot() const override
Definition: eem.h:169
uint getBalloonLineCapacity(uint16 balloonId, int lineH) const
void startLondonTravelMusic(uint8 travelKind)
Definition: mystery.h:50
Definition: advancedDetector.h:164
Definition: random.h:44
Definition: rect.h:524
Definition: path.h:52
Definition: resource.h:46
Definition: audio.h:55
void playAnm(const Common::Path &path, uint frameDelayMs=120, bool holdLastFrame=false, bool fadeIn=false, bool setSkipIntroOnEsc=true)
Definition: stream.h:745
bool canSaveGameStateCurrently(Common::U32String *msg=nullptr) override
void syncSoundSettings() override
uint32 flags
Definition: advancedDetector.h:207
void setHotspotMouseCursor(bool active)
Interactive cursor over searchable hotspots.
bool doPuzzle(uint puzzleId)
void playFlc(const Common::Path &path, bool fadeIn=false, bool holdLastFrame=false)
bool isSpanish() const
Spanish floppy release.
Definition: eem.h:186
uint16 getKDTextBalloon(byte firstChar) const
_GetKDTextBalloon @ 1df2:0105.
T right
Definition: rect.h:171
Common::Error loadGameStream(Common::SeekableReadStream *stream) override
Definition: font.h:55
.DBD + .DBX archive pair (PICS, SITES, ANI, BALLOON, BUTTON).
Definition: resource.h:58
Definition: animation.h:30
Definition: ustr.h:57
void setSitePaletteForSite(uint siteNum)
Public so SiteScreen can switch palettes per site.
Definition: eem.h:459
const Common::String & playerName() const
Active player name (= profile-save description).
Definition: eem.h:221
bool loadKdAnim(uint16 num, Animation &anim, int &px, int &py, uint16 &animId)
Definition: events.h:210
Definition: eem.h:123
void setPartnerIdleAnim(bool has, uint16 animId, int x, int y)
Definition: eem.h:272
Definition: rect.h:144
Common::String parseString(const Common::String &raw, const Common::String &playerName, uint partner) const
_ParseString @ 1b66:07c3.
bool canLoadGameStateCurrently(Common::U32String *msg=nullptr) override
void doHelp()
_KDHelp @ 1560:010a + _DisplayHint @ 1560:0009.
bool getBalloonInsets(uint16 bubNum, uint16 &xInset, uint16 &yInset, uint16 &textW) const
bool doLondonApproach(uint16 approachId)
bool hasFeature(EngineFeature f) const override
void startTravelMusic()
Definition: system.h:165
void displayClue(const byte *clueBlock)
_DisplayClue @ 2404:05e6.
Definition: music.h:51
Add "-demo" to gameid.
Definition: advancedDetector.h:157
void doInterfaceHelp(uint num=0)
_InterfaceHelp @ 1560:0205. Walks HelpData @ 29be:00c8.
void doAccuse()
Accuse flow. _DoAccuseGallery @ 1df2:0a31 + _DisplayEnding @ 1df2:0548.
Definition: engine.h:144
Platform
Definition: platform.h:93
Common::Error saveGameStream(Common::WriteStream *stream, bool isAutosave=false) override
Language
Definition: language.h:45