forked from mirror/openmw-tes3mp
persuasion mechanics, added reputation
This commit is contained in:
parent
ace9ee9c83
commit
33b4b29fbc
11 changed files with 245 additions and 42 deletions
|
@ -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…
Reference in a new issue