From fba32e406c94e13ba23fe8834911f9b520e45895 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 6 Nov 2012 15:26:51 +0100 Subject: [PATCH 1/8] changed OIS includes since OIS_INCLUDE_DIR is already an include directory --- apps/openmw/mwinput/inputmanagerimp.cpp | 2 +- apps/openmw/mwinput/inputmanagerimp.hpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index c3e131440..af30c9b04 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -9,7 +9,7 @@ #include -#include +#include #include #include diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 5e6169f68..718d6b76f 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -42,8 +42,8 @@ namespace OIS class InputManager; } -#include -#include +#include +#include #include #include From ace9ee9c835273686e4b1928335461f89de664f9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 9 Nov 2012 20:18:38 +0100 Subject: [PATCH 2/8] persuasion dialog --- apps/openmw/mwbase/mechanicsmanager.hpp | 12 ++ apps/openmw/mwclass/npc.cpp | 2 +- apps/openmw/mwgui/dialogue.cpp | 103 ++++++++++++++++++ apps/openmw/mwgui/dialogue.hpp | 32 ++++++ .../mwmechanics/mechanicsmanagerimp.cpp | 8 +- .../mwmechanics/mechanicsmanagerimp.hpp | 2 + apps/openmw/mwmechanics/npcstats.cpp | 4 +- apps/openmw/mwmechanics/npcstats.hpp | 4 +- apps/openmw/mwrender/player.cpp | 3 +- files/mygui/CMakeLists.txt | 1 + 10 files changed, 164 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 9f9b5af70..0be111ea7 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -85,6 +85,18 @@ namespace MWBase virtual int countDeaths (const std::string& id) const = 0; ///< Return the number of deaths for actors with the given ID. + + enum PersuasionType + { + PT_Admire, + PT_Intimidate, + PT_Taunt, + PT_Bribe10, + PT_Bribe100, + PT_Bribe1000 + }; + virtual float getPersuasionDispositionChange (MWWorld::Ptr npc, PersuasionType type, bool& success) const = 0; + ///< Get amount to adjust temporary disposition for a given persuasion action on an NPC }; } diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 6a516bcc8..c7f33504e 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -95,7 +95,7 @@ namespace MWClass data->mCreatureStats.setFatigue (ref->mBase->mNpdt52.mFatigue); data->mCreatureStats.setLevel(ref->mBase->mNpdt52.mLevel); - data->mNpcStats.setDisposition(ref->mBase->mNpdt52.mDisposition); + data->mNpcStats.setBaseDisposition(ref->mBase->mNpdt52.mDisposition); } else { diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index e1baaf8e0..be7bfde53 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -49,14 +49,87 @@ std::string::size_type find_str_ci(const std::string& str, const std::string& su } + +PersuasionDialog::PersuasionDialog(MWBase::WindowManager &parWindowManager) + : WindowModal("openmw_persuasion_dialog.layout", parWindowManager) +{ + getWidget(mCancelButton, "CancelButton"); + getWidget(mAdmireButton, "AdmireButton"); + getWidget(mIntimidateButton, "IntimidateButton"); + getWidget(mTauntButton, "TauntButton"); + getWidget(mBribe10Button, "Bribe10Button"); + getWidget(mBribe100Button, "Bribe100Button"); + getWidget(mBribe1000Button, "Bribe1000Button"); + getWidget(mGoldLabel, "GoldLabel"); + + mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PersuasionDialog::onCancel); + mAdmireButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PersuasionDialog::onPersuade); + mIntimidateButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PersuasionDialog::onPersuade); + mTauntButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PersuasionDialog::onPersuade); + mBribe10Button->eventMouseButtonClick += MyGUI::newDelegate(this, &PersuasionDialog::onPersuade); + mBribe100Button->eventMouseButtonClick += MyGUI::newDelegate(this, &PersuasionDialog::onPersuade); + mBribe1000Button->eventMouseButtonClick += MyGUI::newDelegate(this, &PersuasionDialog::onPersuade); +} + +void PersuasionDialog::onCancel(MyGUI::Widget *sender) +{ + setVisible(false); +} + +void PersuasionDialog::onPersuade(MyGUI::Widget *sender) +{ + MWBase::MechanicsManager::PersuasionType type; + if (sender == mAdmireButton) type = MWBase::MechanicsManager::PT_Admire; + else if (sender == mIntimidateButton) type = MWBase::MechanicsManager::PT_Intimidate; + else if (sender == mTauntButton) type = MWBase::MechanicsManager::PT_Taunt; + else if (sender == mBribe10Button) + { + mWindowManager.getTradeWindow()->addOrRemoveGold(-10); + type = MWBase::MechanicsManager::PT_Bribe10; + } + else if (sender == mBribe100Button) + { + mWindowManager.getTradeWindow()->addOrRemoveGold(-100); + type = MWBase::MechanicsManager::PT_Bribe100; + } + else /*if (sender == mBribe1000Button)*/ + { + mWindowManager.getTradeWindow()->addOrRemoveGold(-1000); + type = MWBase::MechanicsManager::PT_Bribe1000; + } + + eventPersuade(type, true, 0); + setVisible(false); +} + +void PersuasionDialog::open() +{ + WindowModal::open(); + center(); + + int playerGold = mWindowManager.getInventoryWindow()->getPlayerGold(); + + mBribe10Button->setEnabled (playerGold >= 10); + mBribe100Button->setEnabled (playerGold >= 100); + mBribe1000Button->setEnabled (playerGold >= 1000); + + mGoldLabel->setCaptionWithReplacing("#{sGold}: " + boost::lexical_cast(playerGold)); +} + +// -------------------------------------------------------------------------------------------------- + DialogueWindow::DialogueWindow(MWBase::WindowManager& parWindowManager) : WindowBase("openmw_dialogue_window.layout", parWindowManager) + , mPersuasionDialog(parWindowManager) , mEnabled(false) , mServices(0) { // Centre dialog center(); + mPersuasionDialog.setVisible(false); + mPersuasionDialog.eventPersuade += MyGUI::newDelegate(this, &DialogueWindow::onPersuade); + //History view getWidget(mHistory, "History"); mHistory->setOverflowToTheLeft(true); @@ -137,6 +210,10 @@ void DialogueWindow::onSelectTopic(std::string topic) mWindowManager.pushGuiMode(GM_Barter); mWindowManager.getTradeWindow()->startTrade(mPtr); } + if (topic == gmst.find("sPersuasion")->getString()) + { + mPersuasionDialog.setVisible(true); + } else if (topic == gmst.find("sSpells")->getString()) { mWindowManager.pushGuiMode(GM_SpellBuying); @@ -187,6 +264,9 @@ void DialogueWindow::setKeywords(std::list keyWords) const MWWorld::Store &gmst = MWBase::Environment::get().getWorld()->getStore().get(); + if (mPtr.getTypeName() == typeid(ESM::NPC).name()) + mTopicsList->addItem(gmst.find("sPersuasion")->getString()); + if (mServices & Service_Trade) mTopicsList->addItem(gmst.find("sBarter")->getString()); @@ -311,6 +391,8 @@ void DialogueWindow::updateOptions() void DialogueWindow::goodbye() { + // Apply temporary disposition change to NPC's base disposition + mHistory->addDialogText("\n#572D21" + MWBase::Environment::get().getWorld()->getStore().get().find("sGoodbye")->getString()); mTopicsList->setEnabled(false); mEnabled = false; @@ -331,3 +413,24 @@ void DialogueWindow::onFrame() mDispositionText->addText("#B29154"+boost::lexical_cast(MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr))+std::string("/100")+"#B29154"); } } + +void DialogueWindow::onPersuade(int type, bool success, float dispositionChange) +{ + std::string text; + + if (type == MWBase::MechanicsManager::PT_Admire) + text = "sAdmire"; + else if (type == MWBase::MechanicsManager::PT_Taunt) + text = "sTaunt"; + else if (type == MWBase::MechanicsManager::PT_Intimidate) + text = "sIntimidate"; + else + text = "sBribe"; + + text += success ? "Fail" : "Success"; + + mHistory->addDialogHeading( MyGUI::LanguageManager::getInstance().replaceTags("#{"+text+"}")); + + /// \todo text from INFO record, how to get the ID? + //mHistory->addDialogText(); +} diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index bb9acf5db..3d0d74d95 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -26,6 +26,31 @@ namespace MWGui { class DialogueHistory; + class PersuasionDialog : public WindowModal + { + public: + PersuasionDialog(MWBase::WindowManager& parWindowManager); + + virtual void open(); + + typedef MyGUI::delegates::CMultiDelegate3 EventHandle_Persuade; + + EventHandle_Persuade eventPersuade; + + private: + MyGUI::Button* mCancelButton; + MyGUI::Button* mAdmireButton; + MyGUI::Button* mIntimidateButton; + MyGUI::Button* mTauntButton; + MyGUI::Button* mBribe10Button; + MyGUI::Button* mBribe100Button; + MyGUI::Button* mBribe1000Button; + MyGUI::TextBox* mGoldLabel; + + void onCancel (MyGUI::Widget* sender); + void onPersuade (MyGUI::Widget* sender); + }; + class DialogueWindow: public WindowBase, public ReferenceInterface { public: @@ -86,6 +111,13 @@ namespace MWGui Widgets::MWList* mTopicsList; MyGUI::ProgressPtr mDispositionBar; MyGUI::EditPtr mDispositionText; + + PersuasionDialog mPersuasionDialog; + + + float mTemporaryDispositionChange; + + void onPersuade (int type, bool success, float dispositionChange); }; } #endif diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 62b116a47..134a7fb06 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -391,7 +391,7 @@ namespace MWMechanics int MechanicsManager::getDerivedDisposition(const MWWorld::Ptr& ptr) { MWMechanics::NpcStats npcSkill = MWWorld::Class::get(ptr).getNpcStats(ptr); - float x = npcSkill.getDisposition(); + float x = npcSkill.getBaseDisposition(); MWWorld::LiveCellRef* npc = ptr.get(); MWWorld::Ptr playerPtr = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); @@ -489,4 +489,10 @@ namespace MWMechanics { return mActors.countDeaths (id); } + + + float MechanicsManager::getPersuasionDispositionChange (MWWorld::Ptr npc, PersuasionType type, bool& success) const + { + return 0.f; + } } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index 0344d951c..1ec65a8af 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -88,6 +88,8 @@ namespace MWMechanics virtual int countDeaths (const std::string& id) const; ///< Return the number of deaths for actors with the given ID. + virtual float getPersuasionDispositionChange (MWWorld::Ptr npc, PersuasionType type, bool& success) const; + ///< Get amount to adjust temporary disposition for a given persuasion action on an NPC }; } diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index 5b2ce739f..70fd29684 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -37,12 +37,12 @@ void MWMechanics::NpcStats::setDrawState (DrawState_ state) mDrawState = state; } -int MWMechanics::NpcStats::getDisposition() const +int MWMechanics::NpcStats::getBaseDisposition() const { return mDisposition; } -void MWMechanics::NpcStats::setDisposition(int disposition) +void MWMechanics::NpcStats::setBaseDisposition(int disposition) { mDisposition = disposition; } diff --git a/apps/openmw/mwmechanics/npcstats.hpp b/apps/openmw/mwmechanics/npcstats.hpp index 35af4afa0..3e39eb7f1 100644 --- a/apps/openmw/mwmechanics/npcstats.hpp +++ b/apps/openmw/mwmechanics/npcstats.hpp @@ -62,9 +62,9 @@ namespace MWMechanics void setDrawState (DrawState_ state); - int getDisposition() const; + int getBaseDisposition() const; - void setDisposition(int disposition); + void setBaseDisposition(int disposition); bool getMovementFlag (Flag flag) const; diff --git a/apps/openmw/mwrender/player.cpp b/apps/openmw/mwrender/player.cpp index bbc75cade..d0b4641b9 100644 --- a/apps/openmw/mwrender/player.cpp +++ b/apps/openmw/mwrender/player.cpp @@ -23,7 +23,8 @@ namespace MWRender mFreeLook(true), mHeight(128.f), mCameraDistance(300.f), - mDistanceAdjusted(false) + mDistanceAdjusted(false), + mAnimation(NULL) { mVanity.enabled = false; mVanity.allowed = true; diff --git a/files/mygui/CMakeLists.txt b/files/mygui/CMakeLists.txt index da8fba62c..562668a90 100644 --- a/files/mygui/CMakeLists.txt +++ b/files/mygui/CMakeLists.txt @@ -80,6 +80,7 @@ set(MYGUI_FILES openmw_enchanting_dialog.layout openmw_trainingwindow.layout openmw_travel_window.layout + openmw_persuasion_dialog.layout smallbars.png VeraMono.ttf markers.png From 33b4b29fbc6285d6aea91b23517751cbe3226960 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 Nov 2012 00:29:36 +0100 Subject: [PATCH 3/8] persuasion mechanics, added reputation --- apps/openmw/mwbase/dialoguemanager.hpp | 3 + apps/openmw/mwbase/mechanicsmanager.hpp | 5 +- apps/openmw/mwclass/npc.cpp | 1 + apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 57 +++++++ apps/openmw/mwdialogue/dialoguemanagerimp.hpp | 5 + apps/openmw/mwgui/dialogue.cpp | 37 ++--- apps/openmw/mwgui/dialogue.hpp | 11 +- .../mwmechanics/mechanicsmanagerimp.cpp | 146 +++++++++++++++++- .../mwmechanics/mechanicsmanagerimp.hpp | 5 +- apps/openmw/mwmechanics/npcstats.cpp | 12 +- apps/openmw/mwmechanics/npcstats.hpp | 5 + 11 files changed, 245 insertions(+), 42 deletions(-) diff --git a/apps/openmw/mwbase/dialoguemanager.hpp b/apps/openmw/mwbase/dialoguemanager.hpp index ccffc6b21..e9854b246 100644 --- a/apps/openmw/mwbase/dialoguemanager.hpp +++ b/apps/openmw/mwbase/dialoguemanager.hpp @@ -40,6 +40,9 @@ namespace MWBase virtual void keywordSelected (const std::string& keyword) = 0; virtual void goodbyeSelected() = 0; virtual void questionAnswered (const std::string& answer) = 0; + + virtual void persuade (int type) = 0; + virtual int getTemporaryDispositionChange () const = 0; }; } diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 0be111ea7..cdee048db 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -95,8 +95,9 @@ namespace MWBase PT_Bribe100, PT_Bribe1000 }; - virtual float getPersuasionDispositionChange (MWWorld::Ptr npc, PersuasionType type, bool& success) const = 0; - ///< Get amount to adjust temporary disposition for a given persuasion action on an NPC + virtual void getPersuasionDispositionChange (const MWWorld::Ptr& npc, PersuasionType type, + float currentTemporaryDispositionDelta, bool& success, float& tempChange, float& permChange) = 0; + ///< Perform a persuasion action on NPC }; } diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index c7f33504e..790d824f5 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -96,6 +96,7 @@ namespace MWClass data->mCreatureStats.setLevel(ref->mBase->mNpdt52.mLevel); data->mNpcStats.setBaseDisposition(ref->mBase->mNpdt52.mDisposition); + data->mNpcStats.setReputation(ref->mBase->mNpdt52.mReputation); } else { diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 46fab0a4b..3eabe7383 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -12,6 +12,7 @@ #include "../mwbase/scriptmanager.hpp" #include "../mwbase/journal.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwbase/mechanicsmanager.hpp" #include "../mwworld/class.hpp" #include "../mwworld/refdata.hpp" @@ -584,6 +585,8 @@ namespace MWDialogue DialogueManager::DialogueManager (const Compiler::Extensions& extensions) : mCompilerContext (MWScript::CompilerContext::Type_Dialgoue), mErrorStream(std::cout.rdbuf()),mErrorHandler(mErrorStream) + , mTemporaryDispositionChange(0.f) + , mPermanentDispositionChange(0.f) { mChoice = -1; mIsInChoice = false; @@ -868,6 +871,12 @@ namespace MWDialogue void DialogueManager::goodbyeSelected() { MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Dialogue); + + // Apply disposition change to NPC's base disposition + MWMechanics::NpcStats npcStats = MWWorld::Class::get(mActor).getNpcStats(mActor); + npcStats.setBaseDisposition(npcStats.getBaseDisposition() + mPermanentDispositionChange); + mPermanentDispositionChange = 0; + mTemporaryDispositionChange = 0; } void DialogueManager::questionAnswered (const std::string& answer) @@ -944,4 +953,52 @@ namespace MWDialogue win->goodbye(); } + + void DialogueManager::persuade(int type) + { + bool success; + float temp, perm; + MWBase::Environment::get().getMechanicsManager()->getPersuasionDispositionChange( + mActor, MWBase::MechanicsManager::PersuasionType(type), mTemporaryDispositionChange, + success, temp, perm); + mTemporaryDispositionChange += temp; + mPermanentDispositionChange += perm; + + // change temp disposition so that final disposition is between 0...100 + int curDisp = MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mActor); + if (curDisp + mTemporaryDispositionChange < 0) + mTemporaryDispositionChange = -curDisp; + else if (curDisp + mTemporaryDispositionChange > 100) + mTemporaryDispositionChange = 100 - curDisp; + + // practice skill + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + + MWWorld::Class::get(player).skillUsageSucceeded(player, ESM::Skill::Speechcraft, 0); + + + // add status message to dialogue window + std::string text; + + if (type == MWBase::MechanicsManager::PT_Admire) + text = "sAdmire"; + else if (type == MWBase::MechanicsManager::PT_Taunt) + text = "sTaunt"; + else if (type == MWBase::MechanicsManager::PT_Intimidate) + text = "sIntimidate"; + else + text = "sBribe"; + + text += (success ? "Success" : "Fail"); + + MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); + win->addTitle(MyGUI::LanguageManager::getInstance().replaceTags("#{"+text+"}")); + + /// \todo text from INFO record, how to get the ID? + } + + int DialogueManager::getTemporaryDispositionChange() const + { + return mTemporaryDispositionChange; + } } diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp index e3e9fd752..d0f48b65a 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp @@ -49,6 +49,9 @@ namespace MWDialogue ESM::DialInfo mLastDialogue; bool mIsInChoice; + float mTemporaryDispositionChange; + float mPermanentDispositionChange; + public: DialogueManager (const Compiler::Extensions& extensions); @@ -69,6 +72,8 @@ namespace MWDialogue virtual void goodbyeSelected(); virtual void questionAnswered (const std::string& answer); + virtual void persuade (int type); + virtual int getTemporaryDispositionChange () const; }; } diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index be7bfde53..d475bc56b 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -14,6 +14,8 @@ #include "../mwbase/windowmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" +#include "../mwmechanics/npcstats.hpp" + #include "dialogue_history.hpp" #include "widgets.hpp" #include "list.hpp" @@ -98,7 +100,8 @@ void PersuasionDialog::onPersuade(MyGUI::Widget *sender) type = MWBase::MechanicsManager::PT_Bribe1000; } - eventPersuade(type, true, 0); + MWBase::Environment::get().getDialogueManager()->persuade(type); + setVisible(false); } @@ -128,7 +131,6 @@ DialogueWindow::DialogueWindow(MWBase::WindowManager& parWindowManager) center(); mPersuasionDialog.setVisible(false); - mPersuasionDialog.eventPersuade += MyGUI::newDelegate(this, &DialogueWindow::onPersuade); //History view getWidget(mHistory, "History"); @@ -212,6 +214,7 @@ void DialogueWindow::onSelectTopic(std::string topic) } if (topic == gmst.find("sPersuasion")->getString()) { + mPersuasionDialog.setPtr(mPtr); mPersuasionDialog.setVisible(true); } else if (topic == gmst.find("sSpells")->getString()) @@ -391,8 +394,6 @@ void DialogueWindow::updateOptions() void DialogueWindow::goodbye() { - // Apply temporary disposition change to NPC's base disposition - mHistory->addDialogText("\n#572D21" + MWBase::Environment::get().getWorld()->getStore().get().find("sGoodbye")->getString()); mTopicsList->setEnabled(false); mEnabled = false; @@ -407,30 +408,12 @@ void DialogueWindow::onFrame() { if(mEnabled && mPtr.getTypeName() == typeid(ESM::NPC).name()) { + int disp = std::max(0, std::min(100, + MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr) + + MWBase::Environment::get().getDialogueManager()->getTemporaryDispositionChange())); mDispositionBar->setProgressRange(100); - mDispositionBar->setProgressPosition(MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr)); + mDispositionBar->setProgressPosition(disp); mDispositionText->eraseText(0, mDispositionText->getTextLength()); - mDispositionText->addText("#B29154"+boost::lexical_cast(MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr))+std::string("/100")+"#B29154"); + mDispositionText->addText("#B29154"+boost::lexical_cast(disp)+std::string("/100")+"#B29154"); } } - -void DialogueWindow::onPersuade(int type, bool success, float dispositionChange) -{ - std::string text; - - if (type == MWBase::MechanicsManager::PT_Admire) - text = "sAdmire"; - else if (type == MWBase::MechanicsManager::PT_Taunt) - text = "sTaunt"; - else if (type == MWBase::MechanicsManager::PT_Intimidate) - text = "sIntimidate"; - else - text = "sBribe"; - - text += success ? "Fail" : "Success"; - - mHistory->addDialogHeading( MyGUI::LanguageManager::getInstance().replaceTags("#{"+text+"}")); - - /// \todo text from INFO record, how to get the ID? - //mHistory->addDialogText(); -} diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index 3d0d74d95..134792226 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -33,9 +33,7 @@ namespace MWGui virtual void open(); - typedef MyGUI::delegates::CMultiDelegate3 EventHandle_Persuade; - - EventHandle_Persuade eventPersuade; + void setPtr(MWWorld::Ptr ptr) { mPtr = ptr; } private: MyGUI::Button* mCancelButton; @@ -49,6 +47,8 @@ namespace MWGui void onCancel (MyGUI::Widget* sender); void onPersuade (MyGUI::Widget* sender); + + MWWorld::Ptr mPtr; }; class DialogueWindow: public WindowBase, public ReferenceInterface @@ -113,11 +113,6 @@ namespace MWGui MyGUI::EditPtr mDispositionText; PersuasionDialog mPersuasionDialog; - - - float mTemporaryDispositionChange; - - void onPersuade (int type, bool success, float dispositionChange); }; } #endif diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 134a7fb06..797369e26 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -491,8 +491,150 @@ namespace MWMechanics } - float MechanicsManager::getPersuasionDispositionChange (MWWorld::Ptr npc, PersuasionType type, bool& success) const + void MechanicsManager::getPersuasionDispositionChange (const MWWorld::Ptr& npc, PersuasionType type, + float currentTemporaryDispositionDelta, bool& success, float& tempChange, float& permChange) { - return 0.f; + const MWWorld::Store &gmst = + MWBase::Environment::get().getWorld()->getStore().get(); + + MWWorld::Ptr playerPtr = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWMechanics::NpcStats playerSkill = MWWorld::Class::get(playerPtr).getNpcStats(playerPtr); + MWMechanics::CreatureStats playerStats = MWWorld::Class::get(playerPtr).getCreatureStats(playerPtr); + + MWMechanics::NpcStats npcSkill = MWWorld::Class::get(npc).getNpcStats(npc); + MWMechanics::CreatureStats npcStats = MWWorld::Class::get(npc).getCreatureStats(npc); + + + float persTerm = playerStats.getAttribute(ESM::Attribute::Personality).getModified() + / gmst.find("fPersonalityMod")->getFloat(); + + float luckTerm = playerStats.getAttribute(ESM::Attribute::Luck).getModified() + / gmst.find("fLuckMod")->getFloat(); + + float repTerm = playerSkill.getReputation() * gmst.find("fReputationMod")->getFloat(); + + float levelTerm = playerStats.getLevel() * gmst.find("fLevelMod")->getFloat(); + + float fatigueTerm = playerStats.getFatigueTerm(); + + float playerRating1 = (repTerm + luckTerm + persTerm + playerSkill.getSkill(ESM::Skill::Speechcraft).getModified()) * fatigueTerm; + float playerRating2 = playerRating1 + levelTerm; + float playerRating3 = (playerSkill.getSkill(ESM::Skill::Mercantile).getModified() + luckTerm + persTerm) * fatigueTerm; + + float npcRating1 = (repTerm + luckTerm + persTerm + playerSkill.getSkill(ESM::Skill::Speechcraft).getModified()) * fatigueTerm; + float npcRating2 = (levelTerm + repTerm + luckTerm + persTerm + npcSkill.getSkill(ESM::Skill::Speechcraft).getModified()) * fatigueTerm; + float npcRating3 = (playerSkill.getSkill(ESM::Skill::Mercantile).getModified() + repTerm + luckTerm + persTerm) * fatigueTerm; + + int currentDisposition = std::min(100, std::max(0, int(getDerivedDisposition(npc) + currentTemporaryDispositionDelta))); + + float d = 1 - 0.02 * abs(currentDisposition - 50); + float target1 = d * (playerRating1 - npcRating1 + 50); + float target2 = d * (playerRating2 - npcRating2 + 50); + + float bribeMod; + if (type == PT_Bribe10) bribeMod = gmst.find("fBribe10Mod")->getFloat(); + if (type == PT_Bribe100) bribeMod = gmst.find("fBribe100Mod")->getFloat(); + else bribeMod = gmst.find("fBribe1000Mod")->getFloat(); + + float target3 = d * (playerRating3 - npcRating3 + 50) + bribeMod; + + float iPerMinChance = gmst.find("iPerMinChance")->getInt(); + float iPerMinChange = gmst.find("iPerMinChange")->getInt(); + float fPerDieRollMult = gmst.find("fPerDieRollMult")->getFloat(); + float fPerTempMult = gmst.find("fPerTempMult")->getFloat(); + + float x,y; + + float roll = static_cast (std::rand()) / RAND_MAX * 100; + + if (type == PT_Admire) + { + target1 = std::max(iPerMinChance, target1); + success = (roll <= target1); + float c = int(fPerDieRollMult * (target1 - roll)); + x = success ? std::max(iPerMinChange, c) : c; + } + else if (type == PT_Intimidate) + { + target2 = std::max(iPerMinChance, target2); + + success = (roll <= target2); + + float r; + if (roll != target2) + r = int(target2 - roll); + else + r = 1; + + if (roll <= target2) + { + float s = int(r * fPerDieRollMult * fPerTempMult); + + npcStats.setFlee ( std::max(0, std::min(100, npcStats.getFlee() + int(std::max(iPerMinChange, s))))); + npcStats.setFight ( std::max(0, std::min(100, npcStats.getFight() + int(std::min(-iPerMinChange, -s))))); + } + + float c = -std::abs(int(r * fPerDieRollMult)); + if (success) + { + if (std::abs(c) < iPerMinChange) + { + x = 0; + y = -iPerMinChange; + } + else + { + x = -int(c * fPerTempMult); + y = c; + } + } + else + { + x = int(c * fPerTempMult); + y = c; + } + } + else if (type == PT_Taunt) + { + target1 = std::max(iPerMinChance, target1); + success = (roll <= target1); + + float c = std::abs(int(target1 - roll)); + + if (roll <= target1) + { + float s = c * fPerDieRollMult * fPerTempMult; + + npcStats.setFlee ( std::max(0, std::min(100, npcStats.getFlee() + std::min(-int(iPerMinChange), int(-s))))); + npcStats.setFight ( std::max(0, std::min(100, npcStats.getFight() + std::max(int(iPerMinChange), int(s))))); + } + x = int(-c * fPerDieRollMult); + + if (success && std::abs(x) < iPerMinChange) + x = -iPerMinChange; + } + else // Bribe + { + target3 = std::max(iPerMinChance, target3); + success = (roll <= target3); + float c = int((target3 - roll) * fPerDieRollMult); + + x = success ? std::max(iPerMinChange, c) : c; + } + + tempChange = type == PT_Intimidate ? x : int(x * fPerTempMult); + + + float cappedDispositionChange = tempChange; + if (currentDisposition + tempChange > 100.f) + cappedDispositionChange = 100 - currentDisposition; + if (currentDisposition + tempChange < 0.f) + cappedDispositionChange = -currentDisposition; + + permChange = int(cappedDispositionChange / fPerTempMult); + if (type == PT_Intimidate) + { + permChange = success ? -int(cappedDispositionChange/ fPerTempMult) : y; + } } } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index 1ec65a8af..b03eacecc 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -88,8 +88,9 @@ namespace MWMechanics virtual int countDeaths (const std::string& id) const; ///< Return the number of deaths for actors with the given ID. - virtual float getPersuasionDispositionChange (MWWorld::Ptr npc, PersuasionType type, bool& success) const; - ///< Get amount to adjust temporary disposition for a given persuasion action on an NPC + virtual void getPersuasionDispositionChange (const MWWorld::Ptr& npc, PersuasionType type, + float currentTemporaryDispositionDelta, bool& success, float& tempChange, float& permChange); + ///< Perform a persuasion action on NPC }; } diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index 70fd29684..f37a45b49 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -19,7 +19,7 @@ MWMechanics::NpcStats::NpcStats() : mMovementFlags (0), mDrawState (DrawState_Nothing), mBounty (0) -, mLevelProgress(0), mDisposition(0) +, mLevelProgress(0), mDisposition(0), mReputation(0) { mSkillIncreases.resize (ESM::Attribute::Length); @@ -259,3 +259,13 @@ void MWMechanics::NpcStats::setBounty (int bounty) { mBounty = bounty; } + +int MWMechanics::NpcStats::getReputation() const +{ + return mReputation; +} + +void MWMechanics::NpcStats::setReputation(int reputation) +{ + mReputation = reputation; +} diff --git a/apps/openmw/mwmechanics/npcstats.hpp b/apps/openmw/mwmechanics/npcstats.hpp index 3e39eb7f1..b6abbd342 100644 --- a/apps/openmw/mwmechanics/npcstats.hpp +++ b/apps/openmw/mwmechanics/npcstats.hpp @@ -47,6 +47,7 @@ namespace MWMechanics unsigned int mMovementFlags; Stat mSkill[27]; int mBounty; + int mReputation; int mLevelProgress; // 0-10 @@ -66,6 +67,10 @@ namespace MWMechanics void setBaseDisposition(int disposition); + int getReputation() const; + + void setReputation(int reputation); + bool getMovementFlag (Flag flag) const; void setMovementFlag (Flag flag, bool state); From 94aeb152202798757e1a246b9e22de953d401454 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 Nov 2012 00:38:45 +0100 Subject: [PATCH 4/8] bartering disposition change --- apps/openmw/mwbase/dialoguemanager.hpp | 1 + apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 12 ++++++++++-- apps/openmw/mwdialogue/dialoguemanagerimp.hpp | 1 + apps/openmw/mwgui/tradewindow.cpp | 14 +++++++++----- 4 files changed, 21 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwbase/dialoguemanager.hpp b/apps/openmw/mwbase/dialoguemanager.hpp index e9854b246..2181ddb58 100644 --- a/apps/openmw/mwbase/dialoguemanager.hpp +++ b/apps/openmw/mwbase/dialoguemanager.hpp @@ -43,6 +43,7 @@ namespace MWBase virtual void persuade (int type) = 0; virtual int getTemporaryDispositionChange () const = 0; + virtual void applyTemporaryDispositionChange (int delta) = 0; }; } diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 3eabe7383..60ccda09f 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -873,8 +873,11 @@ namespace MWDialogue MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Dialogue); // Apply disposition change to NPC's base disposition - MWMechanics::NpcStats npcStats = MWWorld::Class::get(mActor).getNpcStats(mActor); - npcStats.setBaseDisposition(npcStats.getBaseDisposition() + mPermanentDispositionChange); + if (mActor.getTypeName() == typeid(ESM::NPC).name()) + { + MWMechanics::NpcStats npcStats = MWWorld::Class::get(mActor).getNpcStats(mActor); + npcStats.setBaseDisposition(npcStats.getBaseDisposition() + mPermanentDispositionChange); + } mPermanentDispositionChange = 0; mTemporaryDispositionChange = 0; } @@ -1001,4 +1004,9 @@ namespace MWDialogue { return mTemporaryDispositionChange; } + + void DialogueManager::applyTemporaryDispositionChange(int delta) + { + mTemporaryDispositionChange += delta; + } } diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp index d0f48b65a..a8dea3dba 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp @@ -74,6 +74,7 @@ namespace MWDialogue virtual void persuade (int type); virtual int getTemporaryDispositionChange () const; + virtual void applyTemporaryDispositionChange (int delta); }; } diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 0707ad985..c6a21c461 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -7,6 +7,7 @@ #include "../mwbase/soundmanager.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" +#include "../mwbase/dialoguemanager.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwworld/manualref.hpp" @@ -206,7 +207,8 @@ namespace MWGui if (mCurrentMerchantOffer<0) d = int(100 * (a - b) / a); else d = int(100 * (b - a) / a); - float clampedDisposition = std::max(0,std::min(int(MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr)),100)); + float clampedDisposition = std::max(0,std::min(int(MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr) + + MWBase::Environment::get().getDialogueManager()->getTemporaryDispositionChange()),100)); MWMechanics::NpcStats sellerSkill = MWWorld::Class::get(mPtr).getNpcStats(mPtr); MWMechanics::CreatureStats sellerStats = MWWorld::Class::get(mPtr).getCreatureStats(mPtr); @@ -232,13 +234,15 @@ namespace MWGui { MWBase::Environment::get().getWindowManager()-> messageBox("#{sNotifyMessage9}", std::vector()); - /// \todo adjust npc temporary disposition by iBarterSuccessDisposition or iBarterFailDisposition - return ; + + int iBarterFailDisposition = gmst.find("iBarterFailDisposition")->getInt(); + MWBase::Environment::get().getDialogueManager()->applyTemporaryDispositionChange(iBarterFailDisposition); + return; } } - -/// \todo adjust npc temporary disposition by iBarterSuccessDisposition or iBarterFailDisposition + int iBarterSuccessDisposition = gmst.find("iBarterSuccessDisposition")->getInt(); + MWBase::Environment::get().getDialogueManager()->applyTemporaryDispositionChange(iBarterSuccessDisposition); // success! make the item transfer. transferBoughtItems(); From 553ea08eae85562e137d07c4f0597df3dc81a245 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 Nov 2012 00:42:31 +0100 Subject: [PATCH 5/8] consider temporary disposition change when trading --- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 797369e26..e0c028b53 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -6,6 +6,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwbase/dialoguemanager.hpp" #include "../mwworld/class.hpp" #include "../mwworld/player.hpp" @@ -462,7 +463,10 @@ namespace MWMechanics MWMechanics::NpcStats playerSkill = MWWorld::Class::get(playerPtr).getNpcStats(playerPtr); MWMechanics::CreatureStats playerStats = MWWorld::Class::get(playerPtr).getCreatureStats(playerPtr); - int clampedDisposition = std::min(getDerivedDisposition(ptr),100); + // I suppose the temporary disposition change _has_ to be considered here, + // otherwise one would get different prices when exiting and re-entering the dialogue window... + int clampedDisposition = std::max(0, std::min(getDerivedDisposition(ptr) + + MWBase::Environment::get().getDialogueManager()->getTemporaryDispositionChange(),100)); float a = std::min(playerSkill.getSkill(ESM::Skill::Mercantile).getModified(), 100.f); float b = std::min(0.1f * playerStats.getAttribute(ESM::Attribute::Luck).getModified(), 10.f); float c = std::min(0.2f * playerStats.getAttribute(ESM::Attribute::Personality).getModified(), 10.f); From 92bba182189de2baacb21312d61cbfb267294f33 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 Nov 2012 00:47:24 +0100 Subject: [PATCH 6/8] removed useless member --- apps/openmw/mwgui/dialogue.cpp | 1 - apps/openmw/mwgui/dialogue.hpp | 4 ---- 2 files changed, 5 deletions(-) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index d475bc56b..e4c9945b4 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -214,7 +214,6 @@ void DialogueWindow::onSelectTopic(std::string topic) } if (topic == gmst.find("sPersuasion")->getString()) { - mPersuasionDialog.setPtr(mPtr); mPersuasionDialog.setVisible(true); } else if (topic == gmst.find("sSpells")->getString()) diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index 134792226..082d92524 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -33,8 +33,6 @@ namespace MWGui virtual void open(); - void setPtr(MWWorld::Ptr ptr) { mPtr = ptr; } - private: MyGUI::Button* mCancelButton; MyGUI::Button* mAdmireButton; @@ -47,8 +45,6 @@ namespace MWGui void onCancel (MyGUI::Widget* sender); void onPersuade (MyGUI::Widget* sender); - - MWWorld::Ptr mPtr; }; class DialogueWindow: public WindowBase, public ReferenceInterface From 5fdc7ad809f380360965efe05160d4dd65e4e483 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 Nov 2012 13:07:26 +0100 Subject: [PATCH 7/8] forgot to add file --- files/mygui/openmw_persuasion_dialog.layout | 49 +++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 files/mygui/openmw_persuasion_dialog.layout diff --git a/files/mygui/openmw_persuasion_dialog.layout b/files/mygui/openmw_persuasion_dialog.layout new file mode 100644 index 000000000..87851b479 --- /dev/null +++ b/files/mygui/openmw_persuasion_dialog.layout @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 7b1788b03bbc26f7f4b09be5e0d6aead65987c8a Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 10 Nov 2012 15:11:21 +0100 Subject: [PATCH 8/8] minor fix --- apps/openmw/mwrender/player.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/player.cpp b/apps/openmw/mwrender/player.cpp index 4b0b562c4..857878811 100644 --- a/apps/openmw/mwrender/player.cpp +++ b/apps/openmw/mwrender/player.cpp @@ -24,8 +24,7 @@ namespace MWRender mFreeLook(true), mHeight(128.f), mCameraDistance(300.f), - mDistanceAdjusted(false), - mAnimation(NULL) + mDistanceAdjusted(false) { mVanity.enabled = false; mVanity.allowed = true;