diff --git a/apps/openmw-mp/Script/Functions/Objects.cpp b/apps/openmw-mp/Script/Functions/Objects.cpp index 5f3d05dbd..cca9ac7ef 100644 --- a/apps/openmw-mp/Script/Functions/Objects.cpp +++ b/apps/openmw-mp/Script/Functions/Objects.cpp @@ -154,9 +154,14 @@ int ObjectFunctions::GetObjectLockLevel(unsigned int index) noexcept return readObjectList->baseObjects.at(index).lockLevel; } -const char* ObjectFunctions::GetObjectDialogueChoice(unsigned int index) noexcept +unsigned int ObjectFunctions::GetObjectDialogueChoiceType(unsigned int index) noexcept { - return readObjectList->baseObjects.at(index).dialogueChoice.c_str(); + return readObjectList->baseObjects.at(index).dialogueChoiceType; +} + +const char* ObjectFunctions::GetObjectDialogueChoiceTopic(unsigned int index) noexcept +{ + return readObjectList->baseObjects.at(index).topicId.c_str(); } unsigned int ObjectFunctions::GetObjectGoldPool(unsigned int index) noexcept @@ -500,9 +505,14 @@ void ObjectFunctions::SetObjectLockLevel(int lockLevel) noexcept tempObject.lockLevel = lockLevel; } -void ObjectFunctions::SetObjectDialogueChoice(const char* dialogueChoice) noexcept +void ObjectFunctions::SetObjectDialogueChoiceType(unsigned int dialogueChoiceType) noexcept +{ + tempObject.dialogueChoiceType = dialogueChoiceType; +} + +void ObjectFunctions::SetObjectDialogueChoiceTopic(const char* topic) noexcept { - tempObject.dialogueChoice = dialogueChoice; + tempObject.topicId = topic; } void ObjectFunctions::SetObjectGoldPool(unsigned int goldPool) noexcept diff --git a/apps/openmw-mp/Script/Functions/Objects.hpp b/apps/openmw-mp/Script/Functions/Objects.hpp index be67bc717..82682825b 100644 --- a/apps/openmw-mp/Script/Functions/Objects.hpp +++ b/apps/openmw-mp/Script/Functions/Objects.hpp @@ -31,7 +31,8 @@ {"GetObjectState", ObjectFunctions::GetObjectState},\ {"GetObjectDoorState", ObjectFunctions::GetObjectDoorState},\ {"GetObjectLockLevel", ObjectFunctions::GetObjectLockLevel},\ - {"GetObjectDialogueChoice", ObjectFunctions::GetObjectDialogueChoice},\ + {"GetObjectDialogueChoiceType", ObjectFunctions::GetObjectDialogueChoiceType},\ + {"GetObjectDialogueChoiceTopic", ObjectFunctions::GetObjectDialogueChoiceTopic},\ {"GetObjectGoldPool", ObjectFunctions::GetObjectGoldPool},\ {"GetObjectLastGoldRestockHour", ObjectFunctions::GetObjectLastGoldRestockHour},\ {"GetObjectLastGoldRestockDay", ObjectFunctions::GetObjectLastGoldRestockDay},\ @@ -106,7 +107,8 @@ {"SetObjectScale", ObjectFunctions::SetObjectScale},\ {"SetObjectState", ObjectFunctions::SetObjectState},\ {"SetObjectLockLevel", ObjectFunctions::SetObjectLockLevel},\ - {"SetObjectDialogueChoice", ObjectFunctions::SetObjectDialogueChoice},\ + {"SetObjectDialogueChoiceType", ObjectFunctions::SetObjectDialogueChoiceType},\ + {"SetObjectDialogueChoiceTopic", ObjectFunctions::SetObjectDialogueChoiceTopic},\ {"SetObjectGoldPool", ObjectFunctions::SetObjectGoldPool},\ {"SetObjectLastGoldRestockHour", ObjectFunctions::SetObjectLastGoldRestockHour},\ {"SetObjectLastGoldRestockDay", ObjectFunctions::SetObjectLastGoldRestockDay},\ @@ -393,12 +395,20 @@ public: static int GetObjectLockLevel(unsigned int index) noexcept; /** - * \brief Get the dialogue choice for the object at a certain index in the read object list. + * \brief Get the dialogue choice type for the object at a certain index in the read object list. * * \param index The index of the object. - * \return The dialogue choice. + * \return The dialogue choice type. */ - static const char *GetObjectDialogueChoice(unsigned int index) noexcept; + static unsigned int GetObjectDialogueChoiceType(unsigned int index) noexcept; + + /** + * \brief Get the dialogue choice topic for the object at a certain index in the read object list. + * + * \param index The index of the object. + * \return The dialogue choice topic. + */ + static const char *GetObjectDialogueChoiceTopic(unsigned int index) noexcept; /** * \brief Get the gold pool of the object at a certain index in the read object list. @@ -1000,12 +1010,20 @@ public: static void SetObjectLockLevel(int lockLevel) noexcept; /** - * \brief Set the dialogue choice for the temporary object stored on the server. + * \brief Set the dialogue choice type of the temporary object stored on the server. + * + * \param dialogueChoiceType The dialogue choice type. + * \return void + */ + static void SetObjectDialogueChoiceType(unsigned int dialogueChoiceType) noexcept; + + /** + * \brief Set the dialogue choice topic for the temporary object stored on the server. * - * \param dialogueChoice The dialogue choice. + * \param topic The dialogue choice topic. * \return void */ - static void SetObjectDialogueChoice(const char* dialogueChoice) noexcept; + static void SetObjectDialogueChoiceTopic(const char* topic) noexcept; /** * \brief Set the gold pool of the temporary object stored on the server. diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index dca63a533..bc7f3a2f1 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -296,16 +296,7 @@ namespace MWGui //Topics list getWidget(mTopicsList, "TopicsList"); - /* - Start of tes3mp change (major) - - Instead of running DialogueWindow::onSelectListItem() when clicking a list item, run - onSendDialoguePacket() so the server can approve or deny a dialogue choice - */ - mTopicsList->eventItemSelected += MyGUI::newDelegate(this, &DialogueWindow::onSendDialoguePacket); - /* - End of tes3mp change (major) - */ + mTopicsList->eventItemSelected += MyGUI::newDelegate(this, &DialogueWindow::onSelectListItem); getWidget(mGoodbyeButton, "ByeButton"); mGoodbyeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &DialogueWindow::onByeClicked); @@ -382,27 +373,25 @@ namespace MWGui } } - /* - Start of tes3mp addition - - A different event that should be used in multiplayer when clicking on list items - in the dialogue screen, sending DialogueChoice packets to the server so they can - be approved or denied - */ - void DialogueWindow::onSendDialoguePacket(const std::string& topic, int id) + void DialogueWindow::onSelectListItem(const std::string& topic, int id) { + /* + Start of tes3mp change (major) + + Instead of activating a list item here, send an ObjectDialogueChoice packet to the server + and let it decide whether the list item gets activated + */ mwmp::ObjectList* objectList = mwmp::Main::get().getNetworking()->getObjectList(); objectList->reset(); objectList->packetOrigin = mwmp::CLIENT_GAMEPLAY; objectList->addObjectDialogueChoice(mPtr, topic, id); objectList->sendObjectDialogueChoice(); - } - /* - End of tes3mp addition - */ - void DialogueWindow::onSelectListItem(const std::string& topic, int id) - { + return; + /* + End of tes3mp change (major) + */ + MWBase::DialogueManager* dialogueManager = MWBase::Environment::get().getDialogueManager(); if (mGoodbye || dialogueManager->isInChoice()) @@ -453,6 +442,49 @@ namespace MWGui updateTopics(); } + /* + Start of tes3mp addition + + Make it possible to activate any dialogue choice from elsewhere in the code + */ + void DialogueWindow::activateDialogueChoice(unsigned char dialogueChoiceType, std::string topic) + { + if (dialogueChoiceType == mwmp::DialogueChoiceType::TOPIC) + { + // If we're using a translated version of Morrowind, translate this topic from English into our language + if (MWBase::Environment::get().getWindowManager()->getTranslationDataStorage().hasTranslation()) + topic = MWBase::Environment::get().getWindowManager()->getTranslationDataStorage().getLocalizedTopicId(topic); + + onTopicActivated(topic); + } + else if (dialogueChoiceType == mwmp::DialogueChoiceType::PERSUASION) + mPersuasionDialog.setVisible(true); + else if (dialogueChoiceType == mwmp::DialogueChoiceType::COMPANION_SHARE) + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Companion, mPtr); + else + { + MWBase::DialogueManager* dialogueManager = MWBase::Environment::get().getDialogueManager(); + + if (dialogueChoiceType == mwmp::DialogueChoiceType::BARTER && !dialogueManager->checkServiceRefused(mCallback.get(), MWBase::DialogueManager::Barter)) + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Barter, mPtr); + else if (dialogueChoiceType == mwmp::DialogueChoiceType::SPELLS && !dialogueManager->checkServiceRefused(mCallback.get(), MWBase::DialogueManager::Spells)) + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_SpellBuying, mPtr); + else if (dialogueChoiceType == mwmp::DialogueChoiceType::TRAVEL && !dialogueManager->checkServiceRefused(mCallback.get(), MWBase::DialogueManager::Travel)) + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Travel, mPtr); + else if (dialogueChoiceType == mwmp::DialogueChoiceType::SPELLMAKING && !dialogueManager->checkServiceRefused(mCallback.get(), MWBase::DialogueManager::Spellmaking)) + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_SpellCreation, mPtr); + else if (dialogueChoiceType == mwmp::DialogueChoiceType::ENCHANTING && !dialogueManager->checkServiceRefused(mCallback.get(), MWBase::DialogueManager::Enchanting)) + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Enchanting, mPtr); + else if (dialogueChoiceType == mwmp::DialogueChoiceType::TRAINING && !dialogueManager->checkServiceRefused(mCallback.get(), MWBase::DialogueManager::Training)) + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Training, mPtr); + else if (dialogueChoiceType == mwmp::DialogueChoiceType::REPAIR && !dialogueManager->checkServiceRefused(mCallback.get(), MWBase::DialogueManager::Repair)) + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_MerchantRepair, mPtr); + } + } + /* + End of tes3mp addition + */ + /* Start of tes3mp addition diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index aeeeaa113..a6a444a19 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -120,6 +120,16 @@ namespace MWGui void notifyLinkClicked (TypesetBook::InteractiveId link); + /* + Start of tes3mp addition + + Make it possible to activate any dialogue choice from elsewhere in the code + */ + void activateDialogueChoice(unsigned char dialogueChoiceType, std::string topic = ""); + /* + End of tes3mp addition + */ + /* Start of tes3mp addition @@ -150,30 +160,7 @@ namespace MWGui bool isCompanion(const MWWorld::Ptr& actor); bool isCompanion(); - /* - Start of tes3mp addition - - A different event that should be used in multiplayer when clicking on list items - in the dialogue screen, sending DialogueChoice packets to the server so they can - be approved or denied - */ - void onSendDialoguePacket(const std::string& topic, int id); - /* - End of tes3mp addition - */ - - /* - Start of tes3mp change (major) - - Turn onSelectListItem() into a public function so it can be used elsewhere when - receiving ObjectDialogueChoice packets - */ - public: void onSelectListItem(const std::string& topic, int id); - protected: - /* - End of tes3mp change (major) - */ void onByeClicked(MyGUI::Widget* _sender); void onMouseWheel(MyGUI::Widget* _sender, int _rel); void onWindowResize(MyGUI::Window* _sender); diff --git a/apps/openmw/mwmp/ObjectList.cpp b/apps/openmw/mwmp/ObjectList.cpp index ec28f5891..483118f4a 100644 --- a/apps/openmw/mwmp/ObjectList.cpp +++ b/apps/openmw/mwmp/ObjectList.cpp @@ -8,6 +8,7 @@ #include "CellController.hpp" #include "RecordHelper.hpp" +#include #include #include "../mwbase/world.hpp" @@ -1007,8 +1008,8 @@ void ObjectList::makeDialogueChoices(MWWorld::CellStore* cellStore) MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Dialogue, ptrFound); } - LOG_APPEND(TimedLog::LOG_VERBOSE, "-- Making dialogue choice of %s", baseObject.dialogueChoice); - MWBase::Environment::get().getWindowManager()->getDialogueWindow()->onSelectListItem(baseObject.dialogueChoice, baseObject.guiId); + LOG_APPEND(TimedLog::LOG_VERBOSE, "-- Making dialogue choice of type %i", baseObject.dialogueChoiceType); + MWBase::Environment::get().getWindowManager()->getDialogueWindow()->activateDialogueChoice(baseObject.dialogueChoiceType, baseObject.topicId); } else { @@ -1272,7 +1273,40 @@ void ObjectList::addObjectDialogueChoice(const MWWorld::Ptr& ptr, std::string di cell = *ptr.getCell()->getCell(); mwmp::BaseObject baseObject = getBaseObjectFromPtr(ptr); - baseObject.dialogueChoice = dialogueChoice; + + const MWWorld::Store& gmst = MWBase::Environment::get().getWorld()->getStore().get(); + + // Because the actual text for any of the special dialogue choices can vary according to the game language used, + // set the type of dialogue choice by doing a lot of checks + if (dialogueChoice == gmst.find("sPersuasion")->mValue.getString()) + baseObject.dialogueChoiceType = static_cast(DialogueChoiceType::PERSUASION); + else if (dialogueChoice == gmst.find("sCompanionShare")->mValue.getString()) + baseObject.dialogueChoiceType = DialogueChoiceType::COMPANION_SHARE; + else if (dialogueChoice == gmst.find("sBarter")->mValue.getString()) + baseObject.dialogueChoiceType = DialogueChoiceType::BARTER; + else if (dialogueChoice == gmst.find("sSpells")->mValue.getString()) + baseObject.dialogueChoiceType = DialogueChoiceType::SPELLS; + else if (dialogueChoice == gmst.find("sTravel")->mValue.getString()) + baseObject.dialogueChoiceType = DialogueChoiceType::TRAVEL; + else if (dialogueChoice == gmst.find("sSpellMakingMenuTitle")->mValue.getString()) + baseObject.dialogueChoiceType = DialogueChoiceType::SPELLMAKING; + else if (dialogueChoice == gmst.find("sEnchanting")->mValue.getString()) + baseObject.dialogueChoiceType = DialogueChoiceType::ENCHANTING; + else if (dialogueChoice == gmst.find("sServiceTrainingTitle")->mValue.getString()) + baseObject.dialogueChoiceType = DialogueChoiceType::TRAINING; + else if (dialogueChoice == gmst.find("sRepair")->mValue.getString()) + baseObject.dialogueChoiceType = DialogueChoiceType::REPAIR; + else + { + baseObject.dialogueChoiceType = DialogueChoiceType::TOPIC; + + // For translated versions of the game, make sure we translate the topic back into English first + if (MWBase::Environment::get().getWindowManager()->getTranslationDataStorage().hasTranslation()) + baseObject.topicId = MWBase::Environment::get().getWindowManager()->getTranslationDataStorage().topicID(dialogueChoice); + else + baseObject.topicId = dialogueChoice; + } + baseObject.guiId = guiId; addBaseObject(baseObject); } diff --git a/components/openmw-mp/Base/BaseObject.hpp b/components/openmw-mp/Base/BaseObject.hpp index 9445a40e8..f3d004923 100644 --- a/components/openmw-mp/Base/BaseObject.hpp +++ b/components/openmw-mp/Base/BaseObject.hpp @@ -41,7 +41,8 @@ namespace mwmp int lockLevel; float scale; - std::string dialogueChoice; + unsigned char dialogueChoiceType; + std::string topicId; int guiId; std::string soundId; diff --git a/components/openmw-mp/Base/BaseStructs.hpp b/components/openmw-mp/Base/BaseStructs.hpp index 32a82ae19..1dc082b8e 100644 --- a/components/openmw-mp/Base/BaseStructs.hpp +++ b/components/openmw-mp/Base/BaseStructs.hpp @@ -10,6 +10,23 @@ namespace mwmp { + namespace DialogueChoiceType + { + enum DIALOGUE_CHOICE + { + TOPIC, + PERSUASION, + COMPANION_SHARE, + BARTER, + SPELLS, + TRAVEL, + SPELLMAKING, + ENCHANTING, + TRAINING, + REPAIR + }; + } + enum PACKET_ORIGIN { CLIENT_GAMEPLAY = 0, diff --git a/components/openmw-mp/Packets/Object/PacketObjectDialogueChoice.cpp b/components/openmw-mp/Packets/Object/PacketObjectDialogueChoice.cpp index 667d60383..5d49061ea 100644 --- a/components/openmw-mp/Packets/Object/PacketObjectDialogueChoice.cpp +++ b/components/openmw-mp/Packets/Object/PacketObjectDialogueChoice.cpp @@ -12,6 +12,10 @@ PacketObjectDialogueChoice::PacketObjectDialogueChoice(RakNet::RakPeerInterface void PacketObjectDialogueChoice::Object(BaseObject& baseObject, bool send) { ObjectPacket::Object(baseObject, send); - RW(baseObject.dialogueChoice, send, true); + RW(baseObject.dialogueChoiceType, send); + + if (baseObject.dialogueChoiceType == DialogueChoiceType::TOPIC) + RW(baseObject.topicId, send, true); + RW(baseObject.guiId, send); }