aboutsummaryrefslogtreecommitdiff
path: root/engines/mutationofjb
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 /engines/mutationofjb
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.
Diffstat (limited to 'engines/mutationofjb')
-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;
};
}