From d5568906739da23154cacd17aca93802901a9baf Mon Sep 17 00:00:00 2001 From: Ľubomír Remák Date: Sun, 28 Oct 2018 13:08:41 +0100 Subject: MUTATIONOFJB: Add support for combining items. Introduce game screen and game widget. Add status bar to show currently hovered and picked items. Load hardcoded strings from game executable. --- engines/mutationofjb/assets.cpp | 6 +- engines/mutationofjb/assets.h | 25 +++ engines/mutationofjb/detection.cpp | 2 +- engines/mutationofjb/game.cpp | 24 ++- engines/mutationofjb/game.h | 10 +- engines/mutationofjb/gamedata.cpp | 8 + engines/mutationofjb/gamedata.h | 7 + engines/mutationofjb/gamescreen.cpp | 214 ++++++++++++++++++++++-- engines/mutationofjb/gamescreen.h | 24 ++- engines/mutationofjb/guiscreen.cpp | 5 + engines/mutationofjb/guiscreen.h | 8 +- engines/mutationofjb/hardcodedstrings.cpp | 169 +++++++++++++++++++ engines/mutationofjb/hardcodedstrings.h | 107 ++++++++++++ engines/mutationofjb/module.mk | 3 + engines/mutationofjb/mutationofjb.cpp | 164 ++---------------- engines/mutationofjb/mutationofjb.h | 33 +--- engines/mutationofjb/tasks/conversationtask.cpp | 7 +- engines/mutationofjb/widgets/gamewidget.cpp | 179 ++++++++++++++++++++ engines/mutationofjb/widgets/gamewidget.h | 96 +++++++++++ engines/mutationofjb/widgets/labelwidget.cpp | 64 +++++++ engines/mutationofjb/widgets/labelwidget.h | 50 ++++++ engines/mutationofjb/widgets/widget.cpp | 26 ++- engines/mutationofjb/widgets/widget.h | 18 +- 23 files changed, 1024 insertions(+), 225 deletions(-) create mode 100644 engines/mutationofjb/hardcodedstrings.cpp create mode 100644 engines/mutationofjb/hardcodedstrings.h create mode 100644 engines/mutationofjb/widgets/gamewidget.cpp create mode 100644 engines/mutationofjb/widgets/gamewidget.h create mode 100644 engines/mutationofjb/widgets/labelwidget.cpp create mode 100644 engines/mutationofjb/widgets/labelwidget.h (limited to 'engines') diff --git a/engines/mutationofjb/assets.cpp b/engines/mutationofjb/assets.cpp index 6f3236177b..02e0c85d7e 100644 --- a/engines/mutationofjb/assets.cpp +++ b/engines/mutationofjb/assets.cpp @@ -24,7 +24,7 @@ namespace MutationOfJB { -Assets::Assets(Game &game) : _game(game), _toSayList("tosay.ger"), _responseList("response.ger") {} +Assets::Assets(Game &game) : _game(game), _toSayList("tosay.ger"), _responseList("response.ger"), _hardcodedStrings(game) {} Font &Assets::getSystemFont() { return _systemFont; @@ -46,4 +46,8 @@ InventoryItemDefinitionList &Assets::getInventoryItemDefList() { return _invItemDefList; } +HardcodedStrings &Assets::getHardcodedStrings() { + return _hardcodedStrings; +} + } diff --git a/engines/mutationofjb/assets.h b/engines/mutationofjb/assets.h index 89ed678c60..6d9858eec2 100644 --- a/engines/mutationofjb/assets.h +++ b/engines/mutationofjb/assets.h @@ -26,6 +26,7 @@ #include "mutationofjb/font.h" #include "mutationofjb/conversationlinelist.h" #include "mutationofjb/inventoryitemdefinitionlist.h" +#include "mutationofjb/hardcodedstrings.h" namespace MutationOfJB { @@ -38,10 +39,33 @@ public: Font &getSystemFont(); Font &getSpeechFont(); + /** + * Access to "to say" list for conversations. + * + * @return Conversation line list. + */ ConversationLineList &getToSayList(); + + /** + * Access to "response" list for conversations. + * + * @return Conversation line list. + */ ConversationLineList &getResponseList(); + + /** + * Access to inventory definitions. + * + * @return Inventory item definiton list. + */ InventoryItemDefinitionList &getInventoryItemDefList(); + /** + * Access to strings hardcoded in game executable. + * + * @return Hardcoded strings. + */ + HardcodedStrings &getHardcodedStrings(); private: Game &_game; SystemFont _systemFont; @@ -49,6 +73,7 @@ private: ConversationLineList _toSayList; ConversationLineList _responseList; InventoryItemDefinitionList _invItemDefList; + HardcodedStrings _hardcodedStrings; }; } diff --git a/engines/mutationofjb/detection.cpp b/engines/mutationofjb/detection.cpp index 0235f8071e..6ebfa138e8 100644 --- a/engines/mutationofjb/detection.cpp +++ b/engines/mutationofjb/detection.cpp @@ -102,7 +102,7 @@ public: virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const override { if (desc) { - *engine = new MutationOfJB::MutationOfJBEngine(syst); + *engine = new MutationOfJB::MutationOfJBEngine(syst, desc); } return desc != nullptr; } diff --git a/engines/mutationofjb/game.cpp b/engines/mutationofjb/game.cpp index 86755b1abd..134dc72e90 100644 --- a/engines/mutationofjb/game.cpp +++ b/engines/mutationofjb/game.cpp @@ -34,6 +34,8 @@ #include "common/str.h" #include "common/util.h" +#include "engines/advancedDetector.h" + namespace MutationOfJB { Game::Game(MutationOfJBEngine *vm) @@ -41,7 +43,6 @@ Game::Game(MutationOfJBEngine *vm) _randomSource("mutationofjb"), _delayedLocalScript(nullptr), _gui(*this, _vm->getScreen()), - _currentAction(ActionInfo::Walk), _scriptExecCtx(*this), _taskManager(*this), _assets(*this) { @@ -63,6 +64,10 @@ Game::Game(MutationOfJBEngine *vm) _taskManager.startTask(TaskPtr(new ObjectAnimationTask)); } +MutationOfJBEngine &Game::getEngine() { + return *_vm; +} + Common::RandomSource &Game::getRandomSource() { return _randomSource; } @@ -109,7 +114,7 @@ Script *Game::changeSceneLoadScript(uint8 sceneId, bool partB) { _gameData->_partB = partB; _room->load(_gameData->_currentScene, partB); - _room->redraw(); + _gui.refreshAfterSceneChanged(); EncryptedFile scriptFile; Common::String fileName = Common::String::format("scrn%d%s.atn", sceneId, partB ? "b" : ""); @@ -128,8 +133,6 @@ Script *Game::changeSceneLoadScript(uint8 sceneId, bool partB) { localScript->loadFromStream(scriptFile); scriptFile.close(); - _vm->updateCursor(); - return localScript; } @@ -190,7 +193,6 @@ void Game::update() { _delayedLocalScript = nullptr; } - _gui.update(); _taskManager.update(); } @@ -198,14 +200,6 @@ GameScreen &Game::getGameScreen() { return _gui; } -ActionInfo::Action Game::getCurrentAction() const { - return _currentAction; -} - -void Game::setCurrentAction(ActionInfo::Action action) { - _currentAction = action; -} - uint8 Game::colorFromString(const char *colorStr) { struct { const char *str; @@ -265,4 +259,8 @@ bool Game::loadSaveAllowed() const { return true; } +Common::Language Game::getLanguage() const { + return _vm->getGameDescription()->language; +} + } diff --git a/engines/mutationofjb/game.h b/engines/mutationofjb/game.h index adb5bf5c48..27804ea8d8 100644 --- a/engines/mutationofjb/game.h +++ b/engines/mutationofjb/game.h @@ -25,9 +25,9 @@ #include "mutationofjb/assets.h" #include "mutationofjb/gamescreen.h" -#include "mutationofjb/script.h" #include "mutationofjb/tasks/taskmanager.h" +#include "common/language.h" #include "common/ptr.h" #include "common/random.h" #include "common/scummsys.h" @@ -51,6 +51,8 @@ struct Bitmap; class Game { public: Game(MutationOfJBEngine *vm); + MutationOfJBEngine &getEngine(); + Common::RandomSource &getRandomSource(); GameData &getGameData(); Room &getRoom(); @@ -68,9 +70,6 @@ public: GameScreen &getGameScreen(); - ActionInfo::Action getCurrentAction() const; - void setCurrentAction(ActionInfo::Action); - static uint8 colorFromString(const char *colorStr); TaskManager &getTaskManager(); @@ -83,6 +82,8 @@ public: bool loadSaveAllowed() const; + Common::Language getLanguage() const; + private: bool loadGameData(bool partB); void runActiveCommand(); @@ -98,7 +99,6 @@ private: Script *_delayedLocalScript; Room *_room; GameScreen _gui; - ActionInfo::Action _currentAction; ScriptExecutionContext _scriptExecCtx; diff --git a/engines/mutationofjb/gamedata.cpp b/engines/mutationofjb/gamedata.cpp index 71f58c317b..b0d3e7c328 100644 --- a/engines/mutationofjb/gamedata.cpp +++ b/engines/mutationofjb/gamedata.cpp @@ -150,6 +150,14 @@ void Static::saveLoadWithSerializer(Common::Serializer &sz) { sz.syncAsByte(_walkToFrame); } +bool Static::isCombinable() const { + const size_t length = strlen(_name); + if (length == 0) + return false; + + return _name[length - 1] == '['; +} + bool Bitmap::loadInitialState(Common::ReadStream &stream) { _roomFrame = stream.readByte(); _isVisible = stream.readByte(); diff --git a/engines/mutationofjb/gamedata.h b/engines/mutationofjb/gamedata.h index f42e84b963..9daefd8252 100644 --- a/engines/mutationofjb/gamedata.h +++ b/engines/mutationofjb/gamedata.h @@ -248,6 +248,13 @@ struct Static : public Common::Serializable { * @param sz Serializer. */ virtual void saveLoadWithSerializer(Common::Serializer &sz) override; + + /** + * Statics with names ending with '[' are allowed to be combined with other items. + * + * @return True if combinable, false otherwise. + */ + bool isCombinable() const; }; /** diff --git a/engines/mutationofjb/gamescreen.cpp b/engines/mutationofjb/gamescreen.cpp index 3c007f415f..ef7e50baeb 100644 --- a/engines/mutationofjb/gamescreen.cpp +++ b/engines/mutationofjb/gamescreen.cpp @@ -26,13 +26,16 @@ #include "mutationofjb/encryptedfile.h" #include "mutationofjb/game.h" #include "mutationofjb/gamedata.h" +#include "mutationofjb/mutationofjb.h" #include "mutationofjb/inventory.h" #include "mutationofjb/util.h" -#include "mutationofjb/widgets/widget.h" -#include "mutationofjb/widgets/inventorywidget.h" -#include "mutationofjb/widgets/imagewidget.h" #include "mutationofjb/widgets/conversationwidget.h" +#include "mutationofjb/widgets/gamewidget.h" +#include "mutationofjb/widgets/imagewidget.h" +#include "mutationofjb/widgets/inventorywidget.h" +#include "mutationofjb/widgets/labelwidget.h" +#include "common/events.h" #include "common/rect.h" #include "graphics/screen.h" @@ -61,14 +64,20 @@ enum { CONVERSATION_X = 0, CONVERSATION_Y = 139, CONVERSATION_WIDTH = 320, - CONVERSATION_HEIGHT = 61 + CONVERSATION_HEIGHT = 61, + STATUS_BAR_X = 0, + STATUS_BAR_Y = 140, + STATUS_BAR_WIDTH = 320, + STATUS_BAR_HEIGHT = 8 }; GameScreen::GameScreen(Game &game, Graphics::Screen *screen) : GuiScreen(game, screen), _inventoryWidget(nullptr), - _conversationWidget(nullptr) {} + _conversationWidget(nullptr), + _statusBarWidget(nullptr), + _currentAction(ActionInfo::Walk) {} GameScreen::~GameScreen() {} @@ -111,22 +120,105 @@ bool GameScreen::init() { ButtonWidget *button = new ButtonWidget(*this, ButtonRects[i], normalSurface, pressedSurface); button->setId(i); button->setCallback(this); + _buttons.push_back(button); addWidget(button); } + const Common::Rect statusBarRect(STATUS_BAR_X, STATUS_BAR_Y, STATUS_BAR_X + STATUS_BAR_WIDTH, STATUS_BAR_Y + STATUS_BAR_HEIGHT); + _statusBarWidget = new LabelWidget(*this, statusBarRect); + addWidget(_statusBarWidget); + const Common::Rect conversationRect(CONVERSATION_X, CONVERSATION_Y, CONVERSATION_X + CONVERSATION_WIDTH, CONVERSATION_Y + CONVERSATION_HEIGHT); const Graphics::Surface conversationSurface = _hudSurfaces[2].getSubArea(conversationRect); _conversationWidget = new ConversationWidget(*this, conversationRect, conversationSurface); _conversationWidget->setVisible(false); addWidget(_conversationWidget); + _gameWidget = new GameWidget(*this); + _gameWidget->setCallback(this); + addWidget(_gameWidget); + return true; } +void GameScreen::handleEvent(const Common::Event &event) { + switch (event.type) { + case Common::EVENT_KEYUP: { + switch (event.kbd.ascii) { + case 'g': + _currentAction = ActionInfo::Walk; + break; + case 'r': + _currentAction = ActionInfo::Talk; + break; + case 's': + _currentAction = ActionInfo::Look; + break; + case 'b': + _currentAction = ActionInfo::Use; + break; + case 'n': + _currentAction = ActionInfo::PickUp; + break; + } + break; + } + default: + break; + } + + GuiScreen::handleEvent(event); +} + ConversationWidget &GameScreen::getConversationWidget() { return *_conversationWidget; } +void GameScreen::showConversationWidget(bool show) { + _gameWidget->setEnabled(!show); + _conversationWidget->setVisible(show); + _statusBarWidget->setText(Common::String()); + + for (Common::Array::const_iterator it = _buttons.begin(); it != _buttons.end(); ++it) { + (*it)->setVisible(!show); + } + _inventoryWidget->setVisible(!show); +} + +void GameScreen::refreshAfterSceneChanged() { + const Widgets &widgets = getWidgets(); + + if (!getGame().isCurrentSceneMap()) { + _gameWidget->setArea(Common::Rect(GameWidget::GAME_NORMAL_AREA_WIDTH, GameWidget::GAME_NORMAL_AREA_HEIGHT)); + + for (Widgets::const_iterator it = widgets.begin(); it != widgets.end(); ++it) { + if (*it == _gameWidget || *it == _conversationWidget) + continue; + + (*it)->setVisible(true); + } + } else { + _gameWidget->setArea(Common::Rect(GameWidget::GAME_FULL_AREA_WIDTH, GameWidget::GAME_FULL_AREA_HEIGHT)); + for (Widgets::const_iterator it = widgets.begin(); it != widgets.end(); ++it) { + if (*it == _gameWidget || *it == _conversationWidget) + continue; + + (*it)->setVisible(false); + } + } + + _gameWidget->clearState(); + + // Fake mouse move event to update the cursor. + Common::Event event; + event.type = Common::EVENT_MOUSEMOVE; + event.mouse = _game.getEngine().getEventManager()->getMousePos(); + _gameWidget->handleEvent(event); + + _gameWidget->markDirty(); + _gameWidget->update(*_screen); // Force immediate update. +} + class InventoryAnimationDecoderCallback : public AnimationDecoderCallback { public: InventoryAnimationDecoderCallback(GameScreen &gui) : _gui(gui) {} @@ -180,6 +272,56 @@ bool GameScreen::loadHudGfx() { return decoder.decode(&callback); } +void GameScreen::updateStatusBarText(const Common::String &entity, bool inventory) { + const bool hasPrevPickedItem = !_currentPickedItem.empty(); + const bool hasCurrentItem = !entity.empty(); + + if (!hasPrevPickedItem && !hasCurrentItem) { + _statusBarWidget->setText(Common::String()); + return; + } + + HardcodedStrings::StringType actionStringType = HardcodedStrings::LOOK; + + if (inventory) { + switch (_currentAction) { + case ActionInfo::Use: + actionStringType = HardcodedStrings::USE; + break; + default: + actionStringType = HardcodedStrings::LOOK; + break; + } + } else { + switch (_currentAction) { + case ActionInfo::Look: + actionStringType = HardcodedStrings::LOOK; + break; + case ActionInfo::Walk: + actionStringType = HardcodedStrings::WALK; + break; + case ActionInfo::Talk: + actionStringType = HardcodedStrings::TALK; + break; + case ActionInfo::Use: + actionStringType = HardcodedStrings::USE; + break; + case ActionInfo::PickUp: + actionStringType = HardcodedStrings::PICKUP; + break; + } + } + + Common::String text = _game.getAssets().getHardcodedStrings().getString(actionStringType); + + if (hasPrevPickedItem) + text += " " + _currentPickedItem; + if (hasCurrentItem) + text += " " + entity; + + _statusBarWidget->setText(text); +} + void GameScreen::onInventoryChanged() { _inventoryWidget->markDirty(); } @@ -188,7 +330,8 @@ void GameScreen::onButtonClicked(ButtonWidget *button) { const int buttonId = button->getId(); if (buttonId <= BUTTON_PICKUP) { const ActionInfo::Action actions[] = {ActionInfo::Walk, ActionInfo::Talk, ActionInfo::Look, ActionInfo::Use, ActionInfo::PickUp}; - _game.setCurrentAction(actions[buttonId]); + _currentAction = actions[buttonId]; + _currentPickedItem.clear(); } else if (buttonId == BUTTON_SCROLL_LEFT) { _game.getGameData().getInventory().scrollLeft(); } else if (buttonId == BUTTON_SCROLL_RIGHT) { @@ -196,19 +339,64 @@ void GameScreen::onButtonClicked(ButtonWidget *button) { } } -void GameScreen::onInventoryItemHovered(InventoryWidget *widget, int posInWidget) { - // TODO +void GameScreen::onInventoryItemHovered(InventoryWidget *, int posInWidget) { + if (posInWidget == -1) { + updateStatusBarText(Common::String(), true); + } else { + const Common::String &item = _game.getGameData().getInventory().getItems()[posInWidget]; + updateStatusBarText(item, true); + } } -void GameScreen::onInventoryItemClicked(InventoryWidget *widget, int posInWidget) { +void GameScreen::onInventoryItemClicked(InventoryWidget *, int posInWidget) { // Position in widget should match the position in inventory. - const Common::String &item = getGame().getGameData().getInventory().getItems()[posInWidget]; - - if (_game.getCurrentAction() == ActionInfo::Use) { - // TODO + const Common::String &item = _game.getGameData().getInventory().getItems()[posInWidget]; + + if (_currentAction == ActionInfo::Use) { + if (_currentPickedItem.empty()) { + // Inventory items ending with '[' aren't supposed to be combined (e.g. Fisher's mask). + if (item.lastChar() == '[') + _game.startActionSection(ActionInfo::Look, item); + else + _currentPickedItem = item; + } else { + _game.startActionSection(ActionInfo::Use, _currentPickedItem, item); + _currentPickedItem.clear(); + } } else { _game.startActionSection(ActionInfo::Look, item); } } +void GameScreen::onGameDoorClicked(GameWidget *, const Door *door) { + if (!_currentPickedItem.empty()) { + _game.startActionSection(_currentAction, _currentPickedItem, door->_name); + return; + } + + if (!_game.startActionSection(_currentAction, door->_name) && _currentAction == ActionInfo::Walk && door->_destSceneId != 0) { + _game.changeScene(door->_destSceneId, _game.getGameData()._partB); + } +} + +void GameScreen::onGameStaticClicked(GameWidget *, const Static *stat) { + if (_currentAction == ActionInfo::Use) { + if (_currentPickedItem.empty()) { + if (stat->isCombinable()) + _currentPickedItem = stat->_name; + else + _game.startActionSection(ActionInfo::Use, stat->_name); + } else { + _game.startActionSection(_currentAction, _currentPickedItem, stat->_name); + _currentPickedItem.clear(); + } + } else { + _game.startActionSection(_currentAction, stat->_name); + } +} + +void GameScreen::onGameEntityHovered(GameWidget *, const Common::String &entity) { + updateStatusBarText(entity, false); +} + } diff --git a/engines/mutationofjb/gamescreen.h b/engines/mutationofjb/gamescreen.h index bc70580eda..686a504364 100644 --- a/engines/mutationofjb/gamescreen.h +++ b/engines/mutationofjb/gamescreen.h @@ -24,9 +24,11 @@ #define MUTATIONOFJB_GUI_H #include "mutationofjb/inventory.h" +#include "mutationofjb/script.h" +#include "mutationofjb/guiscreen.h" #include "mutationofjb/widgets/buttonwidget.h" #include "mutationofjb/widgets/inventorywidget.h" -#include "mutationofjb/guiscreen.h" +#include "mutationofjb/widgets/gamewidget.h" #include "common/array.h" #include "common/hashmap.h" @@ -48,8 +50,10 @@ class Game; class Widget; class InventoryWidget; class ConversationWidget; +class LabelWidget; +class GameWidget; -class GameScreen : public GuiScreen, public InventoryObserver, public ButtonWidgetCallback, public InventoryWidgetCallback { +class GameScreen : public GuiScreen, public InventoryObserver, public ButtonWidgetCallback, public InventoryWidgetCallback, public GameWidgetCallback { public: friend class InventoryAnimationDecoderCallback; friend class HudAnimationDecoderCallback; @@ -59,24 +63,40 @@ public: bool init(); + virtual void handleEvent(const Common::Event &event) override; + virtual void onInventoryChanged() override; virtual void onButtonClicked(ButtonWidget *) override; virtual void onInventoryItemHovered(InventoryWidget *widget, int posInWidget) override; virtual void onInventoryItemClicked(InventoryWidget *widget, int posInWidget) override; + virtual void onGameDoorClicked(GameWidget *, const Door *door) override; + virtual void onGameStaticClicked(GameWidget *, const Static *stat) override; + virtual void onGameEntityHovered(GameWidget *, const Common::String &entity) override; ConversationWidget &getConversationWidget(); + void showConversationWidget(bool show); + void refreshAfterSceneChanged(); + private: bool loadInventoryGfx(); bool loadHudGfx(); void drawInventoryItem(const Common::String &item, int pos); void drawInventory(); + void updateStatusBarText(const Common::String &entity, bool inventory); + Common::Array _inventorySurfaces; Common::Array _hudSurfaces; + Common::Array _buttons; InventoryWidget *_inventoryWidget; ConversationWidget *_conversationWidget; + LabelWidget *_statusBarWidget; + GameWidget *_gameWidget; + + ActionInfo::Action _currentAction; + Common::String _currentPickedItem; }; } diff --git a/engines/mutationofjb/guiscreen.cpp b/engines/mutationofjb/guiscreen.cpp index 5ad545dc3c..891bcc2222 100644 --- a/engines/mutationofjb/guiscreen.cpp +++ b/engines/mutationofjb/guiscreen.cpp @@ -68,6 +68,11 @@ void GuiScreen::update() { void GuiScreen::addWidget(Widget *widget) { _widgets.push_back(widget); + widget->markDirty(); +} + +const GuiScreen::Widgets &GuiScreen::getWidgets() const { + return _widgets; } } diff --git a/engines/mutationofjb/guiscreen.h b/engines/mutationofjb/guiscreen.h index c1761be39a..3b1e8d4713 100644 --- a/engines/mutationofjb/guiscreen.h +++ b/engines/mutationofjb/guiscreen.h @@ -60,7 +60,7 @@ public: * * @param event ScummVM event. */ - void handleEvent(const Common::Event &event); + virtual void handleEvent(const Common::Event &event); /** * Updates all visible widgets. @@ -76,11 +76,15 @@ public: void addWidget(Widget *widget); protected: + typedef Common::Array Widgets; + Game &_game; Graphics::Screen *_screen; + const Widgets &getWidgets() const; + private: - Common::Array _widgets; + Widgets _widgets; }; } diff --git a/engines/mutationofjb/hardcodedstrings.cpp b/engines/mutationofjb/hardcodedstrings.cpp new file mode 100644 index 0000000000..5635c362b5 --- /dev/null +++ b/engines/mutationofjb/hardcodedstrings.cpp @@ -0,0 +1,169 @@ +/* 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. + * + */ + +#include "mutationofjb/hardcodedstrings.h" + +#include "mutationofjb/game.h" +#include "mutationofjb/util.h" + +#include "common/file.h" + +namespace MutationOfJB { + +HardcodedStrings::HardcodedStrings(Game &game) : _strings(STRING_TYPES_TOTAL) { + loadStrings(game.getLanguage()); +} + +const Common::String &HardcodedStrings::getString(HardcodedStrings::StringType strType) const { + const StringArray::size_type index = static_cast(strType); + assert(index < _strings.size()); + + return _strings[index]; +} + +void HardcodedStrings::loadStrings(Common::Language lang) { + Common::File file; + const char *const fileName = "jb.ex_"; + if (!file.open(fileName)) { + reportFileMissingError(fileName); + return; + } + + if (lang == Common::SK_SVK) + file.seek(0xBAA8); + else if (lang == Common::DE_DEU) + file.seek(0xBC48); + else + return; + + Common::String str; + + file.readPascalString(); // WALK TO + file.readPascalString(); // TALK TO + file.readPascalString(); // PICK UP + file.readPascalString(); // LOOK AT + + str = file.readPascalString(); + if (lang == Common::SK_SVK) + _strings[WALK] = str; + + str = file.readPascalString(); + if (lang == Common::DE_DEU) + _strings[WALK] = str; + + str = file.readPascalString(); + if (lang == Common::SK_SVK) + _strings[LOOK] = str; + + file.readPascalString(); + file.readPascalString(); + + str = file.readPascalString(); + if (lang == Common::DE_DEU) + _strings[LOOK] = str; + + str = file.readPascalString(); + if (lang == Common::SK_SVK) + _strings[PICKUP] = str; + + str = file.readPascalString(); + if (lang == Common::DE_DEU) + _strings[PICKUP] = str; + + str = file.readPascalString(); + if (lang == Common::SK_SVK) + _strings[TALK] = str; + + str = file.readPascalString(); + if (lang == Common::DE_DEU) + _strings[TALK] = str; + + file.readPascalString(); // USE + + str = file.readPascalString(); + if (lang == Common::SK_SVK) + _strings[USE] = str; + + str = file.readPascalString(); + if (lang == Common::DE_DEU) + _strings[USE] = str; + + + if (lang == Common::SK_SVK) + file.seek(0x1982F); + else if (lang == Common::DE_DEU) + file.seek(0x199F0); + else + return; + + _strings[JOHNNY_CANNOT_USE_1] = file.readPascalString(); + _strings[SKEPTO_CANNOT_USE_1] = file.readPascalString(); + file.readPascalString(); + _strings[JOHNNY_CANNOT_USE_2] = file.readPascalString(); + _strings[SKEPTO_CANNOT_USE_2] = file.readPascalString(); + file.readPascalString(); + _strings[JOHNNY_CANNOT_USE_3] = file.readPascalString(); + _strings[SKEPTO_CANNOT_USE_3] = file.readPascalString(); + file.readPascalString(); + _strings[JOHNNY_CANNOT_USE_4] = file.readPascalString(); + _strings[SKEPTO_CANNOT_USE_4] = file.readPascalString(); + file.readPascalString(); + _strings[JOHNNY_CANNOT_TALK_1] = file.readPascalString(); + _strings[SKEPTO_CANNOT_TALK_1] = file.readPascalString(); + file.readPascalString(); + _strings[JOHNNY_CANNOT_TALK_2] = file.readPascalString(); + _strings[SKEPTO_CANNOT_TALK_2] = file.readPascalString(); + file.readPascalString(); + _strings[JOHNNY_CANNOT_TALK_3] = file.readPascalString(); + _strings[SKEPTO_CANNOT_TALK_3] = file.readPascalString(); + file.readPascalString(); + _strings[JOHNNY_CANNOT_TALK_4] = file.readPascalString(); + _strings[SKEPTO_CANNOT_TALK_4] = file.readPascalString(); + file.readPascalString(); + _strings[JOHNNY_CANNOT_LOOK_1] = file.readPascalString(); + _strings[SKEPTO_CANNOT_LOOK_1] = file.readPascalString(); + file.readPascalString(); + _strings[JOHNNY_CANNOT_LOOK_2] = file.readPascalString(); + _strings[SKEPTO_CANNOT_LOOK_2] = file.readPascalString(); + file.readPascalString(); + if (lang != Common::SK_SVK) // This sentence seems to be missing from the Slovak executable. + _strings[JOHNNY_CANNOT_LOOK_3] = file.readPascalString(); + _strings[SKEPTO_CANNOT_LOOK_3] = file.readPascalString(); + file.readPascalString(); + _strings[JOHNNY_CANNOT_LOOK_4] = file.readPascalString(); + _strings[SKEPTO_CANNOT_LOOK_4] = file.readPascalString(); + file.readPascalString(); + _strings[JOHNNY_CANNOT_PICKUP_1] = file.readPascalString(); + _strings[SKEPTO_CANNOT_PICKUP_1] = file.readPascalString(); + file.readPascalString(); + if (lang != Common::SK_SVK) // This sentence seems to be missing from the Slovak executable. + _strings[JOHNNY_CANNOT_PICKUP_2] = file.readPascalString(); + _strings[SKEPTO_CANNOT_PICKUP_2] = file.readPascalString(); + file.readPascalString(); + _strings[JOHNNY_CANNOT_PICKUP_3] = file.readPascalString(); + _strings[SKEPTO_CANNOT_PICKUP_3] = file.readPascalString(); + file.readPascalString(); + _strings[JOHNNY_CANNOT_PICKUP_4] = file.readPascalString(); + _strings[SKEPTO_CANNOT_PICKUP_4] = file.readPascalString(); +} + +} diff --git a/engines/mutationofjb/hardcodedstrings.h b/engines/mutationofjb/hardcodedstrings.h new file mode 100644 index 0000000000..3ee0103838 --- /dev/null +++ b/engines/mutationofjb/hardcodedstrings.h @@ -0,0 +1,107 @@ +/* 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 MUTATIONOFJB_HARDCODEDSTRINGS_H +#define MUTATIONOFJB_HARDCODEDSTRINGS_H + +#include "common/language.h" +#include "common/hashmap.h" + +namespace MutationOfJB { + +class Game; + +/** + * Provides access to hardcoded strings. + * + * Currently, we do not have any agreement with the original author of the game, + * so the strings are loaded from the gmae executable file. + */ +class HardcodedStrings { +public: + enum StringType { + WALK, + TALK, + LOOK, + USE, + PICKUP, + + JOHNNY_CANNOT_USE_1, + SKEPTO_CANNOT_USE_1, + JOHNNY_CANNOT_USE_2, + SKEPTO_CANNOT_USE_2, + JOHNNY_CANNOT_USE_3, + SKEPTO_CANNOT_USE_3, + JOHNNY_CANNOT_USE_4, + SKEPTO_CANNOT_USE_4, + + JOHNNY_CANNOT_TALK_1, + SKEPTO_CANNOT_TALK_1, + JOHNNY_CANNOT_TALK_2, + SKEPTO_CANNOT_TALK_2, + JOHNNY_CANNOT_TALK_3, + SKEPTO_CANNOT_TALK_3, + JOHNNY_CANNOT_TALK_4, + SKEPTO_CANNOT_TALK_4, + + JOHNNY_CANNOT_LOOK_1, + SKEPTO_CANNOT_LOOK_1, + JOHNNY_CANNOT_LOOK_2, + SKEPTO_CANNOT_LOOK_2, + JOHNNY_CANNOT_LOOK_3, + SKEPTO_CANNOT_LOOK_3, + JOHNNY_CANNOT_LOOK_4, + SKEPTO_CANNOT_LOOK_4, + + JOHNNY_CANNOT_PICKUP_1, + SKEPTO_CANNOT_PICKUP_1, + JOHNNY_CANNOT_PICKUP_2, + SKEPTO_CANNOT_PICKUP_2, + JOHNNY_CANNOT_PICKUP_3, + SKEPTO_CANNOT_PICKUP_3, + JOHNNY_CANNOT_PICKUP_4, + SKEPTO_CANNOT_PICKUP_4, + + STRING_TYPES_TOTAL + }; + + HardcodedStrings(Game &game); + + /** + * Get hardcoded string. + * + * @param strType String type. + * @return Hardcoded string. + */ + const Common::String &getString(StringType strType) const; + +private: + typedef Common::Array StringArray; + + void loadStrings(Common::Language lang); + + StringArray _strings; +}; + +} + +#endif diff --git a/engines/mutationofjb/module.mk b/engines/mutationofjb/module.mk index c7de62bfa1..591853623e 100644 --- a/engines/mutationofjb/module.mk +++ b/engines/mutationofjb/module.mk @@ -30,8 +30,10 @@ MODULE_OBJS := \ tasks/taskmanager.o \ widgets/buttonwidget.o \ widgets/conversationwidget.o \ + widgets/gamewidget.o \ widgets/imagewidget.o \ widgets/inventorywidget.o \ + widgets/labelwidget.o \ widgets/widget.o \ animationdecoder.o \ assets.o \ @@ -44,6 +46,7 @@ MODULE_OBJS := \ gamedata.o \ gamescreen.o \ guiscreen.o \ + hardcodedstrings.o \ inventory.o \ inventoryitemdefinitionlist.o \ mutationofjb.o \ diff --git a/engines/mutationofjb/mutationofjb.cpp b/engines/mutationofjb/mutationofjb.cpp index ed4608b330..ea99b328e2 100644 --- a/engines/mutationofjb/mutationofjb.cpp +++ b/engines/mutationofjb/mutationofjb.cpp @@ -37,18 +37,21 @@ #include "mutationofjb/mutationofjb.h" #include "mutationofjb/game.h" #include "mutationofjb/gamedata.h" +#include "mutationofjb/gamescreen.h" #include "mutationofjb/debug.h" #include "mutationofjb/room.h" namespace MutationOfJB { -MutationOfJBEngine::MutationOfJBEngine(OSystem *syst) +MutationOfJBEngine::MutationOfJBEngine(OSystem *syst, const ADGameDescription *gameDesc) : Engine(syst), + _gameDesc(gameDesc), _console(nullptr), _screen(nullptr), _game(nullptr), _mapObjectId(0), - _cursorState(CURSOR_IDLE) { + _cursorState(CURSOR_IDLE), + _currentScreen(nullptr) { const Common::FSNode gameDataDir(ConfMan.get("path")); SearchMan.addSubDirectoryMatching(gameDataDir, "data"); @@ -110,22 +113,6 @@ void MutationOfJBEngine::setCursorState(CursorState cursorState) { updateCursorPalette(); } -void MutationOfJBEngine::updateCursor() { - if (_cursorState == CURSOR_OFF) { - return; - } - - if (_game->isCurrentSceneMap()) { - if (_cursorState != CURSOR_IDLE) { - _cursorState = CURSOR_IDLE; - updateCursorPalette(); - } - } else { - const Common::Point point = _eventMan->getMousePos(); - updateCursorHitTest(point.x, point.y); - } -} - bool MutationOfJBEngine::hasFeature(Engine::EngineFeature f) const { if (f == kSupportsLoadingDuringRuntime || f == kSupportsSavingDuringRuntime) { return true; @@ -179,114 +166,8 @@ Common::Error MutationOfJBEngine::saveGameState(int slot, const Common::String & return Common::kNoError; } -void MutationOfJBEngine::handleNormalScene(const Common::Event &event) { - Scene *const scene = _game->getGameData().getCurrentScene(); - - switch (event.type) { - case Common::EVENT_LBUTTONDOWN: { - const int16 x = event.mouse.x; - const int16 y = event.mouse.y; - - if (Door *const door = scene->findDoor(x, y)) { - if (!_game->startActionSection(_game->getCurrentAction(), door->_name) && _game->getCurrentAction() == ActionInfo::Walk && door->_destSceneId != 0) { - _game->changeScene(door->_destSceneId, _game->getGameData()._partB); - } - } else if (Static *const stat = scene->findStatic(x, y)) { - _game->startActionSection(_game->getCurrentAction(), stat->_name); - } - break; - } - case Common::EVENT_MOUSEMOVE: { - const int16 x = event.mouse.x; - const int16 y = event.mouse.y; - - if (_cursorState != CURSOR_OFF) { - updateCursorHitTest(x, y); - } - break; - } - default: - break; - } - _game->getGameScreen().handleEvent(event); -} - -void MutationOfJBEngine::handleMapScene(const Common::Event &event) { - Scene *const scene = _game->getGameData().getCurrentScene(); - - switch (event.type) { - case Common::EVENT_LBUTTONDOWN: { - const int16 x = event.mouse.x; - const int16 y = event.mouse.y; - - int index = 0; - if (Bitmap *const bitmap = scene->findBitmap(x, y, &index)) { - Static *const stat = scene->getStatic(index); - if (stat && stat->_active == 1) { - _game->startActionSection(ActionInfo::Walk, stat->_name); - } - } - break; - } - case Common::EVENT_MOUSEMOVE: { - const int16 x = event.mouse.x; - const int16 y = event.mouse.y; - - int index = 0; - bool found = false; - if (Bitmap *const bitmap = scene->findBitmap(x, y, &index)) { - Static *const stat = scene->getStatic(index); - if (stat && stat->_active == 1) { - Object *const object = scene->getObject(index); - if (object) { - found = true; - if (index != _mapObjectId) { - if (_mapObjectId) { - _game->getRoom().drawObjectAnimation(_mapObjectId, 1); - _mapObjectId = 0; - } - - _mapObjectId = index; - _game->getRoom().drawObjectAnimation(_mapObjectId, 0); - } - } - } - } - - if (!found && _mapObjectId != 0) { - _game->getRoom().drawObjectAnimation(_mapObjectId, 1); - _mapObjectId = 0; - } - break; - } - default: - break; - } -} - -void MutationOfJBEngine::updateCursorHitTest(int16 x, int16 y) { - Scene *const scene = _game->getGameData().getCurrentScene(); - if (!scene) { - return; - } - - bool entityHit = false; - if (Door *const door = scene->findDoor(x, y)) { - if (door->_destSceneId != 0) { - entityHit = true; - } - } else if (Static *const stat = scene->findStatic(x, y)) { - entityHit = true; - } - bool cursorPaletteChange = false; - if ((_cursorState == CURSOR_ACTIVE && !entityHit) || (_cursorState == CURSOR_IDLE && entityHit)) { - cursorPaletteChange = true; - } - _cursorState = entityHit ? CURSOR_ACTIVE : CURSOR_IDLE; - if (cursorPaletteChange) { - updateCursorPalette(); - } - +const ADGameDescription *MutationOfJBEngine::getGameDescription() const { + return _gameDesc; } Common::Error MutationOfJBEngine::run() { @@ -295,6 +176,7 @@ Common::Error MutationOfJBEngine::run() { _console = new Console(this); _screen = new Graphics::Screen(); _game = new Game(this); + _currentScreen = &_game->getGameScreen(); setupCursor(); @@ -320,39 +202,19 @@ Common::Error MutationOfJBEngine::run() { } break; } - case Common::EVENT_KEYUP: { - switch (event.kbd.ascii) { - case 'g': - _game->setCurrentAction(ActionInfo::Walk); - break; - case 'r': - _game->setCurrentAction(ActionInfo::Talk); - break; - case 's': - _game->setCurrentAction(ActionInfo::Look); - break; - case 'b': - _game->setCurrentAction(ActionInfo::Use); - break; - case 'n': - _game->setCurrentAction(ActionInfo::PickUp); - break; - } - break; - } default: break; } - if (!_game->isCurrentSceneMap()) { - handleNormalScene(event); - } else { - handleMapScene(event); - } + if (_currentScreen) + _currentScreen->handleEvent(event); } _console->onFrame(); _game->update(); + if (_currentScreen) + _currentScreen->update(); + _system->delayMillis(10); _screen->update(); } diff --git a/engines/mutationofjb/mutationofjb.h b/engines/mutationofjb/mutationofjb.h index 3430f13051..a4997690f1 100644 --- a/engines/mutationofjb/mutationofjb.h +++ b/engines/mutationofjb/mutationofjb.h @@ -26,6 +26,8 @@ #include "engines/engine.h" #include "mutationofjb/script.h" +struct ADGameDescription; + namespace Common { struct Event; class Serializer; @@ -39,6 +41,7 @@ namespace MutationOfJB { class Console; class Game; +class GuiScreen; struct SaveHeader { bool sync(Common::Serializer &sz); @@ -54,14 +57,13 @@ public: CURSOR_ACTIVE }; - MutationOfJBEngine(OSystem *syst); + MutationOfJBEngine(OSystem *syst, const ADGameDescription *gameDesc); ~MutationOfJBEngine(); virtual Common::Error run(); Graphics::Screen *getScreen() const; Game &getGame(); void setCursorState(CursorState cursorState); - void updateCursor(); virtual bool hasFeature(EngineFeature f) const override; virtual bool canLoadGameStateCurrently() override; @@ -69,40 +71,21 @@ public: virtual bool canSaveGameStateCurrently() override; virtual Common::Error saveGameState(int slot, const Common::String &desc) override; + const ADGameDescription *getGameDescription() const; + private: bool loadGameData(bool partB); void setupCursor(); - void updateCursorHitTest(int16 x, int16 y); void updateCursorPalette(); - /** - * Handling for normal (non-map) scenes. - * - * Statics and doors define mouse clickable areas. - * Statics are used to start actions. - * Doors are used to transition between scenes. - * - * @param event ScummVM event. - */ - void handleNormalScene(const Common::Event &event); - - /** - * Special handling for map scenes. - * - * Bitmaps define mouse clickable areas. - * Statics are used to start actions. - * Objects are used for showing labels. - * - * @param event ScummVM event. - */ - void handleMapScene(const Common::Event &event); - + const ADGameDescription *_gameDesc; Console *_console; Graphics::Screen *_screen; Game *_game; uint8 _mapObjectId; CursorState _cursorState; + GuiScreen *_currentScreen; }; } diff --git a/engines/mutationofjb/tasks/conversationtask.cpp b/engines/mutationofjb/tasks/conversationtask.cpp index 5167ec5308..ba90013ef1 100644 --- a/engines/mutationofjb/tasks/conversationtask.cpp +++ b/engines/mutationofjb/tasks/conversationtask.cpp @@ -39,10 +39,9 @@ void ConversationTask::start() { setState(RUNNING); Game &game = getTaskManager()->getGame(); + game.getGameScreen().showConversationWidget(true); ConversationWidget &widget = game.getGameScreen().getConversationWidget(); - widget.setCallback(this); - widget.setVisible(true); _currentGroupIndex = 0; @@ -219,9 +218,9 @@ void ConversationTask::finish() { setState(FINISHED); Game &game = getTaskManager()->getGame(); + game.getGameScreen().showConversationWidget(false); ConversationWidget &widget = game.getGameScreen().getConversationWidget(); - widget.setVisible(false); - game.getGameScreen().markDirty(); // TODO: Handle automatically when changing visibility. + widget.setCallback(nullptr); } void ConversationTask::startExtra() { diff --git a/engines/mutationofjb/widgets/gamewidget.cpp b/engines/mutationofjb/widgets/gamewidget.cpp new file mode 100644 index 0000000000..c481869ff3 --- /dev/null +++ b/engines/mutationofjb/widgets/gamewidget.cpp @@ -0,0 +1,179 @@ +/* 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. + * + */ + +#include "mutationofjb/widgets/gamewidget.h" + +#include "mutationofjb/game.h" +#include "mutationofjb/gamedata.h" +#include "mutationofjb/guiscreen.h" +#include "mutationofjb/mutationofjb.h" +#include "mutationofjb/room.h" + +#include "common/events.h" +#include "graphics/screen.h" + +namespace MutationOfJB { + +GameWidget::GameWidget(GuiScreen &gui) : + Widget(gui, Common::Rect(GAME_NORMAL_AREA_WIDTH, GAME_NORMAL_AREA_HEIGHT)), + _currentMapObjectId(0), + _nextMapObjectId(0), + _callback(nullptr) {} + +void GameWidget::handleEvent(const Common::Event &event) { + if (!_enabled) + return; + + if (!_gui.getGame().isCurrentSceneMap()) { + handleNormalScene(event); + } else { + handleMapScene(event); + } +} + +void GameWidget::clearState() { + _currentMapObjectId = _nextMapObjectId = 0; +} + +void GameWidget::draw(Graphics::ManagedSurface &) { + Room &room = _gui.getGame().getRoom(); + + // Only selection changed. + if (_dirtyBits & DIRTY_MAP_SELECTION) { + if (_currentMapObjectId != _nextMapObjectId) { + if (_currentMapObjectId) { + room.drawObjectAnimation(_currentMapObjectId, 1); + } + if (_nextMapObjectId) { + room.drawObjectAnimation(_nextMapObjectId, 0); + } + _currentMapObjectId = _nextMapObjectId; + } + } + + // Full redraw. + if (_dirtyBits == DIRTY_ALL) { + room.redraw(); + return; + } +} + +void GameWidget::handleNormalScene(const Common::Event &event) { + Game &game = _gui.getGame(); + Scene *const scene = game.getGameData().getCurrentScene(); + + switch (event.type) { + case Common::EVENT_LBUTTONDOWN: { + const int16 x = event.mouse.x; + const int16 y = event.mouse.y; + + if (!_area.contains(x, y)) + break; + + if (Door *const door = scene->findDoor(x, y)) { + if (_callback) + _callback->onGameDoorClicked(this, door); + } else if (Static *const stat = scene->findStatic(x, y)) { + if (_callback) + _callback->onGameStaticClicked(this, stat); + } + break; + } + case Common::EVENT_MOUSEMOVE: { + + const int16 x = event.mouse.x; + const int16 y = event.mouse.y; + + if (!_area.contains(x, y)) + break; + + bool entityHit = false; + if (Door *const door = scene->findDoor(x, y)) { + if (door->_destSceneId != 0) { + if (_callback) + _callback->onGameEntityHovered(this, door->_name); + entityHit = true; + } + } else if (Static *const stat = scene->findStatic(x, y)) { + if (_callback) + _callback->onGameEntityHovered(this, stat->_name); + entityHit = true; + } + + if (_callback && !entityHit) + _callback->onGameEntityHovered(this, Common::String()); + + _gui.getGame().getEngine().setCursorState(entityHit ? MutationOfJBEngine::CURSOR_ACTIVE : MutationOfJBEngine::CURSOR_IDLE); + break; + } + default: + break; + } +} + +void GameWidget::handleMapScene(const Common::Event &event) { + Game &game = _gui.getGame(); + Scene *const scene = game.getGameData().getCurrentScene(); + + switch (event.type) { + case Common::EVENT_LBUTTONDOWN: { + const int16 x = event.mouse.x; + const int16 y = event.mouse.y; + + int index = 0; + if (Bitmap *const bitmap = scene->findBitmap(x, y, &index)) { + Static *const stat = scene->getStatic(index); + if (stat && stat->_active == 1) { + game.startActionSection(ActionInfo::Walk, stat->_name); + } + } + break; + } + case Common::EVENT_MOUSEMOVE: { + const int16 x = event.mouse.x; + const int16 y = event.mouse.y; + + _nextMapObjectId = 0; + + int index = 0; + //bool found = false; + if (Bitmap *const bitmap = scene->findBitmap(x, y, &index)) { + Static *const stat = scene->getStatic(index); + if (stat && stat->_active == 1) { + Object *const object = scene->getObject(index); + if (object) { + _nextMapObjectId = index; + } + } + } + if (_currentMapObjectId != _nextMapObjectId) + markDirty(DIRTY_MAP_SELECTION); + + _gui.getGame().getEngine().setCursorState(_nextMapObjectId ? MutationOfJBEngine::CURSOR_ACTIVE : MutationOfJBEngine::CURSOR_IDLE); + break; + } + default: + break; + } +} + +} diff --git a/engines/mutationofjb/widgets/gamewidget.h b/engines/mutationofjb/widgets/gamewidget.h new file mode 100644 index 0000000000..e3fe08a818 --- /dev/null +++ b/engines/mutationofjb/widgets/gamewidget.h @@ -0,0 +1,96 @@ +/* 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 MUTATIONOFJB_GAMEWIDGET_H +#define MUTATIONOFJB_GAMEWIDGET_H + +#include "mutationofjb/widgets/widget.h" + +namespace MutationOfJB { + +class GameWidget; +struct Door; +struct Static; + +class GameWidgetCallback { +public: + virtual ~GameWidgetCallback() {} + virtual void onGameDoorClicked(GameWidget *, const Door *door) = 0; + virtual void onGameStaticClicked(GameWidget *, const Static *stat) = 0; + virtual void onGameEntityHovered(GameWidget *, const Common::String &entity) = 0; +}; + +class GameWidget : public Widget { +public: + enum { + GAME_NORMAL_AREA_WIDTH = 320, + GAME_NORMAL_AREA_HEIGHT = 139, + GAME_FULL_AREA_WIDTH = 320, + GAME_FULL_AREA_HEIGHT = 200 + }; + + GameWidget(GuiScreen &gui); + void setCallback(GameWidgetCallback *callback) { + _callback = callback; + } + + virtual void handleEvent(const Common::Event &); + + void clearState(); +protected: + virtual void draw(Graphics::ManagedSurface &); + +private: + enum { + DIRTY_MAP_SELECTION = 1 << 1 + }; + + /** + * Handling for normal (non-map) scenes. + * + * Statics and doors define mouse clickable areas. + * Statics are used to start actions. + * Doors are used to transition between scenes. + * + * @param event ScummVM event. + */ + void handleNormalScene(const Common::Event &event); + + /** + * Special handling for map scenes. + * + * Bitmaps define mouse clickable areas. + * Statics are used to start actions. + * Objects are used for showing labels. + * + * @param event ScummVM event. + */ + void handleMapScene(const Common::Event &event); + + uint8 _currentMapObjectId; + uint8 _nextMapObjectId; + GameWidgetCallback *_callback; +}; + +} + +#endif diff --git a/engines/mutationofjb/widgets/labelwidget.cpp b/engines/mutationofjb/widgets/labelwidget.cpp new file mode 100644 index 0000000000..0279cb27e1 --- /dev/null +++ b/engines/mutationofjb/widgets/labelwidget.cpp @@ -0,0 +1,64 @@ +/* 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. + * + */ + +#include "mutationofjb/widgets/labelwidget.h" + +#include "mutationofjb/assets.h" +#include "mutationofjb/game.h" +#include "mutationofjb/gamedata.h" + +namespace MutationOfJB { + +LabelWidget::LabelWidget(GuiScreen &gui, const Common::Rect &area) : + Widget(gui, area), + _backgroundColor(0x00) {} + +uint8 LabelWidget::getBackgroundColor() const { + return _backgroundColor; +} + +void LabelWidget::setBackgroundColor(uint8 color) { + if (_backgroundColor == color) + return; + + _backgroundColor = color; + markDirty(); +} + +const Common::String &LabelWidget::getText() const { + return _text; +} + +void LabelWidget::setText(const Common::String &text) { + if (_text == text) + return; + + _text = text; + markDirty(); +} + +void LabelWidget::draw(Graphics::ManagedSurface &surface) { + surface.fillRect(_area, _backgroundColor); + _gui.getGame().getAssets().getSystemFont().drawString(&surface, _text, _area.left, _area.top, _area.width(), LIGHTGRAY, Graphics::kTextAlignCenter); +} + +} diff --git a/engines/mutationofjb/widgets/labelwidget.h b/engines/mutationofjb/widgets/labelwidget.h new file mode 100644 index 0000000000..c87099671b --- /dev/null +++ b/engines/mutationofjb/widgets/labelwidget.h @@ -0,0 +1,50 @@ +/* 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 MUTATIONOJFB_LABELWIDGET_H +#define MUTATIONOJFB_LABELWIDGET_H + +#include "mutationofjb/widgets/widget.h" + +namespace MutationOfJB { + +class LabelWidget : public Widget { +public: + LabelWidget(GuiScreen &gui, const Common::Rect &area); + + uint8 getBackgroundColor() const; + void setBackgroundColor(uint8 color); + + const Common::String &getText() const; + void setText(const Common::String &text); + +protected: + virtual void draw(Graphics::ManagedSurface &) override; + +private: + uint8 _backgroundColor; + Common::String _text; +}; + +} + +#endif diff --git a/engines/mutationofjb/widgets/widget.cpp b/engines/mutationofjb/widgets/widget.cpp index b0302110ea..1b09fe08c3 100644 --- a/engines/mutationofjb/widgets/widget.cpp +++ b/engines/mutationofjb/widgets/widget.cpp @@ -43,20 +43,36 @@ void Widget::setVisible(bool visible) { _visible = visible; } -void Widget::markDirty() { - _dirty = true; +bool Widget::isEnabled() const { + return _enabled; +} + +void Widget::setEnabled(bool enabled) { + _enabled = enabled; +} + +Common::Rect Widget::getArea() const { + return _area; +} + +void Widget::setArea(const Common::Rect &area) { + _area = area; +} + +void Widget::markDirty(uint32 dirtyBits) { + _dirtyBits = dirtyBits; } bool Widget::isDirty() const { - return _dirty; + return _dirtyBits != DIRTY_NONE; } void Widget::update(Graphics::ManagedSurface &surface) { - if (_dirty) { + if (isDirty()) { if (_visible) { draw(surface); } - _dirty = false; + _dirtyBits = DIRTY_NONE; } } diff --git a/engines/mutationofjb/widgets/widget.h b/engines/mutationofjb/widgets/widget.h index 86c912a555..108d86c92f 100644 --- a/engines/mutationofjb/widgets/widget.h +++ b/engines/mutationofjb/widgets/widget.h @@ -40,7 +40,12 @@ class GuiScreen; class Widget { public: - Widget(GuiScreen &gui, const Common::Rect &area) : _gui(gui), _area(area), _id(0), _visible(true), _dirty(true) {} + enum { + DIRTY_NONE = 0, + DIRTY_ALL = 0xFFFFFFFF + }; + + Widget(GuiScreen &gui, const Common::Rect &area) : _gui(gui), _area(area), _id(0), _visible(true), _enabled(true), _dirtyBits(DIRTY_NONE) {} virtual ~Widget() {} int getId() const; @@ -49,8 +54,14 @@ public: bool isVisible() const; void setVisible(bool visible); + bool isEnabled() const; + void setEnabled(bool enabled); + + Common::Rect getArea() const; + void setArea(const Common::Rect &area); + bool isDirty() const; - void markDirty(); + void markDirty(uint32 dirtyBits = DIRTY_ALL); void update(Graphics::ManagedSurface &); virtual void handleEvent(const Common::Event &) {} @@ -61,7 +72,8 @@ protected: Common::Rect _area; int _id; bool _visible; - bool _dirty; + bool _enabled; + uint32 _dirtyBits; }; } -- cgit v1.2.3