aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorĽubomír Remák2018-10-28 13:08:41 +0100
committerĽubomír Remák2018-10-28 13:08:41 +0100
commitd5568906739da23154cacd17aca93802901a9baf (patch)
tree56e9a8060f2c513aade94d18078c1d572c25a31b
parent0cf567de28fbdc0ee3c4aedf2c6da94c5b8ca129 (diff)
downloadscummvm-rg350-d5568906739da23154cacd17aca93802901a9baf.tar.gz
scummvm-rg350-d5568906739da23154cacd17aca93802901a9baf.tar.bz2
scummvm-rg350-d5568906739da23154cacd17aca93802901a9baf.zip
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.
-rw-r--r--engines/mutationofjb/assets.cpp6
-rw-r--r--engines/mutationofjb/assets.h25
-rw-r--r--engines/mutationofjb/detection.cpp2
-rw-r--r--engines/mutationofjb/game.cpp24
-rw-r--r--engines/mutationofjb/game.h10
-rw-r--r--engines/mutationofjb/gamedata.cpp8
-rw-r--r--engines/mutationofjb/gamedata.h7
-rw-r--r--engines/mutationofjb/gamescreen.cpp214
-rw-r--r--engines/mutationofjb/gamescreen.h24
-rw-r--r--engines/mutationofjb/guiscreen.cpp5
-rw-r--r--engines/mutationofjb/guiscreen.h8
-rw-r--r--engines/mutationofjb/hardcodedstrings.cpp169
-rw-r--r--engines/mutationofjb/hardcodedstrings.h107
-rw-r--r--engines/mutationofjb/module.mk3
-rw-r--r--engines/mutationofjb/mutationofjb.cpp164
-rw-r--r--engines/mutationofjb/mutationofjb.h33
-rw-r--r--engines/mutationofjb/tasks/conversationtask.cpp7
-rw-r--r--engines/mutationofjb/widgets/gamewidget.cpp179
-rw-r--r--engines/mutationofjb/widgets/gamewidget.h96
-rw-r--r--engines/mutationofjb/widgets/labelwidget.cpp64
-rw-r--r--engines/mutationofjb/widgets/labelwidget.h50
-rw-r--r--engines/mutationofjb/widgets/widget.cpp26
-rw-r--r--engines/mutationofjb/widgets/widget.h18
23 files changed, 1024 insertions, 225 deletions
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<ButtonWidget *>::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<Graphics::Surface> _inventorySurfaces;
Common::Array<Graphics::Surface> _hudSurfaces;
+ Common::Array<ButtonWidget *> _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<Widget *> Widgets;
+
Game &_game;
Graphics::Screen *_screen;
+ const Widgets &getWidgets() const;
+
private:
- Common::Array<Widget *> _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<StringArray::size_type>(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<Common::String> 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;
};
}