/* 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. * * $URL$ * $Id$ * */ #ifndef DRACI_GAME_H #define DRACI_GAME_H #include "common/str.h" #include "common/serializer.h" #include "draci/barchive.h" #include "draci/script.h" #include "draci/animation.h" #include "draci/sprite.h" #include "draci/walking.h" namespace Draci { class DraciEngine; enum { kDragonObject = 0 }; enum { kDialogueLines = 4 }; enum { kBlackPalette = -1 }; // Constants tuned such that with ScummVM's default talkspeed kStandardSpeed, the speed // computed by equation (kBaseSpeechDuration + kSpeechTimeUnit * #characters) / // talkspeed is equal to the original game. enum SpeechConstants { kBaseSpeechDuration = 12000, kSpeechTimeUnit = 2640, kStandardSpeed = 60 }; // One fading phase is 50ms. enum FadeConstants { kFadingTimeUnit = 50 }; /** Inventory related magical constants */ enum InventoryConstants { kInventoryItemWidth = 25, kInventoryItemHeight = 25, kInventoryColumns = 7, kInventoryLines = 5, kInventoryX = 70, ///< Used for positioning of the inventory sprite on the X axis kInventoryY = 30, ///< Used for positioning of the inventory sprite on the Y axis kInventorySlots = kInventoryLines * kInventoryColumns, kStatusChangeTimeout = 500 }; class GameObject { public: int _absNum; uint _init, _look, _use, _canUse; bool _imInit, _imLook, _imUse; int _walkDir; byte _z; uint _lookX, _lookY, _useX, _useY; SightDirection _lookDir, _useDir; GPL2Program _program; Common::String _title; int _location; bool _visible; Common::Array _anim; int _playingAnim; int getAnim(int animID) const; int addAnim(Animation *anim); int playingAnim() const { return _playingAnim; } void playAnim(int i); void stopAnim(); void deleteAnims(); void deleteAnimsFrom(int index); void load(uint objNum, BArchive *archive); }; struct GameInfo { int _startRoom; int _mapRoom; uint _numObjects; uint _numItems; byte _numVariables; byte _numPersons; byte _numDialogues; uint _maxItemWidth, _maxItemHeight; uint _musicLength; uint _crc[4]; uint _numDialogueBlocks; }; class GameItem { public: int _absNum; uint _init, _look, _use, _canUse; bool _imInit, _imLook, _imUse; GPL2Program _program; Common::String _title; Animation *_anim; void load(int itemID, BArchive *archive); }; struct Person { uint _x, _y; byte _fontColour; }; struct Dialogue { int _canLen; byte *_canBlock; Common::String _title; GPL2Program _program; }; class Room { public: int _roomNum; byte _music; int _mapID; int _palette; int _numOverlays; int _init, _look, _use, _canUse; bool _imInit, _imLook, _imUse; bool _mouseOn, _heroOn; double _pers0, _persStep; int _escRoom; byte _numGates; Common::Array _gates; GPL2Program _program; void load(int roomNum, BArchive *archive); }; enum LoopStatus { kStatusOrdinary, // normal game-play: everything allowed kStatusGate, // during running init-scripts when entering a room: disable interactivity kStatusInventory, // inventory is open: cannot change the room or go to map kStatusDialogue // during a dialogue: cannot change the room, go to inventory }; enum LoopSubstatus { kOuterLoop, // outer loop: everything is allowed kInnerWhileTalk, // playing a voice: inner loop will exit afterwards kInnerWhileFade, // fading a palette: inner loop will exit when done kInnerDuringDialogue, // selecting continuation block: inner block will exit afterwards kInnerUntilExit // other inner loop: either immediately exiting or waiting for an animation to end (whose callback ends the loop) }; class Game { public: Game(DraciEngine *vm); ~Game(); void init(); void start(); void loop(LoopSubstatus substatus, bool shouldExit); // HACK: this is only for testing int nextRoomNum() const { int n = _currentRoom._roomNum; n = n < 37 ? n+1 : n; return n; } // HACK: same as above int prevRoomNum() const { int n = _currentRoom._roomNum; n = n > 0 ? n-1 : n; return n; } Common::Point findNearestWalkable(int x, int y) const { return _walkingMap.findNearestWalkable(x, y); } void heroAnimationFinished() { _walkingState.heroAnimationFinished(); } void stopWalking() { _walkingState.stopWalking(); } // and clear callback void walkHero(int x, int y, SightDirection dir); // start walking and leave callback as is void setHeroPosition(const Common::Point &p); const Common::Point &getHeroPosition() const { return _hero; } void positionAnimAsHero(Animation *anim); void positionHeroAsAnim(Animation *anim); // Makes sure animation anim_index plays on the hero. If the hero's // position has changed, it updates the animation position. If the new // animation is different, it stops the old one and starts the new one, // otherwise it just marks dirty rectangles for moving the position. // Returns the current animation phase of the new animation (usually 0 // unless the animation hasn't changed). int playHeroAnimation(int anim_index); void loadOverlays(); void loadWalkingMap(int mapID); // but leaves _currentRoom._mapID untouched void switchWalkingAnimations(bool enabled); uint getNumObjects() const { return _info._numObjects; } GameObject *getObject(uint objNum) { return _objects + objNum; } const GameObject *getObjectWithAnimation(const Animation *anim) const; void deleteObjectAnimations(); void deleteAnimationsAfterIndex(int lastAnimIndex); int getVariable(int varNum) const { return _variables[varNum]; } void setVariable(int varNum, int value) { _variables[varNum] = value; } const Person *getPerson(int personID) const { return &_persons[personID]; } int getRoomNum() const { return _currentRoom._roomNum; } void setRoomNum(int num) { _currentRoom._roomNum = num; } int getPreviousRoomNum() const { return _previousRoom; } void rememberRoomNumAsPrevious() { _previousRoom = getRoomNum(); } void scheduleEnteringRoomUsingGate(int room, int gate) { _newRoom = room; _newGate = gate; } void pushNewRoom(); void popNewRoom(); double getPers0() const { return _currentRoom._pers0; } double getPersStep() const { return _currentRoom._persStep; } int getMusicTrack() const { return _currentRoom._music; } void setMusicTrack(int num) { _currentRoom._music = num; } int getItemStatus(int itemID) const { return _itemStatus[itemID]; } void setItemStatus(int itemID, int status) { _itemStatus[itemID] = status; } GameItem *getItem(int id) { return id >= 0 ? &_items[id] : NULL; } GameItem *getCurrentItem() const { return _currentItem; } void setCurrentItem(GameItem *item) { _currentItem = item; } void removeItem(GameItem *item); void loadItemAnimation(GameItem *item); void putItem(GameItem *item, int position); void addItem(int itemID); int getEscRoom() const { return _currentRoom._escRoom; } int getMapRoom() const { return _info._mapRoom; } int getMapID() const { return _currentRoom._mapID; } /** * The GPL command Mark sets the animation index (which specifies the * order in which animations were loaded in) which is then used by the * Release command to delete all animations that have an index greater * than the one marked. */ int getMarkedAnimationIndex() const { return _markedAnimationIndex; } void setMarkedAnimationIndex(int index) { _markedAnimationIndex = index; } void setLoopStatus(LoopStatus status) { _loopStatus = status; } void setLoopSubstatus(LoopSubstatus status) { _loopSubstatus = status; } LoopStatus getLoopStatus() const { return _loopStatus; } LoopSubstatus getLoopSubstatus() const { return _loopSubstatus; } bool shouldQuit() const { return _shouldQuit; } void setQuit(bool quit) { _shouldQuit = quit; } bool shouldExitLoop() const { return _shouldExitLoop; } void setExitLoop(bool exit) { _shouldExitLoop = exit; } bool isReloaded() const { return _isReloaded; } void setIsReloaded(bool value) { _isReloaded = value; } void setSpeechTiming(uint tick, uint duration); void shiftSpeechAndFadeTick(int delta); void inventoryInit(); void inventoryDraw(); void inventoryDone(); void inventoryReload(); void dialogueMenu(int dialogueID); int dialogueDraw(); void dialogueInit(int dialogID); void dialogueDone(); bool isDialogueBegin() const { return _dialogueBegin; } bool shouldExitDialogue() const { return _dialogueExit; } void setDialogueExit(bool exit) { _dialogueExit = exit; } int getDialogueBlockNum() const { return _blockNum; } int getDialogueVar(int dialogueID) const { return _dialogueVars[dialogueID]; } void setDialogueVar(int dialogueID, int value) { _dialogueVars[dialogueID] = value; } int getCurrentDialogue() const { return _currentDialogue; } int getDialogueCurrentBlock() const { return _currentBlock; } int getDialogueLastBlock() const { return _lastBlock; } int getDialogueLinesNum() const { return _dialogueLinesNum; } int getCurrentDialogueOffset() const { return _dialogueOffsets[_currentDialogue]; } void schedulePalette(int paletteID) { _scheduledPalette = paletteID; } int getScheduledPalette() const { return _scheduledPalette; } void initializeFading(int phases); void setEnableQuickHero(bool value) { _enableQuickHero = value; } bool getEnableQuickHero() const { return _enableQuickHero; } void setWantQuickHero(bool value) { _wantQuickHero = value; } bool getWantQuickHero() const { return _wantQuickHero; } void setEnableSpeedText(bool value) { _enableSpeedText = value; } bool getEnableSpeedText() const { return _enableSpeedText; } void DoSync(Common::Serializer &s); private: void updateOrdinaryCursor(); void updateInventoryCursor(); void handleOrdinaryLoop(int x, int y); void handleInventoryLoop(); void handleDialogueLoop(); void updateTitle(int x, int y); void updateCursor(); void advanceAnimationsAndTestLoopExit(); void handleStatusChangeByMouse(); void enterNewRoom(); void initWalkingOverlays(); void loadRoomObjects(); void redrawWalkingPath(Animation *anim, byte colour, const WalkingPath &path); DraciEngine *_vm; GameInfo _info; Common::Point _hero; int *_variables; Person *_persons; GameObject *_objects; byte *_itemStatus; GameItem *_items; GameItem *_currentItem; GameItem *_itemUnderCursor; GameItem *_inventory[kInventorySlots]; Room _currentRoom; int _newRoom; int _newGate; int _previousRoom; int _pushedNewRoom; // used in GPL programs int _pushedNewGate; uint *_dialogueOffsets; int _currentDialogue; int *_dialogueVars; BArchive *_dialogueArchive; Dialogue *_dialogueBlocks; bool _dialogueBegin; bool _dialogueExit; int _currentBlock; int _lastBlock; int _dialogueLinesNum; int _blockNum; int _lines[kDialogueLines]; Animation *_dialogueAnims[kDialogueLines]; LoopStatus _loopStatus; LoopSubstatus _loopSubstatus; bool _shouldQuit; bool _shouldExitLoop; bool _isReloaded; uint _speechTick; uint _speechDuration; const GameObject *_objUnderCursor; const Animation *_animUnderCursor; int _markedAnimationIndex; ///< Used by the Mark GPL command int _scheduledPalette; int _fadePhases; int _fadePhase; uint _fadeTick; int _mouseChangeTick; bool _enableQuickHero; bool _wantQuickHero; bool _enableSpeedText; WalkingMap _walkingMap; WalkingState _walkingState; Animation *_titleAnim; Animation *_inventoryAnim; Animation *_walkingMapOverlay; Animation *_walkingShortestPathOverlay; Animation *_walkingObliquePathOverlay; }; } // End of namespace Draci #endif // DRACI_GAME_H