Initial commit
This commit is contained in:
371
engines/crab/event/gameeventmanager.cpp
Normal file
371
engines/crab/event/gameeventmanager.cpp
Normal file
@@ -0,0 +1,371 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on the CRAB engine
|
||||
*
|
||||
* Copyright (c) Arvind Raja Yadav
|
||||
*
|
||||
* Licensed under MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include "crab/event/gameeventmanager.h"
|
||||
|
||||
namespace Crab {
|
||||
|
||||
using namespace pyrodactyl::people;
|
||||
using namespace pyrodactyl::event;
|
||||
using namespace pyrodactyl::level;
|
||||
using namespace pyrodactyl::image;
|
||||
using namespace pyrodactyl::ui;
|
||||
|
||||
void Manager::init() {
|
||||
_eventMap.clear();
|
||||
_activeSeq = UINT_MAX;
|
||||
_curSp = nullptr;
|
||||
_player = false;
|
||||
_curEvent = nullptr;
|
||||
_drawGame = true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Purpose: Load this
|
||||
//------------------------------------------------------------------------
|
||||
void Manager::load(rapidxml::xml_node<char> *node, ParagraphData &popup) {
|
||||
if (nodeValid(node)) {
|
||||
XMLDoc conf(node->first_attribute("list")->value());
|
||||
if (conf.ready()) {
|
||||
rapidxml::xml_node<char> *lnode = conf.doc()->first_node("event_list");
|
||||
for (rapidxml::xml_node<char> *loc = lnode->first_node("loc"); loc != nullptr; loc = loc->next_sibling("loc")) {
|
||||
Common::String locName;
|
||||
loadStr(locName, "name", loc);
|
||||
|
||||
for (auto n = loc->first_node("file"); n != nullptr; n = n->next_sibling("file")) {
|
||||
uint id;
|
||||
Common::Path path;
|
||||
loadNum(id, "name", n);
|
||||
loadPath(path, "path", n);
|
||||
_eventMap[locName].addSeq(id, path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_activeSeq = UINT_MAX;
|
||||
|
||||
conf.load(node->first_attribute("layout")->value());
|
||||
if (conf.ready()) {
|
||||
rapidxml::xml_node<char> *layout = conf.doc()->first_node("layout");
|
||||
if (nodeValid(layout)) {
|
||||
if (nodeValid("character", layout))
|
||||
_oh.load(layout->first_node("character"));
|
||||
|
||||
if (nodeValid("popup", layout))
|
||||
popup.load(layout->first_node("popup"));
|
||||
|
||||
if (nodeValid("intro", layout))
|
||||
_intro.load(layout->first_node("intro"));
|
||||
}
|
||||
}
|
||||
|
||||
_reply.load(node->first_attribute("conversation")->value());
|
||||
|
||||
_per.load(node->first_attribute("char")->value());
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Purpose: Handle events
|
||||
//------------------------------------------------------------------------
|
||||
void Manager::handleEvents(Info &info, const Common::String &playerId, Common::Event &event, HUD &hud, Level &level, Common::Array<EventResult> &result) {
|
||||
// If an event is already being performed
|
||||
if (_eventMap.contains(info.curLocID()) && _eventMap[info.curLocID()].eventInProgress(_activeSeq)) {
|
||||
switch (_curEvent->_type) {
|
||||
case EVENT_DIALOG:
|
||||
if (_oh._showJournal) {
|
||||
info._journal.handleEvents(playerId, event);
|
||||
|
||||
if (hud._back.handleEvents(event) == BUAC_LCLICK || hud._pausekey.handleEvents(event))
|
||||
_oh._showJournal = false;
|
||||
} else {
|
||||
// If journal button is select from within an event, go to the entry corresponding to that person's name
|
||||
if (_oh.handleCommonEvents(event)) {
|
||||
if (info.personValid(_curEvent->_title)) {
|
||||
Person &p = info.personGet(_curEvent->_title);
|
||||
if (p._altJournalName)
|
||||
info._journal.open(playerId, JE_PEOPLE, p._journalName);
|
||||
else
|
||||
info._journal.open(playerId, JE_PEOPLE, p._name);
|
||||
}
|
||||
}
|
||||
|
||||
if (_oh.handleDlboxEvents(event)) {
|
||||
_oh.onExit();
|
||||
_eventMap[info.curLocID()].nextEvent(_activeSeq, info, playerId, result, _endSeq);
|
||||
_oh._showJournal = false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case EVENT_ANIM:
|
||||
// Skip animation if key pressed or mouse pressed
|
||||
if (event.type == Common::EVENT_LBUTTONUP || event.type == Common::EVENT_RBUTTONUP)
|
||||
_eventMap[info.curLocID()].nextEvent(_activeSeq, info, playerId, result, _endSeq);
|
||||
break;
|
||||
case EVENT_REPLY:
|
||||
if (_oh._showJournal) {
|
||||
info._journal.handleEvents(playerId, event);
|
||||
|
||||
if (hud._back.handleEvents(event) == BUAC_LCLICK || hud._pausekey.handleEvents(event))
|
||||
_oh._showJournal = false;
|
||||
} else {
|
||||
// If journal button is select from within an event, go to the entry corresponding to that person's name
|
||||
if (_oh.handleCommonEvents(event))
|
||||
if (info.personValid(_curEvent->_title))
|
||||
info._journal.open(playerId, JE_PEOPLE, info.personGet(_curEvent->_title)._name);
|
||||
|
||||
unsigned int option = static_cast<unsigned int>(_reply.hoverIndex());
|
||||
const auto &replyChoice = g_engine->_eventStore->_con[_curEvent->_special]._reply;
|
||||
if (option < replyChoice.size()) {
|
||||
_intro.onEntry(replyChoice[option]._text);
|
||||
}
|
||||
|
||||
int choice = _reply.handleEvents(info, g_engine->_eventStore->_con[_curEvent->_special], _curEvent->_title, _oh, event);
|
||||
if (choice >= 0) {
|
||||
_reply.onExit();
|
||||
_eventMap[info.curLocID()].nextEvent(_activeSeq, info, playerId, result, _endSeq, choice);
|
||||
_oh._showJournal = false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case EVENT_TEXT:
|
||||
// If journal button is select from within an event, go to the entry corresponding to that person's name
|
||||
if (_oh.handleCommonEvents(event))
|
||||
if (info.personValid(_curEvent->_title))
|
||||
info._journal.open(playerId, JE_PEOPLE, info.personGet(_curEvent->_title)._name);
|
||||
|
||||
if (_textin.handleEvents(event))
|
||||
_eventMap[info.curLocID()].nextEvent(_activeSeq, info, playerId, result, _endSeq);
|
||||
break;
|
||||
case EVENT_SPLASH:
|
||||
if (_intro._showTraits) {
|
||||
_per.handleEvents(info, _curEvent->_title, event);
|
||||
|
||||
if (hud._back.handleEvents(event) == BUAC_LCLICK || hud._pausekey.handleEvents(event))
|
||||
_intro._showTraits = false;
|
||||
} else {
|
||||
if (_intro.handleEvents(event)) {
|
||||
_intro.onExit();
|
||||
_eventMap[info.curLocID()].nextEvent(_activeSeq, info, playerId, result, _endSeq);
|
||||
}
|
||||
if (_intro._showTraits)
|
||||
_per.Cache(info, level.playerId(), level);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
endSequence(info.curLocID());
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Purpose: Internal Events
|
||||
//------------------------------------------------------------------------
|
||||
void Manager::internalEvents(Info &info, Level &level, Common::Array<EventResult> &result) {
|
||||
if (_eventMap.contains(info.curLocID())) {
|
||||
if (_eventMap[info.curLocID()].eventInProgress(_activeSeq)) {
|
||||
switch (_curEvent->_type) {
|
||||
case EVENT_DIALOG:
|
||||
// fallthrough intended
|
||||
case EVENT_REPLY:
|
||||
// fallthrough intended
|
||||
case EVENT_SPLASH:
|
||||
updateDialogBox(info, level);
|
||||
break;
|
||||
case EVENT_ANIM: {
|
||||
using namespace pyrodactyl::anim;
|
||||
|
||||
DrawType drawVal = DRAW_SAME;
|
||||
if (g_engine->_eventStore->_anim[_curEvent->_special].internalEvents(drawVal))
|
||||
_eventMap[info.curLocID()].nextEvent(_activeSeq, info, level.playerId(), result, _endSeq);
|
||||
|
||||
if (drawVal == DRAW_STOP)
|
||||
_drawGame = false;
|
||||
else if (drawVal == DRAW_START)
|
||||
_drawGame = true;
|
||||
} break;
|
||||
case EVENT_SILENT:
|
||||
_eventMap[info.curLocID()].nextEvent(_activeSeq, info, level.playerId(), result, _endSeq);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
endSequence(info.curLocID());
|
||||
} else {
|
||||
_eventMap[info.curLocID()].internalEvents(info);
|
||||
calcActiveSeq(info, level, level.camera());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Manager::updateDialogBox(Info &info, pyrodactyl::level::Level &level) {
|
||||
_oh.internalEvents(_curEvent->_state, _curSp);
|
||||
}
|
||||
//------------------------------------------------------------------------
|
||||
// Purpose: Draw
|
||||
//------------------------------------------------------------------------
|
||||
void Manager::draw(Info &info, HUD &hud, Level &level) {
|
||||
if (_eventMap.contains(info.curLocID()) && _eventMap[info.curLocID()].eventInProgress(_activeSeq)) {
|
||||
switch (_curEvent->_type) {
|
||||
case EVENT_ANIM:
|
||||
g_engine->_eventStore->_anim[_curEvent->_special].draw();
|
||||
break;
|
||||
case EVENT_DIALOG:
|
||||
g_engine->_imageManager->dimScreen();
|
||||
if (_oh._showJournal) {
|
||||
info._journal.draw(level.playerId());
|
||||
hud._back.draw();
|
||||
} else
|
||||
_oh.draw(info, _curEvent, _curEvent->_title, _player, _curSp);
|
||||
break;
|
||||
case EVENT_REPLY:
|
||||
g_engine->_imageManager->dimScreen();
|
||||
if (_oh._showJournal) {
|
||||
info._journal.draw(level.playerId());
|
||||
hud._back.draw();
|
||||
} else {
|
||||
_oh.draw(info, _curEvent, _curEvent->_title, _player, _curSp);
|
||||
_reply.draw();
|
||||
}
|
||||
break;
|
||||
case EVENT_TEXT:
|
||||
_oh.draw(info, _curEvent, _curEvent->_title, _player, _curSp);
|
||||
_textin.draw();
|
||||
break;
|
||||
case EVENT_SPLASH:
|
||||
g_engine->_imageManager->dimScreen();
|
||||
if (_intro._showTraits) {
|
||||
_per.draw(info, _curEvent->_title);
|
||||
hud._back.draw();
|
||||
} else
|
||||
_intro.draw(info, _curEvent->_dialog, _curSp, _curEvent->_state);
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Purpose: Calculate the current sequence in progress
|
||||
//------------------------------------------------------------------------
|
||||
void Manager::calcActiveSeq(Info &info, pyrodactyl::level::Level &level, const Rect &camera) {
|
||||
if (_eventMap[info.curLocID()].activeSeq(_activeSeq)) {
|
||||
// Set all the pointers to the new values
|
||||
_curEvent = _eventMap[info.curLocID()].curEvent(_activeSeq);
|
||||
_oh.reset(_curEvent->_title);
|
||||
_curSp = level.getSprite(_curEvent->_title);
|
||||
|
||||
// The player character's dialog is drawn a bit differently compared to others
|
||||
_player = (_curEvent->_title == level.playerId());
|
||||
|
||||
switch (_curEvent->_type) {
|
||||
case EVENT_DIALOG:
|
||||
_oh.onEntry(_curEvent->_dialog);
|
||||
break;
|
||||
case EVENT_ANIM:
|
||||
g_engine->_eventStore->_anim[_curEvent->_special].start();
|
||||
break;
|
||||
case EVENT_REPLY:
|
||||
_reply.onEntry(_curEvent->_dialog);
|
||||
_reply.cache(info, g_engine->_eventStore->_con[_curEvent->_special]);
|
||||
break;
|
||||
case EVENT_SPLASH:
|
||||
_intro.onEntry(_curEvent->_dialog);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Purpose: Get/set info
|
||||
//------------------------------------------------------------------------
|
||||
void Manager::endSequence(const Common::String &curloc) {
|
||||
if (_endSeq.empty())
|
||||
return;
|
||||
|
||||
for (const auto &i : _endSeq)
|
||||
if (i._cur)
|
||||
_eventMap[curloc].endSeq(_activeSeq);
|
||||
else if (_eventMap.contains(i._loc))
|
||||
_eventMap[i._loc].endSeq(stringToNumber<uint>(i._val));
|
||||
|
||||
_activeSeq = UINT_MAX;
|
||||
_endSeq.clear();
|
||||
}
|
||||
|
||||
bool Manager::eventInProgress() {
|
||||
if (_activeSeq == UINT_MAX)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Purpose: Save the state of the object
|
||||
//------------------------------------------------------------------------
|
||||
void Manager::saveState(rapidxml::xml_document<> &doc, rapidxml::xml_node<char> *root) {
|
||||
for (auto &i : _eventMap) {
|
||||
rapidxml::xml_node<char> *child = doc.allocate_node(rapidxml::node_element, "loc");
|
||||
child->append_attribute(doc.allocate_attribute("name", i._key.c_str()));
|
||||
i._value.saveState(doc, child);
|
||||
root->append_node(child);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Purpose: Load the state of the object
|
||||
//------------------------------------------------------------------------
|
||||
void Manager::loadState(rapidxml::xml_node<char> *node) {
|
||||
for (auto n = node->first_node("loc"); n != nullptr; n = n->next_sibling("loc")) {
|
||||
if (n->first_attribute("name") != nullptr) {
|
||||
Common::String name = n->first_attribute("name")->value();
|
||||
if (_eventMap.contains(name))
|
||||
_eventMap[name].loadState(n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Purpose: Function called when window size is changed to adjust UI
|
||||
//------------------------------------------------------------------------
|
||||
void Manager::setUI() {
|
||||
_oh.setUI();
|
||||
_reply.setUI();
|
||||
_textin.setUI();
|
||||
_per.setUI();
|
||||
}
|
||||
|
||||
} // End of namespace Crab
|
||||
Reference in New Issue
Block a user