Initial commit
This commit is contained in:
284
engines/mutationofjb/tasks/conversationtask.cpp
Normal file
284
engines/mutationofjb/tasks/conversationtask.cpp
Normal file
@@ -0,0 +1,284 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "mutationofjb/tasks/conversationtask.h"
|
||||
|
||||
#include "mutationofjb/assets.h"
|
||||
#include "mutationofjb/game.h"
|
||||
#include "mutationofjb/gamedata.h"
|
||||
#include "mutationofjb/gamescreen.h"
|
||||
#include "mutationofjb/script.h"
|
||||
#include "mutationofjb/tasks/saytask.h"
|
||||
#include "mutationofjb/tasks/sequentialtask.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();
|
||||
game.getGameScreen().showConversationWidget(true);
|
||||
ConversationWidget &widget = game.getGameScreen().getConversationWidget();
|
||||
widget.setCallback(this);
|
||||
|
||||
_currentGroupIndex = 0;
|
||||
|
||||
showChoicesOrPick();
|
||||
}
|
||||
|
||||
void ConversationTask::update() {
|
||||
if (_sayTask) {
|
||||
if (_sayTask->getState() == Task::FINISHED) {
|
||||
_sayTask.reset();
|
||||
|
||||
switch (_substate) {
|
||||
case SAYING_NO_QUESTIONS:
|
||||
finish();
|
||||
break;
|
||||
case SAYING_QUESTION: {
|
||||
const ConversationLineList &responseList = getTaskManager()->getGame().getAssets().getResponseList();
|
||||
const ConversationLineList::Line *const line = responseList.getLine(_currentItem->_response);
|
||||
|
||||
_substate = SAYING_RESPONSE;
|
||||
createSayTasks(line);
|
||||
getTaskManager()->startTask(_sayTask);
|
||||
break;
|
||||
}
|
||||
case SAYING_RESPONSE: {
|
||||
startExtra();
|
||||
|
||||
if (_substate != RUNNING_EXTRA) {
|
||||
gotoNextGroup();
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_innerExecCtx) {
|
||||
Command::ExecuteResult res = _innerExecCtx->runActiveCommand();
|
||||
if (res == Command::Finished) {
|
||||
delete _innerExecCtx;
|
||||
_innerExecCtx = nullptr;
|
||||
|
||||
gotoNextGroup();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ConversationTask::onChoiceClicked(ConversationWidget *convWidget, int, uint32 data) {
|
||||
const ConversationInfo::Item &item = getCurrentGroup()[data];
|
||||
convWidget->clearChoices();
|
||||
|
||||
const ConversationLineList &toSayList = getTaskManager()->getGame().getAssets().getToSayList();
|
||||
const ConversationLineList::Line *line = toSayList.getLine(item._question);
|
||||
|
||||
_substate = SAYING_QUESTION;
|
||||
createSayTasks(line);
|
||||
getTaskManager()->startTask(_sayTask);
|
||||
_currentItem = &item;
|
||||
|
||||
if (!line->_speeches[0].isRepeating()) {
|
||||
getTaskManager()->getGame().getGameData().getCurrentScene()->addExhaustedConvItem(_convInfo._context, data + 1, _currentGroupIndex + 1);
|
||||
}
|
||||
}
|
||||
|
||||
void ConversationTask::showChoicesOrPick() {
|
||||
Game &game = getTaskManager()->getGame();
|
||||
GameData &gameData = game.getGameData();
|
||||
Scene *const scene = gameData.getScene(_sceneId);
|
||||
if (!scene) {
|
||||
return;
|
||||
}
|
||||
|
||||
Common::Array<uint32> itemsWithValidQuestions;
|
||||
Common::Array<uint32> itemsWithValidResponses;
|
||||
Common::Array<uint32> itemsWithValidNext;
|
||||
|
||||
/*
|
||||
Collect valid questions (not exhausted and not empty).
|
||||
Collect valid responses (not exhausted and not empty).
|
||||
If there are at least two visible questions, we show them.
|
||||
If there is just one visible question, pick it automatically ONLY if this is not the first question in this conversation.
|
||||
Otherwise we don't start the conversation.
|
||||
If there are no visible questions, automatically pick the first valid response.
|
||||
If nothing above applies, don't start the conversation.
|
||||
*/
|
||||
|
||||
const ConversationInfo::ItemGroup ¤tGroup = getCurrentGroup();
|
||||
for (ConversationInfo::ItemGroup::size_type i = 0; i < currentGroup.size(); ++i) {
|
||||
const ConversationInfo::Item &item = currentGroup[i];
|
||||
|
||||
if (scene->isConvItemExhausted(_convInfo._context, static_cast<uint8>(i + 1), static_cast<uint8>(_currentGroupIndex + 1))) {
|
||||
continue;
|
||||
}
|
||||
const uint8 toSay = item._question;
|
||||
const uint8 response = item._response;
|
||||
const uint8 next = item._nextGroupIndex;
|
||||
|
||||
if (toSay != 0) {
|
||||
itemsWithValidQuestions.push_back(i);
|
||||
}
|
||||
|
||||
if (response != 0) {
|
||||
itemsWithValidResponses.push_back(i);
|
||||
}
|
||||
|
||||
if (next != 0) {
|
||||
itemsWithValidNext.push_back(i);
|
||||
}
|
||||
}
|
||||
|
||||
if (itemsWithValidQuestions.size() > 1) {
|
||||
ConversationWidget &widget = game.getGameScreen().getConversationWidget();
|
||||
const ConversationLineList &toSayList = game.getAssets().getToSayList();
|
||||
|
||||
for (Common::Array<uint32>::size_type i = 0; i < itemsWithValidQuestions.size() && i < ConversationWidget::CONVERSATION_MAX_CHOICES; ++i) {
|
||||
const ConversationInfo::Item &item = currentGroup[itemsWithValidQuestions[i]];
|
||||
const ConversationLineList::Line *const line = toSayList.getLine(item._question);
|
||||
const Common::String widgetText = toUpperCP895(line->_speeches[0]._text);
|
||||
widget.setChoice(static_cast<int>(i), widgetText, itemsWithValidQuestions[i]);
|
||||
}
|
||||
_substate = IDLE;
|
||||
_currentItem = nullptr;
|
||||
|
||||
_haveChoices = true;
|
||||
} else if (itemsWithValidQuestions.size() == 1 && _haveChoices) {
|
||||
const ConversationLineList &toSayList = game.getAssets().getToSayList();
|
||||
const ConversationInfo::Item &item = currentGroup[itemsWithValidQuestions.front()];
|
||||
const ConversationLineList::Line *const line = toSayList.getLine(item._question);
|
||||
|
||||
_substate = SAYING_QUESTION;
|
||||
createSayTasks(line);
|
||||
getTaskManager()->startTask(_sayTask);
|
||||
_currentItem = &item;
|
||||
|
||||
if (!line->_speeches[0].isRepeating()) {
|
||||
game.getGameData().getCurrentScene()->addExhaustedConvItem(_convInfo._context, itemsWithValidQuestions.front() + 1, _currentGroupIndex + 1);
|
||||
}
|
||||
|
||||
_haveChoices = true;
|
||||
} else if (!itemsWithValidResponses.empty() && _haveChoices) {
|
||||
const ConversationLineList &responseList = game.getAssets().getResponseList();
|
||||
const ConversationInfo::Item &item = currentGroup[itemsWithValidResponses.front()];
|
||||
const ConversationLineList::Line *const line = responseList.getLine(item._response);
|
||||
|
||||
_substate = SAYING_RESPONSE;
|
||||
createSayTasks(line);
|
||||
getTaskManager()->startTask(_sayTask);
|
||||
_currentItem = &item;
|
||||
|
||||
_haveChoices = true;
|
||||
} else if (!itemsWithValidNext.empty() && _haveChoices) {
|
||||
_currentGroupIndex = currentGroup[itemsWithValidNext.front()]._nextGroupIndex - 1;
|
||||
showChoicesOrPick();
|
||||
} else {
|
||||
if (_haveChoices) {
|
||||
finish();
|
||||
} else {
|
||||
_sayTask = TaskPtr(new SayTask("Nothing to talk about.", _convInfo._color)); // TODO: This is hardcoded in executable. Load it.
|
||||
getTaskManager()->startTask(_sayTask);
|
||||
_substate = SAYING_NO_QUESTIONS;
|
||||
_currentItem = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const ConversationInfo::ItemGroup &ConversationTask::getCurrentGroup() const {
|
||||
assert(_currentGroupIndex < _convInfo._itemGroups.size());
|
||||
return _convInfo._itemGroups[_currentGroupIndex];
|
||||
}
|
||||
|
||||
void ConversationTask::finish() {
|
||||
setState(FINISHED);
|
||||
|
||||
Game &game = getTaskManager()->getGame();
|
||||
game.getGameScreen().showConversationWidget(false);
|
||||
ConversationWidget &widget = game.getGameScreen().getConversationWidget();
|
||||
widget.setCallback(nullptr);
|
||||
}
|
||||
|
||||
void ConversationTask::startExtra() {
|
||||
const ConversationLineList &responseList = getTaskManager()->getGame().getAssets().getResponseList();
|
||||
const ConversationLineList::Line *const line = responseList.getLine(_currentItem->_response);
|
||||
if (!line->_extra.empty()) {
|
||||
_innerExecCtx = new ScriptExecutionContext(getTaskManager()->getGame());
|
||||
Command *const extraCmd = _innerExecCtx->getExtra(line->_extra);
|
||||
if (extraCmd) {
|
||||
Command::ExecuteResult res = _innerExecCtx->startCommand(extraCmd);
|
||||
if (res == Command::InProgress) {
|
||||
_substate = RUNNING_EXTRA;
|
||||
} else {
|
||||
delete _innerExecCtx;
|
||||
_innerExecCtx = nullptr;
|
||||
}
|
||||
} else {
|
||||
warning("Extra '%s' not found", line->_extra.c_str());
|
||||
delete _innerExecCtx;
|
||||
_innerExecCtx = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ConversationTask::gotoNextGroup() {
|
||||
if (_currentItem->_nextGroupIndex == 0) {
|
||||
finish();
|
||||
} else {
|
||||
_currentGroupIndex = _currentItem->_nextGroupIndex - 1;
|
||||
showChoicesOrPick();
|
||||
}
|
||||
}
|
||||
|
||||
void ConversationTask::createSayTasks(const ConversationLineList::Line *line) {
|
||||
if (line->_speeches.size() == 1) {
|
||||
const ConversationLineList::Speech &speech = line->_speeches[0];
|
||||
_sayTask = TaskPtr(new SayTask(speech._text, getSpeechColor(speech)));
|
||||
} else {
|
||||
TaskPtrs tasks;
|
||||
for (ConversationLineList::Speeches::const_iterator it = line->_speeches.begin(); it != line->_speeches.end(); ++it) {
|
||||
tasks.push_back(TaskPtr(new SayTask(it->_text, getSpeechColor(*it))));
|
||||
}
|
||||
_sayTask = TaskPtr(new SequentialTask(tasks));
|
||||
}
|
||||
}
|
||||
|
||||
uint8 ConversationTask::getSpeechColor(const ConversationLineList::Speech &speech) {
|
||||
uint8 color = WHITE;
|
||||
if (_substate == SAYING_RESPONSE) {
|
||||
color = _convInfo._color;
|
||||
if (_mode == TalkCommand::RAY_AND_BUTTLEG_MODE) {
|
||||
if (speech.isFirstSpeaker()) {
|
||||
color = GREEN;
|
||||
} else if (speech.isSecondSpeaker()) {
|
||||
color = LIGHTBLUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
return color;
|
||||
}
|
||||
|
||||
}
|
||||
71
engines/mutationofjb/tasks/conversationtask.h
Normal file
71
engines/mutationofjb/tasks/conversationtask.h
Normal file
@@ -0,0 +1,71 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "mutationofjb/commands/talkcommand.h"
|
||||
#include "mutationofjb/conversationlinelist.h"
|
||||
#include "mutationofjb/gamedata.h"
|
||||
#include "mutationofjb/tasks/task.h"
|
||||
#include "mutationofjb/widgets/conversationwidget.h"
|
||||
|
||||
namespace MutationOfJB {
|
||||
|
||||
class SayTask;
|
||||
class ScriptExecutionContext;
|
||||
|
||||
class ConversationTask : public Task, public ConversationWidgetCallback {
|
||||
public:
|
||||
ConversationTask(uint8 sceneId, const ConversationInfo &convInfo, TalkCommand::Mode mode) : _sceneId(sceneId), _convInfo(convInfo), _mode(mode), _currentGroupIndex(0), _currentItem(nullptr), _substate(IDLE), _haveChoices(false), _innerExecCtx(nullptr) {}
|
||||
~ConversationTask() override {}
|
||||
|
||||
void start() override;
|
||||
void update() override;
|
||||
|
||||
void onChoiceClicked(ConversationWidget *, int response, uint32 data) override;
|
||||
private:
|
||||
void showChoicesOrPick();
|
||||
const ConversationInfo::ItemGroup &getCurrentGroup() const;
|
||||
void finish();
|
||||
void startExtra();
|
||||
void gotoNextGroup();
|
||||
void createSayTasks(const ConversationLineList::Line *line);
|
||||
uint8 getSpeechColor(const ConversationLineList::Speech &speech);
|
||||
|
||||
uint8 _sceneId;
|
||||
const ConversationInfo &_convInfo;
|
||||
TalkCommand::Mode _mode;
|
||||
uint _currentGroupIndex;
|
||||
const ConversationInfo::Item *_currentItem;
|
||||
TaskPtr _sayTask;
|
||||
|
||||
enum Substate {
|
||||
IDLE,
|
||||
SAYING_QUESTION,
|
||||
SAYING_RESPONSE,
|
||||
SAYING_NO_QUESTIONS,
|
||||
RUNNING_EXTRA
|
||||
};
|
||||
|
||||
Substate _substate;
|
||||
bool _haveChoices;
|
||||
ScriptExecutionContext *_innerExecCtx;
|
||||
};
|
||||
|
||||
}
|
||||
153
engines/mutationofjb/tasks/objectanimationtask.cpp
Normal file
153
engines/mutationofjb/tasks/objectanimationtask.cpp
Normal file
@@ -0,0 +1,153 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "mutationofjb/tasks/objectanimationtask.h"
|
||||
|
||||
#include "mutationofjb/tasks/taskmanager.h"
|
||||
#include "mutationofjb/game.h"
|
||||
#include "mutationofjb/gamedata.h"
|
||||
#include "mutationofjb/room.h"
|
||||
|
||||
namespace MutationOfJB {
|
||||
|
||||
static const int TICK_MILLIS = 100;
|
||||
|
||||
// TODO: Respect currentScene._delay.
|
||||
ObjectAnimationTask::ObjectAnimationTask() : _timer(TICK_MILLIS) {
|
||||
}
|
||||
|
||||
void ObjectAnimationTask::start() {
|
||||
setState(RUNNING);
|
||||
_timer.start();
|
||||
}
|
||||
|
||||
void ObjectAnimationTask::update() {
|
||||
_timer.update();
|
||||
if (_timer.isFinished()) {
|
||||
_timer.start();
|
||||
updateObjects();
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectAnimationTask::updateObjects() {
|
||||
Scene *const scene = getTaskManager()->getGame().getGameData().getCurrentScene();
|
||||
if (!scene) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint8 i = 1; i <= scene->getNoObjects(); ++i) {
|
||||
Object *const object = scene->getObject(i);
|
||||
// Skip if object animation not active.
|
||||
if (!object->_active)
|
||||
continue;
|
||||
|
||||
// Number of frames must be higher than 1.
|
||||
if (object->_numFrames <= 1)
|
||||
continue;
|
||||
|
||||
const uint8 currentAnimOffset = object->_currentFrame - object->_firstFrame;
|
||||
|
||||
const bool randomized = object->_randomFrame != 0;
|
||||
const bool belowRandomFrame = currentAnimOffset < (object->_randomFrame - 1);
|
||||
|
||||
uint8 maxAnimOffset = object->_numFrames - 1;
|
||||
if (randomized && belowRandomFrame) {
|
||||
maxAnimOffset = object->_randomFrame - 2;
|
||||
}
|
||||
|
||||
uint8 nextAnimationOffset = currentAnimOffset + 1;
|
||||
if (currentAnimOffset == maxAnimOffset) {
|
||||
if (randomized && object->_jumpChance != 0 && getTaskManager()->getGame().getRandomSource().getRandomNumber(object->_jumpChance) == 0)
|
||||
nextAnimationOffset = object->_randomFrame - 1;
|
||||
else
|
||||
nextAnimationOffset = 0;
|
||||
}
|
||||
|
||||
object->_currentFrame = nextAnimationOffset + object->_firstFrame;
|
||||
|
||||
const bool drawObject = handleHardcodedAnimation(object);
|
||||
if (drawObject) {
|
||||
getTaskManager()->getGame().getRoom().drawObject(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ObjectAnimationTask::handleHardcodedAnimation(Object *const object) {
|
||||
GameData &gameData = getTaskManager()->getGame().getGameData();
|
||||
Scene *const scene = gameData.getCurrentScene();
|
||||
|
||||
const bool carnivalScene = gameData._currentScene == 30 && !gameData._partB;
|
||||
const bool tavernScene = gameData._currentScene == 8 && gameData._partB;
|
||||
|
||||
if (carnivalScene) {
|
||||
// This alternates between the two burglars' talking animations.
|
||||
// Each burglar gets to talk for a varying amount of time since
|
||||
// the switch occurs when his random frame is reached.
|
||||
if (object->_WX == 1 && object->_currentFrame == 79) {
|
||||
object->_currentFrame = 68;
|
||||
object->_active = 0;
|
||||
scene->getObject(6)->_active = 1;
|
||||
scene->getObject(7)->_active = 0;
|
||||
scene->getObject(8)->_active = 1;
|
||||
return false;
|
||||
} else if (object->_WX == 2 && object->_currentFrame == 91) {
|
||||
object->_currentFrame = 80;
|
||||
object->_active = 0;
|
||||
scene->getObject(5)->_active = 1;
|
||||
scene->getObject(7)->_active = 1;
|
||||
scene->getObject(8)->_active = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
// The following makes sure you can't interact with the glass
|
||||
// while the scientist is drinking from it.
|
||||
if (scene->getObject(4)->_currentFrame > 52 && scene->getObject(4)->_active) {
|
||||
scene->getStatic(9)->_active = 0; // disable scientist's glass
|
||||
} else {
|
||||
scene->getStatic(9)->_active = 1; // enable scientist's glass
|
||||
}
|
||||
|
||||
if (!scene->getObject(4)->_active) {
|
||||
scene->getStatic(9)->_active = 0; // disable scientist's glass
|
||||
}
|
||||
} else if (tavernScene) {
|
||||
// Similarly to the carnival burglars, this alternates between
|
||||
// the talking animations of the two soldiers in the tavern.
|
||||
//
|
||||
// At some point the script disables their conversation
|
||||
// by nulling their _WX registers.
|
||||
if (object->_WX == 3 && object->_currentFrame == 46) {
|
||||
object->_currentFrame = 30;
|
||||
object->_active = 0;
|
||||
scene->getObject(3)->_active = 1;
|
||||
return false;
|
||||
} else if (object->_WX == 4 && object->_currentFrame == 63) {
|
||||
object->_currentFrame = 47;
|
||||
object->_active = 0;
|
||||
scene->getObject(2)->_active = 1;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
69
engines/mutationofjb/tasks/objectanimationtask.h
Normal file
69
engines/mutationofjb/tasks/objectanimationtask.h
Normal file
@@ -0,0 +1,69 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MUTATIONOFJB_OBJECTANIMATIONTASK_H
|
||||
#define MUTATIONOFJB_OBJECTANIMATIONTASK_H
|
||||
|
||||
#include "mutationofjb/tasks/task.h"
|
||||
|
||||
#include "mutationofjb/timer.h"
|
||||
|
||||
namespace MutationOfJB {
|
||||
|
||||
struct Object;
|
||||
|
||||
class ObjectAnimationTask : public Task {
|
||||
public:
|
||||
ObjectAnimationTask();
|
||||
|
||||
void start() override;
|
||||
void update() override;
|
||||
|
||||
/**
|
||||
* Advances every object animation in the current scene to the next frame.
|
||||
*
|
||||
* Normally the animation restarts after the last object frame. However, some animations have random
|
||||
* elements to them. If _randomFrame is set, the animation restarts when _randomFrame is reached.
|
||||
* Additionally, there is a chance with each frame until _randomFrame that the animation may jump
|
||||
* straight to _randomFrame and continue until the last frame, then wrap around to the first frame.
|
||||
*
|
||||
* Randomness is used to introduce variety - e.g. in the starting scene a perched bird occasionally
|
||||
* spreads its wings.
|
||||
*/
|
||||
void updateObjects();
|
||||
|
||||
/**
|
||||
* Nasty, hacky stuff the original game does to make some complex animations
|
||||
* in the Carnival and Tavern Earthquake scenes possible.
|
||||
*
|
||||
* @param object Object to process.
|
||||
* @return Whether to draw the object. It's important to respect this, otherwise
|
||||
* some of the hardcoded animations would suffer from graphical glitches.
|
||||
*/
|
||||
bool handleHardcodedAnimation(Object *const object);
|
||||
|
||||
private:
|
||||
Timer _timer;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
103
engines/mutationofjb/tasks/saytask.cpp
Normal file
103
engines/mutationofjb/tasks/saytask.cpp
Normal file
@@ -0,0 +1,103 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#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 "mutationofjb/util.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(50 * toSay.size()) {}
|
||||
|
||||
void SayTask::start() {
|
||||
Game &game = getTaskManager()->getGame();
|
||||
if (game.getActiveSayTask()) {
|
||||
getTaskManager()->stopTask(game.getActiveSayTask());
|
||||
}
|
||||
game.setActiveSayTask(getTaskManager()->getTask(this));
|
||||
|
||||
setState(RUNNING);
|
||||
drawSubtitle(_toSay, 160, 0, _color); // TODO: Respect PTALK and LTALK commands.
|
||||
_timer.start();
|
||||
}
|
||||
|
||||
void SayTask::update() {
|
||||
_timer.update();
|
||||
|
||||
if (_timer.isFinished()) {
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
void SayTask::stop() {
|
||||
if (getState() == RUNNING) {
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
void SayTask::drawSubtitle(const Common::String &text, int16 talkX, int16 talkY, uint8 color) {
|
||||
const int MAX_LINE_WIDTH = 250;
|
||||
|
||||
const Font &font = getTaskManager()->getGame().getAssets().getSpeechFont();
|
||||
|
||||
Common::Array<Common::String> lines;
|
||||
const int16 actualMaxWidth = font.wordWrapText(text, MAX_LINE_WIDTH, lines);
|
||||
|
||||
// Get the x, y coordinates of the top center point of the text's bounding box
|
||||
// from the (rather strange) talk coordinates coming from scripts.
|
||||
int16 x = talkX;
|
||||
int16 y = talkY - (lines.size() - 1) * font.getFontHeight() - 15;
|
||||
|
||||
// Clamp to screen edges.
|
||||
x = CLIP<int16>(x, 3 + actualMaxWidth / 2, 317 - actualMaxWidth / 2);
|
||||
y = MAX<int16>(y, 3);
|
||||
|
||||
// Remember the area occupied by the text.
|
||||
_boundingBox.left = x - actualMaxWidth / 2;
|
||||
_boundingBox.top = y;
|
||||
_boundingBox.setWidth(actualMaxWidth);
|
||||
_boundingBox.setHeight(lines.size() * font.getFontHeight());
|
||||
|
||||
// Draw lines.
|
||||
for (uint i = 0; i < lines.size(); i++) {
|
||||
font.drawString(&getTaskManager()->getGame().getScreen(), lines[i], _boundingBox.left, _boundingBox.top + i * font.getFontHeight(), _boundingBox.width(), color, Graphics::kTextAlignCenter);
|
||||
}
|
||||
}
|
||||
|
||||
void SayTask::finish() {
|
||||
getTaskManager()->getGame().getRoom().redraw(); // TODO: Only redraw the area occupied by the text.
|
||||
setState(FINISHED);
|
||||
|
||||
Game &game = getTaskManager()->getGame();
|
||||
if (game.getActiveSayTask().get() == this) {
|
||||
game.setActiveSayTask(Common::SharedPtr<SayTask>());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
54
engines/mutationofjb/tasks/saytask.h
Normal file
54
engines/mutationofjb/tasks/saytask.h
Normal file
@@ -0,0 +1,54 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MUTATIONOFJB_SAYTASK_H
|
||||
#define MUTATIONOFJB_SAYTASK_H
|
||||
|
||||
#include "mutationofjb/tasks/task.h"
|
||||
|
||||
#include "mutationofjb/timer.h"
|
||||
|
||||
#include "common/rect.h"
|
||||
#include "common/str.h"
|
||||
|
||||
namespace MutationOfJB {
|
||||
|
||||
class SayTask : public Task {
|
||||
public:
|
||||
SayTask(const Common::String &toSay, uint8 color);
|
||||
|
||||
void start() override;
|
||||
void update() override;
|
||||
void stop() override;
|
||||
|
||||
private:
|
||||
void drawSubtitle(const Common::String &text, int16 talkX, int16 talkY, uint8 color);
|
||||
void finish();
|
||||
|
||||
Common::String _toSay;
|
||||
uint8 _color;
|
||||
Timer _timer;
|
||||
Common::Rect _boundingBox;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
62
engines/mutationofjb/tasks/sequentialtask.cpp
Normal file
62
engines/mutationofjb/tasks/sequentialtask.cpp
Normal file
@@ -0,0 +1,62 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "mutationofjb/tasks/sequentialtask.h"
|
||||
|
||||
#include "mutationofjb/tasks/taskmanager.h"
|
||||
|
||||
namespace MutationOfJB {
|
||||
|
||||
SequentialTask::SequentialTask(const TaskPtrs &tasks) : _tasks(tasks) {
|
||||
}
|
||||
|
||||
void SequentialTask::start() {
|
||||
setState(RUNNING);
|
||||
runTasks();
|
||||
}
|
||||
|
||||
void SequentialTask::update() {
|
||||
runTasks();
|
||||
}
|
||||
|
||||
void SequentialTask::runTasks() {
|
||||
while (true) {
|
||||
if (_tasks.empty()) {
|
||||
setState(FINISHED);
|
||||
return;
|
||||
}
|
||||
|
||||
const TaskPtr &task = _tasks.front();
|
||||
switch (task->getState()) {
|
||||
case IDLE:
|
||||
getTaskManager()->startTask(task);
|
||||
break;
|
||||
case RUNNING:
|
||||
default:
|
||||
return;
|
||||
case FINISHED:
|
||||
_tasks.remove_at(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
47
engines/mutationofjb/tasks/sequentialtask.h
Normal file
47
engines/mutationofjb/tasks/sequentialtask.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MUTATIONOFJB_SEQUENTIALTASK_H
|
||||
#define MUTATIONOFJB_SEQUENTIALTASK_H
|
||||
|
||||
#include "mutationofjb/tasks/task.h"
|
||||
|
||||
namespace MutationOfJB {
|
||||
|
||||
/**
|
||||
* Queues multiple tasks.
|
||||
*/
|
||||
class SequentialTask : public Task {
|
||||
public:
|
||||
SequentialTask(const TaskPtrs &tasks);
|
||||
|
||||
void start() override;
|
||||
void update() override;
|
||||
|
||||
private:
|
||||
void runTasks();
|
||||
|
||||
TaskPtrs _tasks;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
80
engines/mutationofjb/tasks/task.h
Normal file
80
engines/mutationofjb/tasks/task.h
Normal file
@@ -0,0 +1,80 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MUTATIONOFJB_TASK_H
|
||||
#define MUTATIONOFJB_TASK_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "common/ptr.h"
|
||||
#include "common/array.h"
|
||||
|
||||
namespace MutationOfJB {
|
||||
|
||||
class TaskManager;
|
||||
|
||||
/**
|
||||
* Base class for tasks.
|
||||
*/
|
||||
class Task {
|
||||
public:
|
||||
enum State {
|
||||
IDLE,
|
||||
RUNNING,
|
||||
FINISHED
|
||||
};
|
||||
|
||||
Task() : _taskManager(nullptr), _state(IDLE) {}
|
||||
virtual ~Task() {}
|
||||
|
||||
virtual void start() = 0;
|
||||
virtual void update() = 0;
|
||||
virtual void stop() {
|
||||
assert(false); // Assert by default - stopping might not be safe for all tasks.
|
||||
}
|
||||
|
||||
void setTaskManager(TaskManager *taskMan) {
|
||||
_taskManager = taskMan;
|
||||
}
|
||||
|
||||
TaskManager *getTaskManager() {
|
||||
return _taskManager;
|
||||
}
|
||||
|
||||
State getState() const {
|
||||
return _state;
|
||||
}
|
||||
|
||||
protected:
|
||||
void setState(State state) {
|
||||
_state = state;
|
||||
}
|
||||
|
||||
private:
|
||||
TaskManager *_taskManager;
|
||||
State _state;
|
||||
};
|
||||
|
||||
typedef Common::SharedPtr<Task> TaskPtr;
|
||||
typedef Common::Array<Common::SharedPtr<Task> > TaskPtrs;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
71
engines/mutationofjb/tasks/taskmanager.cpp
Normal file
71
engines/mutationofjb/tasks/taskmanager.cpp
Normal file
@@ -0,0 +1,71 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "mutationofjb/tasks/taskmanager.h"
|
||||
|
||||
#include "mutationofjb/tasks/task.h"
|
||||
|
||||
namespace MutationOfJB {
|
||||
|
||||
void TaskManager::startTask(const TaskPtr &task) {
|
||||
_tasks.push_back(task);
|
||||
task->setTaskManager(this);
|
||||
task->start();
|
||||
}
|
||||
|
||||
void TaskManager::stopTask(const TaskPtr &task) {
|
||||
TaskPtrs::iterator it = Common::find(_tasks.begin(), _tasks.end(), task);
|
||||
if (it == _tasks.end()) {
|
||||
warning("Task is not registered in TaskManager");
|
||||
return;
|
||||
}
|
||||
|
||||
task->stop();
|
||||
assert(task->getState() != Task::RUNNING);
|
||||
_tasks.erase(it);
|
||||
}
|
||||
|
||||
TaskPtr TaskManager::getTask(Task *const task) {
|
||||
for (TaskPtrs::iterator it = _tasks.begin(); it != _tasks.end(); ++it) {
|
||||
if (it->get() == task) {
|
||||
return *it;
|
||||
}
|
||||
}
|
||||
|
||||
return TaskPtr();
|
||||
}
|
||||
|
||||
void TaskManager::update() {
|
||||
for (TaskPtrs::iterator it = _tasks.begin(); it != _tasks.end();) {
|
||||
const Task::State state = (*it)->getState();
|
||||
if (state == Task::RUNNING) {
|
||||
(*it)->update();
|
||||
}
|
||||
|
||||
if (state == Task::FINISHED) {
|
||||
it = _tasks.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
78
engines/mutationofjb/tasks/taskmanager.h
Normal file
78
engines/mutationofjb/tasks/taskmanager.h
Normal file
@@ -0,0 +1,78 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MUTATIONOFJB_TASKMANAGER_H
|
||||
#define MUTATIONOFJB_TASKMANAGER_H
|
||||
|
||||
#include "common/array.h"
|
||||
#include "mutationofjb/tasks/task.h"
|
||||
|
||||
namespace MutationOfJB {
|
||||
|
||||
class Game;
|
||||
|
||||
/**
|
||||
* Handles task management.
|
||||
*
|
||||
* Tasks are a way run game logic asynchronously.
|
||||
*/
|
||||
class TaskManager {
|
||||
public:
|
||||
TaskManager(Game &game) : _game(game) {}
|
||||
|
||||
/**
|
||||
* Adds the task to the internal list and starts it.
|
||||
*
|
||||
* When the task is finished, it is automatically removed from the list.
|
||||
* stopTask does not need to be called for that.
|
||||
*/
|
||||
void startTask(const TaskPtr &task);
|
||||
|
||||
/**
|
||||
* Stops the task and removes it from the internal list.
|
||||
*
|
||||
* Call this only if you need to explicitly stop the task (usually before it's finished).
|
||||
*/
|
||||
void stopTask(const TaskPtr &task);
|
||||
|
||||
/**
|
||||
* Gets task shared pointer from raw pointer.
|
||||
*
|
||||
* Since task lifetime is under control of SharedPtr, raw pointers shouldn't be used.
|
||||
* However, if only a raw pointer is available (e.g. this),
|
||||
* the method can be used to obtain a SharedPtr.
|
||||
*/
|
||||
TaskPtr getTask(Task *task);
|
||||
|
||||
void update();
|
||||
|
||||
Game &getGame() {
|
||||
return _game;
|
||||
}
|
||||
|
||||
private:
|
||||
TaskPtrs _tasks;
|
||||
Game &_game;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user