/* 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 . * */ #ifndef VCRUISE_RUNTIME_H #define VCRUISE_RUNTIME_H #include "graphics/pixelformat.h" #include "common/hashmap.h" #include "common/keyboard.h" #include "common/mutex.h" #include "common/rect.h" #include "vcruise/detection.h" class OSystem; class MidiDriver; namespace Common { class MemoryReadStream; class RandomSource; class ReadStream; class WriteStream; } // End of namespace Commom namespace Audio { class AudioStream; class SeekableAudioStream; class LoopingAudioStream; } // End of namespace Audio namespace Graphics { struct PixelFormat; struct WinCursorGroup; class ManagedSurface; class Font; class Cursor; } // End of namespace Graphics namespace Video { class AVIDecoder; } // End of namespace Video namespace Image { class AniDecoder; } // End of namespace Image namespace VCruise { static const uint kNumDirections = 8; static const uint kNumHighPrecisionDirections = 256; static const uint kHighPrecisionDirectionMultiplier = kNumHighPrecisionDirections / kNumDirections; static const uint kNumStartConfigs = 3; enum StartConfig { kStartConfigCheatMenu, kStartConfigInitial, kStartConfigAlt, }; class AudioPlayer; class CircuitPuzzle; class MidiPlayer; class MenuInterface; class MenuPage; class RuntimeMenuInterface; class TextParser; struct ScriptSet; struct Script; struct IScriptCompilerGlobalState; struct Instruction; struct RoomScriptSet; struct SoundLoopInfo; class SampleLoopAudioStream; struct AD2044Graphics; enum GameState { kGameStateBoot, // Booting the game kGameStateWaitingForAnimation, // Waiting for a blocking animation with no stop frame to complete, then resuming script kGameStateWaitingForAnimationToDelay, // Waiting for a blocking animation with no stop frame to complete, then going to delay kGameStateWaitingForFacing, // Waiting for a blocking animation with a stop frame to complete, then resuming script kGameStateWaitingForFacingToAnim, // Waiting for a blocking animation to complete, then playing _postFacingAnimDef and switching to kGameStateWaitingForAnimation kGameStateQuit, // Quitting kGameStateIdle, // Waiting for input events kGameStateDelay, // Waiting for delay completion time kGameStateScript, // Running a script kGameStateScriptReset, // Resetting script interpreter into a new script kGameStateGyroIdle, // Waiting for mouse movement to run a gyro kGameStateGyroAnimation, // Animating a gyro kGameStatePanLeft, kGameStatePanRight, kGameStateMenu, }; struct AD2044AnimationDef { byte roomID; byte lookupID; short fwdAnimationID; short revAnimationID; }; struct AnimationDef { AnimationDef(); int animNum; // May be negative if reversed uint firstFrame; uint lastFrame; // Inclusive Common::Rect constraintRect; Common::String animName; }; struct RoomDef { Common::HashMap animations; Common::HashMap vars; Common::HashMap values; Common::HashMap texts; Common::HashMap sounds; Common::String name; }; struct InteractionDef { InteractionDef(); Common::Rect rect; uint16 interactionID; uint16 objectType; }; struct MapScreenDirectionDef { Common::Array interactions; }; class MapLoader { public: virtual ~MapLoader(); virtual void setRoomNumber(uint roomNumber) = 0; virtual const MapScreenDirectionDef *getScreenDirection(uint screen, uint direction) = 0; virtual void unload() = 0; protected: static Common::SharedPtr loadScreenDirectionDef(Common::ReadStream &stream); }; struct ScriptEnvironmentVars { ScriptEnvironmentVars(); uint panInteractionID; uint clickInteractionID; uint fpsOverride; uint lastHighlightedItem; uint animChangeFrameOffset; uint animChangeNumFrames; bool lmb; bool lmbDrag; bool esc; bool exitToMenu; bool animChangeSet; bool isEntryScript; bool puzzleWasSet; }; struct SfxSound { Common::Array soundData; Common::SharedPtr memoryStream; Common::SharedPtr audioStream; Common::SharedPtr audioPlayer; }; struct SfxPlaylistEntry { SfxPlaylistEntry(); uint frame; Common::SharedPtr sample; int8 balance; int32 volume; bool isUpdate; }; struct SfxPlaylist { SfxPlaylist(); Common::Array entries; }; struct SfxData { SfxData(); void reset(); void load(Common::SeekableReadStream &stream, Audio::Mixer *mixer); typedef Common::HashMap > PlaylistMap_t; typedef Common::HashMap > SoundMap_t; PlaylistMap_t playlists; SoundMap_t sounds; }; struct SoundParams3D { SoundParams3D(); uint minRange; uint maxRange; // Not sure what this does. It's always shorter than the min range but after many tests, I've been // unable to detect any level changes from altering this parameter. uint unknownRange; void write(Common::WriteStream *stream) const; void read(Common::ReadStream *stream); }; struct SoundCache { SoundCache(); ~SoundCache(); Common::SharedPtr loopInfo; Common::SharedPtr stream; Common::SharedPtr loopingStream; Common::SharedPtr player; bool isLoopActive; }; struct SoundInstance { SoundInstance(); ~SoundInstance(); Common::String name; Common::SharedPtr cache; uint id; int32 rampStartVolume; int32 rampEndVolume; int32 rampRatePerMSec; uint32 rampStartTime; bool rampTerminateOnCompletion; int32 volume; int32 balance; uint effectiveVolume; int32 effectiveBalance; bool is3D; bool isLooping; bool isSpeech; bool restartWhenAudible; bool tryToLoopWhenRestarted; int32 x; int32 y; SoundParams3D params3D; uint32 startTime; uint32 endTime; uint32 duration; }; struct RandomAmbientSound { RandomAmbientSound(); Common::String name; int32 volume; int32 balance; uint frequency; uint sceneChangesRemaining; void write(Common::WriteStream *stream) const; void read(Common::ReadStream *stream); }; struct TriggeredOneShot { TriggeredOneShot(); bool operator==(const TriggeredOneShot &other) const; bool operator!=(const TriggeredOneShot &other) const; uint soundID; uint uniqueSlot; void write(Common::WriteStream *stream) const; void read(Common::ReadStream *stream); }; struct ScoreSectionDef { ScoreSectionDef(); Common::String musicFileName; // If empty, this is silent Common::String nextSection; int32 volumeOrDurationInSeconds; }; struct ScoreTrackDef { typedef Common::HashMap ScoreSectionMap_t; ScoreSectionMap_t sections; }; struct StartConfigDef { StartConfigDef(); uint disc; uint room; uint screen; uint direction; }; struct StaticAnimParams { StaticAnimParams(); uint initialDelay; uint repeatDelay; bool lockInteractions; void write(Common::WriteStream *stream) const; void read(Common::ReadStream *stream); }; struct StaticAnimation { StaticAnimation(); AnimationDef animDefs[2]; StaticAnimParams params; uint32 nextStartTime; uint currentAlternation; }; struct FrameData { FrameData(); uint32 frameIndex; uint16 areaFrameIndex; int8 roomNumber; uint8 frameType; // 0x01 = Keyframe, 0x02 = Intra frame (not used in Schizm), 0x41 = Last frame char areaID[4]; }; struct FrameData2 { FrameData2(); int32 x; int32 y; int32 angle; uint16 frameNumberInArea; uint16 unknown; // Subarea or something? }; struct AnimFrameRange { AnimFrameRange(); uint animationNum; uint firstFrame; uint lastFrame; // Inclusive }; struct InventoryItem { InventoryItem(); Common::SharedPtr graphic; Common::SharedPtr mask; uint itemID; bool highlighted; }; struct Fraction { Fraction(); Fraction(uint pNumerator, uint pDenominator); uint numerator; uint denominator; }; enum LoadGameOutcome { kLoadGameOutcomeSucceeded, kLoadGameOutcomeSaveDataCorrupted, kLoadGameOutcomeMissingVersion, kLoadGameOutcomeInvalidVersion, kLoadGameOutcomeSaveIsTooNew, kLoadGameOutcomeSaveIsTooOld, }; // State that is swapped when switching between characters in Schizm struct SaveGameSwappableState { struct InventoryItem { InventoryItem(); uint itemID; bool highlighted; void write(Common::WriteStream *stream) const; void read(Common::ReadStream *stream); }; struct Sound { Sound(); Common::String name; uint id; int32 volume; int32 balance; bool is3D; bool isLooping; bool tryToLoopWhenRestarted; bool isSpeech; int32 x; int32 y; SoundParams3D params3D; void write(Common::WriteStream *stream) const; void read(Common::ReadStream *stream, uint saveGameVersion); }; SaveGameSwappableState(); uint roomNumber; uint screenNumber; uint direction; uint disc; bool havePendingPostSwapScreenReset; uint loadedAnimation; uint animDisplayingFrame; bool haveIdleAnimationLoop; uint idleAnimNum; uint idleFirstFrame; uint idleLastFrame; int musicTrack; Common::String scoreTrack; Common::String scoreSection; bool musicActive; bool musicMuteDisabled; int32 musicVolume; int32 animVolume; Common::Array inventory; Common::Array sounds; Common::Array randomAmbientSounds; }; struct SaveGameSnapshot { struct PagedInventoryItem { PagedInventoryItem(); uint8 page; uint8 slot; uint8 itemID; void write(Common::WriteStream *stream) const; void read(Common::ReadStream *stream, uint saveGameVersion); }; struct PlacedInventoryItem { PlacedInventoryItem(); uint32 locationID; uint8 itemID; void write(Common::WriteStream *stream) const; void read(Common::ReadStream *stream, uint saveGameVersion); }; SaveGameSnapshot(); void write(Common::WriteStream *stream) const; LoadGameOutcome read(Common::ReadStream *stream); static const uint kSaveGameIdentifier = 0x53566372; static const uint kSaveGameCurrentVersion = 10; static const uint kSaveGameEarliestSupportedVersion = 2; static const uint kMaxStates = 2; static Common::String safeReadString(Common::ReadStream *stream); static void writeString(Common::WriteStream *stream, const Common::String &str); uint hero; uint swapOutRoom; uint swapOutScreen; uint swapOutDirection; uint8 inventoryPage; uint8 inventoryActiveItem; uint numStates; Common::SharedPtr states[kMaxStates]; bool escOn; StaticAnimParams pendingStaticAnimParams; SoundParams3D pendingSoundParams3D; int32 listenerX; int32 listenerY; int32 listenerAngle; Common::Array triggeredOneShots; Common::HashMap sayCycles; Common::HashMap variables; Common::HashMap timers; Common::Array pagedItems; Common::Array placedItems; }; enum OSEventType { kOSEventTypeInvalid, kOSEventTypeMouseMove, kOSEventTypeLButtonDown, kOSEventTypeLButtonUp, kOSEventTypeKeymappedEvent, }; enum KeymappedEvent { kKeymappedEventNone, kKeymappedEventEscape, kKeymappedEventHelp, kKeymappedEventSaveGame, kKeymappedEventLoadGame, kKeymappedEventSoundSettings, kKeymappedEventQuit, kKeymappedEventPause, kKeymappedEventMusicToggle, kKeymappedEventSoundToggle, kKeymappedEventMusicVolumeDown, kKeymappedEventMusicVolumeUp, kKeymappedEventSoundVolumeDown, kKeymappedEventSoundVolumeUp, kKeymappedEventSkipAnimation, kKeymappedEventPutItem, }; struct OSEvent { OSEvent(); OSEventType type; Common::Point pos; KeymappedEvent keymappedEvent; uint32 timestamp; }; struct TextStyleDef { Common::String fontName; uint size; uint unknown1; uint unknown2; uint unknown3; // Seems to always be 0 for English, other values for other languages uint colorRGB; uint shadowColorRGB; uint alignment; // Modulo 10 seems to be alignment: 0 = left, 1 = center, 2 = right uint unknown5; // Possibly drop shadow offset }; struct UILabelDef { Common::String lineID; Common::String styleDefID; uint graphicLeft; uint graphicTop; uint graphicWidth; uint graphicHeight; }; struct FontCacheItem { FontCacheItem(); Common::String fname; uint size; const Graphics::Font *font; Common::SharedPtr keepAlive; }; typedef Common::HashMap ScreenNameToRoomMap_t; typedef Common::HashMap RoomToScreenNameToRoomMap_t; struct AnimatedCursor { struct FrameDef { uint imageIndex; uint delay; }; Common::Array frames; Common::Array images; Common::Array > cursorKeepAlive; Common::SharedPtr cursorGroupKeepAlive; }; class Runtime { public: friend class RuntimeMenuInterface; enum CharSet { kCharSetLatin, kCharSetGreek, kCharSetCyrillic, kCharSetJapanese, kCharSetChineseTraditional, kCharSetChineseSimplified, }; Runtime(OSystem *system, Audio::Mixer *mixer, MidiDriver *midiDrv, const Common::FSNode &rootFSNode, VCruiseGameID gameID, Common::Language defaultLanguage); virtual ~Runtime(); void initSections(const Common::Rect &gameRect, const Common::Rect &menuRect, const Common::Rect &trayRect, const Common::Rect &subtitleRect, const Common::Rect &fullscreenMenuRect, const Graphics::PixelFormat &pixFmt); void loadCursors(const char *exeName); void setDebugMode(bool debugMode); void setFastAnimationMode(bool fastAnimationMode); void setPreloadSounds(bool preloadSounds); void setLowQualityGraphicsMode(bool lowQualityGraphicsMode); bool runFrame(); void drawFrame(); void onLButtonDown(int16 x, int16 y); void onLButtonUp(int16 x, int16 y); void onMouseMove(int16 x, int16 y); void onKeymappedEvent(KeymappedEvent evt); bool canSave(bool onCurrentScreen) const; bool canLoad() const; void recordSaveGameSnapshot(); void recordSounds(SaveGameSwappableState &state); void restoreSaveGameSnapshot(); Common::SharedPtr generateNewGameSnapshot() const; void saveGame(Common::WriteStream *stream) const; LoadGameOutcome loadGame(Common::ReadStream *stream); bool bootGame(bool newGame); static void resolveCodePageForLanguage(Common::Language lang, Common::CodePage &outCodePage, CharSet &outCharSet); void drawLabel(Graphics::ManagedSurface *surface, const Common::String &labelID, const Common::Rect &contentRect); void getLabelDef(const Common::String &labelID, const Graphics::Font *&outFont, const Common::String *&outTextUTF8, uint32 &outColor, uint32 &outShadowColor, uint32 &outShadowOffset); void onMidiTimer(); private: enum IndexParseType { kIndexParseTypeNone, kIndexParseTypeRoom, kIndexParseTypeRRoom, // Rectangle room (constrains animation areas) kIndexParseTypeYRoom, // Yes room (variable/ID mappings) kIndexParseTypeVRoom, // Value room (value/ID mappings?) kIndexParseTypeTRoom, // Text kIndexParseTypeCRoom, // Const kIndexParseTypeSRoom, // Sound kIndexParseTypeNameRoom, }; enum AnimDecoderState { kAnimDecoderStateStopped, kAnimDecoderStatePlaying, kAnimDecoderStatePaused, }; struct IndexPrefixTypePair { const char *prefix; IndexParseType parseType; }; struct RenderSection { Common::SharedPtr surf; Common::Rect rect; Graphics::PixelFormat pixFmt; void init(const Common::Rect ¶mRect, const Graphics::PixelFormat &fmt); }; struct Gyro { static const uint kMaxPreviousStates = 3; int32 currentState; int32 requiredState; int32 previousStates[kMaxPreviousStates]; int32 requiredPreviousStates[kMaxPreviousStates]; uint numPreviousStates; uint numPreviousStatesRequired; bool wrapAround; bool requireState; Gyro(); void reset(); void logState(); }; struct GyroState { GyroState(); void reset(); static const uint kNumGyros = 5; Gyro gyros[kNumGyros]; uint completeInteraction; uint failureInteraction; uint frameSeparation; uint activeGyro; uint dragMargin; uint maxValue; AnimationDef negAnim; AnimationDef posAnim; bool isVertical; Common::Point dragBasePoint; uint dragBaseState; int32 dragCurrentState; bool isWaitingForAnimation; }; enum PanoramaCursorFlags { kPanCursorDraggableHoriz = (1 << 0), kPanCursorDraggableUp = (1 << 1), kPanCursorDraggableDown = (1 << 2), kPanCursorDirectionUp = (0 << 3), kPanCursorDirectionLeft = (1 << 3), kPanCursorDirectionRight = (2 << 3), kPanCursorDirectionDown = (3 << 3), kPanCursorMaxCount = (1 << 5), }; enum PanoramaState { kPanoramaStateInactive, kPanoramaStatePanningUncertainDirection, kPanoramaStatePanningLeft, kPanoramaStatePanningRight, kPanoramaStatePanningUp, kPanoramaStatePanningDown, }; enum InGameMenuState { kInGameMenuStateInvisible, kInGameMenuStateVisible, kInGameMenuStateHoveringInactive, kInGameMenuStateHoveringActive, kInGameMenuStateClickingOver, // Mouse was pressed on a button and is holding on it kInGameMenuStateClickingNotOver, // Mouse was pressed on a button and dragged off kInGameMenuStateClickingInactive, }; enum SoundLoopBehavior { kSoundLoopBehaviorNo, kSoundLoopBehaviorYes, kSoundLoopBehaviorAuto, }; static const uint kPanLeftInteraction = 1; static const uint kPanDownInteraction = 2; static const uint kPanRightInteraction = 3; static const uint kPanUpInteraction = 4; static const uint kPanoramaLeftFlag = 1; static const uint kPanoramaRightFlag = 2; static const uint kPanoramaUpFlag = 4; static const uint kPanoramaDownFlag = 8; static const uint kPanoramaHorizFlags = (kPanoramaLeftFlag | kPanoramaRightFlag); static const uint kNumInventorySlots = 6; static const uint kNumInventoryPages = 8; typedef int32 ScriptArg_t; typedef int32 StackInt_t; struct StackValue { enum StackValueType { kNumber, kString, }; union ValueUnion { StackInt_t i; Common::String s; ValueUnion(); explicit ValueUnion(StackInt_t iVal); explicit ValueUnion(const Common::String &strVal); explicit ValueUnion(Common::String &&strVal); ~ValueUnion(); }; StackValue(); StackValue(const StackValue &other); StackValue(StackValue &&other); explicit StackValue(StackInt_t i); explicit StackValue(const Common::String &str); explicit StackValue(Common::String &&str); ~StackValue(); StackValue &operator=(const StackValue &other); StackValue &operator=(StackValue &&other); StackValueType type; ValueUnion value; }; struct CallStackFrame { CallStackFrame(); Common::SharedPtr