aboutsummaryrefslogtreecommitdiff
path: root/engines/mutationofjb
diff options
context:
space:
mode:
authorĽubomír Remák2018-07-15 00:18:54 +0200
committerEugene Sandulenko2018-08-25 23:12:01 +0200
commitfebff83a4edc89e1dbc6f4c56f5531f0eb8f3287 (patch)
tree756129c1736a39aad5473d7873810a3a742911ae /engines/mutationofjb
parentd2e354b51f637dc2e9b251256b5a017cb41cfe59 (diff)
downloadscummvm-rg350-febff83a4edc89e1dbc6f4c56f5531f0eb8f3287.tar.gz
scummvm-rg350-febff83a4edc89e1dbc6f4c56f5531f0eb8f3287.tar.bz2
scummvm-rg350-febff83a4edc89e1dbc6f4c56f5531f0eb8f3287.zip
MUTATIONOFJB: Draw objects (first frame only) and improve conversation support.
Diffstat (limited to 'engines/mutationofjb')
-rw-r--r--engines/mutationofjb/commands/definestructcommand.cpp2
-rw-r--r--engines/mutationofjb/commands/talkcommand.cpp9
-rw-r--r--engines/mutationofjb/game.cpp8
-rw-r--r--engines/mutationofjb/game.h2
-rw-r--r--engines/mutationofjb/gamedata.cpp22
-rw-r--r--engines/mutationofjb/gamedata.h26
-rw-r--r--engines/mutationofjb/module.mk2
-rw-r--r--engines/mutationofjb/room.cpp31
-rw-r--r--engines/mutationofjb/room.h3
-rw-r--r--engines/mutationofjb/tasks/conversationtask.cpp173
-rw-r--r--engines/mutationofjb/tasks/conversationtask.h25
-rw-r--r--engines/mutationofjb/tasks/saytask.cpp55
-rw-r--r--engines/mutationofjb/tasks/saytask.h44
-rw-r--r--engines/mutationofjb/tasks/task.h5
-rw-r--r--engines/mutationofjb/tasks/taskmanager.cpp4
-rw-r--r--engines/mutationofjb/timer.cpp56
-rw-r--r--engines/mutationofjb/timer.h50
-rw-r--r--engines/mutationofjb/widgets/conversationwidget.cpp29
-rw-r--r--engines/mutationofjb/widgets/conversationwidget.h12
19 files changed, 505 insertions, 53 deletions
diff --git a/engines/mutationofjb/commands/definestructcommand.cpp b/engines/mutationofjb/commands/definestructcommand.cpp
index ee15274a2d..93dbfc80bc 100644
--- a/engines/mutationofjb/commands/definestructcommand.cpp
+++ b/engines/mutationofjb/commands/definestructcommand.cpp
@@ -56,7 +56,7 @@ bool DefineStructCommandParser::parse(const Common::String &line, ScriptParseCon
for (int j = 0; j < 5; ++j) {
ConversationInfo::Item convItem;
- convItem._question = atoi(linePtr);
+ convItem._choice = atoi(linePtr);
linePtr += 6;
convItem._response = atoi(linePtr);
linePtr += 6;
diff --git a/engines/mutationofjb/commands/talkcommand.cpp b/engines/mutationofjb/commands/talkcommand.cpp
index d0775e481f..18ce956696 100644
--- a/engines/mutationofjb/commands/talkcommand.cpp
+++ b/engines/mutationofjb/commands/talkcommand.cpp
@@ -21,9 +21,12 @@
*/
#include "mutationofjb/commands/talkcommand.h"
-#include "mutationofjb/tasks/conversationtask.h"
-#include "mutationofjb/script.h"
+
#include "mutationofjb/game.h"
+#include "mutationofjb/script.h"
+#include "mutationofjb/tasks/conversationtask.h"
+#include "mutationofjb/tasks/taskmanager.h"
+
#include "common/str.h"
namespace MutationOfJB {
@@ -53,7 +56,7 @@ bool TalkCommandParser::parse(const Common::String &line, ScriptParseContext &,
Command::ExecuteResult TalkCommand::execute(ScriptExecutionContext &scriptExeCtx) {
if (!_task) {
- _task = new ConversationTask(scriptExeCtx.getGame().getGameData()._conversationInfo);
+ _task = new ConversationTask(scriptExeCtx.getGameData()._currentScene, scriptExeCtx.getGame().getGameData()._conversationInfo);
scriptExeCtx.getGame().getTaskManager().addTask(_task);
}
diff --git a/engines/mutationofjb/game.cpp b/engines/mutationofjb/game.cpp
index 24159254df..69647f2ef3 100644
--- a/engines/mutationofjb/game.cpp
+++ b/engines/mutationofjb/game.cpp
@@ -100,7 +100,9 @@ Script *Game::changeSceneLoadScript(uint8 sceneId, bool partB) {
_gameData->_lastScene = _gameData->_currentScene;
_gameData->_currentScene = sceneId;
_gameData->_partB = partB;
+
_room->load(_gameData->_currentScene, partB);
+ _room->redraw();
EncryptedFile scriptFile;
Common::String fileName = Common::String::format("scrn%d%s.atn", sceneId, partB ? "b" : "");
@@ -180,6 +182,7 @@ void Game::update() {
}
_gui.update();
+ _taskManager.update();
}
Gui &Game::getGui() {
@@ -227,4 +230,9 @@ Assets& Game::getAssets() {
return _assets;
}
+Graphics::Screen &Game::getScreen()
+{
+ return *_vm->getScreen();
+}
+
}
diff --git a/engines/mutationofjb/game.h b/engines/mutationofjb/game.h
index 33527ae441..056cffb757 100644
--- a/engines/mutationofjb/game.h
+++ b/engines/mutationofjb/game.h
@@ -71,6 +71,8 @@ public:
TaskManager& getTaskManager();
Assets &getAssets();
+ Graphics::Screen &getScreen();
+
private:
bool loadGameData(bool partB);
void runActiveCommand();
diff --git a/engines/mutationofjb/gamedata.cpp b/engines/mutationofjb/gamedata.cpp
index 1ece44c740..6a9c166106 100644
--- a/engines/mutationofjb/gamedata.cpp
+++ b/engines/mutationofjb/gamedata.cpp
@@ -136,7 +136,11 @@ bool Scene::loadFromStream(Common::ReadStream &stream) {
_palRotStart = stream.readByte();
_palRotEnd = stream.readByte();
_palRotPeriod = stream.readByte();
- stream.read(_unknown38A, 80);
+ _exhaustedChoiceNext = stream.readByte();
+
+ for (i = 0; i < 79; ++i) {
+ _exhaustedChoices[i]._encodedData = stream.readByte();
+ }
return true;
}
@@ -222,6 +226,22 @@ Bitmap *Scene::findBitmap(int16 x, int16 y, int *index) {
return nullptr;
}
+void Scene::addExhaustedChoice(uint8 context, uint8 choiceIndex, uint8 choiceIndexList) {
+ _exhaustedChoices[_exhaustedChoiceNext - 1] = ExhaustedChoice(context, choiceIndex, choiceIndexList);
+ _exhaustedChoiceNext++;
+}
+
+bool Scene::isChoiceExhausted(uint8 context, uint8 choiceIndex, uint8 choiceListIndex) const {
+ for (uint i = 0; i < _exhaustedChoiceNext - 1; ++i) {
+ const ExhaustedChoice &choice = _exhaustedChoices[i];
+ if (choice.getContext() == context && choice.getChoiceIndex() == choiceIndex && choice.getChoiceListIndex() == choiceListIndex) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
GameData::GameData()
: _currentScene(0),
diff --git a/engines/mutationofjb/gamedata.h b/engines/mutationofjb/gamedata.h
index d1bbc546b3..62c66a1363 100644
--- a/engines/mutationofjb/gamedata.h
+++ b/engines/mutationofjb/gamedata.h
@@ -121,6 +121,22 @@ struct Bitmap {
bool loadFromStream(Common::ReadStream &stream);
};
+struct ExhaustedChoice {
+ /*
+ 1 bit - context
+ 3 bits - choice index
+ 4 bits - choice list index
+ */
+ uint8 _encodedData;
+
+ uint8 getContext() const { return (_encodedData >> 7) & 0x1; }
+ uint8 getChoiceIndex() const { return (_encodedData >> 4) & 0x7; }
+ uint8 getChoiceListIndex() const { return _encodedData & 0xF; }
+
+ ExhaustedChoice() : _encodedData(0) {}
+ ExhaustedChoice(uint8 context, uint8 choiceIndex, uint8 choiceListIndex) :
+ _encodedData(((context & 0x1) << 7) | ((choiceIndex & 0x7) << 4) | (choiceListIndex & 0xF)) {}
+};
struct Scene {
Door *getDoor(uint8 objectId);
@@ -135,6 +151,9 @@ struct Scene {
Static *findStatic(int16 x, int16 y, int *index = nullptr);
Bitmap *findBitmap(int16 x, int16 y, int *index = nullptr);
+ void addExhaustedChoice(uint8 context, uint8 choiceIndex, uint8 choiceIndexList);
+ bool isChoiceExhausted(uint8 context, uint8 choiceIndex, uint8 choiceIndexList) const;
+
uint8 _startup;
uint8 _unknown001;
uint8 _unknown002;
@@ -156,14 +175,17 @@ struct Scene {
uint8 _palRotStart;
uint8 _palRotEnd;
uint8 _palRotPeriod;
- uint8 _unknown38A[80];
+
+ /* Points to the first free item in exhausted choices list. */
+ uint8 _exhaustedChoiceNext;
+ ExhaustedChoice _exhaustedChoices[79];
bool loadFromStream(Common::ReadStream &stream);
};
struct ConversationInfo {
struct Item {
- uint8 _question;
+ uint8 _choice;
uint8 _response;
uint8 _nextLineIndex;
};
diff --git a/engines/mutationofjb/module.mk b/engines/mutationofjb/module.mk
index 89da245dd4..f3a1d78784 100644
--- a/engines/mutationofjb/module.mk
+++ b/engines/mutationofjb/module.mk
@@ -22,6 +22,7 @@ MODULE_OBJS := \
commands/seqcommand.o \
commands/talkcommand.o \
tasks/conversationtask.o \
+ tasks/saytask.o \
tasks/taskmanager.o \
widgets/buttonwidget.o \
widgets/conversationwidget.o \
@@ -42,6 +43,7 @@ MODULE_OBJS := \
mutationofjb.o \
room.o \
script.o \
+ timer.o \
util.o
# This module can be built as a plugin
diff --git a/engines/mutationofjb/room.cpp b/engines/mutationofjb/room.cpp
index 62af98327e..5577077480 100644
--- a/engines/mutationofjb/room.cpp
+++ b/engines/mutationofjb/room.cpp
@@ -21,17 +21,25 @@
*/
#include "mutationofjb/room.h"
+
#include "mutationofjb/animationdecoder.h"
#include "mutationofjb/encryptedfile.h"
#include "mutationofjb/game.h"
#include "mutationofjb/gamedata.h"
#include "mutationofjb/util.h"
+
#include "common/str.h"
#include "common/translation.h"
+
#include "graphics/screen.h"
namespace MutationOfJB {
+enum {
+ GAME_AREA_WIDTH = 320,
+ GAME_AREA_HEIGHT = 139
+};
+
class RoomAnimationDecoderCallback : public AnimationDecoderCallback {
public:
RoomAnimationDecoderCallback(Room &room) : _room(room) {}
@@ -47,9 +55,11 @@ void RoomAnimationDecoderCallback::onPaletteUpdated(byte palette[PALETTE_SIZE])
void RoomAnimationDecoderCallback::onFrame(int frameNo, Graphics::Surface &surface) {
if (frameNo == 0) {
- Common::Rect rect(0, 0, 320, 139);
+ Common::Rect rect(0, 0, GAME_AREA_WIDTH, GAME_AREA_HEIGHT);
if (_room._game->isCurrentSceneMap()) {
rect = Common::Rect(0, 0, 320, 200);
+ } else {
+ _room._background.blitFrom(surface, rect, Common::Point(0, 0));
}
_room._screen->blitFrom(surface, rect, Common::Point(0, 0));
}
@@ -78,10 +88,11 @@ void RoomAnimationDecoderCallback::onFrame(int frameNo, Graphics::Surface &surfa
}
}
-Room::Room(Game *game, Graphics::Screen *screen) : _game(game), _screen(screen) {}
+Room::Room(Game *game, Graphics::Screen *screen) : _game(game), _screen(screen), _background(GAME_AREA_WIDTH, GAME_AREA_HEIGHT) {}
bool Room::load(uint8 roomNumber, bool roomB) {
_objectsStart.clear();
+ _surfaces.clear(); // TODO: Fix memory leak.
Scene *const scene = _game->getGameData().getCurrentScene();
if (scene) {
@@ -118,7 +129,23 @@ void Room::drawObjectAnimation(uint8 objectId, int animOffset) {
const int startFrame = _objectsStart[objectId - 1];
const int animFrame = startFrame + animOffset;
+ // TODO: Threshold.
_screen->blitFrom(_surfaces[animFrame], Common::Point(object->_x, object->_y));
}
+void Room::redraw() {
+ if (!_game->isCurrentSceneMap()) {
+ Common::Rect rect(0, 0, GAME_AREA_WIDTH, GAME_AREA_HEIGHT);
+ _screen->blitFrom(_background.rawSurface(), rect, Common::Point(0, 0));
+
+ Scene *const currentScene = _game->getGameData().getCurrentScene();
+ for (int i = 0; i < currentScene->getNoObjects(); ++i) {
+ Object *const obj = currentScene->getObject(i + 1);
+ if (obj->_AC) {
+ drawObjectAnimation(i + 1, 0);
+ }
+ }
+ }
+}
+
}
diff --git a/engines/mutationofjb/room.h b/engines/mutationofjb/room.h
index e57d2ebb61..083fba6335 100644
--- a/engines/mutationofjb/room.h
+++ b/engines/mutationofjb/room.h
@@ -26,6 +26,7 @@
#include "common/scummsys.h"
#include "common/array.h"
#include "graphics/surface.h"
+#include "graphics/managed_surface.h"
namespace Graphics {
class Screen;
@@ -44,9 +45,11 @@ public:
Room(Game *game, Graphics::Screen *screen);
bool load(uint8 roomNumber, bool roomB);
void drawObjectAnimation(uint8 objectId, int animOffset);
+ void redraw();
private:
Game *_game;
Graphics::Screen *_screen;
+ Graphics::ManagedSurface _background;
Common::Array<Graphics::Surface> _surfaces;
Common::Array<int> _objectsStart;
};
diff --git a/engines/mutationofjb/tasks/conversationtask.cpp b/engines/mutationofjb/tasks/conversationtask.cpp
index 75d850465b..512b38b710 100644
--- a/engines/mutationofjb/tasks/conversationtask.cpp
+++ b/engines/mutationofjb/tasks/conversationtask.cpp
@@ -21,63 +21,186 @@
*/
#include "mutationofjb/tasks/conversationtask.h"
-#include "mutationofjb/tasks/taskmanager.h"
+
#include "mutationofjb/assets.h"
+#include "mutationofjb/conversationlinelist.h"
#include "mutationofjb/game.h"
#include "mutationofjb/gamedata.h"
#include "mutationofjb/gui.h"
+#include "mutationofjb/tasks/saytask.h"
+#include "mutationofjb/tasks/taskmanager.h"
#include "mutationofjb/util.h"
#include "mutationofjb/widgets/conversationwidget.h"
namespace MutationOfJB {
void ConversationTask::start() {
+ setState(RUNNING);
+
Game &game = getTaskManager()->getGame();
ConversationWidget &widget = game.getGui().getConversationWidget();
widget.setCallback(this);
widget.setVisible(true);
- updateWidget();
+ _currentLineIndex = 0;
+
+ showChoicesOrPick();
}
void ConversationTask::update() {
-}
+ if (_sayTask) {
+ if (_sayTask->getState() == Task::FINISHED) {
+ getTaskManager()->removeTask(_sayTask);
+ delete _sayTask;
+ _sayTask = nullptr;
-void ConversationTask::onResponseClicked(ConversationWidget *, int response) {
+ switch (_substate) {
+ case SAYING_NO_CHOICES:
+ finish();
+ break;
+ case SAYING_CHOICE: {
+ const ConversationLineList& responseList = getTaskManager()->getGame().getAssets().getResponseList();
+ const ConversationLineList::Line *const line = responseList.getLine(_currentItem->_response);
- uint8 nextLineIndex = _convInfo._lines[_currentLine]._items[response]._nextLineIndex;
- if (nextLineIndex == 0) {
- setState(FINISHED);
- Game &game = getTaskManager()->getGame();
- ConversationWidget &widget = game.getGui().getConversationWidget();
- widget.setVisible(false);
- game.getGui().markDirty(); // TODO: Handle automatically when changing visibility.
- return;
+ _sayTask = new SayTask(line->_speeches[0]._text, _convInfo._color);
+ getTaskManager()->addTask(_sayTask);
+ _substate = SAYING_RESPONSE;
+ break;
+ }
+ case SAYING_RESPONSE: {
+ if (_currentItem->_nextLineIndex == 0) {
+ finish();
+ } else {
+ _currentLineIndex = _currentItem->_nextLineIndex - 1;
+ showChoicesOrPick();
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
}
+}
- _currentLine = nextLineIndex - 1;
- updateWidget();
+void ConversationTask::onChoiceClicked(ConversationWidget *convWidget, int, uint32 data) {
+ const ConversationInfo::Item &item = getCurrentLine()->_items[data];
+ convWidget->clearChoices();
+
+ const ConversationLineList& toSayList = getTaskManager()->getGame().getAssets().getToSayList();
+ _sayTask = new SayTask(toSayList.getLine(item._choice)->_speeches[0]._text, _convInfo._color);
+ getTaskManager()->addTask(_sayTask);
+ _substate = SAYING_CHOICE;
+ _currentItem = &item;
+ getTaskManager()->getGame().getGameData().getCurrentScene()->addExhaustedChoice(_convInfo._context, data + 1, _currentLineIndex + 1);
}
-void ConversationTask::updateWidget() {
+void ConversationTask::showChoicesOrPick() {
Game &game = getTaskManager()->getGame();
- ConversationWidget &widget = game.getGui().getConversationWidget();
+ GameData &gameData = game.getGameData();
+ Scene *const scene = gameData.getScene(_sceneId);
+
+ Common::Array<uint32> itemsWithValidChoices;
+ Common::Array<uint32> itemsWithValidResponses;
+ Common::Array<uint32> itemsWithValidNext;
+
+ /*
+ Collect valid "to say" choices (not exhausted and not empty).
+ Collect valid responses (not exhausted and not empty).
+ If there are at least two visible choices, we show them.
+ If there is just one visible choice, pick it automatically.
+ If there are no visible choices, automatically pick first valid response.
+ */
+
+ const ConversationInfo::Line *const currentLine = getCurrentLine();
+ for (ConversationInfo::Items::size_type i = 0; i < currentLine->_items.size(); ++i) {
+ const ConversationInfo::Item &item = currentLine->_items[i];
+
+ if (scene->isChoiceExhausted(_convInfo._context, (uint8) i + 1, (uint8) _currentLineIndex + 1)) {
+ continue;
+ }
+ const uint8 choice = item._choice;
+ const uint8 response = item._response;
+ const uint8 next = item._nextLineIndex;
+
+ if (choice != 0) {
+ itemsWithValidChoices.push_back(i);
+ }
- const ConversationLineList& toSayList = game.getAssets().getToSayList();
+ if (response != 0) {
+ itemsWithValidResponses.push_back(i);
+ }
- const ConversationInfo::Line &convLine = _convInfo._lines[_currentLine];
+ if (next != 0) {
+ itemsWithValidNext.push_back(i);
+ }
+ }
+
+ if (itemsWithValidChoices.size() > 1) {
+ ConversationWidget &widget = game.getGui().getConversationWidget();
+ const ConversationLineList& toSayList = game.getAssets().getToSayList();
- for (ConversationInfo::Items::size_type i = 0; i < convLine._items.size(); ++i) {
- Common::String widgetText;
- const uint8 question = convLine._items[i]._question;
- if (question != 0) {
- const ConversationLineList::Line *line = toSayList.getLine(convLine._items[i]._question);
- widgetText = toUpperCP895(line->_speeches[0]._text);
+ for (Common::Array<uint32>::size_type i = 0; i < itemsWithValidChoices.size() && i < ConversationWidget::CONVERSATION_MAX_CHOICES; ++i) {
+ const ConversationInfo::Item &item = currentLine->_items[itemsWithValidChoices[i]];
+ const ConversationLineList::Line *const line = toSayList.getLine(item._choice);
+ const Common::String widgetText = toUpperCP895(line->_speeches[0]._text);
+ widget.setChoice((int) i, widgetText, itemsWithValidChoices[i]);
}
+ _substate = IDLE;
+ _currentItem = nullptr;
+
+ _haveChoices = true;
+ } else if (itemsWithValidChoices.size() == 1) {
+ const ConversationLineList& toSayList = game.getAssets().getToSayList();
+ const ConversationInfo::Item &item = currentLine->_items[itemsWithValidChoices.front()];
+ const ConversationLineList::Line *const line = toSayList.getLine(item._choice);
+
+ _sayTask = new SayTask(line->_speeches[0]._text, _convInfo._color);
+ getTaskManager()->addTask(_sayTask);
+ _substate = SAYING_CHOICE;
+ _currentItem = &item;
+
+ game.getGameData().getCurrentScene()->addExhaustedChoice(_convInfo._context, itemsWithValidChoices.front() + 1, _currentLineIndex + 1);
+
+ _haveChoices = true;
+ } else if (!itemsWithValidResponses.empty()) {
+ const ConversationLineList& responseList = game.getAssets().getResponseList();
+ const ConversationInfo::Item &item = currentLine->_items[itemsWithValidResponses.front()];
+ const ConversationLineList::Line *const line = responseList.getLine(item._response);
- widget.setLine(i, widgetText);
+ _sayTask = new SayTask(line->_speeches[0]._text, _convInfo._color);
+ getTaskManager()->addTask(_sayTask);
+ _substate = SAYING_RESPONSE;
+ _currentItem = &item;
+
+ _haveChoices = true;
+ } else if (!itemsWithValidNext.empty()) {
+ _currentLineIndex = currentLine->_items[itemsWithValidNext.front()]._nextLineIndex - 1;
+ showChoicesOrPick();
+ } else {
+ if (_haveChoices) {
+ finish();
+ } else {
+ _sayTask = new SayTask("Nothing to talk about.", _convInfo._color); // TODO: This is hardcoded in executable. Load it.
+ getTaskManager()->addTask(_sayTask);
+ _substate = SAYING_NO_CHOICES;
+ _currentItem = nullptr;
+ }
}
}
+const ConversationInfo::Line *ConversationTask::getCurrentLine() const {
+ return &_convInfo._lines[_currentLineIndex];
+}
+
+void ConversationTask::finish() {
+ setState(FINISHED);
+
+ Game &game = getTaskManager()->getGame();
+ ConversationWidget &widget = game.getGui().getConversationWidget();
+ widget.setVisible(false);
+ game.getGui().markDirty(); // TODO: Handle automatically when changing visibility.
+}
+
}
diff --git a/engines/mutationofjb/tasks/conversationtask.h b/engines/mutationofjb/tasks/conversationtask.h
index 5cc0e5f49f..3bcbb6f998 100644
--- a/engines/mutationofjb/tasks/conversationtask.h
+++ b/engines/mutationofjb/tasks/conversationtask.h
@@ -26,20 +26,37 @@
namespace MutationOfJB {
+class SayTask;
+
class ConversationTask : public Task, public ConversationWidgetCallback {
public:
- ConversationTask(const ConversationInfo& convInfo) : _convInfo(convInfo), _currentLine(0) {}
+ ConversationTask(uint8 sceneId, const ConversationInfo& convInfo) : _sceneId(sceneId), _convInfo(convInfo), _currentLineIndex(0), _currentItem(nullptr), _sayTask(nullptr), _substate(IDLE), _haveChoices(false) {}
virtual ~ConversationTask() {}
virtual void start() override;
virtual void update() override;
- virtual void onResponseClicked(ConversationWidget *, int response) override;
+ virtual void onChoiceClicked(ConversationWidget *, int response, uint32 data) override;
private:
- void updateWidget();
+ void showChoicesOrPick();
+ const ConversationInfo::Line *getCurrentLine() const;
+ void finish();
+ uint8 _sceneId;
const ConversationInfo &_convInfo;
- uint _currentLine;
+ uint _currentLineIndex;
+ const ConversationInfo::Item *_currentItem;
+ SayTask* _sayTask;
+
+ enum Substate {
+ IDLE,
+ SAYING_CHOICE,
+ SAYING_RESPONSE,
+ SAYING_NO_CHOICES
+ };
+
+ Substate _substate;
+ bool _haveChoices;
};
}
diff --git a/engines/mutationofjb/tasks/saytask.cpp b/engines/mutationofjb/tasks/saytask.cpp
new file mode 100644
index 0000000000..2ef4cdf5df
--- /dev/null
+++ b/engines/mutationofjb/tasks/saytask.cpp
@@ -0,0 +1,55 @@
+/* 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/tasks/saytask.h"
+
+#include "mutationofjb/tasks/taskmanager.h"
+#include "mutationofjb/assets.h"
+#include "mutationofjb/game.h"
+#include "mutationofjb/gamedata.h"
+#include "mutationofjb/room.h"
+
+#include "graphics/managed_surface.h"
+#include "graphics/screen.h"
+
+namespace MutationOfJB {
+
+SayTask::SayTask(const Common::String &toSay, uint8 color) : _toSay(toSay), _color(color), _timer(1000) {}
+
+void SayTask::start() {
+
+ getTaskManager()->getGame().getAssets().getSpeechFont().drawString(_toSay, _color, 0, 0, getTaskManager()->getGame().getScreen());
+ _timer.start();
+ setState(RUNNING);
+}
+
+void SayTask::update() {
+ _timer.update();
+
+ if (_timer.isFnished()) {
+ getTaskManager()->getGame().getRoom().redraw(); // TODO: Only redraw the area occupied by the text.
+ setState(FINISHED);
+ return;
+ }
+}
+
+}
diff --git a/engines/mutationofjb/tasks/saytask.h b/engines/mutationofjb/tasks/saytask.h
new file mode 100644
index 0000000000..a7ac96d875
--- /dev/null
+++ b/engines/mutationofjb/tasks/saytask.h
@@ -0,0 +1,44 @@
+/* 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/tasks/task.h"
+
+#include "mutationofjb/timer.h"
+
+#include "common/str.h"
+
+namespace MutationOfJB {
+
+class SayTask : public Task {
+public:
+ SayTask(const Common::String &toSay, uint8 color);
+
+ virtual void start() override;
+ virtual void update() override;
+
+private:
+ Common::String _toSay;
+ uint8 _color;
+ Timer _timer;
+};
+
+}
diff --git a/engines/mutationofjb/tasks/task.h b/engines/mutationofjb/tasks/task.h
index 7b43868269..1b98097b9c 100644
--- a/engines/mutationofjb/tasks/task.h
+++ b/engines/mutationofjb/tasks/task.h
@@ -20,6 +20,9 @@
*
*/
+#ifndef MUTATIONOFJB_TASK_H
+#define MUTATIONOFJB_TASK_H
+
#include "common/scummsys.h"
namespace MutationOfJB {
@@ -54,3 +57,5 @@ private:
};
}
+
+#endif
diff --git a/engines/mutationofjb/tasks/taskmanager.cpp b/engines/mutationofjb/tasks/taskmanager.cpp
index 981654981f..7fbf64dc9b 100644
--- a/engines/mutationofjb/tasks/taskmanager.cpp
+++ b/engines/mutationofjb/tasks/taskmanager.cpp
@@ -40,7 +40,9 @@ void TaskManager::removeTask(Task *task) {
void TaskManager::update() {
for (Tasks::const_iterator it = _tasks.begin(); it != _tasks.end(); ++it) {
- (*it)->update();
+ if ((*it)->getState() == Task::RUNNING) {
+ (*it)->update();
+ }
}
}
diff --git a/engines/mutationofjb/timer.cpp b/engines/mutationofjb/timer.cpp
new file mode 100644
index 0000000000..8375445c08
--- /dev/null
+++ b/engines/mutationofjb/timer.cpp
@@ -0,0 +1,56 @@
+/* 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/timer.h"
+
+#include "common/system.h"
+
+namespace MutationOfJB {
+
+Timer::Timer(uint32 millis) : _millis(millis), _startTime(0), _state(IDLE) {
+}
+
+void Timer::start() {
+ _startTime = g_system->getMillis();
+ _state = RUNNING;
+}
+
+bool Timer::isFnished() const {
+ return _state == FINISHED;
+}
+
+bool Timer::isRunning() const {
+ return _state == RUNNING;
+}
+
+void Timer::update() {
+ if (_state != RUNNING) {
+ return;
+ }
+
+ uint32 currentTime = g_system->getMillis();
+ if (currentTime - _startTime >= _millis) {
+ _state = FINISHED;
+ }
+}
+
+}
diff --git a/engines/mutationofjb/timer.h b/engines/mutationofjb/timer.h
new file mode 100644
index 0000000000..b12fe2278c
--- /dev/null
+++ b/engines/mutationofjb/timer.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.
+ *
+ */
+
+#include "common/scummsys.h"
+
+namespace MutationOfJB {
+
+class Timer {
+public:
+ Timer(uint32 millis);
+
+ void start();
+
+ bool isFnished() const;
+ bool isRunning() const;
+
+ void update();
+
+private:
+ enum State {
+ IDLE,
+ RUNNING,
+ FINISHED
+ };
+
+ uint32 _millis;
+ uint32 _startTime;
+ State _state;
+};
+
+}
diff --git a/engines/mutationofjb/widgets/conversationwidget.cpp b/engines/mutationofjb/widgets/conversationwidget.cpp
index 71a3483b75..a46b9c50f8 100644
--- a/engines/mutationofjb/widgets/conversationwidget.cpp
+++ b/engines/mutationofjb/widgets/conversationwidget.cpp
@@ -41,26 +41,35 @@ ConversationWidget::ConversationWidget(Gui &gui, const Common::Rect &area, const
_callback(nullptr) {}
-void ConversationWidget::setLine(int lineNo, const Common::String &str) {
- if (lineNo >= CONVERSATION_LINES) {
+void ConversationWidget::setChoice(int choiceNo, const Common::String &str, uint32 data) {
+ if (choiceNo >= CONVERSATION_MAX_CHOICES) {
return;
}
- _lines[lineNo] = str;
+ _choices[choiceNo]._str = str;
+ _choices[choiceNo]._data = data;
+ markDirty();
+}
+
+void ConversationWidget::clearChoices() {
+ for (int i = 0; i < CONVERSATION_MAX_CHOICES; ++i) {
+ _choices[i]._str.clear();
+ _choices[i]._data = 0;
+ }
markDirty();
}
void ConversationWidget::_draw(Graphics::ManagedSurface &surface) {
surface.blitFrom(_surface, Common::Point(_area.left, _area.top));
- for (int i = 0; i < CONVERSATION_LINES; ++i) {
- Common::String &line = _lines[i];
- if (line.empty()) {
+ for (int i = 0; i < CONVERSATION_MAX_CHOICES; ++i) {
+ Common::String &str = _choices[i]._str;
+ if (str.empty()) {
continue;
}
// TODO: Active line should be WHITE.
- _gui.getGame().getAssets().getSystemFont().drawString(line, LIGHTGRAY, CONVERSATION_LINES_X, CONVERSATION_LINES_Y + i * CONVERSATION_LINE_HEIGHT, surface);
+ _gui.getGame().getAssets().getSystemFont().drawString(str, LIGHTGRAY, CONVERSATION_LINES_X, CONVERSATION_LINES_Y + i * CONVERSATION_LINE_HEIGHT, surface);
}
}
@@ -72,9 +81,9 @@ void ConversationWidget::handleEvent(const Common::Event &event) {
const int16 y = event.mouse.y;
if (_area.contains(x, y)) {
if (_callback) {
- int lineNum = (y - CONVERSATION_LINES_Y) / CONVERSATION_LINE_HEIGHT;
- if (!_lines[lineNum].empty()) {
- _callback->onResponseClicked(this, lineNum);
+ int choiceNo = (y - CONVERSATION_LINES_Y) / CONVERSATION_LINE_HEIGHT;
+ if (!_choices[choiceNo]._str.empty()) {
+ _callback->onChoiceClicked(this, choiceNo, _choices[choiceNo]._data);
}
}
}
diff --git a/engines/mutationofjb/widgets/conversationwidget.h b/engines/mutationofjb/widgets/conversationwidget.h
index b404abc198..51ea86ed02 100644
--- a/engines/mutationofjb/widgets/conversationwidget.h
+++ b/engines/mutationofjb/widgets/conversationwidget.h
@@ -33,17 +33,18 @@ class ConversationWidget;
class ConversationWidgetCallback {
public:
virtual ~ConversationWidgetCallback() {}
- virtual void onResponseClicked(ConversationWidget *, int response) = 0;
+ virtual void onChoiceClicked(ConversationWidget *, int choiceNo, uint32 data) = 0;
};
class ConversationWidget : public Widget {
public:
- enum { CONVERSATION_LINES = 4 };
+ enum { CONVERSATION_MAX_CHOICES = 4 };
ConversationWidget(Gui &gui, const Common::Rect &area, const Graphics::Surface &surface);
void setCallback(ConversationWidgetCallback *callback) { _callback = callback; }
- void setLine(int lineNo, const Common::String &str);
+ void setChoice(int choiceNo, const Common::String &str, uint32 data = 0);
+ void clearChoices();
virtual void handleEvent(const Common::Event &event) override;
@@ -52,7 +53,10 @@ protected:
private:
Graphics::Surface _surface;
- Common::String _lines[CONVERSATION_LINES];
+ struct ChoiceInfo {
+ Common::String _str;
+ uint32 _data;
+ } _choices[CONVERSATION_MAX_CHOICES];
ConversationWidgetCallback *_callback;
};