forked from teamnwah/openmw-tes3coop
Merge branch 'dialogue'
commit
cbb0fd5792
@ -0,0 +1,494 @@
|
||||
|
||||
#include "filter.hpp"
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/journal.hpp"
|
||||
#include "../mwbase/mechanicsmanager.hpp"
|
||||
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwworld/player.hpp"
|
||||
#include "../mwworld/containerstore.hpp"
|
||||
#include "../mwworld/inventorystore.hpp"
|
||||
|
||||
#include "../mwmechanics/npcstats.hpp"
|
||||
#include "../mwmechanics/creaturestats.hpp"
|
||||
#include "../mwmechanics/magiceffects.hpp"
|
||||
|
||||
#include "selectwrapper.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
std::string toLower (const std::string& name)
|
||||
{
|
||||
std::string lowerCase;
|
||||
|
||||
std::transform (name.begin(), name.end(), std::back_inserter (lowerCase),
|
||||
(int(*)(int)) std::tolower);
|
||||
|
||||
return lowerCase;
|
||||
}
|
||||
}
|
||||
|
||||
bool MWDialogue::Filter::testActor (const ESM::DialInfo& info) const
|
||||
{
|
||||
// actor id
|
||||
if (!info.mActor.empty())
|
||||
if (toLower (info.mActor)!=MWWorld::Class::get (mActor).getId (mActor))
|
||||
return false;
|
||||
|
||||
bool isCreature = (mActor.getTypeName() != typeid (ESM::NPC).name());
|
||||
|
||||
// NPC race
|
||||
if (!info.mRace.empty())
|
||||
{
|
||||
if (isCreature)
|
||||
return false;
|
||||
|
||||
MWWorld::LiveCellRef<ESM::NPC> *cellRef = mActor.get<ESM::NPC>();
|
||||
|
||||
if (toLower (info.mRace)!=toLower (cellRef->mBase->mRace))
|
||||
return false;
|
||||
}
|
||||
|
||||
// NPC class
|
||||
if (!info.mClass.empty())
|
||||
{
|
||||
if (isCreature)
|
||||
return false;
|
||||
|
||||
MWWorld::LiveCellRef<ESM::NPC> *cellRef = mActor.get<ESM::NPC>();
|
||||
|
||||
if (toLower (info.mClass)!=toLower (cellRef->mBase->mClass))
|
||||
return false;
|
||||
}
|
||||
|
||||
// NPC faction
|
||||
if (!info.mNpcFaction.empty())
|
||||
{
|
||||
if (isCreature)
|
||||
return false;
|
||||
|
||||
MWMechanics::NpcStats& stats = MWWorld::Class::get (mActor).getNpcStats (mActor);
|
||||
std::map<std::string, int>::iterator iter = stats.getFactionRanks().find (toLower (info.mNpcFaction));
|
||||
|
||||
if (iter==stats.getFactionRanks().end())
|
||||
return false;
|
||||
|
||||
// check rank
|
||||
if (iter->second < info.mData.mRank)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Gender
|
||||
if (!isCreature)
|
||||
{
|
||||
MWWorld::LiveCellRef<ESM::NPC>* npc = mActor.get<ESM::NPC>();
|
||||
if (info.mData.mGender==(npc->mBase->mFlags & npc->mBase->Female ? 0 : 1))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MWDialogue::Filter::testPlayer (const ESM::DialInfo& info) const
|
||||
{
|
||||
const MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
|
||||
|
||||
// check player faction
|
||||
if (!info.mPcFaction.empty())
|
||||
{
|
||||
MWMechanics::NpcStats& stats = MWWorld::Class::get (player).getNpcStats (player);
|
||||
std::map<std::string,int>::iterator iter = stats.getFactionRanks().find (toLower (info.mPcFaction));
|
||||
|
||||
if(iter==stats.getFactionRanks().end())
|
||||
return false;
|
||||
|
||||
// check rank
|
||||
if (iter->second < info.mData.mPCrank)
|
||||
return false;
|
||||
}
|
||||
|
||||
// check cell
|
||||
if (!info.mCell.empty())
|
||||
if (toLower (player.getCell()->mCell->mName) != toLower (info.mCell))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MWDialogue::Filter::testSelectStructs (const ESM::DialInfo& info) const
|
||||
{
|
||||
for (std::vector<ESM::DialInfo::SelectStruct>::const_iterator iter (info.mSelects.begin());
|
||||
iter != info.mSelects.end(); ++iter)
|
||||
if (!testSelectStruct (*iter))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MWDialogue::Filter::testSelectStruct (const SelectWrapper& select) const
|
||||
{
|
||||
if (select.isNpcOnly() && mActor.getTypeName()!=typeid (ESM::NPC).name())
|
||||
return select.isInverted();
|
||||
|
||||
switch (select.getType())
|
||||
{
|
||||
case SelectWrapper::Type_None: return true;
|
||||
case SelectWrapper::Type_Integer: return select.selectCompare (getSelectStructInteger (select));
|
||||
case SelectWrapper::Type_Numeric: return testSelectStructNumeric (select);
|
||||
case SelectWrapper::Type_Boolean: return select.selectCompare (getSelectStructBoolean (select));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MWDialogue::Filter::testSelectStructNumeric (const SelectWrapper& select) const
|
||||
{
|
||||
switch (select.getFunction())
|
||||
{
|
||||
case SelectWrapper::Function_Global:
|
||||
|
||||
// internally all globals are float :(
|
||||
return select.selectCompare (
|
||||
MWBase::Environment::get().getWorld()->getGlobalVariable (select.getName()).mFloat);
|
||||
|
||||
case SelectWrapper::Function_Local:
|
||||
{
|
||||
std::string scriptName = MWWorld::Class::get (mActor).getScript (mActor);
|
||||
|
||||
if (scriptName.empty())
|
||||
return false; // no script
|
||||
|
||||
const ESM::Script *script =
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::Script>().find (scriptName);
|
||||
|
||||
std::string name = select.getName();
|
||||
|
||||
int i = 0;
|
||||
|
||||
for (; i<static_cast<int> (script->mVarNames.size()); ++i)
|
||||
if (script->mVarNames[i]==name)
|
||||
break;
|
||||
|
||||
if (i>=static_cast<int> (script->mVarNames.size()))
|
||||
return false; // script does not have a variable of this name
|
||||
|
||||
const MWScript::Locals& locals = mActor.getRefData().getLocals();
|
||||
|
||||
if (i<script->mData.mNumShorts)
|
||||
return select.selectCompare (static_cast<int> (locals.mShorts[i]));
|
||||
|
||||
i -= script->mData.mNumShorts;
|
||||
|
||||
if (i<script->mData.mNumLongs)
|
||||
return select.selectCompare (locals.mLongs[i]);
|
||||
|
||||
i -= script->mData.mNumShorts;
|
||||
|
||||
return select.selectCompare (locals.mFloats.at (i));
|
||||
}
|
||||
|
||||
case SelectWrapper::Function_PcHealthPercent:
|
||||
{
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
|
||||
|
||||
float ratio = MWWorld::Class::get (player).getCreatureStats (player).getHealth().getCurrent() /
|
||||
MWWorld::Class::get (player).getCreatureStats (player).getHealth().getModified();
|
||||
|
||||
return select.selectCompare (ratio);
|
||||
}
|
||||
|
||||
case SelectWrapper::Function_PcDynamicStat:
|
||||
{
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
|
||||
|
||||
float value = MWWorld::Class::get (player).getCreatureStats (player).
|
||||
getDynamic (select.getArgument()).getCurrent();
|
||||
|
||||
return select.selectCompare (value);
|
||||
}
|
||||
|
||||
case SelectWrapper::Function_HealthPercent:
|
||||
{
|
||||
float ratio = MWWorld::Class::get (mActor).getCreatureStats (mActor).getHealth().getCurrent() /
|
||||
MWWorld::Class::get (mActor).getCreatureStats (mActor).getHealth().getModified();
|
||||
|
||||
return select.selectCompare (ratio);
|
||||
}
|
||||
|
||||
default:
|
||||
|
||||
throw std::runtime_error ("unknown numeric select function");
|
||||
}
|
||||
}
|
||||
|
||||
int MWDialogue::Filter::getSelectStructInteger (const SelectWrapper& select) const
|
||||
{
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
|
||||
|
||||
switch (select.getFunction())
|
||||
{
|
||||
case SelectWrapper::Function_Journal:
|
||||
|
||||
return MWBase::Environment::get().getJournal()->getJournalIndex (select.getName());
|
||||
|
||||
case SelectWrapper::Function_Item:
|
||||
{
|
||||
MWWorld::ContainerStore& store = MWWorld::Class::get (player).getContainerStore (player);
|
||||
|
||||
int sum = 0;
|
||||
|
||||
std::string name = select.getName();
|
||||
|
||||
for (MWWorld::ContainerStoreIterator iter (store.begin()); iter!=store.end(); ++iter)
|
||||
if (toLower(iter->getCellRef().mRefID) == name)
|
||||
sum += iter->getRefData().getCount();
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
case SelectWrapper::Function_Dead:
|
||||
|
||||
return MWBase::Environment::get().getMechanicsManager()->countDeaths (select.getName());
|
||||
|
||||
case SelectWrapper::Function_Choice:
|
||||
|
||||
return mChoice;
|
||||
|
||||
case SelectWrapper::Function_AiSetting:
|
||||
|
||||
return MWWorld::Class::get (mActor).getCreatureStats (mActor).getAiSetting (select.getArgument());
|
||||
|
||||
case SelectWrapper::Function_PcAttribute:
|
||||
|
||||
return MWWorld::Class::get (player).getCreatureStats (player).
|
||||
getAttribute (select.getArgument()).getModified();
|
||||
|
||||
case SelectWrapper::Function_PcSkill:
|
||||
|
||||
return static_cast<int> (MWWorld::Class::get (player).
|
||||
getNpcStats (player).getSkill (select.getArgument()).getModified());
|
||||
|
||||
case SelectWrapper::Function_FriendlyHit:
|
||||
{
|
||||
int hits = MWWorld::Class::get (mActor).getCreatureStats (mActor).getFriendlyHits();
|
||||
|
||||
return hits>4 ? 4 : hits;
|
||||
}
|
||||
|
||||
case SelectWrapper::Function_PcLevel:
|
||||
|
||||
return MWWorld::Class::get (player).getCreatureStats (player).getLevel();
|
||||
|
||||
case SelectWrapper::Function_PcGender:
|
||||
|
||||
return player.get<ESM::NPC>()->mBase->mFlags & ESM::NPC::Female ? 0 : 1;
|
||||
|
||||
case SelectWrapper::Function_PcClothingModifier:
|
||||
{
|
||||
MWWorld::InventoryStore& store = MWWorld::Class::get (player).getInventoryStore (player);
|
||||
|
||||
int value = 0;
|
||||
|
||||
for (int i=0; i<=15; ++i) // everything except thigns held in hands and amunition
|
||||
{
|
||||
MWWorld::ContainerStoreIterator slot = store.getSlot (i);
|
||||
|
||||
if (slot!=store.end())
|
||||
value += MWWorld::Class::get (*slot).getValue (*slot);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
case SelectWrapper::Function_PcCrimeLevel:
|
||||
|
||||
return MWWorld::Class::get (player).getNpcStats (player).getBounty();
|
||||
|
||||
case SelectWrapper::Function_RankRequirement:
|
||||
{
|
||||
if (MWWorld::Class::get (mActor).getNpcStats (mActor).getFactionRanks().empty())
|
||||
return 0;
|
||||
|
||||
std::string faction =
|
||||
MWWorld::Class::get (mActor).getNpcStats (mActor).getFactionRanks().begin()->first;
|
||||
|
||||
int rank = getFactionRank (player, faction);
|
||||
|
||||
if (rank>=9)
|
||||
return 0; // max rank
|
||||
|
||||
int result = 0;
|
||||
|
||||
if (hasFactionRankSkillRequirements (player, faction, rank+1))
|
||||
result += 1;
|
||||
|
||||
if (hasFactionRankReputationRequirements (player, faction, rank+1))
|
||||
result += 2;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
case SelectWrapper::Function_Level:
|
||||
|
||||
return MWWorld::Class::get (mActor).getCreatureStats (mActor).getLevel();
|
||||
|
||||
case SelectWrapper::Function_PCReputation:
|
||||
|
||||
return MWWorld::Class::get (player).getNpcStats (player).getReputation();
|
||||
|
||||
default:
|
||||
|
||||
throw std::runtime_error ("unknown integer select function");
|
||||
}
|
||||
}
|
||||
|
||||
bool MWDialogue::Filter::getSelectStructBoolean (const SelectWrapper& select) const
|
||||
{
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
|
||||
|
||||
switch (select.getFunction())
|
||||
{
|
||||
case SelectWrapper::Function_False:
|
||||
|
||||
return false;
|
||||
|
||||
case SelectWrapper::Function_Id:
|
||||
|
||||
return select.getName()==toLower (MWWorld::Class::get (mActor).getId (mActor));
|
||||
|
||||
case SelectWrapper::Function_Faction:
|
||||
|
||||
return toLower (mActor.get<ESM::NPC>()->mBase->mFaction)==select.getName();
|
||||
|
||||
case SelectWrapper::Function_Class:
|
||||
|
||||
return toLower (mActor.get<ESM::NPC>()->mBase->mClass)==select.getName();
|
||||
|
||||
case SelectWrapper::Function_Race:
|
||||
|
||||
return toLower (mActor.get<ESM::NPC>()->mBase->mRace)==select.getName();
|
||||
|
||||
case SelectWrapper::Function_Cell:
|
||||
|
||||
return toLower (mActor.getCell()->mCell->mName)==select.getName();
|
||||
|
||||
case SelectWrapper::Function_SameGender:
|
||||
|
||||
return (player.get<ESM::NPC>()->mBase->mFlags & ESM::NPC::Female)==
|
||||
(mActor.get<ESM::NPC>()->mBase->mFlags & ESM::NPC::Female);
|
||||
|
||||
case SelectWrapper::Function_SameRace:
|
||||
|
||||
return toLower (mActor.get<ESM::NPC>()->mBase->mRace)!=
|
||||
toLower (player.get<ESM::NPC>()->mBase->mRace);
|
||||
|
||||
case SelectWrapper::Function_SameFaction:
|
||||
|
||||
return MWWorld::Class::get (mActor).getNpcStats (mActor).isSameFaction (
|
||||
MWWorld::Class::get (player).getNpcStats (player));
|
||||
|
||||
case SelectWrapper::Function_PcCommonDisease:
|
||||
|
||||
return MWWorld::Class::get (player).getCreatureStats (player).hasCommonDisease();
|
||||
|
||||
case SelectWrapper::Function_PcBlightDisease:
|
||||
|
||||
return MWWorld::Class::get (player).getCreatureStats (player).hasBlightDisease();
|
||||
|
||||
case SelectWrapper::Function_PcCorprus:
|
||||
|
||||
return MWWorld::Class::get (player).getCreatureStats (player).
|
||||
getMagicEffects().get (132).mMagnitude!=0;
|
||||
|
||||
case SelectWrapper::Function_PcExpelled:
|
||||
{
|
||||
if (MWWorld::Class::get (mActor).getNpcStats (mActor).getFactionRanks().empty())
|
||||
return false;
|
||||
|
||||
std::string faction =
|
||||
MWWorld::Class::get (mActor).getNpcStats (mActor).getFactionRanks().begin()->first;
|
||||
|
||||
std::set<std::string>& expelled = MWWorld::Class::get (player).getNpcStats (player).getExpelled();
|
||||
|
||||
return expelled.find (faction)!=expelled.end();
|
||||
}
|
||||
|
||||
case SelectWrapper::Function_PcVampire:
|
||||
|
||||
return MWWorld::Class::get (player).getNpcStats (player).isVampire();
|
||||
|
||||
case SelectWrapper::Function_TalkedToPc:
|
||||
|
||||
return mTalkedToPlayer;
|
||||
|
||||
default:
|
||||
|
||||
throw std::runtime_error ("unknown boolean select function");
|
||||
}
|
||||
}
|
||||
|
||||
int MWDialogue::Filter::getFactionRank (const MWWorld::Ptr& actor, const std::string& factionId) const
|
||||
{
|
||||
MWMechanics::NpcStats& stats = MWWorld::Class::get (actor).getNpcStats (actor);
|
||||
|
||||
std::map<std::string, int>::const_iterator iter = stats.getFactionRanks().find (factionId);
|
||||
|
||||
if (iter==stats.getFactionRanks().end())
|
||||
return -1;
|
||||
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
bool MWDialogue::Filter::hasFactionRankSkillRequirements (const MWWorld::Ptr& actor,
|
||||
const std::string& factionId, int rank) const
|
||||
{
|
||||
if (rank<0 || rank>=10)
|
||||
throw std::runtime_error ("rank index out of range");
|
||||
|
||||
if (!MWWorld::Class::get (actor).getNpcStats (actor).hasSkillsForRank (factionId, rank))
|
||||
return false;
|
||||
|
||||
const ESM::Faction& faction =
|
||||
*MWBase::Environment::get().getWorld()->getStore().get<ESM::Faction>().find (factionId);
|
||||
|
||||
MWMechanics::CreatureStats& stats = MWWorld::Class::get (actor).getCreatureStats (actor);
|
||||
|
||||
return stats.getAttribute (faction.mData.mAttribute1).getBase()>=faction.mData.mRankData[rank].mAttribute1 &&
|
||||
stats.getAttribute (faction.mData.mAttribute2).getBase()>=faction.mData.mRankData[rank].mAttribute2;
|
||||
}
|
||||
|
||||
bool MWDialogue::Filter::hasFactionRankReputationRequirements (const MWWorld::Ptr& actor,
|
||||
const std::string& factionId, int rank) const
|
||||
{
|
||||
if (rank<0 || rank>=10)
|
||||
throw std::runtime_error ("rank index out of range");
|
||||
|
||||
MWMechanics::NpcStats& stats = MWWorld::Class::get (actor).getNpcStats (actor);
|
||||
|
||||
const ESM::Faction& faction =
|
||||
*MWBase::Environment::get().getWorld()->getStore().get<ESM::Faction>().find (factionId);
|
||||
|
||||
return stats.getFactionReputation (factionId)>=faction.mData.mRankData[rank].mFactReaction;
|
||||
}
|
||||
|
||||
MWDialogue::Filter::Filter (const MWWorld::Ptr& actor, int choice, bool talkedToPlayer)
|
||||
: mActor (actor), mChoice (choice), mTalkedToPlayer (talkedToPlayer)
|
||||
{}
|
||||
|
||||
bool MWDialogue::Filter::operator() (const ESM::DialInfo& info) const
|
||||
{
|
||||
return testActor (info) && testPlayer (info) && testSelectStructs (info);
|
||||
}
|
||||
|
||||
const ESM::DialInfo *MWDialogue::Filter::search (const ESM::Dialogue& dialogue) const
|
||||
{
|
||||
for (std::vector<ESM::DialInfo>::const_iterator iter = dialogue.mInfo.begin();
|
||||
iter!=dialogue.mInfo.end(); ++iter)
|
||||
if ((*this) (*iter))
|
||||
return &*iter;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -0,0 +1,58 @@
|
||||
#ifndef GAME_MWDIALOGUE_FILTER_H
|
||||
#define GAME_MWDIALOGUE_FILTER_H
|
||||
|
||||
#include "../mwworld/ptr.hpp"
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
struct DialInfo;
|
||||
struct Dialogue;
|
||||
}
|
||||
|
||||
namespace MWDialogue
|
||||
{
|
||||
class SelectWrapper;
|
||||
|
||||
class Filter
|
||||
{
|
||||
MWWorld::Ptr mActor;
|
||||
int mChoice;
|
||||
bool mTalkedToPlayer;
|
||||
|
||||
bool testActor (const ESM::DialInfo& info) const;
|
||||
///< Is this the right actor for this \a info?
|
||||
|
||||
bool testPlayer (const ESM::DialInfo& info) const;
|
||||
///< Do the player and the cell the player is currently in match \a info?
|
||||
|
||||
bool testSelectStructs (const ESM::DialInfo& info) const;
|
||||
///< Are all select structs matching?
|
||||
|
||||
bool testSelectStruct (const SelectWrapper& select) const;
|
||||
|
||||
bool testSelectStructNumeric (const SelectWrapper& select) const;
|
||||
|
||||
int getSelectStructInteger (const SelectWrapper& select) const;
|
||||
|
||||
bool getSelectStructBoolean (const SelectWrapper& select) const;
|
||||
|
||||
int getFactionRank (const MWWorld::Ptr& actor, const std::string& factionId) const;
|
||||
|
||||
bool hasFactionRankSkillRequirements (const MWWorld::Ptr& actor, const std::string& factionId,
|
||||
int rank) const;
|
||||
|
||||
bool hasFactionRankReputationRequirements (const MWWorld::Ptr& actor, const std::string& factionId,
|
||||
int rank) const;
|
||||
|
||||
public:
|
||||
|
||||
Filter (const MWWorld::Ptr& actor, int choice, bool talkedToPlayer);
|
||||
|
||||
bool operator() (const ESM::DialInfo& info) const;
|
||||
///< \return does the dialogue match?
|
||||
|
||||
const ESM::DialInfo *search (const ESM::Dialogue& dialogue) const;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,294 @@
|
||||
|
||||
#include "selectwrapper.hpp"
|
||||
|
||||
#include <cctype>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
|
||||
namespace
|
||||
{
|
||||
std::string toLower (const std::string& name)
|
||||
{
|
||||
std::string lowerCase;
|
||||
|
||||
std::transform (name.begin(), name.end(), std::back_inserter (lowerCase),
|
||||
(int(*)(int)) std::tolower);
|
||||
|
||||
return lowerCase;
|
||||
}
|
||||
|
||||
template<typename T1, typename T2>
|
||||
bool selectCompareImp (char comp, T1 value1, T2 value2)
|
||||
{
|
||||
switch (comp)
|
||||
{
|
||||
case '0': return value1==value2;
|
||||
case '1': return value1!=value2;
|
||||
case '2': return value1>value2;
|
||||
case '3': return value1>=value2;
|
||||
case '4': return value1<value2;
|
||||
case '5': return value1<=value2;
|
||||
}
|
||||
|
||||
throw std::runtime_error ("unknown compare type in dialogue info select");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool selectCompareImp (const ESM::DialInfo::SelectStruct& select, T value1)
|
||||
{
|
||||
if (select.mType==ESM::VT_Short || select.mType==ESM::VT_Int ||
|
||||
select.mType==ESM::VT_Long)
|
||||
{
|
||||
return selectCompareImp (select.mSelectRule[4], value1, select.mI);
|
||||
}
|
||||
else if (select.mType==ESM::VT_Float)
|
||||
{
|
||||
return selectCompareImp (select.mSelectRule[4], value1, select.mF);
|
||||
}
|
||||
else
|
||||
throw std::runtime_error (
|
||||
"unsupported variable type in dialogue info select");
|
||||
}
|
||||
}
|
||||
|
||||
MWDialogue::SelectWrapper::Function MWDialogue::SelectWrapper::decodeFunction() const
|
||||
{
|
||||
int index = 0;
|
||||
|
||||
std::istringstream (mSelect.mSelectRule.substr(2,2)) >> index;
|
||||
|
||||
switch (index)
|
||||
{
|
||||
// 0, 1
|
||||
case 2: return Function_RankRequirement;
|
||||
// 3
|
||||
case 4: return Function_HealthPercent;
|
||||
case 5: return Function_PCReputation;
|
||||
case 6: return Function_PcLevel;
|
||||
case 7: return Function_PcHealthPercent;
|
||||
case 8: case 9: return Function_PcDynamicStat;
|
||||
case 10: return Function_PcAttribute;
|
||||
case 11: case 12: case 13: case 14: case 15: case 16: case 17: case 18: case 19: case 20:
|
||||
case 21: case 22: case 23: case 24: case 25: case 26: case 27: case 28: case 29: case 30:
|
||||
case 31: case 32: case 33: case 34: case 35: case 36: case 37: return Function_PcSkill;
|
||||
case 38: return Function_PcGender;
|
||||
case 39: return Function_PcExpelled;
|
||||
case 40: return Function_PcCommonDisease;
|
||||
case 41: return Function_PcBlightDisease;
|
||||
case 42: return Function_PcClothingModifier;
|
||||
case 43: return Function_PcCrimeLevel;
|
||||
case 44: return Function_SameGender;
|
||||
case 45: return Function_SameRace;
|
||||
case 46: return Function_SameFaction;
|
||||
// 47-49
|
||||
case 50: return Function_Choice;
|
||||
case 51: case 52: case 53: case 54: case 55: case 56: case 57: return Function_PcAttribute;
|
||||
case 58: return Function_PcCorprus;
|
||||
// 59
|
||||
case 60: return Function_PcVampire;
|
||||
case 61: return Function_Level;
|
||||
// 62
|
||||
case 63: return Function_TalkedToPc;
|
||||
case 64: return Function_PcDynamicStat;
|
||||
// 65
|
||||
case 66: return Function_FriendlyHit;
|
||||
case 67: case 68: case 69: case 70: return Function_AiSetting;
|
||||
// 71
|
||||
}
|
||||
|
||||
return Function_False;
|
||||
}
|
||||
|
||||
MWDialogue::SelectWrapper::SelectWrapper (const ESM::DialInfo::SelectStruct& select) : mSelect (select) {}
|
||||
|
||||
MWDialogue::SelectWrapper::Function MWDialogue::SelectWrapper::getFunction() const
|
||||
{
|
||||
char type = mSelect.mSelectRule[1];
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case '1': return decodeFunction();
|
||||
case '2': return Function_Global;
|
||||
case '3': return Function_Local;
|
||||
case '4': return Function_Journal;
|
||||
case '5': return Function_Item;
|
||||
case '6': return Function_Dead;
|
||||
case '7': return Function_Id;
|
||||
case '8': return Function_Faction;
|
||||
case '9': return Function_Class;
|
||||
case 'A': return Function_Race;
|
||||
case 'B': return Function_Cell;
|
||||
case 'C': return Function_Local;
|
||||
}
|
||||
|
||||
return Function_None;
|
||||
}
|
||||
|
||||
int MWDialogue::SelectWrapper::getArgument() const
|
||||
{
|
||||
if (mSelect.mSelectRule[1]!='1')
|
||||
return 0;
|
||||
|
||||
int index = 0;
|
||||
|
||||
std::istringstream (mSelect.mSelectRule.substr(2,2)) >> index;
|
||||
|
||||
switch (index)
|
||||
{
|
||||
// AI settings
|
||||
case 67: return 1;
|
||||
case 68: return 0;
|
||||
case 69: return 3;
|
||||
case 70: return 2;
|
||||
|
||||
// attributes
|
||||
case 10: return 0;
|
||||
case 51: return 1;
|
||||
case 52: return 2;
|
||||
case 53: return 3;
|
||||
case 54: return 4;
|
||||
case 55: return 5;
|
||||
case 56: return 6;
|
||||
case 57: return 7;
|
||||
|
||||
// skills
|
||||
case 11: return 0;
|
||||
case 12: return 1;
|
||||
case 13: return 2;
|
||||
case 14: return 3;
|
||||
case 15: return 4;
|
||||
case 16: return 5;
|
||||
case 17: return 6;
|
||||
case 18: return 7;
|
||||
case 19: return 8;
|
||||
case 20: return 9;
|
||||
case 21: return 10;
|
||||
case 22: return 11;
|
||||
case 23: return 12;
|
||||
case 24: return 13;
|
||||
case 25: return 14;
|
||||
case 26: return 15;
|
||||
case 27: return 16;
|
||||
case 28: return 17;
|
||||
case 29: return 18;
|
||||
case 30: return 19;
|
||||
case 31: return 20;
|
||||
case 32: return 21;
|
||||
case 33: return 22;
|
||||
case 34: return 23;
|
||||
case 35: return 24;
|
||||
case 36: return 25;
|
||||
case 37: return 26;
|
||||
|
||||
// dynamic stats
|
||||
case 8: return 1;
|
||||
case 9: return 2;
|
||||
case 64: return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
MWDialogue::SelectWrapper::Type MWDialogue::SelectWrapper::getType() const
|
||||
{
|
||||
static const Function integerFunctions[] =
|
||||
{
|
||||
Function_Journal, Function_Item, Function_Dead,
|
||||
Function_Choice,
|
||||
Function_AiSetting,
|
||||
Function_PcAttribute, Function_PcSkill,
|
||||
Function_FriendlyHit,
|
||||
Function_PcLevel, Function_PcGender, Function_PcClothingModifier,
|
||||
Function_PcCrimeLevel,
|
||||
Function_RankRequirement,
|
||||
Function_Level, Function_PCReputation,
|
||||
Function_None // end marker
|
||||
};
|
||||
|
||||
static const Function numericFunctions[] =
|
||||
{
|
||||
Function_Global, Function_Local,
|
||||
Function_PcDynamicStat, Function_PcHealthPercent,
|
||||
Function_HealthPercent,
|
||||
Function_None // end marker
|
||||
};
|
||||
|
||||
static const Function booleanFunctions[] =
|
||||
{
|
||||
Function_False,
|
||||
Function_Id, Function_Faction, Function_Class, Function_Race, Function_Cell,
|
||||
Function_SameGender, Function_SameRace, Function_SameFaction,
|
||||
Function_PcCommonDisease, Function_PcBlightDisease, Function_PcCorprus,
|
||||
Function_PcExpelled,
|
||||
Function_PcVampire, Function_TalkedToPc,
|
||||
Function_None // end marker
|
||||
};
|
||||
|
||||
Function function = getFunction();
|
||||
|
||||
for (int i=0; integerFunctions[i]!=Function_None; ++i)
|
||||
if (integerFunctions[i]==function)
|
||||
return Type_Integer;
|
||||
|
||||
for (int i=0; numericFunctions[i]!=Function_None; ++i)
|
||||
if (numericFunctions[i]==function)
|
||||
return Type_Numeric;
|
||||
|
||||
for (int i=0; booleanFunctions[i]!=Function_None; ++i)
|
||||
if (booleanFunctions[i]==function)
|
||||
return Type_Boolean;
|
||||
|
||||
return Type_None;
|
||||
}
|
||||
|
||||
bool MWDialogue::SelectWrapper::isInverted() const
|
||||
{
|
||||
char type = mSelect.mSelectRule[1];
|
||||
|
||||
return type=='7' || type=='8' || type=='9' || type=='A' || type=='B' || type=='C';
|
||||
}
|
||||
|
||||
bool MWDialogue::SelectWrapper::isNpcOnly() const
|
||||
{
|
||||
static const Function functions[] =
|
||||
{
|
||||
Function_Faction, SelectWrapper::Function_Class, SelectWrapper::Function_Race,
|
||||
Function_SameGender, Function_SameRace, Function_SameFaction,
|
||||
Function_PcSkill,
|
||||
Function_PcExpelled,
|
||||
Function_PcVampire,
|
||||
Function_PcCrimeLevel,
|
||||
Function_RankRequirement,
|
||||
Function_None // end marker
|
||||
};
|
||||
|
||||
Function function = getFunction();
|
||||
|
||||
for (int i=0; functions[i]!=Function_None; ++i)
|
||||
if (functions[i]==function)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MWDialogue::SelectWrapper::selectCompare (int value) const
|
||||
{
|
||||
return selectCompareImp (mSelect, value)!=isInverted(); // logic XOR
|
||||
}
|
||||
|
||||
bool MWDialogue::SelectWrapper::selectCompare (float value) const
|
||||
{
|
||||
return selectCompareImp (mSelect, value)!=isInverted(); // logic XOR
|
||||
}
|
||||
|
||||
bool MWDialogue::SelectWrapper::selectCompare (bool value) const
|
||||
{
|
||||
return selectCompareImp (mSelect, static_cast<int> (value))!=isInverted(); // logic XOR
|
||||
}
|
||||
|
||||
std::string MWDialogue::SelectWrapper::getName() const
|
||||
{
|
||||
return toLower (mSelect.mSelectRule.substr (5));
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
#ifndef GAME_MWDIALOGUE_SELECTWRAPPER_H
|
||||
#define GAME_MWDIALOGUE_SELECTWRAPPER_H
|
||||
|
||||
#include <components/esm/loadinfo.hpp>
|
||||
|
||||
namespace MWDialogue
|
||||
{
|
||||
class SelectWrapper
|
||||
{
|
||||
const ESM::DialInfo::SelectStruct& mSelect;
|
||||
|
||||
public:
|
||||
|
||||
enum Function
|
||||
{
|
||||
Function_None, Function_False,
|
||||
Function_Journal,
|
||||
Function_Item,
|
||||
Function_Dead,
|
||||
Function_Id,
|
||||
Function_Faction,
|
||||
Function_Class,
|
||||
Function_Race,
|
||||
Function_Cell,
|
||||
Function_Local,
|
||||
Function_Global,
|
||||
Function_SameGender, Function_SameRace, Function_SameFaction,
|
||||
Function_Choice,
|
||||
Function_PcCommonDisease, Function_PcBlightDisease, Function_PcCorprus,
|
||||
Function_AiSetting,
|
||||
Function_PcAttribute, Function_PcSkill,
|
||||
Function_PcExpelled,
|
||||
Function_PcVampire,
|
||||
Function_FriendlyHit,
|
||||
Function_TalkedToPc,
|
||||
Function_PcLevel, Function_PcHealthPercent, Function_PcDynamicStat,
|
||||
Function_PcGender, Function_PcClothingModifier, Function_PcCrimeLevel,
|
||||
Function_RankRequirement,
|
||||
Function_HealthPercent, Function_Level, Function_PCReputation
|
||||
};
|
||||
|
||||
enum Type
|
||||
{
|
||||
Type_None,
|
||||
Type_Integer,
|
||||
Type_Numeric,
|
||||
Type_Boolean
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
Function decodeFunction() const;
|
||||
|
||||
public:
|
||||
|
||||
SelectWrapper (const ESM::DialInfo::SelectStruct& select);
|
||||
|
||||
Function getFunction() const;
|
||||
|
||||
int getArgument() const;
|
||||
|
||||
Type getType() const;
|
||||
|
||||
bool isInverted() const;
|
||||
|
||||
bool isNpcOnly() const;
|
||||
///< \attention Do not call any of the select functions for this select struct!
|
||||
|
||||
bool selectCompare (int value) const;
|
||||
|
||||
bool selectCompare (float value) const;
|
||||
|
||||
bool selectCompare (bool value) const;
|
||||
|
||||
std::string getName() const;
|
||||
///< Return case-smashed name.
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue