diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 9bc27b16d..b20693417 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -70,9 +70,17 @@ source_group(apps\\openmw\\mwgui FILES ${GAMEGUI_HEADER} ${GAMEGUI}) set(GAMEDIALOGUE_HEADER mwdialogue/dialoguemanager.hpp + mwdialogue/journal.hpp + mwdialogue/journalentry.hpp + mwdialogue/quest.hpp + mwdialogue/topic.hpp ) set(GAMEDIALOGUE mwdialogue/dialoguemanager.cpp + mwdialogue/journal.cpp + mwdialogue/journalentry.cpp + mwdialogue/quest.cpp + mwdialogue/topic.cpp ) source_group(apps\\openmw\\mwdialogue FILES ${GAMEDIALOGUE_HEADER} ${GAMEDIALOGUE}) @@ -91,6 +99,7 @@ set(GAMESCRIPT mwscript/controlextensions.cpp mwscript/extensions.cpp mwscript/globalscripts.cpp + mwscript/dialogueextensions.cpp ) set(GAMESCRIPT_HEADER mwscript/locals.hpp @@ -109,6 +118,7 @@ set(GAMESCRIPT_HEADER mwscript/extensions.hpp mwscript/globalscripts.hpp mwscript/ref.hpp + mwscript/dialogueextensions.hpp ) source_group(apps\\openmw\\mwscript FILES ${GAMESCRIPT} ${GAMESCRIPT_HEADER}) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 047bc3751..1ca5c68b4 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -38,6 +38,7 @@ #include "mwclass/classes.hpp" #include "mwdialogue/dialoguemanager.hpp" +#include "mwdialogue/journal.hpp" #include "mwmechanics/mechanicsmanager.hpp" @@ -229,6 +230,7 @@ OMW::Engine::~Engine() delete mEnvironment.mGlobalScripts; delete mEnvironment.mMechanicsManager; delete mEnvironment.mDialogueManager; + delete mEnvironment.mJournal; delete mScriptManager; delete mScriptContext; delete mPhysicEngine; @@ -395,6 +397,7 @@ void OMW::Engine::go() mEnvironment.mMechanicsManager = new MWMechanics::MechanicsManager (mEnvironment); // Create dialog system + mEnvironment.mJournal = new MWDialogue::Journal (mEnvironment); mEnvironment.mDialogueManager = new MWDialogue::DialogueManager (mEnvironment); // load cell diff --git a/apps/openmw/mwdialogue/journal.cpp b/apps/openmw/mwdialogue/journal.cpp new file mode 100644 index 000000000..42cce5cf5 --- /dev/null +++ b/apps/openmw/mwdialogue/journal.cpp @@ -0,0 +1,95 @@ + +#include "journal.hpp" + +#include "../mwworld/environment.hpp" + +namespace MWDialogue +{ + Quest& Journal::getQuest (const std::string& id) + { + TQuestContainer::iterator iter = mQuests.find (id); + + if (iter==mQuests.end()) + { + std::pair result = + mQuests.insert (std::make_pair (id, Quest (id))); + + iter = result.first; + } + + return iter->second; + } + + Journal::Journal (MWWorld::Environment& environment) + : mEnvironment (environment) + {} + + void Journal::addEntry (const std::string& id, int index) + { + StampedJournalEntry entry = + StampedJournalEntry::makeFromQuest (id, index, *mEnvironment.mWorld); + + mJournal.push_back (entry); + + Quest& quest = getQuest (id); + + quest.addEntry (entry, *mEnvironment.mWorld); // we are doing slicing on purpose here + } + + void Journal::setJournalIndex (const std::string& id, int index) + { + Quest& quest = getQuest (id); + + quest.setIndex (index, *mEnvironment.mWorld); + } + + void Journal::addTopic (const std::string& topicId, const std::string& infoId) + { + TTopicContainer::iterator iter = mTopics.find (topicId); + + if (iter==mTopics.end()) + { + std::pair result + = mTopics.insert (std::make_pair (topicId, Topic (topicId))); + + iter = result.first; + } + + iter->second.addEntry (JournalEntry (topicId, infoId), *mEnvironment.mWorld); + } + + int Journal::getJournalIndex (const std::string& id) const + { + return 0; + } + + Journal::TEntryIter Journal::begin() const + { + return mJournal.begin(); + } + + Journal::TEntryIter Journal::end() const + { + return mJournal.end(); + } + + Journal::TQuestIter Journal::questBegin() const + { + return mQuests.begin(); + } + + Journal::TQuestIter Journal::questEnd() const + { + return mQuests.end(); + } + + Journal::TTopicIter Journal::topicBegin() const + { + return mTopics.begin(); + } + + Journal::TTopicIter Journal::topicEnd() const + { + return mTopics.end(); + } +} diff --git a/apps/openmw/mwdialogue/journal.hpp b/apps/openmw/mwdialogue/journal.hpp new file mode 100644 index 000000000..ff1343945 --- /dev/null +++ b/apps/openmw/mwdialogue/journal.hpp @@ -0,0 +1,78 @@ +#ifndef GAME_MMDIALOG_JOURNAL_H +#define GAME_MWDIALOG_JOURNAL_H + +#include +#include +#include + +#include "journalentry.hpp" +#include "quest.hpp" + +namespace MWWorld +{ + struct Environment; +} + +namespace MWDialogue +{ + /// \brief The player's journal + class Journal + { + public: + + typedef std::deque TEntryContainer; + typedef TEntryContainer::const_iterator TEntryIter; + typedef std::map TQuestContainer; // topc, quest + typedef TQuestContainer::const_iterator TQuestIter; + typedef std::map TTopicContainer; // topic-id, topic-content + typedef TTopicContainer::const_iterator TTopicIter; + + private: + + MWWorld::Environment& mEnvironment; + TEntryContainer mJournal; + TQuestContainer mQuests; + TTopicContainer mTopics; + + Quest& getQuest (const std::string& id); + + public: + + Journal (MWWorld::Environment& environment); + + void addEntry (const std::string& id, int index); + ///< Add a journal entry. + + void setJournalIndex (const std::string& id, int index); + ///< Set the journal index without adding an entry. + + int getJournalIndex (const std::string& id) const; + ///< Get the journal index. + + void addTopic (const std::string& topicId, const std::string& infoId); + + TEntryIter begin() const; + ///< Iterator pointing to the begin of the main journal. + /// + /// \note Iterators to main journal entries will never become invalid. + + TEntryIter end() const; + ///< Iterator pointing past the end of the main journal. + + TQuestIter questBegin() const; + ///< Iterator pointing to the first quest (sorted by topic ID) + + TQuestIter questEnd() const; + ///< Iterator pointing past the last quest. + + TTopicIter topicBegin() const; + ///< Iterator pointing to the first topic (sorted by topic ID) + /// + /// \note The topic ID is identical with the user-visible topic string. + + TTopicIter topicEnd() const; + ///< Iterator pointing past the last topic. + }; +} + +#endif diff --git a/apps/openmw/mwdialogue/journalentry.cpp b/apps/openmw/mwdialogue/journalentry.cpp new file mode 100644 index 000000000..5e9dfa674 --- /dev/null +++ b/apps/openmw/mwdialogue/journalentry.cpp @@ -0,0 +1,69 @@ + +#include "journalentry.hpp" + +#include + +#include + +#include "../mwworld/world.hpp" + +namespace MWDialogue +{ + JournalEntry::JournalEntry() {} + + JournalEntry::JournalEntry (const std::string& topic, const std::string& infoId) + : mTopic (topic), mInfoId (infoId) + {} + + std::string JournalEntry::getText (const ESMS::ESMStore& store) const + { + const ESM::Dialogue *dialogue = store.dialogs.find (mTopic); + + for (std::vector::const_iterator iter (dialogue->mInfo.begin()); + iter!=dialogue->mInfo.end(); ++iter) + if (iter->id==mInfoId) + return iter->response; + + throw std::runtime_error ("unknown info ID " + mInfoId + " for topic " + mTopic); + } + + JournalEntry JournalEntry::makeFromQuest (const std::string& topic, int index, + const MWWorld::World& world) + { + return JournalEntry (topic, idFromIndex (topic, index, world)); + } + + std::string JournalEntry::idFromIndex (const std::string& topic, int index, + const MWWorld::World& world) + { + const ESM::Dialogue *dialogue = world.getStore().dialogs.find (topic); + + for (std::vector::const_iterator iter (dialogue->mInfo.begin()); + iter!=dialogue->mInfo.end(); ++iter) + if (iter->data.disposition==index) /// \todo cleanup info structure + { + iter->id; + } + + throw std::runtime_error ("unknown journal index for topic " + topic); + } + + StampedJournalEntry::StampedJournalEntry() + : mDay (0), mMonth (0), mDayOfMonth (0) + {} + + StampedJournalEntry::StampedJournalEntry (const std::string& topic, const std::string& infoId, + int day, int month, int dayOfMonth) + : JournalEntry (topic, infoId), mDay (day), mMonth (month), mDayOfMonth (dayOfMonth) + {} + + StampedJournalEntry StampedJournalEntry::makeFromQuest (const std::string& topic, int index, + const MWWorld::World& world) + { + int day = world.getGlobalVariable ("dayspassed").mLong; + int month = world.getGlobalVariable ("day").mLong; + int dayOfMonth = world.getGlobalVariable ("month").mLong; + + return StampedJournalEntry (topic, idFromIndex (topic, index, world), day, month, dayOfMonth); + } +} diff --git a/apps/openmw/mwdialogue/journalentry.hpp b/apps/openmw/mwdialogue/journalentry.hpp new file mode 100644 index 000000000..11b715630 --- /dev/null +++ b/apps/openmw/mwdialogue/journalentry.hpp @@ -0,0 +1,54 @@ +#ifndef GAME_MMDIALOGUE_JOURNALENTRY_H +#define GAME_MMDIALOGUE_JOURNALENTRY_H + +#include + +namespace ESMS +{ + struct ESMStore; +} + +namespace MWWorld +{ + class World; +} + +namespace MWDialogue +{ + /// \brief A quest or dialogue entry + struct JournalEntry + { + std::string mTopic; + std::string mInfoId; + + JournalEntry(); + + JournalEntry (const std::string& topic, const std::string& infoId); + + std::string getText (const ESMS::ESMStore& store) const; + + static JournalEntry makeFromQuest (const std::string& topic, int index, + const MWWorld::World& world); + + static std::string idFromIndex (const std::string& topic, int index, + const MWWorld::World& world); + }; + + /// \biref A quest entry with a timestamp. + struct StampedJournalEntry : public JournalEntry + { + int mDay; + int mMonth; + int mDayOfMonth; + + StampedJournalEntry(); + + StampedJournalEntry (const std::string& topic, const std::string& infoId, + int day, int month, int dayOfMonth); + + static StampedJournalEntry makeFromQuest (const std::string& topic, int index, + const MWWorld::World& world); + }; +} + +#endif diff --git a/apps/openmw/mwdialogue/quest.cpp b/apps/openmw/mwdialogue/quest.cpp new file mode 100644 index 000000000..1f387e862 --- /dev/null +++ b/apps/openmw/mwdialogue/quest.cpp @@ -0,0 +1,86 @@ + +#include "quest.hpp" + +#include + +#include "../mwworld/world.hpp" + +namespace MWDialogue +{ + Quest::Quest() + : Topic(), mIndex (0), mFinished (false) + {} + + Quest::Quest (const std::string& topic) + : Topic (topic), mIndex (0), mFinished (false) + {} + + const std::string Quest::getName (const MWWorld::World& world) const + { + const ESM::Dialogue *dialogue = world.getStore().dialogs.find (mTopic); + + for (std::vector::const_iterator iter (dialogue->mInfo.begin()); + iter!=dialogue->mInfo.end(); ++iter) + if (iter->questStatus==ESM::DialInfo::QS_Name) + return iter->response; + + return ""; + } + + int Quest::getIndex() const + { + return mIndex; + } + + void Quest::setIndex (int index, const MWWorld::World& world) + { + const ESM::Dialogue *dialogue = world.getStore().dialogs.find (mTopic); + + for (std::vector::const_iterator iter (dialogue->mInfo.begin()); + iter!=dialogue->mInfo.end(); ++iter) + if (iter->data.disposition==index && iter->questStatus!=ESM::DialInfo::QS_Name) + { + mIndex = index; + + if (iter->questStatus==ESM::DialInfo::QS_Finished) + mFinished = true; + else if (iter->questStatus==ESM::DialInfo::QS_Restart) + mFinished = false; + + return; + } + + throw std::runtime_error ("unknown journal index for topic " + mTopic); + } + + bool Quest::isFinished() const + { + return mFinished; + } + + void Quest::addEntry (const JournalEntry& entry, const MWWorld::World& world) + { + int index = -1; + + const ESM::Dialogue *dialogue = world.getStore().dialogs.find (entry.mTopic); + + for (std::vector::const_iterator iter (dialogue->mInfo.begin()); + iter!=dialogue->mInfo.end(); ++iter) + if (iter->id==entry.mInfoId) + { + index = iter->data.disposition; /// \todo cleanup info structure + break; + } + + if (index==-1) + throw std::runtime_error ("unknown journal entry for topic " + mTopic); + + setIndex (index, world); + + for (TEntryIter iter (mEntries.begin()); iter!=mEntries.end(); ++iter) + if (*iter==entry.mInfoId) + return; + + mEntries.push_back (entry.mInfoId); + } +} diff --git a/apps/openmw/mwdialogue/quest.hpp b/apps/openmw/mwdialogue/quest.hpp new file mode 100644 index 000000000..c162c03f4 --- /dev/null +++ b/apps/openmw/mwdialogue/quest.hpp @@ -0,0 +1,37 @@ +#ifndef GAME_MMDIALOG_QUEST_H +#define GAME_MWDIALOG_QUEST_H + +#include "topic.hpp" + +namespace MWDialogue +{ + /// \brief A quest in progress or a compelted quest + class Quest : public Topic + { + int mIndex; + bool mFinished; + + public: + + Quest(); + + Quest (const std::string& topic); + + const std::string getName (const MWWorld::World& world) const; + ///< May be an empty string + + int getIndex() const; + + void setIndex (int index, const MWWorld::World& world); + ///< Calling this function with a non-existant index while throw an exception. + + bool isFinished() const; + + virtual void addEntry (const JournalEntry& entry, const MWWorld::World& world); + ///< Add entry and adjust index accordingly. + /// + /// \note Redundant entries are ignored, but the index is still adjusted. + }; +} + +#endif diff --git a/apps/openmw/mwdialogue/topic.cpp b/apps/openmw/mwdialogue/topic.cpp new file mode 100644 index 000000000..8f165d3c8 --- /dev/null +++ b/apps/openmw/mwdialogue/topic.cpp @@ -0,0 +1,46 @@ + +#include "topic.hpp" + +#include + +#include "../mwworld/world.hpp" + +namespace MWDialogue +{ + Topic::Topic() + {} + + Topic::Topic (const std::string& topic) + : mTopic (topic) + {} + + Topic::~Topic() + {} + + void Topic::addEntry (const JournalEntry& entry, const MWWorld::World& world) + { + if (entry.mTopic!=mTopic) + throw std::runtime_error ("topic does not match: " + mTopic); + + for (TEntryIter iter = begin(); iter!=end(); ++iter) + if (*iter==entry.mInfoId) + return; + + mEntries.push_back (entry.mInfoId); + } + + Topic::TEntryIter Topic::begin() + { + return mEntries.begin(); + } + + Topic::TEntryIter Topic::end() + { + return mEntries.end(); + } + + JournalEntry Topic::getEntry (const std::string& infoId) + { + return JournalEntry (mTopic, infoId); + } +} diff --git a/apps/openmw/mwdialogue/topic.hpp b/apps/openmw/mwdialogue/topic.hpp new file mode 100644 index 000000000..c085f1ed9 --- /dev/null +++ b/apps/openmw/mwdialogue/topic.hpp @@ -0,0 +1,52 @@ +#ifndef GAME_MMDIALOG_TOPIC_H +#define GAME_MWDIALOG_TOPIC_H + +#include +#include + +#include "journalentry.hpp" + +namespace MWWorld +{ + class World; +} + +namespace MWDialogue +{ + /// \brief Collection of seen responses for a topic + class Topic + { + public: + + typedef std::vector TEntryContainer; + typedef TEntryContainer::const_iterator TEntryIter; + + protected: + + std::string mTopic; + TEntryContainer mEntries; // info-IDs + + public: + + Topic(); + + Topic (const std::string& topic); + + virtual ~Topic(); + + virtual void addEntry (const JournalEntry& entry, const MWWorld::World& world); + ///< Add entry + /// + /// \note Redundant entries are ignored. + + TEntryIter begin(); + ///< Iterator pointing to the begin of the journal for this topic. + + TEntryIter end(); + ///< Iterator pointing past the end of the journal for this topic. + + JournalEntry getEntry (const std::string& infoId); + }; +} + +#endif diff --git a/apps/openmw/mwgui/birth.cpp b/apps/openmw/mwgui/birth.cpp index 7db93a508..93dde9f1b 100644 --- a/apps/openmw/mwgui/birth.cpp +++ b/apps/openmw/mwgui/birth.cpp @@ -119,8 +119,8 @@ void BirthDialog::updateBirths() { birthList->removeAllItems(); - ESMS::ESMStore &store = mWindowManager.getStore(); - + const ESMS::ESMStore &store = mWindowManager.getStore(); + ESMS::RecListT::MapType::const_iterator it = store.birthSigns.list.begin(); ESMS::RecListT::MapType::const_iterator end = store.birthSigns.list.end(); int index = 0; @@ -149,7 +149,7 @@ void BirthDialog::updateSpells() const int lineHeight = 18; MyGUI::IntCoord coord(0, 0, spellArea->getWidth(), 18); - ESMS::ESMStore &store = mWindowManager.getStore(); + const ESMS::ESMStore &store = mWindowManager.getStore(); const ESM::BirthSign *birth = store.birthSigns.find(currentBirthId); std::string texturePath = std::string("textures\\") + birth->texture; diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index 01516cfe2..ad94f30b1 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -50,7 +50,7 @@ void GenerateClassResultDialog::setClassId(const std::string &classId) { currentClassId = classId; classImage->setImageTexture(std::string("textures\\levelup\\") + currentClassId + ".dds"); - ESMS::ESMStore &store = mWindowManager.getStore(); + const ESMS::ESMStore &store = mWindowManager.getStore(); className->setCaption(store.classes.find(currentClassId)->name); } @@ -196,8 +196,8 @@ void PickClassDialog::updateClasses() { classList->removeAllItems(); - ESMS::ESMStore &store = mWindowManager.getStore(); - + const ESMS::ESMStore &store = mWindowManager.getStore(); + ESMS::RecListT::MapType::const_iterator it = store.classes.list.begin(); ESMS::RecListT::MapType::const_iterator end = store.classes.list.end(); int index = 0; @@ -220,7 +220,7 @@ void PickClassDialog::updateStats() { if (currentClassId.empty()) return; - ESMS::ESMStore &store = mWindowManager.getStore(); + const ESMS::ESMStore &store = mWindowManager.getStore(); const ESM::Class *klass = store.classes.search(currentClassId); if (!klass) return; @@ -767,7 +767,7 @@ SelectSkillDialog::SelectSkillDialog(WindowManager& parWindowManager) { char theIndex = '0'+i; getWidget(combatSkill[i], std::string("CombatSkill").append(1, theIndex)); - getWidget(magicSkill[i], std::string("MagicSkill").append(1, theIndex)); + getWidget(magicSkill[i], std::string("MagicSkill").append(1, theIndex)); getWidget(stealthSkill[i], std::string("StealthSkill").append(1, theIndex)); } @@ -782,8 +782,8 @@ SelectSkillDialog::SelectSkillDialog(WindowManager& parWindowManager) {combatSkill[6], ESM::Skill::Axe}, {combatSkill[7], ESM::Skill::Spear}, {combatSkill[8], ESM::Skill::Athletics} - }, - { + }, + { {magicSkill[0], ESM::Skill::Enchant}, {magicSkill[1], ESM::Skill::Destruction}, {magicSkill[2], ESM::Skill::Alteration}, @@ -793,8 +793,8 @@ SelectSkillDialog::SelectSkillDialog(WindowManager& parWindowManager) {magicSkill[6], ESM::Skill::Restoration}, {magicSkill[7], ESM::Skill::Alchemy}, {magicSkill[8], ESM::Skill::Unarmored} - }, - { + }, + { {stealthSkill[0], ESM::Skill::Security}, {stealthSkill[1], ESM::Skill::Sneak}, {stealthSkill[2], ESM::Skill::Acrobatics}, diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index 65e6afd2e..037f97fc3 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -212,8 +212,8 @@ void RaceDialog::updateRaces() { raceList->removeAllItems(); - ESMS::ESMStore &store = mWindowManager.getStore(); - + const ESMS::ESMStore &store = mWindowManager.getStore(); + ESMS::RecListT::MapType::const_iterator it = store.races.list.begin(); ESMS::RecListT::MapType::const_iterator end = store.races.list.end(); int index = 0; @@ -246,7 +246,7 @@ void RaceDialog::updateSkills() const int lineHeight = 18; MyGUI::IntCoord coord1(0, 0, skillList->getWidth(), 18); - ESMS::ESMStore &store = mWindowManager.getStore(); + const ESMS::ESMStore &store = mWindowManager.getStore(); const ESM::Race *race = store.races.find(currentRaceId); int count = sizeof(race->data.bonus)/sizeof(race->data.bonus[0]); // TODO: Find a portable macro for this ARRAYSIZE? for (int i = 0; i < count; ++i) @@ -282,7 +282,7 @@ void RaceDialog::updateSpellPowers() const int lineHeight = 18; MyGUI::IntCoord coord(0, 0, spellPowerList->getWidth(), 18); - ESMS::ESMStore &store = mWindowManager.getStore(); + const ESMS::ESMStore &store = mWindowManager.getStore(); const ESM::Race *race = store.races.find(currentRaceId); std::vector::const_iterator it = race->powers.list.begin(); diff --git a/apps/openmw/mwgui/stats_window.cpp b/apps/openmw/mwgui/stats_window.cpp index d08e6384d..30a4015e3 100644 --- a/apps/openmw/mwgui/stats_window.cpp +++ b/apps/openmw/mwgui/stats_window.cpp @@ -323,7 +323,7 @@ void StatsWindow::updateSkillArea() if (!miscSkills.empty()) addSkills(miscSkills, "sSkillClassMisc", "Misc Skills", coord1, coord2); - ESMS::ESMStore &store = mWindowManager.getStore(); + const ESMS::ESMStore &store = mWindowManager.getStore(); if (!factions.empty()) { diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index 861939b7e..f62da2bab 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -278,7 +278,7 @@ void MWSpell::setSpellId(const std::string &spellId) void MWSpell::createEffectWidgets(std::vector &effects, MyGUI::WidgetPtr creator, MyGUI::IntCoord &coord) { - ESMS::ESMStore &store = mWindowManager->getStore(); + const ESMS::ESMStore &store = mWindowManager->getStore(); const ESM::Spell *spell = store.spells.search(id); MYGUI_ASSERT(spell, "spell with id '" << id << "' not found"); @@ -298,7 +298,7 @@ void MWSpell::updateWidgets() { if (spellNameWidget && mWindowManager) { - ESMS::ESMStore &store = mWindowManager->getStore(); + const ESMS::ESMStore &store = mWindowManager->getStore(); const ESM::Spell *spell = store.spells.search(id); if (spell) spellNameWidget->setCaption(spell->name); @@ -363,7 +363,7 @@ void MWSpellEffect::updateWidgets() if (!mWindowManager) return; - ESMS::ESMStore &store = mWindowManager->getStore(); + const ESMS::ESMStore &store = mWindowManager->getStore(); const ESM::MagicEffect *magicEffect = store.magicEffects.search(effect.effectID); if (textWidget) { diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index f0c409cbe..2d7f70ef8 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -940,7 +940,7 @@ void WindowManager::onReviewActivateDialog(int parDialog) }; } -ESMS::ESMStore& WindowManager::getStore() +const ESMS::ESMStore& WindowManager::getStore() const { return environment.mWorld->getStore(); } diff --git a/apps/openmw/mwgui/window_manager.hpp b/apps/openmw/mwgui/window_manager.hpp index 1bf620496..d3fbf3ea3 100644 --- a/apps/openmw/mwgui/window_manager.hpp +++ b/apps/openmw/mwgui/window_manager.hpp @@ -257,7 +257,7 @@ namespace MWGui */ const std::string &getGameSettingString(const std::string &id, const std::string &default_); - ESMS::ESMStore& getStore(); + const ESMS::ESMStore& getStore() const; private: diff --git a/apps/openmw/mwscript/dialogueextensions.cpp b/apps/openmw/mwscript/dialogueextensions.cpp new file mode 100644 index 000000000..c2ff9ed8b --- /dev/null +++ b/apps/openmw/mwscript/dialogueextensions.cpp @@ -0,0 +1,94 @@ + +#include "dialogueextensions.hpp" + +#include + +#include +#include +#include + +#include "../mwdialogue/journal.hpp" + +#include "interpretercontext.hpp" + +namespace MWScript +{ + namespace Dialogue + { + class OpJournal : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWScript::InterpreterContext& context + = static_cast (runtime.getContext()); + + std::string quest = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + Interpreter::Type_Integer index = runtime[0].mInteger; + runtime.pop(); + + context.getEnvironment().mJournal->addEntry (quest, index); + } + }; + + class OpSetJournalIndex : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWScript::InterpreterContext& context + = static_cast (runtime.getContext()); + + std::string quest = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + Interpreter::Type_Integer index = runtime[0].mInteger; + runtime.pop(); + + context.getEnvironment().mJournal->setJournalIndex (quest, index); + } + }; + + class OpGetJournalIndex : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWScript::InterpreterContext& context + = static_cast (runtime.getContext()); + + std::string quest = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + int index = context.getEnvironment().mJournal->getJournalIndex (quest); + + runtime.push (index); + + } + }; + + const int opcodeJournal = 0x2000133; + const int opcodeSetJournalIndex = 0x2000134; + const int opcodeGetJournalIndex = 0x2000135; + + void registerExtensions (Compiler::Extensions& extensions) + { + extensions.registerInstruction ("journal", "cl", opcodeJournal); + extensions.registerInstruction ("setjournalindex", "cl", opcodeSetJournalIndex); + extensions.registerFunction ("getjournalindex", 'l', "c", opcodeGetJournalIndex); + } + + void installOpcodes (Interpreter::Interpreter& interpreter) + { + interpreter.installSegment5 (opcodeJournal, new OpJournal); + interpreter.installSegment5 (opcodeSetJournalIndex, new OpSetJournalIndex); + interpreter.installSegment5 (opcodeGetJournalIndex, new OpGetJournalIndex); + } + } + +} diff --git a/apps/openmw/mwscript/dialogueextensions.hpp b/apps/openmw/mwscript/dialogueextensions.hpp new file mode 100644 index 000000000..ece7d62ce --- /dev/null +++ b/apps/openmw/mwscript/dialogueextensions.hpp @@ -0,0 +1,25 @@ +#ifndef GAME_SCRIPT_DIALOGUEEXTENSIONS_H +#define GAME_SCRIPT_DIALOGUEEXTENSIONS_H + +namespace Compiler +{ + class Extensions; +} + +namespace Interpreter +{ + class Interpreter; +} + +namespace MWScript +{ + /// \brief Dialogue/Journal-related script functionality + namespace Dialogue + { + void registerExtensions (Compiler::Extensions& extensions); + + void installOpcodes (Interpreter::Interpreter& interpreter); + } +} + +#endif diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index d803d0bac..90962f56b 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -104,4 +104,7 @@ op 0x2000115-0x200012f: ModSKill, explicit reference op 0x2000130: ToggleCollision op 0x2000131: GetInterior op 0x2000132: ToggleCollsionDebug -opcodes 0x2000133-0x3ffffff unused +op 0x2000133: Journal +op 0x2000134: SetJournalIndex +op 0x2000135: GetJournalIndex +opcodes 0x2000136-0x3ffffff unused diff --git a/apps/openmw/mwscript/extensions.cpp b/apps/openmw/mwscript/extensions.cpp index 15d482fc1..86161d2b1 100644 --- a/apps/openmw/mwscript/extensions.cpp +++ b/apps/openmw/mwscript/extensions.cpp @@ -13,6 +13,7 @@ #include "containerextensions.hpp" #include "aiextensions.hpp" #include "controlextensions.hpp" +#include "dialogueextensions.hpp" namespace MWScript { @@ -27,6 +28,7 @@ namespace MWScript Container::registerExtensions (extensions); Ai::registerExtensions (extensions); Control::registerExtensions (extensions); + Dialogue::registerExtensions (extensions); } void installOpcodes (Interpreter::Interpreter& interpreter) @@ -41,5 +43,6 @@ namespace MWScript Container::installOpcodes (interpreter); Ai::installOpcodes (interpreter); Control::installOpcodes (interpreter); + Dialogue::installOpcodes (interpreter); } } diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index f2f1e6e10..cb6ecb218 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -260,6 +260,11 @@ namespace MWScript mEnvironment.mWorld->disable (ref); } + MWWorld::Environment& InterpreterContext::getEnvironment() + { + return mEnvironment; + } + MWGui::WindowManager& InterpreterContext::getWindowManager() { return *mEnvironment.mWindowManager; diff --git a/apps/openmw/mwscript/interpretercontext.hpp b/apps/openmw/mwscript/interpretercontext.hpp index 031820d5d..aebfc620e 100644 --- a/apps/openmw/mwscript/interpretercontext.hpp +++ b/apps/openmw/mwscript/interpretercontext.hpp @@ -106,6 +106,10 @@ namespace MWScript virtual void disable (const std::string& id = ""); + MWWorld::Environment& getEnvironment(); + + /// \todo remove the following functions (extentions should use getEnvironment instead) + MWWorld::World& getWorld(); MWSound::SoundManager& getSoundManager(); diff --git a/apps/openmw/mwworld/environment.hpp b/apps/openmw/mwworld/environment.hpp index c04dfcbf1..a403ee165 100644 --- a/apps/openmw/mwworld/environment.hpp +++ b/apps/openmw/mwworld/environment.hpp @@ -24,6 +24,7 @@ namespace MWMechanics namespace MWDialogue { class DialogueManager; + class Journal; } namespace MWInput @@ -41,7 +42,7 @@ namespace MWWorld public: Environment() : mWorld (0), mSoundManager (0), mGlobalScripts (0), mWindowManager (0), - mMechanicsManager (0), mDialogueManager (0), mFrameDuration (0), + mMechanicsManager (0), mDialogueManager (0), mJournal (0), mFrameDuration (0), mInputManager (0) {} @@ -51,6 +52,7 @@ namespace MWWorld MWGui::WindowManager *mWindowManager; MWMechanics::MechanicsManager *mMechanicsManager; MWDialogue::DialogueManager *mDialogueManager; + MWDialogue::Journal *mJournal; float mFrameDuration; // For setting GUI mode diff --git a/apps/openmw/mwworld/world.cpp b/apps/openmw/mwworld/world.cpp index 63019349c..f10bbfc9a 100644 --- a/apps/openmw/mwworld/world.cpp +++ b/apps/openmw/mwworld/world.cpp @@ -460,7 +460,7 @@ namespace MWWorld return *mPlayer; } - ESMS::ESMStore& World::getStore() + const ESMS::ESMStore& World::getStore() const { return mStore; } @@ -480,6 +480,11 @@ namespace MWWorld return (*mGlobalVariables)[name]; } + Globals::Data World::getGlobalVariable (const std::string& name) const + { + return (*mGlobalVariables)[name]; + } + char World::getGlobalVariableType (const std::string& name) const { return mGlobalVariables->getType (name); diff --git a/apps/openmw/mwworld/world.hpp b/apps/openmw/mwworld/world.hpp index 6965aebc6..f7e5bd3f7 100644 --- a/apps/openmw/mwworld/world.hpp +++ b/apps/openmw/mwworld/world.hpp @@ -115,7 +115,7 @@ namespace MWWorld MWWorld::Player& getPlayer(); - ESMS::ESMStore& getStore(); + const ESMS::ESMStore& getStore() const; const ScriptList& getLocalScripts() const; ///< Names and local variable state of all local scripts in active cells. @@ -125,6 +125,8 @@ namespace MWWorld Globals::Data& getGlobalVariable (const std::string& name); + Globals::Data getGlobalVariable (const std::string& name) const; + char getGlobalVariableType (const std::string& name) const; ///< Return ' ', if there is no global variable with this name.