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.
This commit is contained in:
Ľubomír Remák 2018-10-28 13:08:41 +01:00
parent 0cf567de28
commit d556890673
23 changed files with 1023 additions and 224 deletions

View File

@ -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;
}
}

View File

@ -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;
};
}

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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();

View File

@ -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;
};
/**

View File

@ -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];
const Common::String &item = _game.getGameData().getInventory().getItems()[posInWidget];
if (_game.getCurrentAction() == ActionInfo::Use) {
// TODO
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);
}
}

View File

@ -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;
};
}

View File

@ -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;
}
}

View File

@ -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;
};
}

View File

@ -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();
}
}

View File

@ -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

View File

@ -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 \

View File

@ -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();
}

View File

@ -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;
};
}

View File

@ -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() {

View File

@ -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;
}
}
}

View File

@ -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

View File

@ -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);
}
}

View File

@ -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

View File

@ -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;
}
}

View File

@ -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;
};
}