diff --git a/apps/openmw/mwbase/dialoguemanager.hpp b/apps/openmw/mwbase/dialoguemanager.hpp index ccffc6b21..2181ddb58 100644 --- a/apps/openmw/mwbase/dialoguemanager.hpp +++ b/apps/openmw/mwbase/dialoguemanager.hpp @@ -40,6 +40,10 @@ 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; + virtual void applyTemporaryDispositionChange (int delta) = 0; }; } diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 164f1644d..a1023c986 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -85,6 +85,19 @@ 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 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 6a516bcc8..790d824f5 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -95,7 +95,8 @@ 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); + data->mNpcStats.setReputation(ref->mBase->mNpdt52.mReputation); } else { diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 46fab0a4b..60ccda09f 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,15 @@ namespace MWDialogue void DialogueManager::goodbyeSelected() { MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Dialogue); + + // Apply disposition change to NPC's base disposition + 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; } void DialogueManager::questionAnswered (const std::string& answer) @@ -944,4 +956,57 @@ 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; + } + + void DialogueManager::applyTemporaryDispositionChange(int delta) + { + mTemporaryDispositionChange += delta; + } } diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp index e3e9fd752..a8dea3dba 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,9 @@ namespace MWDialogue virtual void goodbyeSelected(); virtual void questionAnswered (const std::string& answer); + virtual void persuade (int type); + virtual int getTemporaryDispositionChange () const; + virtual void applyTemporaryDispositionChange (int delta); }; } diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index e1baaf8e0..e4c9945b4 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" @@ -49,14 +51,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; + } + + MWBase::Environment::get().getDialogueManager()->persuade(type); + + 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); + //History view getWidget(mHistory, "History"); mHistory->setOverflowToTheLeft(true); @@ -137,6 +212,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 +266,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()); @@ -325,9 +407,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"); } } diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index bb9acf5db..082d92524 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -26,6 +26,27 @@ namespace MWGui { class DialogueHistory; + class PersuasionDialog : public WindowModal + { + public: + PersuasionDialog(MWBase::WindowManager& parWindowManager); + + virtual void open(); + + 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 +107,8 @@ namespace MWGui Widgets::MWList* mTopicsList; MyGUI::ProgressPtr mDispositionBar; MyGUI::EditPtr mDispositionText; + + PersuasionDialog mPersuasionDialog; }; } #endif 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(); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 69ad65a8d..2d59b87f8 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" @@ -389,7 +390,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(); @@ -460,7 +461,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); @@ -487,4 +491,152 @@ namespace MWMechanics { return mActors.countDeaths (id); } + + + void MechanicsManager::getPersuasionDispositionChange (const MWWorld::Ptr& npc, PersuasionType type, + float currentTemporaryDispositionDelta, bool& success, float& tempChange, float& permChange) + { + 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 5e07725c5..f8d470a4e 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -88,6 +88,9 @@ namespace MWMechanics virtual int countDeaths (const std::string& id) const; ///< Return the number of deaths for actors with the given ID. + 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 5b2ce739f..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); @@ -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; } @@ -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 35af4afa0..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 @@ -62,9 +63,13 @@ namespace MWMechanics void setDrawState (DrawState_ state); - int getDisposition() const; + int getBaseDisposition() const; - void setDisposition(int disposition); + void setBaseDisposition(int disposition); + + int getReputation() const; + + void setReputation(int reputation); bool getMovementFlag (Flag flag) const; diff --git a/apps/openmw/mwrender/player.cpp b/apps/openmw/mwrender/player.cpp index 857878811..4b0b562c4 100644 --- a/apps/openmw/mwrender/player.cpp +++ b/apps/openmw/mwrender/player.cpp @@ -24,7 +24,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 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 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +