Files
2026-02-02 04:50:13 +01:00

556 lines
14 KiB
C++

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef PRIVATE_H
#define PRIVATE_H
#include "common/random.h"
#include "common/serializer.h"
#include "engines/engine.h"
#include "graphics/managed_surface.h"
#include "graphics/wincursor.h"
#include "video/smk_decoder.h"
#include "video/subtitles.h"
#include "private/grammar.h"
namespace Common {
class Archive;
}
namespace Image {
class ImageDecoder;
}
namespace Graphics {
class ManagedSurface;
}
struct ADGameDescription;
namespace Private {
enum PRIVATEActions {
kActionSkip,
};
// debug channels
enum {
kPrivateDebugFunction = 1,
kPrivateDebugCode,
kPrivateDebugScript,
};
// sounds
const int kPaperShuffleSound[7] = {32, 33, 34, 35, 36, 37, 39};
// police
const int kPoliceBustVideos[6] = {1, 2, 4, 5, 7, 8};
// points
const int kOriginZero[2] = {0, 0};
const int kOriginOne[2] = {64, 48};
// vm
extern Gen::VM *Gen::g_vm;
// structs
typedef struct ExitInfo {
Common::String nextSetting;
Common::Rect rect;
Common::String cursor;
void clear() {
nextSetting.clear();
rect.setEmpty();
cursor.clear();
}
} ExitInfo;
typedef struct MaskInfo {
Graphics::Surface *surf;
Common::String nextSetting;
Common::Point point;
Symbol *flag1;
Symbol *flag2;
Common::String cursor;
Common::String inventoryItem;
bool useBoxCollision;
Common::Rect box;
MaskInfo() {
clear();
}
void clear() {
surf = nullptr;
useBoxCollision = false;
box = Common::Rect();
flag1 = nullptr;
flag2 = nullptr;
nextSetting.clear();
cursor.clear();
point = Common::Point();
inventoryItem.clear();
}
} MaskInfo;
enum PhoneStatus : byte {
kPhoneStatusWaiting,
kPhoneStatusAvailable,
kPhoneStatusCalling,
kPhoneStatusMissed,
kPhoneStatusAnswered
};
typedef struct Sound {
Common::String name;
Audio::SoundHandle handle;
} Sound;
typedef struct PhoneInfo {
Common::String name;
bool once;
int startIndex;
int endIndex;
Common::String flagName;
int flagValue;
PhoneStatus status;
int callCount;
uint32 soundIndex;
Common::Array<Common::String> sounds;
} PhoneInfo;
typedef struct RadioClip {
Common::String name;
bool played;
int priority;
int disabledPriority1; // 0 == none
bool exactPriorityMatch1;
int disabledPriority2; // 0 == none
bool exactPriorityMatch2;
Common::String flagName;
int flagValue;
} RadioClip;
typedef struct Radio {
Common::String path;
Sound *sound;
Common::Array<RadioClip> clips;
int channels[3];
Radio() : sound(nullptr) {
clear();
}
void clear() {
clips.clear();
for (uint i = 0; i < ARRAYSIZE(channels); i++) {
channels[i] = -1;
}
}
} Radio;
typedef struct DossierInfo {
Common::String page1;
Common::String page2;
} DossierInfo;
typedef struct CursorInfo {
Common::String name;
Common::String aname;
Graphics::Cursor *cursor;
Graphics::WinCursorGroup *winCursorGroup;
} CursorInfo;
typedef struct MemoryInfo {
Common::String image;
Common::String movie;
} MemoryInfo;
typedef struct DiaryPage {
Common::String locationName;
Common::Array<MemoryInfo> memories;
int locationID;
} DiaryPage;
typedef struct InventoryItem {
Common::String diaryImage;
Common::String flag;
} InventoryItem;
// funcs
typedef struct FuncTable {
void (*func)(Private::ArgArray);
const char *name;
} FunctTable;
typedef Common::HashMap<Common::String, void *> NameToPtr;
extern const FuncTable funcTable[];
// lists
typedef Common::List<ExitInfo> ExitList;
typedef Common::List<MaskInfo> MaskList;
typedef Common::List<PhoneInfo> PhoneList;
typedef Common::List<InventoryItem> InvList;
typedef Common::List<Common::Rect *> RectList;
// arrays
typedef Common::Array<DossierInfo> DossierArray;
typedef Common::Array<DiaryPage> DiaryPages;
// hash tables
typedef Common::HashMap<Common::String, bool> PlayedMediaTable;
enum SubtitleType {
kSubtitleAudio,
kSubtitleVideo
};
struct SubtitleSlot {
Audio::SoundHandle handle;
Video::Subtitles *subs;
SubtitleSlot() : subs(nullptr) {}
};
class PrivateEngine : public Engine {
private:
Common::RandomSource *_rnd;
Graphics::PixelFormat _pixelFormat;
Image::ImageDecoder *_image;
int _screenW, _screenH;
// helper to generate the correct subtitle path
Common::Path getSubtitlePath(const Common::String &soundName);
bool isSfxSubtitle(const Video::Subtitles *subs);
bool isSlotActive(const SubtitleSlot &slot);
public:
bool _shouldHighlightMasks;
bool _highlightMasks;
PrivateEngine(OSystem *syst, const ADGameDescription *gd);
~PrivateEngine();
const ADGameDescription *_gameDescription;
bool isDemo() const;
Common::Language _language;
Common::Platform _platform;
SymbolMaps maps;
Video::SmackerDecoder *_videoDecoder;
Video::SmackerDecoder *_pausedVideo;
Common::String _pausedMovieName;
Common::Error run() override;
void restartGame();
void clearAreas();
void initializePath(const Common::FSNode &gamePath) override;
void pauseEngineIntern(bool pause) override;
Common::SeekableReadStream *loadAssets();
Common::Archive *loadMacInstaller();
// Functions
NameToPtr _functions;
void initFuncs();
// User input
void selectPauseGame(Common::Point);
bool selectMask(Common::Point);
bool selectExit(Common::Point);
bool selectLoadGame(Common::Point);
bool selectSaveGame(Common::Point);
void resumeGame();
// Cursors
void updateCursor(Common::Point);
bool cursorPauseMovie(Common::Point);
bool cursorExit(Common::Point);
bool cursorSafeDigit(Common::Point);
bool cursorMask(Common::Point);
bool hasFeature(EngineFeature f) const override;
bool canLoadGameStateCurrently(Common::U32String *msg = nullptr) override {
return true;
}
bool canSaveAutosaveCurrently() override {
return false;
}
bool canSaveGameStateCurrently(Common::U32String *msg = nullptr) override {
return true;
}
Common::Error loadGameStream(Common::SeekableReadStream *stream) override;
Common::Error saveGameStream(Common::WriteStream *stream, bool isAutosave = false) override;
static Common::Path convertPath(const Common::String &name);
static Common::String getVideoViewScreen(Common::String video);
void playVideo(const Common::String &);
void skipVideo();
void destroyVideo();
void loadSubtitles(const Common::Path &path, SubtitleType type, Sound *sound = nullptr);
// use to clean up sounds which have finished playing once
void updateSubtitles();
void destroySubtitles();
void adjustSubtitleSize();
Video::Subtitles *_videoSubtitles;
SubtitleSlot _voiceSlot; // high priority (speech)
SubtitleSlot _sfxSlot; // low priority (sfxs)
bool _useSubtitles;
bool _sfxSubtitles;
Graphics::Surface *decodeImage(const Common::String &file, byte **palette, bool *isNewPalette);
//byte *decodePalette(const Common::String &name);
void remapImage(uint16 ncolors, const Graphics::Surface *oldImage, const byte *oldPalette, Graphics::Surface *newImage, const byte *currentPalette);
static uint32 findMaskTransparentColor(const byte *palette, uint32 defaultColor);
static void swapImageColors(Graphics::Surface *image, byte *palette, uint32 a, uint32 b);
void loadImage(const Common::String &file, int x, int y);
void drawScreenFrame(const byte *videoPalette);
// Cursors
Graphics::Cursor *_defaultCursor;
Common::Array<CursorInfo> _cursors;
Common::String _currentCursor;
void changeCursor(const Common::String &);
Common::String getInventoryCursor();
Common::String getExitCursor();
void loadCursors();
// Rendering
Graphics::ManagedSurface *_compositeSurface;
Graphics::Surface *loadMask(const Common::String &, int, int, bool);
void loadMaskAndInfo(MaskInfo *m, const Common::String &name, int x, int y, bool drawn);
void drawMask(Graphics::Surface *);
void fillRect(uint32, Common::Rect);
bool inMask(Graphics::Surface *, Common::Point);
uint32 _transparentColor;
Common::Rect _screenRect;
Common::String _framePath;
Graphics::Surface *_frameImage;
Graphics::Surface *_mframeImage;
byte *_framePalette;
Common::String _nextVS;
Common::String _currentVS;
Common::Point _origin;
void drawScreen();
bool _needToDrawScreenFrame;
// settings
Common::String _nextSetting;
Common::String _pausedSetting;
Common::String _currentSetting;
Common::String getPauseMovieSetting();
Common::String getGoIntroSetting();
Common::String getMainDesktopSetting();
Common::String getDiaryTOCSetting();
Common::String getDiaryMiddleSetting();
Common::String getDiaryLastPageSetting();
Common::String getPOGoBustMovieSetting();
Common::String getPoliceBustFromMOSetting();
Common::String getListenToPhoneSetting();
Common::String getAlternateGameVariable();
Common::String getPoliceIndexVariable();
Common::String getWallSafeValueVariable();
Common::String getPoliceArrivedVariable();
Common::String getBeenDowntownVariable();
Common::String getPoliceStationLocation();
const char *getSymbolName(const char *name, const char *strippedName, const char *demoName = nullptr);
// movies
Common::String _nextMovie;
Common::String _currentMovie;
// Dossiers
DossierArray _dossiers;
uint _dossierSuspect;
uint _dossierPage;
MaskInfo _dossierPageMask;
MaskInfo _dossierNextSuspectMask;
MaskInfo _dossierPrevSuspectMask;
MaskInfo _dossierNextSheetMask;
MaskInfo _dossierPrevSheetMask;
bool selectDossierPage(Common::Point);
bool selectDossierNextSuspect(Common::Point);
bool selectDossierPrevSuspect(Common::Point);
bool selectDossierNextSheet(Common::Point);
bool selectDossierPrevSheet(Common::Point);
void addDossier(Common::String &page1, Common::String &page2);
void loadDossier();
// Police Bust
bool _policeBustEnabled;
bool _policeSirenPlayed;
int _numberOfClicks;
int _numberClicksAfterSiren;
int _policeBustMovieIndex;
Common::String _policeBustMovie;
Common::String _policeBustPreviousSetting;
void resetPoliceBust();
void startPoliceBust();
void stopPoliceBust();
void wallSafeAlarm();
void completePoliceBust();
void checkPoliceBust();
// Diary
InvList inventory;
bool inInventory(const Common::String &bmp) const;
void addInventory(const Common::String &bmp, Common::String &flag);
void removeInventory(const Common::String &bmp);
void removeRandomInventory();
Common::String _diaryLocPrefix;
void loadLocations(const Common::Rect &);
void loadInventory(uint32, const Common::Rect &, const Common::Rect &);
bool _toTake;
bool _haveTakenItem;
DiaryPages _diaryPages;
int _currentDiaryPage;
ExitInfo _diaryNextPageExit;
ExitInfo _diaryPrevPageExit;
bool selectDiaryNextPage(Common::Point mousePos);
bool selectDiaryPrevPage(Common::Point mousePos);
void addMemory(const Common::String &path);
void loadMemories(const Common::Rect &rect, uint rightPageOffset, uint verticalOffset);
bool selectLocation(const Common::Point &mousePos);
Common::Array<MaskInfo> _locationMasks;
Common::Array<MaskInfo> _memoryMasks;
bool selectMemory(const Common::Point &mousePos);
void setLocationAsVisited(Symbol *location);
int getMaxLocationValue();
bool selectSkipMemoryVideo(Common::Point mousePos);
// Save/Load games
MaskInfo _saveGameMask;
MaskInfo _loadGameMask;
int _mode;
bool _modified;
PlayedMediaTable _playedMovies;
Common::String _repeatedMovieExit;
// Masks/Exits
ExitList _exits;
MaskList _masks;
// Sounds
void playBackgroundSound(const Common::String &name);
void playForegroundSound(const Common::String &name);
void playForegroundSound(Sound &sound, const Common::String &name);
void playSound(Sound &sound, const Common::String &name, bool loop);
void stopForegroundSounds();
void stopSounds();
void stopSound(Sound &sound);
bool isSoundPlaying();
bool isSoundPlaying(Sound &sound);
void waitForSoundsToStop();
bool consumeEvents();
Sound _bgSound;
Sound _fgSounds[4];
Sound _phoneCallSound;
Sound _AMRadioSound;
Sound _policeRadioSound;
Sound _takeLeaveSound;
bool _noStopSounds;
Common::String _pausedBackgroundSoundName;
Common::String getPaperShuffleSound();
Common::String _globalAudioPath;
Common::String getTakeSound();
Common::String getTakeLeaveSound();
Common::String getLeaveSound();
Common::String _sirenSound;
// Radios
MaskInfo _AMRadioArea;
MaskInfo _policeRadioArea;
Radio _AMRadio;
Radio _policeRadio;
void addRadioClip(
Radio &radio, const Common::String &name, int priority,
int disabledPriority1, bool exactPriorityMatch1,
int disabledPriority2, bool exactPriorityMatch2,
const Common::String &flagName, int flagValue);
void initializeAMRadioChannels(uint clipCount);
void initializePoliceRadioChannels();
void disableRadioClips(Radio &radio, int priority);
void playRadio(Radio &radio, bool randomlyDisableClips);
bool selectAMRadioArea(Common::Point);
bool selectPoliceRadioArea(Common::Point);
// Phone
MaskInfo _phoneArea;
Common::String _phonePrefix;
PhoneList _phones;
void addPhone(const Common::String &name, bool once, int startIndex, int endIndex, const Common::String &flagName, int flagValue);
void initializePhoneOnDesktop();
void checkPhoneCall();
bool cursorPhoneArea(Common::Point mousePos);
bool selectPhoneArea(Common::Point mousePos);
// Safe
Common::String _safeNumberPath;
MaskInfo _safeDigitArea[3];
Common::Rect _safeDigitRect[3];
void initializeWallSafeValue();
bool selectSafeDigit(Common::Point);
void addSafeDigit(uint32, Common::Rect*);
int getSafeDigit(uint32 d);
void incrementSafeDigit(uint32 d);
// Random values
bool getRandomBool(uint);
// Timer
Common::String _timerSetting;
Common::String _timerSkipSetting;
uint32 _timerStartTime;
uint32 _timerDelay;
void setTimer(uint32 duration, const Common::String &setting, const Common::String &skipSetting);
void clearTimer();
void skipTimer();
void checkTimer();
// VM objects
RectList _rects; // created by fCRect
};
extern PrivateEngine *g_private;
} // End of namespace Private
#endif