persuasion mechanics, added reputation

actorid
scrawl 12 years ago
parent ace9ee9c83
commit 33b4b29fbc

@ -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;
};
}

@ -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
};
}

@ -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
{

@ -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;
}
}

@ -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;
};
}

@ -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<ESM::GameSetting>().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<std::string>(MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr))+std::string("/100")+"#B29154");
mDispositionText->addText("#B29154"+boost::lexical_cast<std::string>(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();
}

@ -33,9 +33,7 @@ namespace MWGui
virtual void open();
typedef MyGUI::delegates::CMultiDelegate3<int, bool, float> 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

@ -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<ESM::GameSetting> &gmst =
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
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<float> (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;
}
}
}

@ -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
};
}

@ -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;
}

@ -47,6 +47,7 @@ namespace MWMechanics
unsigned int mMovementFlags;
Stat<float> 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);

Loading…
Cancel
Save