/* 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 2 * 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef STARTREK_H #define STARTREK_H #include "common/events.h" #include "common/list.h" #include "common/ptr.h" #include "common/random.h" #include "common/rect.h" #include "common/scummsys.h" #include "common/serializer.h" #include "common/str.h" #include "common/stream.h" #include "common/system.h" #include "common/util.h" #include "gui/saveload-dialog.h" #include "engines/engine.h" #include "startrek/action.h" #include "startrek/awaymission.h" #include "startrek/filestream.h" #include "startrek/graphics.h" #include "startrek/items.h" #include "startrek/object.h" #include "startrek/sound.h" #include "startrek/space.h" using Common::SharedPtr; using Common::String; namespace Common { class MacResManager; } namespace StarTrek { class StarTrekEngine; class Room; typedef String (StarTrekEngine::*TextGetterFunc)(int, uintptr, String *); const int SAVEGAME_DESCRIPTION_LEN = 30; struct SavegameMetadata { uint32 version; char description[SAVEGAME_DESCRIPTION_LEN + 1]; uint32 saveDate; uint16 saveTime; byte saveTimeSecs; uint32 playTime; ::Graphics::Surface *thumbnail; void setSaveTimeAndDate(TimeDate time) { saveDate = ((time.tm_mday & 0xFF) << 24) | (((time.tm_mon + 1) & 0xFF) << 16) | ((time.tm_year + 1900) & 0xFFFF); saveTime = ((time.tm_hour & 0xFF) << 8) | ((time.tm_min) & 0xFF); saveTimeSecs = time.tm_sec & 0xFF; } int getDay() { return (saveDate >> 24) & 0xFF; } int getMonth() { return (saveDate >> 16) & 0xFF; } int getYear() { return saveDate & 0xFFFF; } int getHour() { return (saveTime >> 8) & 0xFF; } int getMinute() { return saveTime & 0xFF; } }; const int MAX_MENUBUTTONS = 32; const int TEXTBOX_WIDTH = 26; const int TEXT_CHARS_PER_LINE = TEXTBOX_WIDTH - 2; const int MAX_TEXTBOX_LINES = 12; const int MAX_BUFFERED_WALK_ACTIONS = 32; enum StarTrekGameType { GType_ST25 = 1, GType_STJR = 2 }; enum StarTrekGameFeatures { GF_DEMO = (1 << 0) }; enum kDebugLevels { kDebugSound = 1 << 0, kDebugGraphics = 1 << 1, kDebugSavegame = 2 << 1 }; enum GameMode { GAMEMODE_START = 0, GAMEMODE_BRIDGE, GAMEMODE_AWAYMISSION, GAMEMODE_BEAMDOWN, GAMEMODE_BEAMUP }; enum TextDisplayMode { TEXTDISPLAY_WAIT = 0, // Wait for input before closing text TEXTDISPLAY_SUBTITLES, // Automatically continue when speech is done TEXTDISPLAY_NONE // No text displayed }; enum TextColor { TEXTCOLOR_GREY = 0x88, TEXTCOLOR_RED = 0xa1, TEXTCOLOR_YELLOW = 0xb0, TEXTCOLOR_BLUE = 0xc0 }; // Keeps track of data for a list of buttons making up a menu struct Menu { Sprite sprites[MAX_MENUBUTTONS]; uint16 retvals[MAX_MENUBUTTONS]; uint32 disabledButtons; SharedPtr menuFile; uint16 numButtons; int16 selectedButton; SharedPtr nextMenu; }; // Special events that can be returned by handleMenuEvents. // (Normally it returns the "retval" of a pressed button, which is positive.) enum MenuEvent { MENUEVENT_RCLICK_OFFBUTTON = -4, MENUEVENT_ENABLEINPUT, // Makes buttons selectable (occurs after a delay) MENUEVENT_RCLICK_ONBUTTON, MENUEVENT_LCLICK_OFFBUTTON }; // Buttons for standard text display enum TextButtons { TEXTBUTTON_CONFIRM = 0, TEXTBUTTON_SCROLLUP, TEXTBUTTON_SCROLLDOWN, TEXTBUTTON_PREVCHOICE, TEXTBUTTON_NEXTCHOICE, TEXTBUTTON_SCROLLUP_ONELINE, TEXTBUTTON_SCROLLDOWN_ONELINE, TEXTBUTTON_GOTO_TOP, TEXTBUTTON_GOTO_BOTTOM, TEXTBUTTON_SPEECH_DONE // "Virtual" button? }; // Buttons for option menu (corresponding to button indices, not button retvals, which are // different for some reason) enum OptionMenuButtons { OPTIONBUTTON_TEXT, OPTIONBUTTON_SAVE, OPTIONBUTTON_LOAD, OPTIONBUTTON_ENABLEMUSIC, OPTIONBUTTON_DISABLEMUSIC, OPTIONBUTTON_ENABLESFX, OPTIONBUTTON_DISABLESFX, OPTIONBUTTON_QUIT }; enum TrekEventType { TREKEVENT_TICK = 0, // DOS clock changes TREKEVENT_LBUTTONDOWN = 1, TREKEVENT_MOUSEMOVE = 2, TREKEVENT_LBUTTONUP = 3, TREKEVENT_RBUTTONDOWN = 4, TREKEVENT_RBUTTONUP = 5, TREKEVENT_KEYDOWN = 6 }; struct TrekEvent { TrekEventType type; Common::KeyState kbd; Common::Point mouse; uint32 tick; }; struct StarTrekGameDescription; class Graphics; class IWFile; class Sound; class StarTrekEngine : public ::Engine { protected: Common::Error run(); public: // Game modes Common::Error runGameMode(int mode); // Away missions void initAwayMission(); void runAwayMission(); void cleanupAwayMission(); void loadRoom(const Common::String &missionName, int roomIndex); void initAwayCrewPositions(int warpEntryIndex); void handleAwayMissionEvents(); void unloadRoom(); int loadActorAnimWithRoomScaling(int actorIndex, const Common::String &animName, int16 x, int16 y); uint16 getActorScaleAtPosition(int16 y); void addAction(const Action &action); void addAction(byte type, byte b1, byte b2, byte b3); bool checkItemInteractionExists(int action, int activeItem, int passiveItem, int16 arg6); void handleAwayMissionAction(); bool isPointInPolygon(int16 *data, int16 x, int16 y); void checkTouchedLoadingZone(int16 x, int16 y); void updateAwayMissionTimers(); bool isPositionSolid(int16 x, int16 y); void loadRoomIndex(int roomIndex, int spawnIndex); public: SharedPtr getRoom(); private: // Intro void playIntro(); void loadSubtitleSprite(int index, Sprite *sprite); // Space, pseudo-3D (space.cpp) void initStarfieldPosition(); void initStarfield(int16 x, int16 y, int16 width, int16 height, int16 arg8); void clearStarfieldPixels(); void drawStarfield(); void updateStarfieldAndShips(bool arg0); Point3 constructPoint3ForStarfield(int16 x, int16 y, int16 z); Point3 applyPointWeightings(Point3W *weight, const Point3 &point); Point3 applyPointWeightings2(const Point3 &point, Point3W *weight); // Transporter room void runTransportSequence(const Common::String &name); // Bridge void initBridge(bool b) {}; // TODO void cleanupBridge() {}; // TODO public: StarTrekEngine(OSystem *syst, const StarTrekGameDescription *gamedesc); virtual ~StarTrekEngine(); // Running the game void playSoundEffectIndex(int index); void playMidiMusicTracks(int startTrack, int loopTrack); void playSpeech(const Common::String &filename); void stopPlayingSpeech(); // Actors void initActors(); int loadActorAnim(int actorIndex, const Common::String &animName, int16 x, int16 y, Fixed16 scale); bool actorWalkToPosition(int actorIndex, const Common::String &animFile, int16 srcX, int16 srcY, int16 destX, int16 destY); void updateActorAnimations(); void removeActorFromScreen(int actorIndex); void actorFunc1(); void drawActorToScreen(Actor *actor, const Common::String &animName, int16 x, int16 y, Fixed16 scale, bool addSprite); void releaseAnim(Actor *actor); void initStandAnim(int actorIndex); void updateActorPositionWhileWalking(Actor *actor, int16 x, int16 y); void chooseActorDirectionForWalking(Actor *actor, int16 srcX, int16 srcY, int16 destX, int16 destY); bool directPathExists(int16 srcX, int16 srcY, int16 destX, int16 destY); int findObjectAt(int x, int y); int findObjectAt(Common::Point p) { return findObjectAt(p.x, p.y); } SharedPtr loadAnimationFrame(const Common::String &filename, Fixed16 scale); int selectObjectForUseAction(); Common::String getCrewmanAnimFilename(int actorIndex, const Common::String &basename); void updateMouseBitmap(); bool walkActiveObjectToHotspot(); bool isObjectUnusable(int objectIndex, int action); void updateCrewmanGetupTimers(); void showInventoryIcons(bool showItem); void hideInventoryIcons(); int showInventoryMenu(int x, int y, bool restoreMouse); void initStarfieldSprite(Sprite *sprite, SharedPtr bitmap, const Common::Rect &rect); SharedPtr scaleBitmap(SharedPtr bitmap, Fixed16 scale); void scaleBitmapRow(byte *src, byte *dest, uint16 origWidth, uint16 scaledWidth); // Events public: /** * Checks for all events, and updates Star Trek's event queue if queueEvents is set. * This does not account for "tick" events (getNextEvent/popNextEvent handle that). */ void pollEvents(bool queueEvents = true); void waitForNextTick(bool queueEvents = true); void initializeEventsAndMouse(); /** * Returns false if there is no event waiting. If "poll" is true, this always returns * something (waits until an event occurs if necessary). */ bool getNextEvent(TrekEvent *e, bool poll = true); void removeNextEvent(); bool popNextEvent(TrekEvent *e, bool poll = true); void addEventToQueue(const TrekEvent &e); void clearEventBuffer(); void updateEvents(); void updateTimerEvent(); void updateMouseEvents(); void updateKeyboardEvents(); void updateClockTicks(); bool checkKeyPressed(); Common::EventManager *getEventMan() { return _eventMan; } private: Common::List _eventQueue; bool _mouseMoveEventInQueue; bool _tickEventInQueue; uint32 _frameStartMillis; // text.cpp public: const char *getNextTextLine(const char *text, char *line, int lineWidth); String centerTextboxHeader(String headerText); void getTextboxHeader(String *headerTextOutput, String speakerText, int choiceIndex); String readTextFromRdf(int choiceIndex, uintptr data, String *headerTextOutput); String readTextFromBuffer(int choiceIndex, uintptr data, String *headerTextOutput); void showTextbox(String headerText, const String &mainText, int xoffset, int yoffset, byte textColor, int maxTextLines); // TODO: better name. (return type?) String skipTextAudioPrompt(const String &str); String playTextAudio(const String &str); int showText(TextGetterFunc textGetter, uintptr var, int xoffset, int yoffset, int textColor, bool loopChoices, int maxTextLines, bool rclickCancelsChoice); int getNumTextboxLines(const String &str); String putTextIntoLines(const String &text); SharedPtr initTextSprite(int *xoffsetPtr, int *yoffsetPtr, byte textColor, int numTextLines, bool withHeader, Sprite *sprite); void drawMainText(SharedPtr bitmap, int numTextLines, int numTextboxLines, const String &text, bool withHeader); String readLineFormattedText(TextGetterFunc textGetter, uintptr var, int choiceIndex, SharedPtr textBitmap, int numTextboxLines, int *numLines); String readTextFromArray(int choiceIndex, uintptr data, String *headerTextOutput); String readTextFromArrayWithChoices(int choiceIndex, uintptr data, String *headerTextOutput); // menu.cpp public: int getMenuButtonAt(Sprite *sprites, int numSprites, int x, int y); void chooseMousePositionFromSprites(Sprite *sprites, int numSprites, int spriteIndex, int mode); void drawMenuButtonOutline(SharedPtr bitmap, byte color); void showOptionsMenu(int x, int y); int showActionMenu(); void loadMenuButtons(String mnuFilename, int xpos, int ypos); void setVisibleMenuButtons(uint32 bits); void disableMenuButtons(uint32 bits); void enableMenuButtons(uint32 bits); int handleMenuEvents(uint32 ticksUntilClickingEnabled, bool inTextbox); void unloadMenuButtons(); void chooseMouseBitmapForAction(int action, bool withRedOutline); void showQuitGamePrompt(int x, int y); void showGameOverMenu(); void showTextConfigurationMenu(bool fromOptionMenu); int loadTextDisplayMode(); void saveTextDisplayMode(int value); private: int16 _textDisplayMode; uint32 _textboxVar2; uint16 _textboxVar6; bool _textboxHasMultipleChoices; SharedPtr _activeMenu; // Saved value of StarTrekEngine::_keyboardControlsMouse when menus are up bool _keyboardControlsMouseOutsideMenu; // saveload.cpp public: bool showSaveMenu(); bool showLoadMenu(); bool saveGame(int slot, Common::String desc); bool loadGame(int slot); bool saveOrLoadGameData(Common::SeekableReadStream *in, Common::WriteStream *out, SavegameMetadata *meta); Common::String getSavegameFilename(int slotId) const; // Detection related functions public: const StarTrekGameDescription *_gameDescription; uint32 getFeatures() const; uint16 getVersion() const; Common::Platform getPlatform() const; uint8 getGameType(); Common::Language getLanguage(); // Resource related functions SharedPtr loadFile(Common::String filename, int fileIndex=0); /** * TODO: Figure out what the extra parameters are, and if they're important. */ SharedPtr loadFileWithParams(Common::String filename, bool unk1, bool unk2, bool unk3); // Movie related functions void playMovie(Common::String filename); void playMovieMac(Common::String filename); // Misc uint16 getRandomWord(); Common::String getLoadedText(int textIndex); public: int _gameMode; int _lastGameMode; // NOTE: this has a different meaning than the original game. When non-empty, a new // room load is triggered, as opposed to original behaviour where this was only read // when "loadRoom" was called. Common::String _missionToLoad; int _roomIndexToLoad; int _spawnIndexToLoad; Common::String _missionName; int _roomIndex; Common::String _screenName; // _screenName = _missionName + _roomIndex Common::String _mapFilename; // Similar to _screenName, but used for .map files? SharedPtr _mapFile; int32 _playerActorScale; Common::String _txtFilename; Common::String _loadedText; // TODO: might be OK to delete this // Queue of "actions" (ie. next frame, clicked on object) for away mission or bridge Common::Queue _actionQueue; AwayMission _awayMission; bool _warpHotspotsActive; int16 _activeWarpHotspot; int16 _activeDoorWarpHotspot; int16 _lookActionBitmapIndex; Item _itemList[NUM_OBJECTS]; Actor _actorList[NUM_ACTORS]; Actor * const _kirkActor; Actor * const _spockActor; Actor * const _mccoyActor; Actor * const _redshirtActor; SharedPtr _actorBanFiles[NUM_ACTORS / 2]; uint16 _actorBanVar2[NUM_ACTORS / 2]; // TODO: initialize? Sprite _inventoryIconSprite; Sprite _itemIconSprite; // Certain hotspots store a position value where objects must walk to before // interacting with them. After calling "findObjectAt", these values are updated. bool _objectHasWalkPosition; Common::Point _objectWalkPosition; // Actions to perform after a crewman finishes walking to a position. // Room-specific code can specify that a specific action of type // "ACTION_FINISHED_WALKING" occurs after moving a crewman somewhere. Action _actionOnWalkCompletion[MAX_BUFFERED_WALK_ACTIONS]; bool _actionOnWalkCompletionInUse[MAX_BUFFERED_WALK_ACTIONS]; // _clockTicks is based on DOS interrupt 1A, AH=0; read system clock counter. // Updates 18.206 times every second. uint32 _clockTicks; uint32 _frameIndex; uint32 _roomFrameCounter; // Resets to 0 on loading a room bool _musicEnabled; bool _sfxEnabled; uint16 _word_467a6; uint16 _musicWorking; bool _sfxWorking; bool _finishedPlayingSpeech; bool _mouseControllingShip; // TODO: make this work. // When false, the keyboard generally acts in a more specific way (ie. move mouse // between items in a menu). bool _keyboardControlsMouse; bool _inQuitGameMenu; bool _showSubtitles; byte _byte_45b3c; // Pseudo-3D / starfield stuff Sprite _starfieldSprite; Star _starList[NUM_STARS]; Point3 _starfieldPosition; int32 _starfieldPointDivisor; int16 _starfieldXVar1, _starfieldYVar1; int16 _starfieldXVar2, _starfieldYVar2; Common::Rect _starfieldRect; Graphics *_gfx; Sound *_sound; SharedPtr _iwFile; private: Common::RandomSource _randomSource; Common::MacResManager *_macResFork; SharedPtr _room; }; // Static function bool saveOrLoadMetadata(Common::SeekableReadStream *in, Common::WriteStream *out, SavegameMetadata *meta); } // End of namespace StarTrek #endif