mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-01-25 06:35:30 +00:00
fix merging problem/some logic fixes
This commit is contained in:
commit
f2ad1c18f2
@ -93,8 +93,6 @@ set(OENGINE_GUI
|
||||
)
|
||||
|
||||
set(OENGINE_BULLET
|
||||
${LIBDIR}/openengine/bullet/btKinematicCharacterController.cpp
|
||||
${LIBDIR}/openengine/bullet/btKinematicCharacterController.h
|
||||
${LIBDIR}/openengine/bullet/BtOgre.cpp
|
||||
${LIBDIR}/openengine/bullet/BtOgreExtras.h
|
||||
${LIBDIR}/openengine/bullet/BtOgreGP.h
|
||||
|
@ -717,16 +717,26 @@ std::string landFlags(int flags)
|
||||
return properties;
|
||||
}
|
||||
|
||||
std::string leveledListFlags(int flags)
|
||||
std::string itemListFlags(int flags)
|
||||
{
|
||||
std::string properties = "";
|
||||
if (flags == 0) properties += "[None] ";
|
||||
if (flags & ESM::LeveledListBase::AllLevels) properties += "AllLevels ";
|
||||
// This flag apparently not present on creature lists...
|
||||
if (flags & ESM::LeveledListBase::Each) properties += "Each ";
|
||||
if (flags & ESM::ItemLevList::AllLevels) properties += "AllLevels ";
|
||||
if (flags & ESM::ItemLevList::Each) properties += "Each ";
|
||||
int unused = (0xFFFFFFFF ^
|
||||
(ESM::LeveledListBase::AllLevels|
|
||||
ESM::LeveledListBase::Each));
|
||||
(ESM::ItemLevList::AllLevels|
|
||||
ESM::ItemLevList::Each));
|
||||
if (flags & unused) properties += "Invalid ";
|
||||
properties += str(boost::format("(0x%08X)") % flags);
|
||||
return properties;
|
||||
}
|
||||
|
||||
std::string creatureListFlags(int flags)
|
||||
{
|
||||
std::string properties = "";
|
||||
if (flags == 0) properties += "[None] ";
|
||||
if (flags & ESM::CreatureLevList::AllLevels) properties += "AllLevels ";
|
||||
int unused = (0xFFFFFFFF ^ ESM::CreatureLevList::AllLevels);
|
||||
if (flags & unused) properties += "Invalid ";
|
||||
properties += str(boost::format("(0x%08X)") % flags);
|
||||
return properties;
|
||||
@ -764,34 +774,19 @@ std::string magicEffectFlags(int flags)
|
||||
{
|
||||
std::string properties = "";
|
||||
if (flags == 0) properties += "[None] ";
|
||||
// Enchanting & SpellMaking occur on the same list of effects.
|
||||
// "EXTRA SPELL" appears in the construction set under both the
|
||||
// spell making and enchanting tabs as an allowed effect. Since
|
||||
// most of the effects without this flags are defective in various
|
||||
// ways, it's still very unclear what these flag bits are.
|
||||
if (flags & ESM::MagicEffect::SpellMaking) properties += "SpellMaking ";
|
||||
if (flags & ESM::MagicEffect::Enchanting) properties += "Enchanting ";
|
||||
if (flags & 0x00000040) properties += "RangeNoSelf ";
|
||||
if (flags & 0x00000080) properties += "RangeTouch ";
|
||||
if (flags & 0x00000100) properties += "RangeTarget ";
|
||||
if (flags & 0x00001000) properties += "Unknown2 ";
|
||||
if (flags & 0x00000001) properties += "AffectSkill ";
|
||||
if (flags & 0x00000002) properties += "AffectAttribute ";
|
||||
if (flags & ESM::MagicEffect::TargetAttribute) properties += "TargetAttribute ";
|
||||
if (flags & ESM::MagicEffect::TargetSkill) properties += "TargetSkill ";
|
||||
if (flags & ESM::MagicEffect::NoDuration) properties += "NoDuration ";
|
||||
if (flags & 0x00000008) properties += "NoMagnitude ";
|
||||
if (flags & 0x00000010) properties += "Negative ";
|
||||
if (flags & 0x00000020) properties += "Unknown1 ";
|
||||
// ESM componet says 0x800 is negative, but none of the magic
|
||||
// effects have this flags set.
|
||||
if (flags & ESM::MagicEffect::Negative) properties += "Unused ";
|
||||
// Since only Chameleon has this flag it could be anything
|
||||
// that uniquely distinguishes Chameleon.
|
||||
if (flags & 0x00002000) properties += "Chameleon ";
|
||||
if (flags & 0x00004000) properties += "Bound ";
|
||||
if (flags & 0x00008000) properties += "Summon ";
|
||||
// Calm, Demoralize, Frenzy, Lock, Open, Rally, Soultrap, Turn Unded
|
||||
if (flags & 0x00010000) properties += "Unknown3 ";
|
||||
if (flags & 0x00020000) properties += "Absorb ";
|
||||
if (flags & ESM::MagicEffect::NoMagnitude) properties += "NoMagnitude ";
|
||||
if (flags & ESM::MagicEffect::Harmful) properties += "Harmful ";
|
||||
if (flags & ESM::MagicEffect::ContinuousVfx) properties += "ContinuousVFX ";
|
||||
if (flags & ESM::MagicEffect::CastSelf) properties += "CastSelf ";
|
||||
if (flags & ESM::MagicEffect::CastTouch) properties += "CastTouch ";
|
||||
if (flags & ESM::MagicEffect::CastTarget) properties += "CastTarget ";
|
||||
if (flags & ESM::MagicEffect::UncappedDamage) properties += "UncappedDamage ";
|
||||
if (flags & ESM::MagicEffect::NonRecastable) properties += "NonRecastable ";
|
||||
if (flags & ESM::MagicEffect::Unreflectable) properties += "Unreflectable ";
|
||||
if (flags & ESM::MagicEffect::CasterLinked) properties += "CasterLinked ";
|
||||
if (flags & 0xFFFC0000) properties += "Invalid ";
|
||||
properties += str(boost::format("(0x%08X)") % flags);
|
||||
return properties;
|
||||
|
@ -50,7 +50,8 @@ std::string cellFlags(int flags);
|
||||
std::string containerFlags(int flags);
|
||||
std::string creatureFlags(int flags);
|
||||
std::string landFlags(int flags);
|
||||
std::string leveledListFlags(int flags);
|
||||
std::string creatureListFlags(int flags);
|
||||
std::string itemListFlags(int flags);
|
||||
std::string lightFlags(int flags);
|
||||
std::string magicEffectFlags(int flags);
|
||||
std::string npcFlags(int flags);
|
||||
|
@ -13,8 +13,8 @@ void printAIPackage(ESM::AIPackage p)
|
||||
std::cout << " Distance: " << p.mWander.mDistance << std::endl;
|
||||
std::cout << " Duration: " << p.mWander.mDuration << std::endl;
|
||||
std::cout << " Time of Day: " << (int)p.mWander.mTimeOfDay << std::endl;
|
||||
if (p.mWander.mUnk != 1)
|
||||
std::cout << " Unknown: " << (int)p.mWander.mUnk << std::endl;
|
||||
if (p.mWander.mShouldRepeat != 1)
|
||||
std::cout << " Should repeat: " << (bool)p.mWander.mShouldRepeat << std::endl;
|
||||
|
||||
std::cout << " Idle: ";
|
||||
for (int i = 0; i != 8; i++)
|
||||
@ -834,7 +834,7 @@ template<>
|
||||
void Record<ESM::CreatureLevList>::print()
|
||||
{
|
||||
std::cout << " Chance for None: " << (int)mData.mChanceNone << std::endl;
|
||||
std::cout << " Flags: " << leveledListFlags(mData.mFlags) << std::endl;
|
||||
std::cout << " Flags: " << creatureListFlags(mData.mFlags) << std::endl;
|
||||
std::cout << " Number of items: " << mData.mList.size() << std::endl;
|
||||
std::vector<ESM::LeveledListBase::LevelItem>::iterator iit;
|
||||
for (iit = mData.mList.begin(); iit != mData.mList.end(); iit++)
|
||||
@ -846,11 +846,11 @@ template<>
|
||||
void Record<ESM::ItemLevList>::print()
|
||||
{
|
||||
std::cout << " Chance for None: " << (int)mData.mChanceNone << std::endl;
|
||||
std::cout << " Flags: " << leveledListFlags(mData.mFlags) << std::endl;
|
||||
std::cout << " Flags: " << itemListFlags(mData.mFlags) << std::endl;
|
||||
std::cout << " Number of items: " << mData.mList.size() << std::endl;
|
||||
std::vector<ESM::LeveledListBase::LevelItem>::iterator iit;
|
||||
for (iit = mData.mList.begin(); iit != mData.mList.end(); iit++)
|
||||
std::cout << " Inventory: Count: " << iit->mLevel
|
||||
std::cout << " Inventory: Level: " << iit->mLevel
|
||||
<< " Item: " << iit->mId << std::endl;
|
||||
}
|
||||
|
||||
@ -958,7 +958,7 @@ void Record<ESM::MagicEffect>::print()
|
||||
std::cout << " RGB Color: " << "("
|
||||
<< mData.mData.mRed << ","
|
||||
<< mData.mData.mGreen << ","
|
||||
<< mData.mData.mGreen << ")" << std::endl;
|
||||
<< mData.mData.mBlue << ")" << std::endl;
|
||||
}
|
||||
|
||||
template<>
|
||||
|
@ -16,6 +16,7 @@
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
SDL_SetHint(SDL_HINT_RENDER_DRIVER, "software");
|
||||
SDL_SetMainReady();
|
||||
if (SDL_Init(SDL_INIT_VIDEO) != 0)
|
||||
{
|
||||
qDebug() << "SDL_Init failed: " << QString::fromStdString(SDL_GetError());
|
||||
|
@ -235,7 +235,7 @@ namespace
|
||||
{
|
||||
for ( bfs::recursive_directory_iterator end, dir(in); dir != end; ++dir )
|
||||
{
|
||||
if(Misc::StringUtils::lowerCase(dir->path().filename().string()) == filename)
|
||||
if(Misc::StringUtils::ciEqual(dir->path().filename().string(), filename))
|
||||
return dir->path();
|
||||
}
|
||||
}
|
||||
@ -243,7 +243,7 @@ namespace
|
||||
{
|
||||
for ( bfs::directory_iterator end, dir(in); dir != end; ++dir )
|
||||
{
|
||||
if(Misc::StringUtils::lowerCase(dir->path().filename().string()) == filename)
|
||||
if(Misc::StringUtils::ciEqual(dir->path().filename().string(), filename))
|
||||
return dir->path();
|
||||
}
|
||||
}
|
||||
@ -255,7 +255,7 @@ namespace
|
||||
{
|
||||
for(bfs::directory_iterator end, dir(in); dir != end; ++dir)
|
||||
{
|
||||
if(Misc::StringUtils::lowerCase(dir->path().filename().string()) == filename)
|
||||
if(Misc::StringUtils::ciEqual(dir->path().filename().string(), filename))
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -38,7 +38,7 @@ opencs_units (model/tools
|
||||
|
||||
opencs_units_noqt (model/tools
|
||||
mandatoryid skillcheck classcheck factioncheck racecheck soundcheck regioncheck
|
||||
birthsigncheck spellcheck
|
||||
birthsigncheck spellcheck referenceablecheck
|
||||
)
|
||||
|
||||
|
||||
|
1095
apps/opencs/model/tools/referenceablecheck.cpp
Normal file
1095
apps/opencs/model/tools/referenceablecheck.cpp
Normal file
File diff suppressed because it is too large
Load Diff
78
apps/opencs/model/tools/referenceablecheck.hpp
Normal file
78
apps/opencs/model/tools/referenceablecheck.hpp
Normal file
@ -0,0 +1,78 @@
|
||||
#ifndef REFERENCEABLECHECKSTAGE_H
|
||||
#define REFERENCEABLECHECKSTAGE_H
|
||||
|
||||
#include "../world/universalid.hpp"
|
||||
#include "../doc/stage.hpp"
|
||||
#include "../world/data.hpp"
|
||||
#include "../world/refiddata.hpp"
|
||||
|
||||
namespace CSMTools
|
||||
{
|
||||
class ReferenceableCheckStage : public CSMDoc::Stage
|
||||
{
|
||||
public:
|
||||
ReferenceableCheckStage(const CSMWorld::RefIdData& referenceable,
|
||||
const CSMWorld::IdCollection<ESM::Race>& races,
|
||||
const CSMWorld::IdCollection<ESM::Class>& classes,
|
||||
const CSMWorld::IdCollection<ESM::Faction>& factions);
|
||||
|
||||
virtual void perform(int stage, std::vector< std::string >& messages);
|
||||
virtual int setup();
|
||||
|
||||
private:
|
||||
//CONCRETE CHECKS
|
||||
void bookCheck(int stage, const CSMWorld::RefIdDataContainer< ESM::Book >& records, std::vector< std::string >& messages);
|
||||
void activatorCheck(int stage, const CSMWorld::RefIdDataContainer< ESM::Activator >& records, std::vector< std::string >& messages);
|
||||
void potionCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Potion>& records, std::vector<std::string>& messages);
|
||||
void apparatusCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Apparatus>& records, std::vector<std::string>& messages);
|
||||
void armorCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Armor>& records, std::vector<std::string>& messages);
|
||||
void clothingCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Clothing>& records, std::vector<std::string>& messages);
|
||||
void containerCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Container>& records, std::vector<std::string>& messages);
|
||||
void creatureCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Creature>& records, std::vector<std::string>& messages);
|
||||
void doorCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Door>& records, std::vector<std::string>& messages);
|
||||
void ingredientCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Ingredient>& records, std::vector<std::string>& messages);
|
||||
void creaturesLevListCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::CreatureLevList>& records, std::vector<std::string>& messages);
|
||||
void itemLevelledListCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::ItemLevList>& records, std::vector<std::string>& messages);
|
||||
void lightCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Light>& records, std::vector<std::string>& messages);
|
||||
void lockpickCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Lockpick>& records, std::vector<std::string>& messages);
|
||||
void miscCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Miscellaneous>& records, std::vector<std::string>& messages);
|
||||
void npcCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::NPC>& records, std::vector<std::string>& messages);
|
||||
void weaponCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Weapon>& records, std::vector<std::string>& messages);
|
||||
void probeCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Probe>& records, std::vector<std::string>& messages);
|
||||
void repairCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Repair>& records, std::vector<std::string>& messages);
|
||||
void staticCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Static>& records, std::vector<std::string>& messages);
|
||||
|
||||
//FINAL CHECK
|
||||
void finalCheck(std::vector<std::string>& messages);
|
||||
|
||||
//TEMPLATE CHECKS
|
||||
template<typename ITEM> void inventoryItemCheck(const ITEM& someItem,
|
||||
std::vector<std::string>& messages,
|
||||
const std::string& someID,
|
||||
bool enchantable); //for all enchantable items.
|
||||
|
||||
template<typename ITEM> void inventoryItemCheck(const ITEM& someItem,
|
||||
std::vector<std::string>& messages,
|
||||
const std::string& someID); //for non-enchantable items.
|
||||
|
||||
template<typename TOOL> void toolCheck(const TOOL& someTool,
|
||||
std::vector<std::string>& messages,
|
||||
const std::string& someID,
|
||||
bool canbebroken); //for tools with uses.
|
||||
|
||||
template<typename TOOL> void toolCheck(const TOOL& someTool,
|
||||
std::vector<std::string>& messages,
|
||||
const std::string& someID); //for tools without uses.
|
||||
|
||||
template<typename LIST> void listCheck(const LIST& someList,
|
||||
std::vector< std::string >& messages,
|
||||
const std::string& someID);
|
||||
|
||||
const CSMWorld::RefIdData& mReferencables;
|
||||
const CSMWorld::IdCollection<ESM::Race>& mRaces;
|
||||
const CSMWorld::IdCollection<ESM::Class>& mClasses;
|
||||
const CSMWorld::IdCollection<ESM::Faction>& mFactions;
|
||||
bool mPlayerPresent;
|
||||
};
|
||||
}
|
||||
#endif // REFERENCEABLECHECKSTAGE_H
|
@ -68,4 +68,4 @@ void CSMTools::ReportModel::add (const std::string& row)
|
||||
const CSMWorld::UniversalId& CSMTools::ReportModel::getUniversalId (int row) const
|
||||
{
|
||||
return mRows.at (row).first;
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "regioncheck.hpp"
|
||||
#include "birthsigncheck.hpp"
|
||||
#include "spellcheck.hpp"
|
||||
#include "referenceablecheck.hpp"
|
||||
|
||||
CSMDoc::Operation *CSMTools::Tools::get (int type)
|
||||
{
|
||||
@ -74,6 +75,8 @@ CSMDoc::Operation *CSMTools::Tools::getVerifier()
|
||||
mVerifier->appendStage (new BirthsignCheckStage (mData.getBirthsigns()));
|
||||
|
||||
mVerifier->appendStage (new SpellCheckStage (mData.getSpells()));
|
||||
|
||||
mVerifier->appendStage (new ReferenceableCheckStage (mData.getReferenceables().getDataSet(), mData.getRaces(), mData.getClasses(), mData.getFactions()));
|
||||
}
|
||||
|
||||
return mVerifier;
|
||||
@ -138,4 +141,5 @@ void CSMTools::Tools::verifierMessage (const QString& message, int type)
|
||||
|
||||
if (iter!=mActiveReports.end())
|
||||
mReports[iter->second]->add (message.toStdString());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -220,7 +220,7 @@ int CSMWorld::Columns::getId (const std::string& name)
|
||||
std::string name2 = Misc::StringUtils::lowerCase (name);
|
||||
|
||||
for (int i=0; sNames[i].mName; ++i)
|
||||
if (name2==Misc::StringUtils::lowerCase (sNames[i].mName))
|
||||
if (Misc::StringUtils::ciEqual(sNames[i].mName, name2))
|
||||
return sNames[i].mId;
|
||||
|
||||
return -1;
|
||||
|
@ -67,7 +67,7 @@ int CSMWorld::InfoCollection::getIndex (const std::string& id, const std::string
|
||||
std::pair<RecordConstIterator, RecordConstIterator> range = getTopicRange (topic);
|
||||
|
||||
for (; range.first!=range.second; ++range.first)
|
||||
if (Misc::StringUtils::lowerCase (range.first->get().mId)==fullId)
|
||||
if (Misc::StringUtils::ciEqual(range.first->get().mId, fullId))
|
||||
return std::distance (getRecords().begin(), range.first);
|
||||
|
||||
return -1;
|
||||
@ -177,8 +177,8 @@ CSMWorld::InfoCollection::Range CSMWorld::InfoCollection::getTopicRange (const s
|
||||
RecordConstIterator end = begin;
|
||||
|
||||
for (; end!=getRecords().end(); ++end)
|
||||
if (Misc::StringUtils::lowerCase (end->get().mTopicId)!=topic2)
|
||||
if (!Misc::StringUtils::ciEqual(end->get().mTopicId, topic2))
|
||||
break;
|
||||
|
||||
return Range (begin, end);
|
||||
}
|
||||
}
|
||||
|
@ -549,3 +549,9 @@ void CSMWorld::RefIdCollection::save (int index, ESM::ESMWriter& writer) const
|
||||
{
|
||||
mData.save (index, writer);
|
||||
}
|
||||
|
||||
const CSMWorld::RefIdData& CSMWorld::RefIdCollection::getDataSet() const
|
||||
{
|
||||
return mData;
|
||||
}
|
||||
|
||||
|
@ -107,7 +107,10 @@ namespace CSMWorld
|
||||
/// \return Success?
|
||||
|
||||
void save (int index, ESM::ESMWriter& writer) const;
|
||||
|
||||
const RefIdData& getDataSet() const; //I can't figure out a better name for this one :(
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -230,4 +230,104 @@ void CSMWorld::RefIdData::save (int index, ESM::ESMWriter& writer) const
|
||||
throw std::logic_error ("invalid local index type");
|
||||
|
||||
iter->second->save (localIndex.first, writer);
|
||||
}
|
||||
|
||||
const CSMWorld::RefIdDataContainer< ESM::Book >& CSMWorld::RefIdData::getBooks() const
|
||||
{
|
||||
return mBooks;
|
||||
}
|
||||
|
||||
const CSMWorld::RefIdDataContainer< ESM::Activator >& CSMWorld::RefIdData::getActivators() const
|
||||
{
|
||||
return mActivators;
|
||||
}
|
||||
|
||||
const CSMWorld::RefIdDataContainer< ESM::Potion >& CSMWorld::RefIdData::getPotions() const
|
||||
{
|
||||
return mPotions;
|
||||
}
|
||||
|
||||
const CSMWorld::RefIdDataContainer< ESM::Apparatus >& CSMWorld::RefIdData::getApparati() const
|
||||
{
|
||||
return mApparati;
|
||||
}
|
||||
|
||||
const CSMWorld::RefIdDataContainer< ESM::Armor >& CSMWorld::RefIdData::getArmors() const
|
||||
{
|
||||
return mArmors;
|
||||
}
|
||||
|
||||
const CSMWorld::RefIdDataContainer< ESM::Clothing >& CSMWorld::RefIdData::getClothing() const
|
||||
{
|
||||
return mClothing;
|
||||
}
|
||||
|
||||
const CSMWorld::RefIdDataContainer< ESM::Container >& CSMWorld::RefIdData::getContainers() const
|
||||
{
|
||||
return mContainers;
|
||||
}
|
||||
|
||||
const CSMWorld::RefIdDataContainer< ESM::Creature >& CSMWorld::RefIdData::getCreatures() const
|
||||
{
|
||||
return mCreatures;
|
||||
}
|
||||
|
||||
const CSMWorld::RefIdDataContainer< ESM::Door >& CSMWorld::RefIdData::getDoors() const
|
||||
{
|
||||
return mDoors;
|
||||
}
|
||||
|
||||
const CSMWorld::RefIdDataContainer< ESM::Ingredient >& CSMWorld::RefIdData::getIngredients() const
|
||||
{
|
||||
return mIngredients;
|
||||
}
|
||||
|
||||
const CSMWorld::RefIdDataContainer< ESM::CreatureLevList >& CSMWorld::RefIdData::getCreatureLevelledLists() const
|
||||
{
|
||||
return mCreatureLevelledLists;
|
||||
}
|
||||
|
||||
const CSMWorld::RefIdDataContainer< ESM::ItemLevList >& CSMWorld::RefIdData::getItemLevelledList() const
|
||||
{
|
||||
return mItemLevelledLists;
|
||||
}
|
||||
|
||||
const CSMWorld::RefIdDataContainer< ESM::Light >& CSMWorld::RefIdData::getLights() const
|
||||
{
|
||||
return mLights;
|
||||
}
|
||||
|
||||
const CSMWorld::RefIdDataContainer< ESM::Lockpick >& CSMWorld::RefIdData::getLocpicks() const
|
||||
{
|
||||
return mLockpicks;
|
||||
}
|
||||
|
||||
const CSMWorld::RefIdDataContainer< ESM::Miscellaneous >& CSMWorld::RefIdData::getMiscellaneous() const
|
||||
{
|
||||
return mMiscellaneous;
|
||||
}
|
||||
|
||||
const CSMWorld::RefIdDataContainer< ESM::NPC >& CSMWorld::RefIdData::getNPCs() const
|
||||
{
|
||||
return mNpcs;
|
||||
}
|
||||
|
||||
const CSMWorld::RefIdDataContainer< ESM::Weapon >& CSMWorld::RefIdData::getWeapons() const
|
||||
{
|
||||
return mWeapons;
|
||||
}
|
||||
|
||||
const CSMWorld::RefIdDataContainer< ESM::Probe >& CSMWorld::RefIdData::getProbes() const
|
||||
{
|
||||
return mProbes;
|
||||
}
|
||||
|
||||
const CSMWorld::RefIdDataContainer< ESM::Repair >& CSMWorld::RefIdData::getRepairs() const
|
||||
{
|
||||
return mRepairs;
|
||||
}
|
||||
|
||||
const CSMWorld::RefIdDataContainer< ESM::Static >& CSMWorld::RefIdData::getStatics() const
|
||||
{
|
||||
return mStatics;
|
||||
}
|
@ -219,7 +219,33 @@ namespace CSMWorld
|
||||
/// \param listDeleted include deleted record in the list
|
||||
|
||||
void save (int index, ESM::ESMWriter& writer) const;
|
||||
|
||||
//RECORD CONTAINERS ACCESS METHODS
|
||||
const RefIdDataContainer<ESM::Book>& getBooks() const;
|
||||
const RefIdDataContainer<ESM::Activator>& getActivators() const;
|
||||
const RefIdDataContainer<ESM::Potion>& getPotions() const;
|
||||
const RefIdDataContainer<ESM::Apparatus>& getApparati() const;
|
||||
const RefIdDataContainer<ESM::Armor>& getArmors() const;
|
||||
const RefIdDataContainer<ESM::Clothing>& getClothing() const;
|
||||
const RefIdDataContainer<ESM::Container>& getContainers() const;
|
||||
const RefIdDataContainer<ESM::Creature>& getCreatures() const;
|
||||
const RefIdDataContainer<ESM::Door>& getDoors() const;
|
||||
const RefIdDataContainer<ESM::Ingredient>& getIngredients() const;
|
||||
const RefIdDataContainer<ESM::CreatureLevList>& getCreatureLevelledLists() const;
|
||||
const RefIdDataContainer<ESM::ItemLevList>& getItemLevelledList() const;
|
||||
const RefIdDataContainer<ESM::Light>& getLights() const;
|
||||
const RefIdDataContainer<ESM::Lockpick>& getLocpicks() const;
|
||||
const RefIdDataContainer<ESM::Miscellaneous>& getMiscellaneous() const;
|
||||
const RefIdDataContainer<ESM::NPC>& getNPCs() const;
|
||||
const RefIdDataContainer<ESM::Weapon >& getWeapons() const;
|
||||
const RefIdDataContainer<ESM::Probe >& getProbes() const;
|
||||
const RefIdDataContainer<ESM::Repair>& getRepairs() const;
|
||||
const RefIdDataContainer<ESM::Static>& getStatics() const;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include <OgreRoot.h>
|
||||
#include <OgreRenderWindow.h>
|
||||
#include <OgreEntity.h>
|
||||
#include <OgreCamera.h>
|
||||
|
||||
namespace CSVRender
|
||||
{
|
||||
|
@ -74,7 +74,7 @@ add_openmw_dir (mwmechanics
|
||||
mechanicsmanagerimp stat character creaturestats magiceffects movement actors objects
|
||||
drawstate spells activespells npcstats aipackage aisequence alchemy aiwander aitravel aifollow
|
||||
aiescort aiactivate aicombat repair enchanting pathfinding security spellsuccess spellcasting
|
||||
disease pickpocket
|
||||
disease pickpocket levelledlist
|
||||
)
|
||||
|
||||
add_openmw_dir (mwbase
|
||||
|
@ -157,6 +157,7 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager)
|
||||
//kindly ask SDL not to trash our OGL context
|
||||
//might this be related to http://bugzilla.libsdl.org/show_bug.cgi?id=748 ?
|
||||
SDL_SetHint(SDL_HINT_RENDER_DRIVER, "software");
|
||||
SDL_SetMainReady();
|
||||
if(SDL_Init(flags) != 0)
|
||||
{
|
||||
throw std::runtime_error("Could not initialize SDL! " + std::string(SDL_GetError()));
|
||||
|
@ -76,8 +76,12 @@ namespace MWBase
|
||||
virtual void setPlayerClass (const ESM::Class& class_) = 0;
|
||||
///< Set player class to custom class.
|
||||
|
||||
virtual void restoreDynamicStats() = 0;
|
||||
///< If the player is sleeping, this should be called every hour.
|
||||
virtual void rest(bool sleep) = 0;
|
||||
///< If the player is sleeping or waiting, this should be called every hour.
|
||||
/// @param sleep is the player sleeping or waiting?
|
||||
|
||||
virtual int getHoursToRest() const = 0;
|
||||
///< Calculate how many hours the player needs to rest in order to be fully healed
|
||||
|
||||
virtual int getBarterOffer(const MWWorld::Ptr& ptr,int basePrice, bool buying) = 0;
|
||||
///< This is used by every service to determine the price of objects given the trading skills of the player and NPC.
|
||||
@ -112,6 +116,8 @@ namespace MWBase
|
||||
OffenseType type, int arg=0) = 0;
|
||||
/// Utility to check if taking this item is illegal and calling commitCrime if so
|
||||
virtual void itemTaken (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, int count) = 0;
|
||||
/// Utility to check if opening (i.e. unlocking) this object is illegal and calling commitCrime if so
|
||||
virtual void objectOpened (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item) = 0;
|
||||
/// Attempt sleeping in a bed. If this is illegal, call commitCrime.
|
||||
/// @return was it illegal, and someone saw you doing it?
|
||||
virtual bool sleepInBed (const MWWorld::Ptr& ptr, const MWWorld::Ptr& bed) = 0;
|
||||
|
@ -227,9 +227,6 @@ namespace MWBase
|
||||
virtual void messageBox (const std::string& message, const std::vector<std::string>& buttons = std::vector<std::string>(), bool showInDialogueModeOnly = false) = 0;
|
||||
virtual void staticMessageBox(const std::string& message) = 0;
|
||||
virtual void removeStaticMessageBox() = 0;
|
||||
|
||||
virtual void enterPressed () = 0;
|
||||
virtual void activateKeyPressed () = 0;
|
||||
virtual int readPressedButton() = 0;
|
||||
///< returns the index of the pressed button or -1 if no button was pressed (->MessageBoxmanager->InteractiveMessageBox)
|
||||
|
||||
|
@ -157,6 +157,10 @@ namespace MWBase
|
||||
///< Return a pointer to a liveCellRef with the given name.
|
||||
/// \param activeOnly do non search inactive cells.
|
||||
|
||||
virtual MWWorld::Ptr searchPtr (const std::string& name, bool activeOnly) = 0;
|
||||
///< Return a pointer to a liveCellRef with the given name.
|
||||
/// \param activeOnly do non search inactive cells.
|
||||
|
||||
virtual MWWorld::Ptr getPtrViaHandle (const std::string& handle) = 0;
|
||||
///< Return a pointer to a liveCellRef with the given Ogre handle.
|
||||
|
||||
@ -451,6 +455,14 @@ namespace MWBase
|
||||
/// Update the value of some globals according to the world state, which may be used by dialogue entries.
|
||||
/// This should be called when initiating a dialogue.
|
||||
virtual void updateDialogueGlobals() = 0;
|
||||
|
||||
/// Moves all stolen items from \a ptr to the closest evidence chest.
|
||||
virtual void confiscateStolenItems(const MWWorld::Ptr& ptr) = 0;
|
||||
|
||||
virtual void goToJail () = 0;
|
||||
|
||||
/// Spawn a random creature from a levelled list next to the player
|
||||
virtual void spawnRandomCreature(const std::string& creatureList) = 0;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -61,6 +61,14 @@ namespace MWClass
|
||||
|
||||
fMinWalkSpeedCreature = gmst.find("fMinWalkSpeedCreature");
|
||||
fMaxWalkSpeedCreature = gmst.find("fMaxWalkSpeedCreature");
|
||||
fEncumberedMoveEffect = gmst.find("fEncumberedMoveEffect");
|
||||
fSneakSpeedMultiplier = gmst.find("fSneakSpeedMultiplier");
|
||||
fAthleticsRunBonus = gmst.find("fAthleticsRunBonus");
|
||||
fBaseRunMultiplier = gmst.find("fBaseRunMultiplier");
|
||||
fMinFlySpeed = gmst.find("fMinFlySpeed");
|
||||
fMaxFlySpeed = gmst.find("fMaxFlySpeed");
|
||||
fSwimRunBase = gmst.find("fSwimRunBase");
|
||||
fSwimRunAthleticsMult = gmst.find("fSwimRunAthleticsMult");
|
||||
|
||||
inited = true;
|
||||
}
|
||||
@ -286,10 +294,51 @@ namespace MWClass
|
||||
float Creature::getSpeed(const MWWorld::Ptr &ptr) const
|
||||
{
|
||||
MWMechanics::CreatureStats& stats = getCreatureStats(ptr);
|
||||
|
||||
float walkSpeed = fMinWalkSpeedCreature->getFloat() + 0.01 * stats.getAttribute(ESM::Attribute::Speed).getModified()
|
||||
* (fMaxWalkSpeedCreature->getFloat() - fMinWalkSpeedCreature->getFloat());
|
||||
/// \todo what about the rest?
|
||||
return walkSpeed;
|
||||
|
||||
const MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||
const MWMechanics::MagicEffects &mageffects = stats.getMagicEffects();
|
||||
|
||||
const float normalizedEncumbrance = 0; //getEncumbrance(ptr) / getCapacity(ptr);
|
||||
|
||||
bool running = ptr.getClass().getCreatureStats(ptr).getStance(MWMechanics::CreatureStats::Stance_Run);
|
||||
|
||||
float runSpeed = walkSpeed*(0.01f * getSkill(ptr, ESM::Skill::Athletics) *
|
||||
fAthleticsRunBonus->getFloat() + fBaseRunMultiplier->getFloat());
|
||||
|
||||
float moveSpeed;
|
||||
if(normalizedEncumbrance >= 1.0f)
|
||||
moveSpeed = 0.0f;
|
||||
else if(mageffects.get(ESM::MagicEffect::Levitate).mMagnitude > 0 &&
|
||||
world->isLevitationEnabled())
|
||||
{
|
||||
float flySpeed = 0.01f*(stats.getAttribute(ESM::Attribute::Speed).getModified() +
|
||||
mageffects.get(ESM::MagicEffect::Levitate).mMagnitude);
|
||||
flySpeed = fMinFlySpeed->getFloat() + flySpeed*(fMaxFlySpeed->getFloat() - fMinFlySpeed->getFloat());
|
||||
flySpeed *= 1.0f - fEncumberedMoveEffect->getFloat() * normalizedEncumbrance;
|
||||
flySpeed = std::max(0.0f, flySpeed);
|
||||
moveSpeed = flySpeed;
|
||||
}
|
||||
else if(world->isSwimming(ptr))
|
||||
{
|
||||
float swimSpeed = walkSpeed;
|
||||
if(running)
|
||||
swimSpeed = runSpeed;
|
||||
swimSpeed *= 1.0f + 0.01f * mageffects.get(ESM::MagicEffect::SwiftSwim).mMagnitude;
|
||||
swimSpeed *= fSwimRunBase->getFloat() + 0.01f*getSkill(ptr, ESM::Skill::Athletics) *
|
||||
fSwimRunAthleticsMult->getFloat();
|
||||
moveSpeed = swimSpeed;
|
||||
}
|
||||
else if(running)
|
||||
moveSpeed = runSpeed;
|
||||
else
|
||||
moveSpeed = walkSpeed;
|
||||
if(getMovementSettings(ptr).mPosition[0] != 0 && getMovementSettings(ptr).mPosition[1] == 0)
|
||||
moveSpeed *= 0.75f;
|
||||
|
||||
return moveSpeed;
|
||||
}
|
||||
|
||||
MWMechanics::Movement& Creature::getMovementSettings (const MWWorld::Ptr& ptr) const
|
||||
@ -461,6 +510,35 @@ namespace MWClass
|
||||
throw std::runtime_error(std::string("Unexpected soundgen type: ")+name);
|
||||
}
|
||||
|
||||
int Creature::getSkill(const MWWorld::Ptr &ptr, int skill) const
|
||||
{
|
||||
MWWorld::LiveCellRef<ESM::Creature> *ref =
|
||||
ptr.get<ESM::Creature>();
|
||||
|
||||
const ESM::Skill* skillRecord = MWBase::Environment::get().getWorld()->getStore().get<ESM::Skill>().find(skill);
|
||||
|
||||
switch (skillRecord->mData.mSpecialization)
|
||||
{
|
||||
case ESM::Class::Combat:
|
||||
return ref->mBase->mData.mCombat;
|
||||
case ESM::Class::Magic:
|
||||
return ref->mBase->mData.mMagic;
|
||||
case ESM::Class::Stealth:
|
||||
return ref->mBase->mData.mStealth;
|
||||
default:
|
||||
throw std::runtime_error("invalid specialisation");
|
||||
}
|
||||
}
|
||||
|
||||
const ESM::GameSetting* Creature::fMinWalkSpeedCreature;
|
||||
const ESM::GameSetting* Creature::fMaxWalkSpeedCreature;
|
||||
const ESM::GameSetting *Creature::fEncumberedMoveEffect;
|
||||
const ESM::GameSetting *Creature::fSneakSpeedMultiplier;
|
||||
const ESM::GameSetting *Creature::fAthleticsRunBonus;
|
||||
const ESM::GameSetting *Creature::fBaseRunMultiplier;
|
||||
const ESM::GameSetting *Creature::fMinFlySpeed;
|
||||
const ESM::GameSetting *Creature::fMaxFlySpeed;
|
||||
const ESM::GameSetting *Creature::fSwimRunBase;
|
||||
const ESM::GameSetting *Creature::fSwimRunAthleticsMult;
|
||||
|
||||
}
|
||||
|
@ -16,6 +16,14 @@ namespace MWClass
|
||||
|
||||
static const ESM::GameSetting *fMinWalkSpeedCreature;
|
||||
static const ESM::GameSetting *fMaxWalkSpeedCreature;
|
||||
static const ESM::GameSetting *fEncumberedMoveEffect;
|
||||
static const ESM::GameSetting *fSneakSpeedMultiplier;
|
||||
static const ESM::GameSetting *fAthleticsRunBonus;
|
||||
static const ESM::GameSetting *fBaseRunMultiplier;
|
||||
static const ESM::GameSetting *fMinFlySpeed;
|
||||
static const ESM::GameSetting *fMaxFlySpeed;
|
||||
static const ESM::GameSetting *fSwimRunBase;
|
||||
static const ESM::GameSetting *fSwimRunAthleticsMult;
|
||||
|
||||
public:
|
||||
|
||||
@ -101,6 +109,8 @@ namespace MWClass
|
||||
}
|
||||
|
||||
virtual bool isFlying (const MWWorld::Ptr &ptr) const;
|
||||
|
||||
virtual int getSkill(const MWWorld::Ptr &ptr, int skill) const;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -3,8 +3,6 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
#include <OgreSceneNode.h>
|
||||
|
||||
#include <components/esm/loadmgef.hpp>
|
||||
@ -242,6 +240,9 @@ namespace MWClass
|
||||
fJumpAcroMultiplier = gmst.find("fJumpAcroMultiplier");
|
||||
fJumpRunMultiplier = gmst.find("fJumpRunMultiplier");
|
||||
fWereWolfRunMult = gmst.find("fWereWolfRunMult");
|
||||
fKnockDownMult = gmst.find("fKnockDownMult");
|
||||
iKnockDownOddsMult = gmst.find("iKnockDownOddsMult");
|
||||
iKnockDownOddsBase = gmst.find("iKnockDownOddsBase");
|
||||
|
||||
inited = true;
|
||||
}
|
||||
@ -307,6 +308,17 @@ namespace MWClass
|
||||
autoCalculateSkills(ref->mBase, data->mNpcStats);
|
||||
}
|
||||
|
||||
if (data->mNpcStats.getFactionRanks().size())
|
||||
{
|
||||
static const int iAutoRepFacMod = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>()
|
||||
.find("iAutoRepFacMod")->getInt();
|
||||
static const int iAutoRepLevMod = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>()
|
||||
.find("iAutoRepLevMod")->getInt();
|
||||
int rank = data->mNpcStats.getFactionRanks().begin()->second;
|
||||
|
||||
data->mNpcStats.setReputation(iAutoRepFacMod * (rank+1) + iAutoRepLevMod * (data->mNpcStats.getLevel()-1));
|
||||
}
|
||||
|
||||
data->mNpcStats.getAiSequence().fill(ref->mBase->mAiPackage);
|
||||
|
||||
data->mNpcStats.setAiSetting (MWMechanics::CreatureStats::AI_Hello, ref->mBase->mAiData.mHello);
|
||||
@ -425,6 +437,20 @@ namespace MWClass
|
||||
if(!weapon.isEmpty() && weapon.getTypeName() != typeid(ESM::Weapon).name())
|
||||
weapon = MWWorld::Ptr();
|
||||
|
||||
// Reduce fatigue
|
||||
// somewhat of a guess, but using the weapon weight makes sense
|
||||
const float fFatigueAttackBase = gmst.find("fFatigueAttackBase")->getFloat();
|
||||
const float fFatigueAttackMult = gmst.find("fFatigueAttackMult")->getFloat();
|
||||
const float fWeaponFatigueMult = gmst.find("fWeaponFatigueMult")->getFloat();
|
||||
MWMechanics::DynamicStat<float> fatigue = getCreatureStats(ptr).getFatigue();
|
||||
const float normalizedEncumbrance = getEncumbrance(ptr) / getCapacity(ptr);
|
||||
float fatigueLoss = fFatigueAttackBase + normalizedEncumbrance * fFatigueAttackMult;
|
||||
if (!weapon.isEmpty())
|
||||
fatigueLoss += weapon.getClass().getWeight(weapon) * getNpcStats(ptr).getAttackStrength() * fWeaponFatigueMult;
|
||||
fatigue.setCurrent(fatigue.getCurrent() - fatigueLoss);
|
||||
getCreatureStats(ptr).setFatigue(fatigue);
|
||||
|
||||
|
||||
float dist = 100.0f * (!weapon.isEmpty() ?
|
||||
weapon.get<ESM::Weapon>()->mBase->mData.mReach :
|
||||
gmst.find("fHandToHandReach")->getFloat());
|
||||
@ -486,12 +512,6 @@ namespace MWClass
|
||||
weapon.getCellRef().mCharge = weapmaxhealth;
|
||||
damage *= float(weapon.getCellRef().mCharge) / weapmaxhealth;
|
||||
}
|
||||
if(!othercls.hasDetected(victim, ptr))
|
||||
{
|
||||
damage *= gmst.find("fCombatCriticalStrikeMult")->getFloat();
|
||||
MWBase::Environment::get().getWindowManager()->messageBox("#{sTargetCriticalStrike}");
|
||||
MWBase::Environment::get().getSoundManager()->playSound3D(victim, "critical damage", 1.0f, 1.0f);
|
||||
}
|
||||
|
||||
if (!MWBase::Environment::get().getWorld()->getGodModeState())
|
||||
weapon.getCellRef().mCharge -= std::min(std::max(1,
|
||||
@ -513,12 +533,6 @@ namespace MWClass
|
||||
float maxstrike = gmst.find("fMaxHandToHandMult")->getFloat();
|
||||
damage = stats.getSkill(weapskill).getModified();
|
||||
damage *= minstrike + ((maxstrike-minstrike)*stats.getAttackStrength());
|
||||
if(!othercls.hasDetected(victim, ptr))
|
||||
{
|
||||
damage *= gmst.find("fCombatCriticalStrikeMult")->getFloat();
|
||||
MWBase::Environment::get().getWindowManager()->messageBox("#{sTargetCriticalStrike}");
|
||||
MWBase::Environment::get().getSoundManager()->playSound3D(victim, "critical damage", 1.0f, 1.0f);
|
||||
}
|
||||
|
||||
healthdmg = (otherstats.getFatigue().getCurrent() < 1.0f)
|
||||
|| (otherstats.getMagicEffects().get(ESM::MagicEffect::Paralyze).mMagnitude > 0);
|
||||
@ -545,6 +559,16 @@ namespace MWClass
|
||||
if(ptr.getRefData().getHandle() == "player")
|
||||
skillUsageSucceeded(ptr, weapskill, 0);
|
||||
|
||||
bool detected = MWBase::Environment::get().getMechanicsManager()->awarenessCheck(ptr, victim);
|
||||
if(!detected)
|
||||
{
|
||||
damage *= gmst.find("fCombatCriticalStrikeMult")->getFloat();
|
||||
MWBase::Environment::get().getWindowManager()->messageBox("#{sTargetCriticalStrike}");
|
||||
MWBase::Environment::get().getSoundManager()->playSound3D(victim, "critical damage", 1.0f, 1.0f);
|
||||
}
|
||||
if (othercls.getCreatureStats(victim).getKnockedDown())
|
||||
damage *= gmst.find("fCombatKODamageMult")->getFloat();
|
||||
|
||||
// Apply "On hit" enchanted weapons
|
||||
std::string enchantmentName = !weapon.isEmpty() ? weapon.getClass().getEnchantment(weapon) : "";
|
||||
if (!enchantmentName.empty())
|
||||
@ -587,6 +611,10 @@ namespace MWClass
|
||||
|
||||
// NOTE: 'object' and/or 'attacker' may be empty.
|
||||
|
||||
// Attacking peaceful NPCs is a crime
|
||||
if (!attacker.isEmpty() && ptr.getClass().isNpc() && ptr.getClass().getCreatureStats(ptr).getAiSetting(MWMechanics::CreatureStats::AI_Fight).getModified() <= 30)
|
||||
MWBase::Environment::get().getMechanicsManager()->commitCrime(attacker, ptr, MWBase::MechanicsManager::OT_Assault);
|
||||
|
||||
if(!successful)
|
||||
{
|
||||
// TODO: Handle HitAttemptOnMe script function
|
||||
@ -601,7 +629,7 @@ namespace MWClass
|
||||
|
||||
if(!attacker.isEmpty() && attacker.getRefData().getHandle() == "player")
|
||||
{
|
||||
const std::string &script = ptr.get<ESM::NPC>()->mBase->mScript;
|
||||
const std::string &script = ptr.getClass().getScript(ptr);
|
||||
/* Set the OnPCHitMe script variable. The script is responsible for clearing it. */
|
||||
if(!script.empty())
|
||||
ptr.getRefData().getLocals().setVarByInt(script, "onpchitme", 1);
|
||||
@ -615,8 +643,27 @@ namespace MWClass
|
||||
// 'ptr' is losing health. Play a 'hit' voiced dialog entry if not already saying
|
||||
// something, alert the character controller, scripts, etc.
|
||||
|
||||
MWBase::Environment::get().getDialogueManager()->say(ptr, "hit");
|
||||
getCreatureStats(ptr).setAttacked(true);//used in CharacterController
|
||||
const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore();
|
||||
int chance = store.get<ESM::GameSetting>().find("iVoiceHitOdds")->getInt();
|
||||
int roll = std::rand()/ (static_cast<double> (RAND_MAX) + 1) * 100; // [0, 99]
|
||||
if (roll < chance)
|
||||
{
|
||||
MWBase::Environment::get().getDialogueManager()->say(ptr, "hit");
|
||||
}
|
||||
getCreatureStats(ptr).setAttacked(true);
|
||||
|
||||
// Check for knockdown
|
||||
float agilityTerm = getCreatureStats(ptr).getAttribute(ESM::Attribute::Agility).getModified() * fKnockDownMult->getFloat();
|
||||
float knockdownTerm = getCreatureStats(ptr).getAttribute(ESM::Attribute::Agility).getModified()
|
||||
* iKnockDownOddsMult->getInt() * 0.01 + iKnockDownOddsBase->getInt();
|
||||
roll = std::rand()/ (static_cast<double> (RAND_MAX) + 1) * 100; // [0, 99]
|
||||
if (ishealth && agilityTerm <= damage && knockdownTerm <= roll)
|
||||
{
|
||||
getCreatureStats(ptr).setKnockedDown(true);
|
||||
|
||||
}
|
||||
else
|
||||
getCreatureStats(ptr).setHitRecovery(true); // Is this supposed to always occur?
|
||||
|
||||
if(object.isEmpty())
|
||||
{
|
||||
@ -728,7 +775,7 @@ namespace MWClass
|
||||
}
|
||||
if(getCreatureStats(ptr).isDead())
|
||||
return boost::shared_ptr<MWWorld::Action>(new MWWorld::ActionOpen(ptr, true));
|
||||
if(get(actor).getStance(actor, MWWorld::Class::Sneak))
|
||||
if(getCreatureStats(ptr).getStance(MWMechanics::CreatureStats::Stance_Sneak))
|
||||
return boost::shared_ptr<MWWorld::Action>(new MWWorld::ActionOpen(ptr)); // stealing
|
||||
if(get(ptr).getCreatureStats(ptr).isHostile())
|
||||
return boost::shared_ptr<MWWorld::Action>(new MWWorld::FailedAction("#{sActorInCombat}"));
|
||||
@ -759,80 +806,6 @@ namespace MWClass
|
||||
return ref->mBase->mScript;
|
||||
}
|
||||
|
||||
void Npc::setForceStance (const MWWorld::Ptr& ptr, Stance stance, bool force) const
|
||||
{
|
||||
MWMechanics::NpcStats& stats = getNpcStats (ptr);
|
||||
|
||||
switch (stance)
|
||||
{
|
||||
case Run:
|
||||
|
||||
stats.setMovementFlag (MWMechanics::NpcStats::Flag_ForceRun, force);
|
||||
break;
|
||||
|
||||
case Sneak:
|
||||
|
||||
stats.setMovementFlag (MWMechanics::NpcStats::Flag_ForceSneak, force);
|
||||
break;
|
||||
|
||||
case Combat:
|
||||
|
||||
throw std::runtime_error ("combat stance not enforcable for NPCs");
|
||||
}
|
||||
}
|
||||
|
||||
void Npc::setStance (const MWWorld::Ptr& ptr, Stance stance, bool set) const
|
||||
{
|
||||
MWMechanics::NpcStats& stats = getNpcStats (ptr);
|
||||
|
||||
switch (stance)
|
||||
{
|
||||
case Run:
|
||||
|
||||
stats.setMovementFlag (MWMechanics::NpcStats::Flag_Run, set);
|
||||
break;
|
||||
|
||||
case Sneak:
|
||||
|
||||
stats.setMovementFlag (MWMechanics::NpcStats::Flag_Sneak, set);
|
||||
break;
|
||||
|
||||
case Combat:
|
||||
|
||||
// Combat stance ignored for now; need to be determined based on draw state instead of
|
||||
// being maunally set.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool Npc::getStance (const MWWorld::Ptr& ptr, Stance stance, bool ignoreForce) const
|
||||
{
|
||||
MWMechanics::NpcStats& stats = getNpcStats (ptr);
|
||||
|
||||
switch (stance)
|
||||
{
|
||||
case Run:
|
||||
|
||||
if (!ignoreForce && stats.getMovementFlag (MWMechanics::NpcStats::Flag_ForceRun))
|
||||
return true;
|
||||
|
||||
return stats.getMovementFlag (MWMechanics::NpcStats::Flag_Run);
|
||||
|
||||
case Sneak:
|
||||
|
||||
if (!ignoreForce && stats.getMovementFlag (MWMechanics::NpcStats::Flag_ForceSneak))
|
||||
return true;
|
||||
|
||||
return stats.getMovementFlag (MWMechanics::NpcStats::Flag_Sneak);
|
||||
|
||||
case Combat:
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
float Npc::getSpeed(const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
const MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||
@ -841,11 +814,14 @@ namespace MWClass
|
||||
|
||||
const float normalizedEncumbrance = Npc::getEncumbrance(ptr) / Npc::getCapacity(ptr);
|
||||
|
||||
bool sneaking = ptr.getClass().getCreatureStats(ptr).getStance(MWMechanics::CreatureStats::Stance_Sneak);
|
||||
bool running = ptr.getClass().getCreatureStats(ptr).getStance(MWMechanics::CreatureStats::Stance_Run);
|
||||
|
||||
float walkSpeed = fMinWalkSpeed->getFloat() + 0.01f*npcdata->mNpcStats.getAttribute(ESM::Attribute::Speed).getModified()*
|
||||
(fMaxWalkSpeed->getFloat() - fMinWalkSpeed->getFloat());
|
||||
walkSpeed *= 1.0f - fEncumberedMoveEffect->getFloat()*normalizedEncumbrance;
|
||||
walkSpeed = std::max(0.0f, walkSpeed);
|
||||
if(Npc::getStance(ptr, Sneak, false))
|
||||
if(sneaking)
|
||||
walkSpeed *= fSneakSpeedMultiplier->getFloat();
|
||||
|
||||
float runSpeed = walkSpeed*(0.01f * npcdata->mNpcStats.getSkill(ESM::Skill::Athletics).getModified() *
|
||||
@ -869,14 +845,14 @@ namespace MWClass
|
||||
else if(world->isSwimming(ptr))
|
||||
{
|
||||
float swimSpeed = walkSpeed;
|
||||
if(Npc::getStance(ptr, Run, false))
|
||||
if(running)
|
||||
swimSpeed = runSpeed;
|
||||
swimSpeed *= 1.0f + 0.01f * mageffects.get(ESM::MagicEffect::SwiftSwim).mMagnitude;
|
||||
swimSpeed *= fSwimRunBase->getFloat() + 0.01f*npcdata->mNpcStats.getSkill(ESM::Skill::Athletics).getModified()*
|
||||
fSwimRunAthleticsMult->getFloat();
|
||||
moveSpeed = swimSpeed;
|
||||
}
|
||||
else if(Npc::getStance(ptr, Run, false) && !Npc::getStance(ptr, Sneak, false))
|
||||
else if(running && !sneaking)
|
||||
moveSpeed = runSpeed;
|
||||
else
|
||||
moveSpeed = walkSpeed;
|
||||
@ -908,7 +884,7 @@ namespace MWClass
|
||||
x += mageffects.get(ESM::MagicEffect::Jump).mMagnitude * 64;
|
||||
x *= encumbranceTerm;
|
||||
|
||||
if(Npc::getStance(ptr, Run, false))
|
||||
if(ptr.getClass().getCreatureStats(ptr).getStance(MWMechanics::CreatureStats::Stance_Run))
|
||||
x *= fJumpRunMultiplier->getFloat();
|
||||
x *= npcdata->mNpcStats.getFatigueTerm();
|
||||
x -= -627.2f;/*gravity constant*/
|
||||
@ -1020,7 +996,8 @@ namespace MWClass
|
||||
float Npc::getCapacity (const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
const MWMechanics::CreatureStats& stats = getCreatureStats (ptr);
|
||||
return stats.getAttribute(0).getModified()*5;
|
||||
static const float fEncumbranceStrMult = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fEncumbranceStrMult")->getFloat();
|
||||
return stats.getAttribute(0).getModified()*fEncumbranceStrMult;
|
||||
}
|
||||
|
||||
float Npc::getEncumbrance (const MWWorld::Ptr& ptr) const
|
||||
@ -1234,6 +1211,11 @@ namespace MWClass
|
||||
return MWWorld::Ptr(&cell.mNpcs.insert(*ref), &cell);
|
||||
}
|
||||
|
||||
int Npc::getSkill(const MWWorld::Ptr& ptr, int skill) const
|
||||
{
|
||||
return ptr.getClass().getNpcStats(ptr).getSkill(skill).getModified();
|
||||
}
|
||||
|
||||
const ESM::GameSetting *Npc::fMinWalkSpeed;
|
||||
const ESM::GameSetting *Npc::fMaxWalkSpeed;
|
||||
const ESM::GameSetting *Npc::fEncumberedMoveEffect;
|
||||
@ -1250,4 +1232,7 @@ namespace MWClass
|
||||
const ESM::GameSetting *Npc::fJumpAcroMultiplier;
|
||||
const ESM::GameSetting *Npc::fJumpRunMultiplier;
|
||||
const ESM::GameSetting *Npc::fWereWolfRunMult;
|
||||
const ESM::GameSetting *Npc::fKnockDownMult;
|
||||
const ESM::GameSetting *Npc::iKnockDownOddsMult;
|
||||
const ESM::GameSetting *Npc::iKnockDownOddsBase;
|
||||
}
|
||||
|
@ -33,6 +33,9 @@ namespace MWClass
|
||||
static const ESM::GameSetting *fJumpAcroMultiplier;
|
||||
static const ESM::GameSetting *fJumpRunMultiplier;
|
||||
static const ESM::GameSetting *fWereWolfRunMult;
|
||||
static const ESM::GameSetting *fKnockDownMult;
|
||||
static const ESM::GameSetting *iKnockDownOddsMult;
|
||||
static const ESM::GameSetting *iKnockDownOddsBase;
|
||||
|
||||
public:
|
||||
|
||||
@ -81,16 +84,6 @@ namespace MWClass
|
||||
virtual std::string getScript (const MWWorld::Ptr& ptr) const;
|
||||
///< Return name of the script attached to ptr
|
||||
|
||||
virtual void setForceStance (const MWWorld::Ptr& ptr, Stance stance, bool force) const;
|
||||
///< Force or unforce a stance.
|
||||
|
||||
virtual void setStance (const MWWorld::Ptr& ptr, Stance stance, bool set) const;
|
||||
///< Set or unset a stance.
|
||||
|
||||
virtual bool getStance (const MWWorld::Ptr& ptr, Stance stance, bool ignoreForce = false)
|
||||
const;
|
||||
///< Check if a stance is active or not.
|
||||
|
||||
virtual float getSpeed (const MWWorld::Ptr& ptr) const;
|
||||
///< Return movement speed.
|
||||
|
||||
@ -147,6 +140,8 @@ namespace MWClass
|
||||
|
||||
virtual std::string getModel(const MWWorld::Ptr &ptr) const;
|
||||
|
||||
virtual int getSkill(const MWWorld::Ptr& ptr, int skill) const;
|
||||
|
||||
virtual bool isActor() const {
|
||||
return true;
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ bool MWDialogue::Filter::testActor (const ESM::DialInfo& info) const
|
||||
// actor id
|
||||
if (!info.mActor.empty())
|
||||
{
|
||||
if ( Misc::StringUtils::lowerCase (info.mActor)!=MWWorld::Class::get (mActor).getId (mActor))
|
||||
if ( !Misc::StringUtils::ciEqual(info.mActor, MWWorld::Class::get (mActor).getId (mActor)))
|
||||
return false;
|
||||
}
|
||||
else if (isCreature)
|
||||
@ -41,7 +41,7 @@ bool MWDialogue::Filter::testActor (const ESM::DialInfo& info) const
|
||||
|
||||
MWWorld::LiveCellRef<ESM::NPC> *cellRef = mActor.get<ESM::NPC>();
|
||||
|
||||
if (Misc::StringUtils::lowerCase (info.mRace)!= Misc::StringUtils::lowerCase (cellRef->mBase->mRace))
|
||||
if (!Misc::StringUtils::ciEqual(info.mRace, cellRef->mBase->mRace))
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -53,7 +53,7 @@ bool MWDialogue::Filter::testActor (const ESM::DialInfo& info) const
|
||||
|
||||
MWWorld::LiveCellRef<ESM::NPC> *cellRef = mActor.get<ESM::NPC>();
|
||||
|
||||
if ( Misc::StringUtils::lowerCase (info.mClass)!= Misc::StringUtils::lowerCase (cellRef->mBase->mClass))
|
||||
if ( !Misc::StringUtils::ciEqual(info.mClass, cellRef->mBase->mClass))
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -110,7 +110,7 @@ bool MWDialogue::Filter::testPlayer (const ESM::DialInfo& info) const
|
||||
|
||||
// check cell
|
||||
if (!info.mCell.empty())
|
||||
if (Misc::StringUtils::lowerCase (player.getCell()->mCell->mName) != Misc::StringUtils::lowerCase (info.mCell))
|
||||
if (!Misc::StringUtils::ciEqual(player.getCell()->mCell->mName, info.mCell))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
@ -188,7 +188,7 @@ bool MWDialogue::Filter::testSelectStructNumeric (const SelectWrapper& select) c
|
||||
int i = 0;
|
||||
|
||||
for (; i<static_cast<int> (script->mVarNames.size()); ++i)
|
||||
if (Misc::StringUtils::lowerCase(script->mVarNames[i]) == name)
|
||||
if (Misc::StringUtils::ciEqual(script->mVarNames[i], name))
|
||||
break;
|
||||
|
||||
if (i>=static_cast<int> (script->mVarNames.size()))
|
||||
@ -262,7 +262,7 @@ int MWDialogue::Filter::getSelectStructInteger (const SelectWrapper& select) con
|
||||
std::string name = select.getName();
|
||||
|
||||
for (MWWorld::ContainerStoreIterator iter (store.begin()); iter!=store.end(); ++iter)
|
||||
if (Misc::StringUtils::lowerCase(iter->getCellRef().mRefID) == name)
|
||||
if (Misc::StringUtils::ciEqual(iter->getCellRef().mRefID, name))
|
||||
sum += iter->getRefData().getCount();
|
||||
|
||||
return sum;
|
||||
@ -429,23 +429,23 @@ bool MWDialogue::Filter::getSelectStructBoolean (const SelectWrapper& select) co
|
||||
|
||||
case SelectWrapper::Function_NotId:
|
||||
|
||||
return select.getName()!=Misc::StringUtils::lowerCase (MWWorld::Class::get (mActor).getId (mActor));
|
||||
return !Misc::StringUtils::ciEqual(MWWorld::Class::get (mActor).getId (mActor), select.getName());
|
||||
|
||||
case SelectWrapper::Function_NotFaction:
|
||||
|
||||
return Misc::StringUtils::lowerCase (mActor.get<ESM::NPC>()->mBase->mFaction)!=select.getName();
|
||||
return !Misc::StringUtils::ciEqual(mActor.get<ESM::NPC>()->mBase->mFaction, select.getName());
|
||||
|
||||
case SelectWrapper::Function_NotClass:
|
||||
|
||||
return Misc::StringUtils::lowerCase (mActor.get<ESM::NPC>()->mBase->mClass)!=select.getName();
|
||||
return !Misc::StringUtils::ciEqual(mActor.get<ESM::NPC>()->mBase->mClass, select.getName());
|
||||
|
||||
case SelectWrapper::Function_NotRace:
|
||||
|
||||
return Misc::StringUtils::lowerCase (mActor.get<ESM::NPC>()->mBase->mRace)!=select.getName();
|
||||
return !Misc::StringUtils::ciEqual(mActor.get<ESM::NPC>()->mBase->mRace, select.getName());
|
||||
|
||||
case SelectWrapper::Function_NotCell:
|
||||
|
||||
return Misc::StringUtils::lowerCase (mActor.getCell()->mCell->mName)!=select.getName();
|
||||
return !Misc::StringUtils::ciEqual(mActor.getCell()->mCell->mName, select.getName());
|
||||
|
||||
case SelectWrapper::Function_NotLocal:
|
||||
{
|
||||
@ -462,7 +462,7 @@ bool MWDialogue::Filter::getSelectStructBoolean (const SelectWrapper& select) co
|
||||
|
||||
int i = 0;
|
||||
for (; i < static_cast<int> (script->mVarNames.size()); ++i)
|
||||
if (Misc::StringUtils::lowerCase(script->mVarNames[i]) == name)
|
||||
if (Misc::StringUtils::ciEqual(script->mVarNames[i], name))
|
||||
break;
|
||||
|
||||
if (i >= static_cast<int> (script->mVarNames.size()))
|
||||
@ -478,8 +478,7 @@ bool MWDialogue::Filter::getSelectStructBoolean (const SelectWrapper& select) co
|
||||
|
||||
case SelectWrapper::Function_SameRace:
|
||||
|
||||
return Misc::StringUtils::lowerCase (mActor.get<ESM::NPC>()->mBase->mRace)!=
|
||||
Misc::StringUtils::lowerCase (player.get<ESM::NPC>()->mBase->mRace);
|
||||
return !Misc::StringUtils::ciEqual(mActor.get<ESM::NPC>()->mBase->mRace, player.get<ESM::NPC>()->mBase->mRace);
|
||||
|
||||
case SelectWrapper::Function_SameFaction:
|
||||
|
||||
@ -525,7 +524,7 @@ bool MWDialogue::Filter::getSelectStructBoolean (const SelectWrapper& select) co
|
||||
|
||||
case SelectWrapper::Function_Detected:
|
||||
|
||||
return MWWorld::Class::get (mActor).hasDetected (mActor, player);
|
||||
return MWBase::Environment::get().getMechanicsManager()->awarenessCheck(player, mActor);
|
||||
|
||||
case SelectWrapper::Function_Attacked:
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
#include "birth.hpp"
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
@ -77,7 +76,7 @@ namespace MWGui
|
||||
size_t count = mBirthList->getItemCount();
|
||||
for (size_t i = 0; i < count; ++i)
|
||||
{
|
||||
if (boost::iequals(*mBirthList->getItemDataAt<std::string>(i), birthId))
|
||||
if (Misc::StringUtils::ciEqual(*mBirthList->getItemDataAt<std::string>(i), birthId))
|
||||
{
|
||||
mBirthList->setIndexSelected(i);
|
||||
MyGUI::Button* okButton;
|
||||
@ -112,7 +111,7 @@ namespace MWGui
|
||||
getWidget(okButton, "OKButton");
|
||||
|
||||
const std::string *birthId = mBirthList->getItemDataAt<std::string>(_index);
|
||||
if (boost::iequals(mCurrentBirthId, *birthId))
|
||||
if (Misc::StringUtils::ciEqual(mCurrentBirthId, *birthId))
|
||||
return;
|
||||
|
||||
mCurrentBirthId = *birthId;
|
||||
@ -148,7 +147,7 @@ namespace MWGui
|
||||
mBirthList->setIndexSelected(index);
|
||||
mCurrentBirthId = it2->first;
|
||||
}
|
||||
else if (boost::iequals(it2->first, mCurrentBirthId))
|
||||
else if (Misc::StringUtils::ciEqual(it2->first, mCurrentBirthId))
|
||||
{
|
||||
mBirthList->setIndexSelected(index);
|
||||
}
|
||||
|
@ -1,7 +1,5 @@
|
||||
#include "class.hpp"
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
@ -29,11 +27,12 @@ namespace MWGui
|
||||
|
||||
MyGUI::Button* backButton;
|
||||
getWidget(backButton, "BackButton");
|
||||
backButton->setCaptionWithReplacing("#{sMessageQuestionAnswer3}");
|
||||
backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &GenerateClassResultDialog::onBackClicked);
|
||||
|
||||
MyGUI::Button* okButton;
|
||||
getWidget(okButton, "OKButton");
|
||||
okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", ""));
|
||||
okButton->setCaptionWithReplacing("#{sMessageQuestionAnswer2}");
|
||||
okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &GenerateClassResultDialog::onOkClicked);
|
||||
}
|
||||
|
||||
@ -127,7 +126,7 @@ namespace MWGui
|
||||
size_t count = mClassList->getItemCount();
|
||||
for (size_t i = 0; i < count; ++i)
|
||||
{
|
||||
if (boost::iequals(*mClassList->getItemDataAt<std::string>(i), classId))
|
||||
if (Misc::StringUtils::ciEqual(*mClassList->getItemDataAt<std::string>(i), classId))
|
||||
{
|
||||
mClassList->setIndexSelected(i);
|
||||
MyGUI::Button* okButton;
|
||||
@ -162,7 +161,7 @@ namespace MWGui
|
||||
getWidget(okButton, "OKButton");
|
||||
|
||||
const std::string *classId = mClassList->getItemDataAt<std::string>(_index);
|
||||
if (boost::iequals(mCurrentClassId, *classId))
|
||||
if (Misc::StringUtils::ciEqual(mCurrentClassId, *classId))
|
||||
return;
|
||||
|
||||
mCurrentClassId = *classId;
|
||||
@ -192,7 +191,7 @@ namespace MWGui
|
||||
mCurrentClassId = id;
|
||||
mClassList->setIndexSelected(index);
|
||||
}
|
||||
else if (boost::iequals(id, mCurrentClassId))
|
||||
else if (Misc::StringUtils::ciEqual(id, mCurrentClassId))
|
||||
{
|
||||
mClassList->setIndexSelected(index);
|
||||
}
|
||||
|
@ -139,6 +139,7 @@ namespace MWGui
|
||||
|
||||
mDisposeCorpseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onDisposeCorpseButtonClicked);
|
||||
mCloseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onCloseButtonClicked);
|
||||
mCloseButton->eventKeyButtonPressed += MyGUI::newDelegate(this, &ContainerWindow::onKeyPressed);
|
||||
mTakeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onTakeAllButtonClicked);
|
||||
|
||||
setCoord(200,0,600,300);
|
||||
@ -234,11 +235,21 @@ namespace MWGui
|
||||
|
||||
mItemView->setModel (mSortModel);
|
||||
|
||||
MyGUI::InputManager::getInstance().setKeyFocusWidget(mCloseButton);
|
||||
|
||||
// Careful here. setTitle may cause size updates, causing itemview redraw, so make sure to do it last
|
||||
// or we end up using a possibly invalid model.
|
||||
setTitle(MWWorld::Class::get(container).getName(container));
|
||||
}
|
||||
|
||||
void ContainerWindow::onKeyPressed(MyGUI::Widget *_sender, MyGUI::KeyCode _key, MyGUI::Char _char)
|
||||
{
|
||||
if (_key == MyGUI::KeyCode::Space)
|
||||
onCloseButtonClicked(mCloseButton);
|
||||
if (_key == MyGUI::KeyCode::Return || _key == MyGUI::KeyCode::NumpadEnter)
|
||||
onTakeAllButtonClicked(mTakeButton);
|
||||
}
|
||||
|
||||
void ContainerWindow::close()
|
||||
{
|
||||
WindowBase::close();
|
||||
@ -338,6 +349,8 @@ namespace MWGui
|
||||
mPickpocketDetected = true;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
player.getClass().skillUsageSucceeded(player, ESM::Skill::Sneak, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -75,6 +75,7 @@ namespace MWGui
|
||||
void onCloseButtonClicked(MyGUI::Widget* _sender);
|
||||
void onTakeAllButtonClicked(MyGUI::Widget* _sender);
|
||||
void onDisposeCorpseButtonClicked(MyGUI::Widget* sender);
|
||||
void onKeyPressed(MyGUI::Widget* _sender, MyGUI::KeyCode _key, MyGUI::Char _char);
|
||||
|
||||
/// @return is taking the item allowed?
|
||||
bool onTakeItem(const ItemStack& item, int count);
|
||||
|
@ -545,7 +545,7 @@ namespace MWGui
|
||||
for (size_t i=0; i<mTopicsList->getItemCount(); ++i)
|
||||
{
|
||||
std::string item = mTopicsList->getItemNameAt(i);
|
||||
if (Misc::StringUtils::lowerCase(item) == title)
|
||||
if (Misc::StringUtils::ciEqual(item, title))
|
||||
{
|
||||
realTitle = item;
|
||||
break;
|
||||
|
@ -257,7 +257,7 @@ namespace MWGui
|
||||
{
|
||||
if (mEffects.size() <= 0)
|
||||
{
|
||||
MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage30}");
|
||||
MWBase::Environment::get().getWindowManager()->messageBox ("#{sEnchantmentMenu11}");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,8 @@
|
||||
#include "../mwworld/inventorystore.hpp"
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwworld/action.hpp"
|
||||
#include "../mwscript/interpretercontext.hpp"
|
||||
#include "../mwbase/scriptmanager.hpp"
|
||||
|
||||
#include "bookwindow.hpp"
|
||||
#include "scrollwindow.hpp"
|
||||
@ -351,6 +353,48 @@ namespace MWGui
|
||||
MWBase::Environment::get().getWindowManager()->setWeaponVisibility(!mPinned);
|
||||
}
|
||||
|
||||
void InventoryWindow::useItem(const MWWorld::Ptr &ptr)
|
||||
{
|
||||
const std::string& script = ptr.getClass().getScript(ptr);
|
||||
|
||||
// If the item has a script, set its OnPcEquip to 1
|
||||
if (!script.empty()
|
||||
// Another morrowind oddity: when an item has skipped equipping and pcskipequip is reset to 0 afterwards,
|
||||
// the next time it is equipped will work normally, but will not set onpcequip
|
||||
&& (ptr != mSkippedToEquip || ptr.getRefData().getLocals().getIntVar(script, "pcskipequip") == 1))
|
||||
ptr.getRefData().getLocals().setVarByInt(script, "onpcequip", 1);
|
||||
|
||||
// Give the script a chance to run once before we do anything else
|
||||
// this is important when setting pcskipequip as a reaction to onpcequip being set (bk_treasuryreport does this)
|
||||
if (!script.empty())
|
||||
{
|
||||
MWScript::InterpreterContext interpreterContext (&ptr.getRefData().getLocals(), ptr);
|
||||
MWBase::Environment::get().getScriptManager()->run (script, interpreterContext);
|
||||
}
|
||||
|
||||
if (script.empty() || ptr.getRefData().getLocals().getIntVar(script, "pcskipequip") == 0)
|
||||
{
|
||||
boost::shared_ptr<MWWorld::Action> action = MWWorld::Class::get(ptr).use(ptr);
|
||||
|
||||
action->execute (MWBase::Environment::get().getWorld()->getPlayerPtr());
|
||||
|
||||
// this is necessary for books/scrolls: if they are already in the player's inventory,
|
||||
// the "Take" button should not be visible.
|
||||
// NOTE: the take button is "reset" when the window opens, so we can safely do the following
|
||||
// without screwing up future book windows
|
||||
MWBase::Environment::get().getWindowManager()->getBookWindow()->setTakeButtonShow(false);
|
||||
MWBase::Environment::get().getWindowManager()->getScrollWindow()->setTakeButtonShow(false);
|
||||
|
||||
mSkippedToEquip = MWWorld::Ptr();
|
||||
}
|
||||
else
|
||||
mSkippedToEquip = ptr;
|
||||
|
||||
mItemView->update();
|
||||
|
||||
notifyContentChanged();
|
||||
}
|
||||
|
||||
void InventoryWindow::onAvatarClicked(MyGUI::Widget* _sender)
|
||||
{
|
||||
if (mDragAndDrop->mIsOnDragAndDrop)
|
||||
@ -369,21 +413,7 @@ namespace MWGui
|
||||
mDragAndDrop->mSourceModel->removeItem(mDragAndDrop->mItem, mDragAndDrop->mDraggedCount);
|
||||
ptr = *it;
|
||||
}
|
||||
|
||||
boost::shared_ptr<MWWorld::Action> action = MWWorld::Class::get(ptr).use(ptr);
|
||||
|
||||
action->execute (MWBase::Environment::get().getWorld()->getPlayerPtr());
|
||||
|
||||
// this is necessary for books/scrolls: if they are already in the player's inventory,
|
||||
// the "Take" button should not be visible.
|
||||
// NOTE: the take button is "reset" when the window opens, so we can safely do the following
|
||||
// without screwing up future book windows
|
||||
MWBase::Environment::get().getWindowManager()->getBookWindow()->setTakeButtonShow(false);
|
||||
MWBase::Environment::get().getWindowManager()->getScrollWindow()->setTakeButtonShow(false);
|
||||
|
||||
mItemView->update();
|
||||
|
||||
notifyContentChanged();
|
||||
useItem(ptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -46,6 +46,8 @@ namespace MWGui
|
||||
|
||||
void updatePlayer();
|
||||
|
||||
void useItem(const MWWorld::Ptr& ptr);
|
||||
|
||||
void setGuiMode(GuiMode mode);
|
||||
|
||||
private:
|
||||
@ -74,6 +76,8 @@ namespace MWGui
|
||||
MyGUI::Button* mFilterMagic;
|
||||
MyGUI::Button* mFilterMisc;
|
||||
|
||||
MWWorld::Ptr mSkippedToEquip;
|
||||
|
||||
GuiMode mGuiMode;
|
||||
|
||||
int mLastXSize;
|
||||
|
@ -8,13 +8,12 @@
|
||||
namespace MWGui
|
||||
{
|
||||
|
||||
MessageBoxManager::MessageBoxManager ()
|
||||
MessageBoxManager::MessageBoxManager (float timePerChar)
|
||||
{
|
||||
// TODO: fMessageTimePerChar
|
||||
mMessageBoxSpeed = 0.1;
|
||||
mInterMessageBoxe = NULL;
|
||||
mStaticMessageBox = NULL;
|
||||
mLastButtonPressed = -1;
|
||||
mMessageBoxSpeed = timePerChar;
|
||||
}
|
||||
|
||||
MessageBoxManager::~MessageBoxManager ()
|
||||
@ -63,7 +62,8 @@ namespace MWGui
|
||||
{
|
||||
MessageBox *box = new MessageBox(*this, message);
|
||||
box->mCurrentTime = 0;
|
||||
box->mMaxTime = message.length()*mMessageBoxSpeed;
|
||||
std::string realMessage = MyGUI::LanguageManager::getInstance().replaceTags(message);
|
||||
box->mMaxTime = realMessage.length()*mMessageBoxSpeed;
|
||||
|
||||
if(stat)
|
||||
mStaticMessageBox = box;
|
||||
@ -127,12 +127,6 @@ namespace MWGui
|
||||
mMessageBoxSpeed = speed;
|
||||
}
|
||||
|
||||
void MessageBoxManager::okayPressed ()
|
||||
{
|
||||
if(mInterMessageBoxe != NULL)
|
||||
mInterMessageBoxe->okayPressed();
|
||||
}
|
||||
|
||||
int MessageBoxManager::readPressedButton ()
|
||||
{
|
||||
int pressed = mLastButtonPressed;
|
||||
@ -333,23 +327,25 @@ namespace MWGui
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void InteractiveMessageBox::okayPressed()
|
||||
{
|
||||
|
||||
// Set key focus to "Ok" button
|
||||
std::string ok = Misc::StringUtils::lowerCase(MyGUI::LanguageManager::getInstance().replaceTags("#{sOK}"));
|
||||
std::vector<MyGUI::Button*>::const_iterator button;
|
||||
for(button = mButtons.begin(); button != mButtons.end(); ++button)
|
||||
{
|
||||
if(Misc::StringUtils::lowerCase((*button)->getCaption()) == ok)
|
||||
if(Misc::StringUtils::ciEqual((*button)->getCaption(), ok))
|
||||
{
|
||||
buttonActivated(*button);
|
||||
MWBase::Environment::get().getSoundManager()->playSound("Menu Click", 1.f, 1.f);
|
||||
MyGUI::InputManager::getInstance().setKeyFocusWidget(*button);
|
||||
(*button)->eventKeyButtonPressed += MyGUI::newDelegate(this, &InteractiveMessageBox::onKeyPressed);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void InteractiveMessageBox::onKeyPressed(MyGUI::Widget *_sender, MyGUI::KeyCode _key, MyGUI::Char _char)
|
||||
{
|
||||
if (_key == MyGUI::KeyCode::Return || _key == MyGUI::KeyCode::NumpadEnter || _key == MyGUI::KeyCode::Space)
|
||||
buttonActivated(_sender);
|
||||
}
|
||||
|
||||
void InteractiveMessageBox::mousePressed (MyGUI::Widget* pressed)
|
||||
|
@ -22,7 +22,7 @@ namespace MWGui
|
||||
class MessageBoxManager
|
||||
{
|
||||
public:
|
||||
MessageBoxManager ();
|
||||
MessageBoxManager (float timePerChar);
|
||||
~MessageBoxManager ();
|
||||
void onFrame (float frameDuration);
|
||||
void createMessageBox (const std::string& message, bool stat = false);
|
||||
@ -33,7 +33,6 @@ namespace MWGui
|
||||
bool removeMessageBox (MessageBox *msgbox);
|
||||
void setMessageBoxSpeed (int speed);
|
||||
|
||||
void okayPressed();
|
||||
int readPressedButton ();
|
||||
|
||||
typedef MyGUI::delegates::CMultiDelegate1<int> EventHandle_Int;
|
||||
@ -74,7 +73,6 @@ namespace MWGui
|
||||
{
|
||||
public:
|
||||
InteractiveMessageBox (MessageBoxManager& parMessageBoxManager, const std::string& message, const std::vector<std::string>& buttons);
|
||||
void okayPressed ();
|
||||
void mousePressed (MyGUI::Widget* _widget);
|
||||
int readPressedButton ();
|
||||
|
||||
@ -82,6 +80,7 @@ namespace MWGui
|
||||
|
||||
private:
|
||||
void buttonActivated (MyGUI::Widget* _widget);
|
||||
void onKeyPressed(MyGUI::Widget* _sender, MyGUI::KeyCode _key, MyGUI::Char _char);
|
||||
|
||||
MessageBoxManager& mMessageBoxManager;
|
||||
MyGUI::EditBox* mMessageWidget;
|
||||
|
@ -9,7 +9,7 @@ namespace MWGui
|
||||
PickpocketItemModel::PickpocketItemModel(const MWWorld::Ptr& thief, ItemModel *sourceModel)
|
||||
{
|
||||
mSourceModel = sourceModel;
|
||||
int chance = MWWorld::Class::get(thief).getNpcStats(thief).getSkill(ESM::Skill::Sneak).getModified();
|
||||
int chance = thief.getClass().getSkill(thief, ESM::Skill::Sneak);
|
||||
|
||||
mSourceModel->update();
|
||||
for (size_t i = 0; i<mSourceModel->getItemCount(); ++i)
|
||||
|
@ -308,19 +308,7 @@ namespace MWGui
|
||||
{
|
||||
MWWorld::Ptr item = *button->getChildAt (0)->getUserData<MWWorld::Ptr>();
|
||||
|
||||
boost::shared_ptr<MWWorld::Action> action = MWWorld::Class::get(item).use(item);
|
||||
|
||||
action->execute (MWBase::Environment::get().getWorld()->getPlayerPtr());
|
||||
|
||||
// this is necessary for books/scrolls: if they are already in the player's inventory,
|
||||
// the "Take" button should not be visible.
|
||||
// NOTE: the take button is "reset" when the window opens, so we can safely do the following
|
||||
// without screwing up future book windows
|
||||
MWBase::Environment::get().getWindowManager()->getBookWindow()->setTakeButtonShow(false);
|
||||
MWBase::Environment::get().getWindowManager()->getScrollWindow()->setTakeButtonShow(false);
|
||||
|
||||
// since we changed equipping status, update the inventory window
|
||||
MWBase::Environment::get().getWindowManager()->getInventoryWindow()->updateItemView();
|
||||
MWBase::Environment::get().getWindowManager()->getInventoryWindow()->useItem(item);
|
||||
}
|
||||
else if (type == Type_MagicItem)
|
||||
{
|
||||
|
@ -1,6 +1,5 @@
|
||||
#include "race.hpp"
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/format.hpp>
|
||||
|
||||
@ -140,7 +139,7 @@ namespace MWGui
|
||||
size_t count = mRaceList->getItemCount();
|
||||
for (size_t i = 0; i < count; ++i)
|
||||
{
|
||||
if (boost::iequals(*mRaceList->getItemDataAt<std::string>(i), raceId))
|
||||
if (Misc::StringUtils::ciEqual(*mRaceList->getItemDataAt<std::string>(i), raceId))
|
||||
{
|
||||
mRaceList->setIndexSelected(i);
|
||||
MyGUI::Button* okButton;
|
||||
@ -230,7 +229,7 @@ namespace MWGui
|
||||
MyGUI::Button* okButton;
|
||||
getWidget(okButton, "OKButton");
|
||||
const std::string *raceId = mRaceList->getItemDataAt<std::string>(_index);
|
||||
if (boost::iequals(mCurrentRaceId, *raceId))
|
||||
if (Misc::StringUtils::ciEqual(mCurrentRaceId, *raceId))
|
||||
return;
|
||||
|
||||
mCurrentRaceId = *raceId;
|
||||
@ -320,7 +319,7 @@ namespace MWGui
|
||||
continue;
|
||||
|
||||
mRaceList->addItem(it->mName, it->mId);
|
||||
if (boost::iequals(it->mId, mCurrentRaceId))
|
||||
if (Misc::StringUtils::ciEqual(it->mId, mCurrentRaceId))
|
||||
mRaceList->setIndexSelected(index);
|
||||
++index;
|
||||
}
|
||||
|
@ -185,8 +185,8 @@ namespace MWGui
|
||||
MyGUI::TextBox* widget = mSkillWidgetMap[(int)parSkill];
|
||||
if (widget)
|
||||
{
|
||||
float modified = value.getModified(), base = value.getBase();
|
||||
std::string text = boost::lexical_cast<std::string>(std::floor(modified));
|
||||
int modified = value.getModified(), base = value.getBase();
|
||||
std::string text = boost::lexical_cast<std::string>(modified);
|
||||
std::string state = "normal";
|
||||
if (modified > base)
|
||||
state = "increased";
|
||||
|
@ -296,10 +296,10 @@ namespace MWGui
|
||||
const MWMechanics::NpcStats &sellerStats = mPtr.getClass().getNpcStats(mPtr);
|
||||
const MWMechanics::NpcStats &playerStats = player.getClass().getNpcStats(player);
|
||||
|
||||
float a1 = std::min(playerStats.getSkill(ESM::Skill::Mercantile).getModified(), 100);
|
||||
float a1 = std::min(player.getClass().getSkill(player, ESM::Skill::Mercantile), 100);
|
||||
float b1 = std::min(0.1f * playerStats.getAttribute(ESM::Attribute::Luck).getModified(), 10.f);
|
||||
float c1 = std::min(0.2f * playerStats.getAttribute(ESM::Attribute::Personality).getModified(), 10.f);
|
||||
float d1 = std::min(sellerStats.getSkill(ESM::Skill::Mercantile).getModified(), 100);
|
||||
float d1 = std::min(mPtr.getClass().getSkill(mPtr, ESM::Skill::Mercantile), 100);
|
||||
float e1 = std::min(0.1f * sellerStats.getAttribute(ESM::Attribute::Luck).getModified(), 10.f);
|
||||
float f1 = std::min(0.2f * sellerStats.getAttribute(ESM::Attribute::Personality).getModified(), 10.f);
|
||||
|
||||
@ -318,7 +318,8 @@ namespace MWGui
|
||||
messageBox("#{sNotifyMessage9}");
|
||||
|
||||
int iBarterFailDisposition = gmst.find("iBarterFailDisposition")->getInt();
|
||||
MWBase::Environment::get().getDialogueManager()->applyDispositionChange(iBarterFailDisposition);
|
||||
if (mPtr.getClass().isNpc())
|
||||
MWBase::Environment::get().getDialogueManager()->applyDispositionChange(iBarterFailDisposition);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -327,7 +328,8 @@ namespace MWGui
|
||||
}
|
||||
|
||||
int iBarterSuccessDisposition = gmst.find("iBarterSuccessDisposition")->getInt();
|
||||
MWBase::Environment::get().getDialogueManager()->applyDispositionChange(iBarterSuccessDisposition);
|
||||
if (mPtr.getClass().isNpc())
|
||||
MWBase::Environment::get().getDialogueManager()->applyDispositionChange(iBarterSuccessDisposition);
|
||||
|
||||
// make the item transfer
|
||||
mTradeModel->transferItems();
|
||||
|
@ -130,6 +130,14 @@ namespace MWGui
|
||||
return;
|
||||
}
|
||||
|
||||
// You can not train a skill above its governing attribute
|
||||
const ESM::Skill* skill = MWBase::Environment::get().getWorld()->getStore().get<ESM::Skill>().find(skillId);
|
||||
if (pcStats.getSkill(skillId).getBase() >= pcStats.getAttribute(skill->mData.mAttribute).getBase())
|
||||
{
|
||||
MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage17}");
|
||||
return;
|
||||
}
|
||||
|
||||
// increase skill
|
||||
MWWorld::LiveCellRef<ESM::NPC> *playerRef = player.get<ESM::NPC>();
|
||||
|
||||
@ -146,6 +154,8 @@ namespace MWGui
|
||||
|
||||
// advance time
|
||||
MWBase::Environment::get().getWorld ()->advanceTime (2);
|
||||
MWBase::Environment::get().getMechanicsManager()->rest(false);
|
||||
MWBase::Environment::get().getMechanicsManager()->rest(false);
|
||||
|
||||
MWBase::Environment::get().getWorld ()->getFader()->fadeOut(0.25);
|
||||
mFadeTimeRemaining = 0.5;
|
||||
|
@ -148,7 +148,7 @@ namespace MWGui
|
||||
int hours = static_cast<int>(d /MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fTravelTimeMult")->getFloat());
|
||||
for(int i = 0;i < hours;i++)
|
||||
{
|
||||
MWBase::Environment::get().getMechanicsManager ()->restoreDynamicStats ();
|
||||
MWBase::Environment::get().getMechanicsManager ()->rest (true);
|
||||
}
|
||||
MWBase::Environment::get().getWorld()->advanceTime(hours);
|
||||
|
||||
|
@ -48,6 +48,7 @@ namespace MWGui
|
||||
, mRemainingTime(0.05)
|
||||
, mCurHour(0)
|
||||
, mManualHours(1)
|
||||
, mInterruptAt(-1)
|
||||
{
|
||||
getWidget(mDateTimeText, "DateTimeText");
|
||||
getWidget(mRestText, "RestText");
|
||||
@ -144,43 +145,7 @@ namespace MWGui
|
||||
|
||||
void WaitDialog::onUntilHealedButtonClicked(MyGUI::Widget* sender)
|
||||
{
|
||||
// we need to sleep for a specific time, and since that isn't calculated yet, we'll do it here
|
||||
// I'm making the assumption here that the # of hours rested is calculated when rest is started
|
||||
// TODO: the rougher logic here (calculating the hourly deltas) should really go into helper funcs elsewhere
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||
const MWMechanics::CreatureStats& stats = MWWorld::Class::get(player).getCreatureStats(player);
|
||||
const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore();
|
||||
|
||||
float hourlyHealthDelta = stats.getAttribute(ESM::Attribute::Endurance).getModified() * 0.1;
|
||||
|
||||
bool stunted = (stats.getMagicEffects().get(ESM::MagicEffect::StuntedMagicka).mMagnitude > 0);
|
||||
float fRestMagicMult = store.get<ESM::GameSetting>().find("fRestMagicMult")->getFloat();
|
||||
float hourlyMagickaDelta = fRestMagicMult * stats.getAttribute(ESM::Attribute::Intelligence).getModified();
|
||||
|
||||
// this massive duplication is why it has to be put into helper functions instead
|
||||
float fFatigueReturnBase = store.get<ESM::GameSetting>().find("fFatigueReturnBase")->getFloat();
|
||||
float fFatigueReturnMult = store.get<ESM::GameSetting>().find("fFatigueReturnMult")->getFloat();
|
||||
float fEndFatigueMult = store.get<ESM::GameSetting>().find("fEndFatigueMult")->getFloat();
|
||||
float capacity = MWWorld::Class::get(player).getCapacity(player);
|
||||
float encumbrance = MWWorld::Class::get(player).getEncumbrance(player);
|
||||
float normalizedEncumbrance = (capacity == 0 ? 1 : encumbrance/capacity);
|
||||
if (normalizedEncumbrance > 1)
|
||||
normalizedEncumbrance = 1;
|
||||
float hourlyFatigueDelta = fFatigueReturnBase + fFatigueReturnMult * (1 - normalizedEncumbrance);
|
||||
hourlyFatigueDelta *= 3600 * fEndFatigueMult * stats.getAttribute(ESM::Attribute::Endurance).getModified();
|
||||
|
||||
float healthHours = hourlyHealthDelta >= 0.0
|
||||
? (stats.getHealth().getBase() - stats.getHealth().getCurrent()) / hourlyHealthDelta
|
||||
: 1.0f;
|
||||
float magickaHours = stunted ? 0.0 :
|
||||
hourlyMagickaDelta >= 0.0
|
||||
? (stats.getMagicka().getBase() - stats.getMagicka().getCurrent()) / hourlyMagickaDelta
|
||||
: 1.0f;
|
||||
float fatigueHours = hourlyFatigueDelta >= 0.0
|
||||
? (stats.getFatigue().getBase() - stats.getFatigue().getCurrent()) / hourlyFatigueDelta
|
||||
: 1.0f;
|
||||
|
||||
int autoHours = int(std::ceil( std::max(std::max(healthHours, magickaHours), std::max(fatigueHours, 1.0f)) )); // this should use a variadic max if possible
|
||||
int autoHours = MWBase::Environment::get().getMechanicsManager()->getHoursToRest();
|
||||
|
||||
startWaiting(autoHours);
|
||||
}
|
||||
@ -192,7 +157,8 @@ namespace MWGui
|
||||
|
||||
void WaitDialog::startWaiting(int hoursToWait)
|
||||
{
|
||||
MWBase::Environment::get().getWorld ()->getFader ()->fadeOut(0.2);
|
||||
MWBase::World* world = MWBase::Environment::get().getWorld();
|
||||
world->getFader ()->fadeOut(0.2);
|
||||
setVisible(false);
|
||||
mProgressBar.setVisible (true);
|
||||
|
||||
@ -200,6 +166,30 @@ namespace MWGui
|
||||
mCurHour = 0;
|
||||
mHours = hoursToWait;
|
||||
|
||||
// FIXME: move this somewhere else?
|
||||
mInterruptAt = -1;
|
||||
MWWorld::Ptr player = world->getPlayerPtr();
|
||||
if (mSleeping && player.getCell()->isExterior())
|
||||
{
|
||||
std::string regionstr = player.getCell()->mCell->mRegion;
|
||||
if (!regionstr.empty())
|
||||
{
|
||||
const ESM::Region *region = world->getStore().get<ESM::Region>().find (regionstr);
|
||||
if (!region->mSleepList.empty())
|
||||
{
|
||||
float fSleepRandMod = world->getStore().get<ESM::GameSetting>().find("fSleepRandMod")->getFloat();
|
||||
int x = std::rand()/ (static_cast<double> (RAND_MAX) + 1) * hoursToWait; // [0, hoursRested]
|
||||
float y = fSleepRandMod * hoursToWait;
|
||||
if (x > y)
|
||||
{
|
||||
float fSleepRestMod = world->getStore().get<ESM::GameSetting>().find("fSleepRestMod")->getFloat();
|
||||
mInterruptAt = hoursToWait - int(fSleepRestMod * hoursToWait);
|
||||
mInterruptCreatureList = region->mSleepList;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mRemainingTime = 0.05;
|
||||
mProgressBar.setProgress (0, mHours);
|
||||
}
|
||||
@ -242,6 +232,13 @@ namespace MWGui
|
||||
if (!mWaiting)
|
||||
return;
|
||||
|
||||
if (mCurHour == mInterruptAt)
|
||||
{
|
||||
MWBase::Environment::get().getWindowManager()->messageBox("#{sSleepInterrupt}");
|
||||
MWBase::Environment::get().getWorld()->spawnRandomCreature(mInterruptCreatureList);
|
||||
stopWaiting();
|
||||
}
|
||||
|
||||
mRemainingTime -= dt;
|
||||
|
||||
while (mRemainingTime < 0)
|
||||
@ -253,8 +250,7 @@ namespace MWGui
|
||||
if (mCurHour <= mHours)
|
||||
{
|
||||
MWBase::Environment::get().getWorld ()->advanceTime (1);
|
||||
if (mSleeping)
|
||||
MWBase::Environment::get().getMechanicsManager ()->restoreDynamicStats ();
|
||||
MWBase::Environment::get().getMechanicsManager ()->rest (mSleeping);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -51,6 +51,9 @@ namespace MWGui
|
||||
int mManualHours; // stores the hours to rest selected via slider
|
||||
float mRemainingTime;
|
||||
|
||||
int mInterruptAt;
|
||||
std::string mInterruptCreatureList;
|
||||
|
||||
WaitDialogProgressBar mProgressBar;
|
||||
|
||||
void onUntilHealedButtonClicked(MyGUI::Widget* sender);
|
||||
|
@ -207,7 +207,8 @@ namespace MWGui
|
||||
mConsole = new Console(w,h, mConsoleOnlyScripts);
|
||||
trackWindow(mConsole, "console");
|
||||
mJournal = JournalWindow::create(JournalViewModel::create ());
|
||||
mMessageBoxManager = new MessageBoxManager();
|
||||
mMessageBoxManager = new MessageBoxManager(
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fMessageTimePerChar")->getFloat());
|
||||
mInventoryWindow = new InventoryWindow(mDragAndDrop);
|
||||
mTradeWindow = new TradeWindow();
|
||||
trackWindow(mTradeWindow, "barter");
|
||||
@ -676,17 +677,6 @@ namespace MWGui
|
||||
mMessageBoxManager->removeStaticMessageBox();
|
||||
}
|
||||
|
||||
void WindowManager::enterPressed ()
|
||||
{
|
||||
mMessageBoxManager->okayPressed();
|
||||
}
|
||||
|
||||
void WindowManager::activateKeyPressed ()
|
||||
{
|
||||
mMessageBoxManager->okayPressed();
|
||||
mCountDialog->cancel();
|
||||
}
|
||||
|
||||
int WindowManager::readPressedButton ()
|
||||
{
|
||||
return mMessageBoxManager->readPressedButton();
|
||||
|
@ -222,8 +222,6 @@ namespace MWGui
|
||||
virtual void messageBox (const std::string& message, const std::vector<std::string>& buttons = std::vector<std::string>(), bool showInDialogueModeOnly = false);
|
||||
virtual void staticMessageBox(const std::string& message);
|
||||
virtual void removeStaticMessageBox();
|
||||
virtual void enterPressed ();
|
||||
virtual void activateKeyPressed ();
|
||||
virtual int readPressedButton (); ///< returns the index of the pressed button or -1 if no button was pressed (->MessageBoxmanager->InteractiveMessageBox)
|
||||
|
||||
virtual void onFrame (float frameDuration);
|
||||
|
@ -195,14 +195,7 @@ namespace MWInput
|
||||
case A_Activate:
|
||||
resetIdleTime();
|
||||
|
||||
if (MWBase::Environment::get().getWindowManager()->isGuiMode())
|
||||
{
|
||||
if (MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_Container)
|
||||
toggleContainer ();
|
||||
else
|
||||
MWBase::Environment::get().getWindowManager()->activateKeyPressed();
|
||||
}
|
||||
else
|
||||
if (!MWBase::Environment::get().getWindowManager()->isGuiMode())
|
||||
activate();
|
||||
break;
|
||||
case A_Journal:
|
||||
@ -511,13 +504,6 @@ namespace MWInput
|
||||
|
||||
mInputBinder->keyPressed (arg);
|
||||
|
||||
if((arg.keysym.sym == SDLK_RETURN || arg.keysym.sym == SDLK_KP_ENTER)
|
||||
&& MWBase::Environment::get().getWindowManager()->isGuiMode())
|
||||
{
|
||||
// Pressing enter when a messagebox is prompting for "ok" will activate the ok button
|
||||
MWBase::Environment::get().getWindowManager()->enterPressed();
|
||||
}
|
||||
|
||||
OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(arg.keysym.sym);
|
||||
|
||||
if (kc != OIS::KC_UNASSIGNED)
|
||||
@ -730,21 +716,6 @@ namespace MWInput
|
||||
// .. but don't touch any other mode, except container.
|
||||
}
|
||||
|
||||
void InputManager::toggleContainer()
|
||||
{
|
||||
if (MyGUI::InputManager::getInstance ().isModalAny())
|
||||
return;
|
||||
|
||||
if(MWBase::Environment::get().getWindowManager()->isGuiMode())
|
||||
{
|
||||
if (MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_Container)
|
||||
MWBase::Environment::get().getWindowManager()->popGuiMode();
|
||||
else
|
||||
MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Container);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void InputManager::toggleConsole()
|
||||
{
|
||||
if (MyGUI::InputManager::getInstance ().isModalAny())
|
||||
|
@ -173,7 +173,6 @@ namespace MWInput
|
||||
void toggleSpell();
|
||||
void toggleWeapon();
|
||||
void toggleInventory();
|
||||
void toggleContainer();
|
||||
void toggleConsole();
|
||||
void screenshot();
|
||||
void toggleJournal();
|
||||
|
@ -205,4 +205,22 @@ namespace MWMechanics
|
||||
}
|
||||
mSpellsChanged = true;
|
||||
}
|
||||
|
||||
void ActiveSpells::purge(const std::string &actorHandle)
|
||||
{
|
||||
for (TContainer::iterator it = mSpells.begin(); it != mSpells.end(); ++it)
|
||||
{
|
||||
for (std::vector<Effect>::iterator effectIt = it->second.mEffects.begin();
|
||||
effectIt != it->second.mEffects.end();)
|
||||
{
|
||||
const ESM::MagicEffect* effect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find(effectIt->mKey.mId);
|
||||
if (effect->mData.mFlags & ESM::MagicEffect::CasterLinked
|
||||
&& it->second.mCasterHandle == actorHandle)
|
||||
effectIt = it->second.mEffects.erase(effectIt);
|
||||
else
|
||||
effectIt++;
|
||||
}
|
||||
}
|
||||
mSpellsChanged = true;
|
||||
}
|
||||
}
|
||||
|
@ -90,6 +90,9 @@ namespace MWMechanics
|
||||
/// Remove all active effects, if roll succeeds (for each effect)
|
||||
void purgeAll (float chance);
|
||||
|
||||
/// Remove all effects with CASTER_LINKED flag that were cast by \a actorHandle
|
||||
void purge (const std::string& actorHandle);
|
||||
|
||||
bool isSpellActive (std::string id) const;
|
||||
///< case insensitive
|
||||
|
||||
|
@ -83,6 +83,23 @@ bool disintegrateSlot (MWWorld::Ptr ptr, int slot, float disintegrate)
|
||||
return false;
|
||||
}
|
||||
|
||||
void getRestorationPerHourOfSleep (const MWWorld::Ptr& ptr, float& health, float& magicka)
|
||||
{
|
||||
MWMechanics::CreatureStats& stats = ptr.getClass().getCreatureStats (ptr);
|
||||
const MWWorld::Store<ESM::GameSetting>& settings = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
||||
|
||||
bool stunted = stats.getMagicEffects ().get(ESM::MagicEffect::StuntedMagicka).mMagnitude > 0;
|
||||
int endurance = stats.getAttribute (ESM::Attribute::Endurance).getModified ();
|
||||
|
||||
health = 0.1 * endurance;
|
||||
|
||||
magicka = 0;
|
||||
if (!stunted)
|
||||
{
|
||||
float fRestMagicMult = settings.find("fRestMagicMult")->getFloat ();
|
||||
magicka = fRestMagicMult * stats.getAttribute(ESM::Attribute::Intelligence).getModified();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -200,7 +217,7 @@ namespace MWMechanics
|
||||
}
|
||||
|
||||
// fatigue restoration
|
||||
calculateRestoration(ptr, duration);
|
||||
calculateRestoration(ptr, duration, false);
|
||||
}
|
||||
|
||||
void Actors::updateNpc (const MWWorld::Ptr& ptr, float duration, bool paused)
|
||||
@ -258,44 +275,37 @@ namespace MWMechanics
|
||||
creatureStats.setFatigue(fatigue);
|
||||
}
|
||||
|
||||
void Actors::calculateRestoration (const MWWorld::Ptr& ptr, float duration)
|
||||
void Actors::calculateRestoration (const MWWorld::Ptr& ptr, float duration, bool sleep)
|
||||
{
|
||||
if (ptr.getClass().getCreatureStats(ptr).isDead())
|
||||
return;
|
||||
CreatureStats& stats = MWWorld::Class::get (ptr).getCreatureStats (ptr);
|
||||
|
||||
MWMechanics::CreatureStats& stats = ptr.getClass().getCreatureStats (ptr);
|
||||
const MWWorld::Store<ESM::GameSetting>& settings = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
||||
|
||||
if (sleep)
|
||||
{
|
||||
float health, magicka;
|
||||
getRestorationPerHourOfSleep(ptr, health, magicka);
|
||||
|
||||
DynamicStat<float> stat = stats.getHealth();
|
||||
stat.setCurrent(stat.getCurrent() + health);
|
||||
stats.setHealth(stat);
|
||||
|
||||
stat = stats.getMagicka();
|
||||
stat.setCurrent(stat.getCurrent() + magicka);
|
||||
stats.setMagicka(stat);
|
||||
}
|
||||
|
||||
int endurance = stats.getAttribute (ESM::Attribute::Endurance).getModified ();
|
||||
|
||||
float capacity = MWWorld::Class::get(ptr).getCapacity(ptr);
|
||||
float encumbrance = MWWorld::Class::get(ptr).getEncumbrance(ptr);
|
||||
float capacity = ptr.getClass().getCapacity(ptr);
|
||||
float encumbrance = ptr.getClass().getEncumbrance(ptr);
|
||||
float normalizedEncumbrance = (capacity == 0 ? 1 : encumbrance/capacity);
|
||||
if (normalizedEncumbrance > 1)
|
||||
normalizedEncumbrance = 1;
|
||||
|
||||
if (duration == 3600)
|
||||
{
|
||||
// the actor is sleeping, restore health and magicka
|
||||
|
||||
bool stunted = stats.getMagicEffects ().get(ESM::MagicEffect::StuntedMagicka).mMagnitude > 0;
|
||||
|
||||
DynamicStat<float> health = stats.getHealth();
|
||||
health.setCurrent (health.getCurrent() + 0.1 * endurance);
|
||||
stats.setHealth (health);
|
||||
|
||||
if (!stunted)
|
||||
{
|
||||
float fRestMagicMult = settings.find("fRestMagicMult")->getFloat ();
|
||||
|
||||
DynamicStat<float> magicka = stats.getMagicka();
|
||||
magicka.setCurrent (magicka.getCurrent()
|
||||
+ fRestMagicMult * stats.getAttribute(ESM::Attribute::Intelligence).getModified());
|
||||
stats.setMagicka (magicka);
|
||||
}
|
||||
}
|
||||
|
||||
// restore fatigue
|
||||
|
||||
float fFatigueReturnBase = settings.find("fFatigueReturnBase")->getFloat ();
|
||||
float fFatigueReturnMult = settings.find("fFatigueReturnMult")->getFloat ();
|
||||
float fEndFatigueMult = settings.find("fEndFatigueMult")->getFloat ();
|
||||
@ -306,6 +316,7 @@ namespace MWMechanics
|
||||
DynamicStat<float> fatigue = stats.getFatigue();
|
||||
fatigue.setCurrent (fatigue.getCurrent() + duration * x);
|
||||
stats.setFatigue (fatigue);
|
||||
|
||||
}
|
||||
|
||||
void Actors::calculateCreatureStatModifiers (const MWWorld::Ptr& ptr, float duration)
|
||||
@ -335,7 +346,7 @@ namespace MWMechanics
|
||||
float currentDiff = creatureStats.getMagicEffects().get(ESM::MagicEffect::RestoreHealth+i).mMagnitude
|
||||
- creatureStats.getMagicEffects().get(ESM::MagicEffect::DamageHealth+i).mMagnitude
|
||||
- creatureStats.getMagicEffects().get(ESM::MagicEffect::AbsorbHealth+i).mMagnitude;
|
||||
stat.setCurrent(stat.getCurrent() + currentDiff * duration);
|
||||
stat.setCurrent(stat.getCurrent() + currentDiff * duration, i == 2);
|
||||
|
||||
creatureStats.setDynamic(i, stat);
|
||||
}
|
||||
@ -505,7 +516,7 @@ namespace MWMechanics
|
||||
if (magnitude > 0)
|
||||
{
|
||||
ESM::Position ipos = ptr.getRefData().getPosition();
|
||||
Ogre::Vector3 pos(ipos.pos[0],ipos.pos[1],ipos.pos[2]);
|
||||
Ogre::Vector3 pos(ipos.pos);
|
||||
Ogre::Quaternion rot(Ogre::Radian(-ipos.rot[2]), Ogre::Vector3::UNIT_Z);
|
||||
const float distance = 50;
|
||||
pos = pos + distance*rot.yAxis();
|
||||
@ -526,7 +537,7 @@ namespace MWMechanics
|
||||
ref.getPtr().getCellRef().mPos = ipos;
|
||||
|
||||
// TODO: Add AI to follow player and fight for him
|
||||
|
||||
// TODO: VFX_SummonStart, VFX_SummonEnd
|
||||
creatureStats.mSummonedCreatures.insert(std::make_pair(it->first,
|
||||
MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),*store,ipos).getRefData().getHandle()));
|
||||
}
|
||||
@ -582,7 +593,8 @@ namespace MWMechanics
|
||||
if(timeLeft == 0.0f)
|
||||
{
|
||||
// If drowning, apply 3 points of damage per second
|
||||
ptr.getClass().setActorHealth(ptr, stats.getHealth().getCurrent() - 3.0f*duration);
|
||||
static const float fSuffocationDamage = world->getStore().get<ESM::GameSetting>().find("fSuffocationDamage")->getFloat();
|
||||
ptr.getClass().setActorHealth(ptr, stats.getHealth().getCurrent() - fSuffocationDamage*duration);
|
||||
|
||||
// Play a drowning sound as necessary for the player
|
||||
if(ptr == world->getPlayerPtr())
|
||||
@ -594,7 +606,10 @@ namespace MWMechanics
|
||||
}
|
||||
}
|
||||
else
|
||||
stats.setTimeToStartDrowning(20);
|
||||
{
|
||||
static const float fHoldBreathTime = world->getStore().get<ESM::GameSetting>().find("fHoldBreathTime")->getFloat();
|
||||
stats.setTimeToStartDrowning(fHoldBreathTime);
|
||||
}
|
||||
}
|
||||
|
||||
void Actors::updateEquippedLight (const MWWorld::Ptr& ptr, float duration)
|
||||
@ -811,6 +826,13 @@ namespace MWMechanics
|
||||
stats.setMagicEffects(MWMechanics::MagicEffects());
|
||||
calculateCreatureStatModifiers(iter->first, 0);
|
||||
|
||||
// Make sure spell effects with CasterLinked flag are removed
|
||||
for(PtrControllerMap::iterator iter2(mActors.begin());iter2 != mActors.end();++iter2)
|
||||
{
|
||||
MWMechanics::ActiveSpells& spells = iter2->first.getClass().getCreatureStats(iter2->first).getActiveSpells();
|
||||
spells.purge(iter->first.getRefData().getHandle());
|
||||
}
|
||||
|
||||
++mDeathCount[cls.getId(iter->first)];
|
||||
|
||||
if(cls.isEssential(iter->first))
|
||||
@ -837,10 +859,28 @@ namespace MWMechanics
|
||||
}
|
||||
}
|
||||
}
|
||||
void Actors::restoreDynamicStats()
|
||||
void Actors::restoreDynamicStats(bool sleep)
|
||||
{
|
||||
for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter)
|
||||
calculateRestoration(iter->first, 3600);
|
||||
calculateRestoration(iter->first, 3600, sleep);
|
||||
}
|
||||
|
||||
int Actors::getHoursToRest(const MWWorld::Ptr &ptr) const
|
||||
{
|
||||
float healthPerHour, magickaPerHour;
|
||||
getRestorationPerHourOfSleep(ptr, healthPerHour, magickaPerHour);
|
||||
|
||||
CreatureStats& stats = ptr.getClass().getCreatureStats(ptr);
|
||||
|
||||
float healthHours = healthPerHour >= 0
|
||||
? (stats.getHealth().getModified() - stats.getHealth().getCurrent()) / healthPerHour
|
||||
: 1.0f;
|
||||
float magickaHours = magickaPerHour >= 0
|
||||
? (stats.getMagicka().getModified() - stats.getMagicka().getCurrent()) / magickaPerHour
|
||||
: 1.0f;
|
||||
|
||||
int autoHours = std::ceil(std::max(1.f, std::max(healthHours, magickaHours)));
|
||||
return autoHours;
|
||||
}
|
||||
|
||||
int Actors::countDeaths (const std::string& id) const
|
||||
|
@ -36,7 +36,7 @@ namespace MWMechanics
|
||||
void calculateCreatureStatModifiers (const MWWorld::Ptr& ptr, float duration);
|
||||
void calculateNpcStatModifiers (const MWWorld::Ptr& ptr);
|
||||
|
||||
void calculateRestoration (const MWWorld::Ptr& ptr, float duration);
|
||||
void calculateRestoration (const MWWorld::Ptr& ptr, float duration, bool sleep);
|
||||
|
||||
void updateDrowning (const MWWorld::Ptr& ptr, float duration);
|
||||
|
||||
@ -79,8 +79,11 @@ namespace MWMechanics
|
||||
///< This function is normally called automatically during the update process, but it can
|
||||
/// also be called explicitly at any time to force an update.
|
||||
|
||||
void restoreDynamicStats();
|
||||
void restoreDynamicStats(bool sleep);
|
||||
///< If the player is sleeping, this should be called every hour.
|
||||
|
||||
int getHoursToRest(const MWWorld::Ptr& ptr) const;
|
||||
///< Calculate how many hours the given actor needs to rest in order to be fully healed
|
||||
|
||||
int countDeaths (const std::string& id) const;
|
||||
///< Return the number of deaths for actors with the given ID.
|
||||
|
@ -1,21 +1,21 @@
|
||||
#include "aiactivate.hpp"
|
||||
#include <iostream>
|
||||
#include <iostream>
|
||||
|
||||
MWMechanics::AiActivate::AiActivate(const std::string &objectId)
|
||||
: mObjectId(objectId)
|
||||
{
|
||||
}
|
||||
MWMechanics::AiActivate *MWMechanics::AiActivate::clone() const
|
||||
{
|
||||
return new AiActivate(*this);
|
||||
}
|
||||
bool MWMechanics::AiActivate::execute (const MWWorld::Ptr& actor,float duration)
|
||||
{
|
||||
std::cout << "AiActivate completed.\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
int MWMechanics::AiActivate::getTypeId() const
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
MWMechanics::AiActivate::AiActivate(const std::string &objectId)
|
||||
: mObjectId(objectId)
|
||||
{
|
||||
}
|
||||
MWMechanics::AiActivate *MWMechanics::AiActivate::clone() const
|
||||
{
|
||||
return new AiActivate(*this);
|
||||
}
|
||||
bool MWMechanics::AiActivate::execute (const MWWorld::Ptr& actor,float duration)
|
||||
{
|
||||
std::cout << "AiActivate completed.\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
int MWMechanics::AiActivate::getTypeId() const
|
||||
{
|
||||
return TypeIdActivate;
|
||||
}
|
||||
|
@ -51,8 +51,9 @@ namespace MWMechanics
|
||||
if(actor.getClass().getCreatureStats(actor).getHealth().getCurrent() <= 0)
|
||||
return true;
|
||||
|
||||
//update every frame
|
||||
determineAttackType(actor, mMovement);
|
||||
//Update every frame
|
||||
if(mReadyToAttack)
|
||||
determineAttackType(actor, mMovement);
|
||||
|
||||
if(mCombatMove)
|
||||
{
|
||||
@ -77,10 +78,10 @@ namespace MWMechanics
|
||||
mTimerReact += duration;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
mTimerReact = 0;
|
||||
}
|
||||
|
||||
//Update with period = tReaction
|
||||
|
||||
mTimerReact = 0;
|
||||
|
||||
//actual attacking logic
|
||||
//TODO: Some skills affect period of strikes.For berserk-like style period ~ 0.25f
|
||||
@ -120,9 +121,11 @@ namespace MWMechanics
|
||||
const ESM::Weapon *weapon = NULL;
|
||||
MWMechanics::WeaponType weaptype;
|
||||
float weapRange, weapSpeed = 1.0f;
|
||||
|
||||
actor.getClass().getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, true);
|
||||
|
||||
if(actor.getTypeName() == typeid(ESM::NPC).name())
|
||||
{
|
||||
actor.getClass().setStance(actor, MWWorld::Class::Run,true);
|
||||
MWMechanics::DrawState_ state = actor.getClass().getNpcStats(actor).getDrawState();
|
||||
if (state == MWMechanics::DrawState_Spell || state == MWMechanics::DrawState_Nothing)
|
||||
actor.getClass().getNpcStats(actor).setDrawState(MWMechanics::DrawState_Weapon);
|
||||
@ -267,7 +270,7 @@ namespace MWMechanics
|
||||
mReadyToAttack = true;
|
||||
if(mTimerAttack <= -attackPeriod)
|
||||
{
|
||||
mTimerAttack = 0.45f*static_cast<float>(rand())/RAND_MAX;
|
||||
mTimerAttack = 0.3f*static_cast<float>(rand())/RAND_MAX;
|
||||
mStrike = true;
|
||||
}
|
||||
}
|
||||
@ -337,7 +340,7 @@ namespace MWMechanics
|
||||
|
||||
int AiCombat::getTypeId() const
|
||||
{
|
||||
return 5;
|
||||
return TypeIdCombat;
|
||||
}
|
||||
|
||||
unsigned int AiCombat::getPriority() const
|
||||
@ -345,6 +348,11 @@ namespace MWMechanics
|
||||
return 1;
|
||||
}
|
||||
|
||||
const std::string &AiCombat::getTargetId() const
|
||||
{
|
||||
return mTarget.getRefData().getHandle();
|
||||
}
|
||||
|
||||
AiCombat *MWMechanics::AiCombat::clone() const
|
||||
{
|
||||
return new AiCombat(*this);
|
||||
@ -362,8 +370,22 @@ namespace MWMechanics
|
||||
|
||||
static void chooseBestAttack(const ESM::Weapon* weapon, MWMechanics::Movement &movement)
|
||||
{
|
||||
//the more damage attackType deals the more probability it has
|
||||
|
||||
if (weapon == NULL)
|
||||
{
|
||||
//hand-to-hand deals equal damage
|
||||
float roll = static_cast<float>(rand())/RAND_MAX;
|
||||
if(roll <= 0.333f) //side punch
|
||||
{
|
||||
movement.mPosition[0] = (static_cast<float>(rand())/RAND_MAX < 0.5f)? 1: -1;
|
||||
movement.mPosition[1] = 0;
|
||||
}
|
||||
else if(roll <= 0.666f) //forward punch
|
||||
movement.mPosition[1] = 1;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int slash = (weapon->mData.mSlash[0] + weapon->mData.mSlash[1])/2;
|
||||
int chop = (weapon->mData.mChop[0] + weapon->mData.mChop[1])/2;
|
||||
@ -371,12 +393,13 @@ namespace MWMechanics
|
||||
|
||||
float total = slash + chop + thrust;
|
||||
|
||||
if(static_cast<float>(rand())/RAND_MAX <= static_cast<float>(slash)/total)
|
||||
float roll = static_cast<float>(rand())/RAND_MAX;
|
||||
if(roll <= static_cast<float>(slash)/total)
|
||||
{
|
||||
movement.mPosition[0] = (static_cast<float>(rand())/RAND_MAX < 0.5f)? 1: -1;
|
||||
movement.mPosition[1] = 0;
|
||||
}
|
||||
if (static_cast<float>(rand())/RAND_MAX <= static_cast<float>(thrust)/total)
|
||||
else if(roll <= (static_cast<float>(slash) + static_cast<float>(thrust))/total)
|
||||
movement.mPosition[1] = 1;
|
||||
//else chop
|
||||
}
|
||||
|
@ -25,6 +25,8 @@ namespace MWMechanics
|
||||
|
||||
virtual unsigned int getPriority() const;
|
||||
|
||||
const std::string &getTargetId() const;
|
||||
|
||||
private:
|
||||
PathFinder mPathFinder;
|
||||
//controls duration of the actual strike
|
||||
@ -49,4 +51,4 @@ namespace MWMechanics
|
||||
static void chooseBestAttack(const ESM::Weapon* weapon, MWMechanics::Movement &movement);
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
@ -178,7 +178,7 @@ namespace MWMechanics
|
||||
|
||||
int AiEscort::getTypeId() const
|
||||
{
|
||||
return 2;
|
||||
return TypeIdEscort;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
#include "aifollow.hpp"
|
||||
#include <iostream>
|
||||
#include <iostream>
|
||||
|
||||
MWMechanics::AiFollow::AiFollow(const std::string &actorId,float duration, float x, float y, float z)
|
||||
MWMechanics::AiFollow::AiFollow(const std::string &actorId,float duration, float x, float y, float z)
|
||||
: mDuration(duration), mX(x), mY(y), mZ(z), mActorId(actorId)
|
||||
{
|
||||
}
|
||||
@ -10,18 +10,18 @@ MWMechanics::AiFollow::AiFollow(const std::string &actorId,const std::string &ce
|
||||
{
|
||||
}
|
||||
|
||||
MWMechanics::AiFollow *MWMechanics::AiFollow::clone() const
|
||||
{
|
||||
return new AiFollow(*this);
|
||||
}
|
||||
|
||||
bool MWMechanics::AiFollow::execute (const MWWorld::Ptr& actor,float duration)
|
||||
{
|
||||
std::cout << "AiFollow completed.\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
int MWMechanics::AiFollow::getTypeId() const
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
MWMechanics::AiFollow *MWMechanics::AiFollow::clone() const
|
||||
{
|
||||
return new AiFollow(*this);
|
||||
}
|
||||
|
||||
bool MWMechanics::AiFollow::execute (const MWWorld::Ptr& actor,float duration)
|
||||
{
|
||||
std::cout << "AiFollow completed.\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
int MWMechanics::AiFollow::getTypeId() const
|
||||
{
|
||||
return TypeIdFollow;
|
||||
}
|
||||
|
@ -12,7 +12,16 @@ namespace MWMechanics
|
||||
class AiPackage
|
||||
{
|
||||
public:
|
||||
|
||||
enum TypeId {
|
||||
TypeIdNone = -1,
|
||||
TypeIdWander = 0,
|
||||
TypeIdTravel = 1,
|
||||
TypeIdEscort = 2,
|
||||
TypeIdFollow = 3,
|
||||
TypeIdActivate = 4,
|
||||
TypeIdCombat = 5
|
||||
};
|
||||
|
||||
virtual ~AiPackage();
|
||||
|
||||
virtual AiPackage *clone() const = 0;
|
||||
@ -21,7 +30,7 @@ namespace MWMechanics
|
||||
///< \return Package completed?
|
||||
|
||||
virtual int getTypeId() const = 0;
|
||||
///< 0: Wanter, 1 Travel, 2 Escort, 3 Follow, 4 Activate
|
||||
///< @see enum TypeId
|
||||
|
||||
virtual unsigned int getPriority() const {return 0;}
|
||||
///< higher number is higher priority (0 beeing the lowest)
|
||||
|
@ -55,6 +55,24 @@ int MWMechanics::AiSequence::getTypeId() const
|
||||
return mPackages.front()->getTypeId();
|
||||
}
|
||||
|
||||
bool MWMechanics::AiSequence::getCombatTarget(std::string &targetActorId) const
|
||||
{
|
||||
if (getTypeId() != AiPackage::TypeIdCombat)
|
||||
return false;
|
||||
const AiCombat *combat = static_cast<const AiCombat *>(mPackages.front());
|
||||
targetActorId = combat->getTargetId();
|
||||
return true;
|
||||
}
|
||||
|
||||
void MWMechanics::AiSequence::stopCombat()
|
||||
{
|
||||
while (getTypeId() == AiPackage::TypeIdCombat)
|
||||
{
|
||||
delete *mPackages.begin();
|
||||
mPackages.erase (mPackages.begin());
|
||||
}
|
||||
}
|
||||
|
||||
bool MWMechanics::AiSequence::isPackageDone() const
|
||||
{
|
||||
return mDone;
|
||||
@ -68,6 +86,7 @@ void MWMechanics::AiSequence::execute (const MWWorld::Ptr& actor,float duration)
|
||||
{
|
||||
if (mPackages.front()->execute (actor,duration))
|
||||
{
|
||||
delete *mPackages.begin();
|
||||
mPackages.erase (mPackages.begin());
|
||||
mDone = true;
|
||||
}
|
||||
@ -113,7 +132,7 @@ void MWMechanics::AiSequence::fill(const ESM::AIPackageList &list)
|
||||
std::vector<int> idles;
|
||||
for (int i=0; i<8; ++i)
|
||||
idles.push_back(data.mIdle[i]);
|
||||
package = new MWMechanics::AiWander(data.mDistance, data.mDuration, data.mTimeOfDay, idles, data.mUnk);
|
||||
package = new MWMechanics::AiWander(data.mDistance, data.mDuration, data.mTimeOfDay, idles, data.mShouldRepeat);
|
||||
}
|
||||
else if (it->mType == ESM::AI_Escort)
|
||||
{
|
||||
|
@ -34,7 +34,14 @@ namespace MWMechanics
|
||||
virtual ~AiSequence();
|
||||
|
||||
int getTypeId() const;
|
||||
///< -1: None, 0: Wanter, 1 Travel, 2 Escort, 3 Follow, 4 Activate, 5 Combat
|
||||
///< @see enum AiPackage::TypeId
|
||||
|
||||
bool getCombatTarget (std::string &targetActorId) const;
|
||||
///< Return true and assign target if combat package is currently
|
||||
/// active, return false otherwise
|
||||
|
||||
void stopCombat();
|
||||
///< Removes all combat packages until first non-combat or stack empty.
|
||||
|
||||
bool isPackageDone() const;
|
||||
///< Has a package been completed during the last update?
|
||||
|
@ -105,7 +105,7 @@ namespace MWMechanics
|
||||
|
||||
int AiTravel::getTypeId() const
|
||||
{
|
||||
return 1;
|
||||
return TypeIdTravel;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/mechanicsmanager.hpp"
|
||||
#include "../mwmechanics/npcstats.hpp"
|
||||
|
||||
#include <OgreVector3.h>
|
||||
|
||||
@ -64,6 +65,8 @@ namespace MWMechanics
|
||||
|
||||
bool AiWander::execute (const MWWorld::Ptr& actor,float duration)
|
||||
{
|
||||
if (actor.getClass().isNpc())
|
||||
actor.getClass().getNpcStats(actor).setDrawState(DrawState_Nothing);
|
||||
MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||
if(mDuration)
|
||||
{
|
||||
@ -253,7 +256,7 @@ namespace MWMechanics
|
||||
|
||||
int AiWander::getTypeId() const
|
||||
{
|
||||
return 0;
|
||||
return TypeIdWander;
|
||||
}
|
||||
|
||||
void AiWander::stopWalking(const MWWorld::Ptr& actor)
|
||||
|
@ -62,7 +62,7 @@ void MWMechanics::Alchemy::applyTools (int flags, float& value) const
|
||||
{
|
||||
bool magnitude = !(flags & ESM::MagicEffect::NoMagnitude);
|
||||
bool duration = !(flags & ESM::MagicEffect::NoDuration);
|
||||
bool negative = flags & (ESM::MagicEffect::Negative | ESM::MagicEffect::Harmful);
|
||||
bool negative = flags & (ESM::MagicEffect::Harmful);
|
||||
|
||||
int tool = negative ? ESM::Apparatus::Retort : ESM::Apparatus::Albemic;
|
||||
|
||||
|
@ -157,40 +157,40 @@ public:
|
||||
|
||||
void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterState movement, bool force)
|
||||
{
|
||||
//hit recoils/knockdown animations handling
|
||||
if(MWWorld::Class::get(mPtr).isActor())
|
||||
// hit recoils/knockdown animations handling
|
||||
if(mPtr.getClass().isActor())
|
||||
{
|
||||
if(MWWorld::Class::get(mPtr).getCreatureStats(mPtr).getAttacked())
|
||||
bool recovery = mPtr.getClass().getCreatureStats(mPtr).getHitRecovery();
|
||||
bool knockdown = mPtr.getClass().getCreatureStats(mPtr).getKnockedDown();
|
||||
if(mHitState == CharState_None)
|
||||
{
|
||||
MWWorld::Class::get(mPtr).getCreatureStats(mPtr).setAttacked(false);
|
||||
|
||||
if(mHitState == CharState_None)
|
||||
if(knockdown)
|
||||
{
|
||||
if(mJumpState != JumpState_None && !MWBase::Environment::get().getWorld()->isFlying(mPtr)
|
||||
&& !MWBase::Environment::get().getWorld()->isSwimming(mPtr) )
|
||||
mHitState = CharState_KnockDown;
|
||||
mCurrentHit = sHitList[sHitListSize-1];
|
||||
mAnimation->play(mCurrentHit, Priority_Knockdown, MWRender::Animation::Group_All, true, 1, "start", "stop", 0.0f, 0);
|
||||
}
|
||||
else if (recovery)
|
||||
{
|
||||
mHitState = CharState_Hit;
|
||||
int iHit = rand() % (sHitListSize-1);
|
||||
mCurrentHit = sHitList[iHit];
|
||||
if(mPtr.getRefData().getHandle()=="player" && !mAnimation->hasAnimation(mCurrentHit))
|
||||
{
|
||||
mHitState = CharState_KnockDown;
|
||||
mCurrentHit = sHitList[sHitListSize-1];
|
||||
mAnimation->play(mCurrentHit, Priority_Knockdown, MWRender::Animation::Group_All, true, 1, "start", "stop", 0.0f, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
mHitState = CharState_Hit;
|
||||
int iHit = rand() % (sHitListSize-1);
|
||||
//only 3 different hit animations if player is in 1st person
|
||||
int iHit = rand() % (sHitListSize-3);
|
||||
mCurrentHit = sHitList[iHit];
|
||||
if(mPtr.getRefData().getHandle()=="player" && !mAnimation->hasAnimation(mCurrentHit))
|
||||
{
|
||||
//only 3 different hit animations if player is in 1st person
|
||||
int iHit = rand() % (sHitListSize-3);
|
||||
mCurrentHit = sHitList[iHit];
|
||||
}
|
||||
mAnimation->play(mCurrentHit, Priority_Hit, MWRender::Animation::Group_All, true, 1, "start", "stop", 0.0f, 0);
|
||||
}
|
||||
mAnimation->play(mCurrentHit, Priority_Hit, MWRender::Animation::Group_All, true, 1, "start", "stop", 0.0f, 0);
|
||||
}
|
||||
}
|
||||
else if(mHitState != CharState_None && !mAnimation->isPlaying(mCurrentHit))
|
||||
else if(!mAnimation->isPlaying(mCurrentHit))
|
||||
{
|
||||
mCurrentHit.erase();
|
||||
if (knockdown)
|
||||
mPtr.getClass().getCreatureStats(mPtr).setKnockedDown(false);
|
||||
if (recovery)
|
||||
mPtr.getClass().getCreatureStats(mPtr).setHitRecovery(false);
|
||||
mHitState = CharState_None;
|
||||
}
|
||||
}
|
||||
@ -599,7 +599,12 @@ bool CharacterController::updateNpcState(bool onground, bool inwater, bool isrun
|
||||
const ESM::MagicEffect *effect;
|
||||
effect = store.get<ESM::MagicEffect>().find(effectentry.mEffectID);
|
||||
|
||||
const ESM::Static* castStatic = store.get<ESM::Static>().find (effect->mCasting);
|
||||
const ESM::Static* castStatic;
|
||||
if (!effect->mCasting.empty())
|
||||
castStatic = store.get<ESM::Static>().find (effect->mCasting);
|
||||
else
|
||||
castStatic = store.get<ESM::Static>().find ("VFX_DefaultCast");
|
||||
|
||||
mAnimation->addEffect("meshes\\" + castStatic->mModel, effect->mIndex);
|
||||
|
||||
castStatic = MWBase::Environment::get().getWorld()->getStore().get<ESM::Static>().find ("VFX_Hands");
|
||||
@ -854,10 +859,11 @@ void CharacterController::update(float duration)
|
||||
{
|
||||
bool onground = world->isOnGround(mPtr);
|
||||
bool inwater = world->isSwimming(mPtr);
|
||||
bool isrunning = cls.getStance(mPtr, MWWorld::Class::Run);
|
||||
bool sneak = cls.getStance(mPtr, MWWorld::Class::Sneak);
|
||||
bool isrunning = cls.getCreatureStats(mPtr).getStance(MWMechanics::CreatureStats::Stance_Run);
|
||||
bool sneak = cls.getCreatureStats(mPtr).getStance(MWMechanics::CreatureStats::Stance_Sneak);
|
||||
bool flying = world->isFlying(mPtr);
|
||||
Ogre::Vector3 vec = cls.getMovementVector(mPtr);
|
||||
vec.normalise();
|
||||
if(mHitState != CharState_None && mJumpState == JumpState_None)
|
||||
vec = Ogre::Vector3(0.0f);
|
||||
Ogre::Vector3 rot = cls.getRotationVector(mPtr);
|
||||
@ -896,6 +902,41 @@ void CharacterController::update(float duration)
|
||||
}
|
||||
}
|
||||
|
||||
// reduce fatigue
|
||||
const MWWorld::Store<ESM::GameSetting> &gmst = world->getStore().get<ESM::GameSetting>();
|
||||
float fatigueLoss = 0;
|
||||
static const float fFatigueRunBase = gmst.find("fFatigueRunBase")->getFloat();
|
||||
static const float fFatigueRunMult = gmst.find("fFatigueRunMult")->getFloat();
|
||||
static const float fFatigueSwimWalkBase = gmst.find("fFatigueSwimWalkBase")->getFloat();
|
||||
static const float fFatigueSwimRunBase = gmst.find("fFatigueSwimRunBase")->getFloat();
|
||||
static const float fFatigueSwimWalkMult = gmst.find("fFatigueSwimWalkMult")->getFloat();
|
||||
static const float fFatigueSwimRunMult = gmst.find("fFatigueSwimRunMult")->getFloat();
|
||||
static const float fFatigueSneakBase = gmst.find("fFatigueSneakBase")->getFloat();
|
||||
static const float fFatigueSneakMult = gmst.find("fFatigueSneakMult")->getFloat();
|
||||
|
||||
const float encumbrance = cls.getEncumbrance(mPtr) / cls.getCapacity(mPtr);
|
||||
if (encumbrance < 1)
|
||||
{
|
||||
if (sneak)
|
||||
fatigueLoss = fFatigueSneakBase + encumbrance * fFatigueSneakMult;
|
||||
else
|
||||
{
|
||||
if (inwater)
|
||||
{
|
||||
if (!isrunning)
|
||||
fatigueLoss = fFatigueSwimWalkBase + encumbrance * fFatigueSwimWalkMult;
|
||||
else
|
||||
fatigueLoss = fFatigueSwimRunBase + encumbrance * fFatigueSwimRunMult;
|
||||
}
|
||||
if (isrunning)
|
||||
fatigueLoss = fFatigueRunBase + encumbrance * fFatigueRunMult;
|
||||
}
|
||||
}
|
||||
fatigueLoss *= duration;
|
||||
DynamicStat<float> fatigue = cls.getCreatureStats(mPtr).getFatigue();
|
||||
fatigue.setCurrent(fatigue.getCurrent() - fatigueLoss, fatigue.getCurrent() < 0);
|
||||
cls.getCreatureStats(mPtr).setFatigue(fatigue);
|
||||
|
||||
if(sneak || inwater || flying)
|
||||
vec.z = 0.0f;
|
||||
|
||||
@ -912,8 +953,6 @@ void CharacterController::update(float duration)
|
||||
cls.getCreatureStats(mPtr).land();
|
||||
}
|
||||
|
||||
const MWWorld::Store<ESM::GameSetting> &gmst = world->getStore().get<ESM::GameSetting>();
|
||||
|
||||
forcestateupdate = (mJumpState != JumpState_Falling);
|
||||
mJumpState = JumpState_Falling;
|
||||
|
||||
@ -978,14 +1017,16 @@ void CharacterController::update(float duration)
|
||||
cls.getCreatureStats(mPtr).setHealth(health);
|
||||
cls.onHit(mPtr, realHealthLost, true, MWWorld::Ptr(), MWWorld::Ptr(), true);
|
||||
|
||||
// report acrobatics progression
|
||||
if (mPtr.getRefData().getHandle() == "player")
|
||||
cls.skillUsageSucceeded(mPtr, ESM::Skill::Acrobatics, 1);
|
||||
|
||||
const float acrobaticsSkill = cls.getNpcStats(mPtr).getSkill(ESM::Skill::Acrobatics).getModified();
|
||||
const float acrobaticsSkill = cls.getSkill(mPtr, ESM::Skill::Acrobatics);
|
||||
if (healthLost > (acrobaticsSkill * fatigueTerm))
|
||||
{
|
||||
//TODO: actor falls over
|
||||
cls.getCreatureStats(mPtr).setKnockedDown(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
// report acrobatics progression
|
||||
if (mPtr.getRefData().getHandle() == "player")
|
||||
cls.skillUsageSucceeded(mPtr, ESM::Skill::Acrobatics, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1081,9 +1122,11 @@ void CharacterController::update(float duration)
|
||||
else
|
||||
moved = Ogre::Vector3(0.0f);
|
||||
|
||||
// Ensure we're moving in generally the right direction
|
||||
// Ensure we're moving in generally the right direction...
|
||||
if(mMovementSpeed > 0.f)
|
||||
{
|
||||
float l = moved.length();
|
||||
|
||||
if((movement.x < 0.0f && movement.x < moved.x*2.0f) ||
|
||||
(movement.x > 0.0f && movement.x > moved.x*2.0f))
|
||||
moved.x = movement.x;
|
||||
@ -1093,7 +1136,12 @@ void CharacterController::update(float duration)
|
||||
if((movement.z < 0.0f && movement.z < moved.z*2.0f) ||
|
||||
(movement.z > 0.0f && movement.z > moved.z*2.0f))
|
||||
moved.z = movement.z;
|
||||
// but keep the original speed
|
||||
float newLength = moved.length();
|
||||
if (newLength > 0)
|
||||
moved *= (l / newLength);
|
||||
}
|
||||
|
||||
// Update movement
|
||||
if(moved.squaredLength() > 1.0f)
|
||||
world->queueMovement(mPtr, moved);
|
||||
|
@ -15,7 +15,8 @@ namespace MWMechanics
|
||||
mAttacked (false), mHostile (false),
|
||||
mAttackingOrSpell(false), mAttackType(AT_Chop),
|
||||
mIsWerewolf(false),
|
||||
mFallHeight(0), mRecalcDynamicStats(false)
|
||||
mFallHeight(0), mRecalcDynamicStats(false), mKnockdown(false), mHitRecovery(false),
|
||||
mMovementFlags(0)
|
||||
{
|
||||
for (int i=0; i<4; ++i)
|
||||
mAiSettings[i] = 0;
|
||||
@ -207,6 +208,9 @@ namespace MWMechanics
|
||||
|
||||
mDynamic[index] = value;
|
||||
|
||||
if (index == 2 && value.getCurrent() < 0)
|
||||
setKnockedDown(true);
|
||||
|
||||
if (index==0 && mDynamic[index].getCurrent()<1)
|
||||
{
|
||||
if (!mDead)
|
||||
@ -402,4 +406,50 @@ namespace MWMechanics
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void CreatureStats::setKnockedDown(bool value)
|
||||
{
|
||||
mKnockdown = value;
|
||||
}
|
||||
|
||||
bool CreatureStats::getKnockedDown() const
|
||||
{
|
||||
return mKnockdown;
|
||||
}
|
||||
|
||||
void CreatureStats::setHitRecovery(bool value)
|
||||
{
|
||||
mHitRecovery = value;
|
||||
}
|
||||
|
||||
bool CreatureStats::getHitRecovery() const
|
||||
{
|
||||
return mHitRecovery;
|
||||
}
|
||||
|
||||
bool CreatureStats::getMovementFlag (Flag flag) const
|
||||
{
|
||||
return mMovementFlags & flag;
|
||||
}
|
||||
|
||||
void CreatureStats::setMovementFlag (Flag flag, bool state)
|
||||
{
|
||||
if (state)
|
||||
mMovementFlags |= flag;
|
||||
else
|
||||
mMovementFlags &= ~flag;
|
||||
}
|
||||
|
||||
bool CreatureStats::getStance(Stance flag) const
|
||||
{
|
||||
switch (flag)
|
||||
{
|
||||
case Stance_Run:
|
||||
return getMovementFlag (Flag_Run) || getMovementFlag (Flag_ForceRun);
|
||||
case Stance_Sneak:
|
||||
return getMovementFlag (Flag_Sneak) || getMovementFlag (Flag_ForceSneak);
|
||||
}
|
||||
return false; // shut up, compiler
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -34,7 +34,10 @@ namespace MWMechanics
|
||||
bool mAlarmed;
|
||||
bool mAttacked;
|
||||
bool mHostile;
|
||||
bool mAttackingOrSpell;//for the player, this is true if the left mouse button is pressed, false if not.
|
||||
bool mAttackingOrSpell;
|
||||
bool mKnockdown;
|
||||
bool mHitRecovery;
|
||||
unsigned int mMovementFlags;
|
||||
|
||||
float mFallHeight;
|
||||
|
||||
@ -45,6 +48,7 @@ namespace MWMechanics
|
||||
// Do we need to recalculate stats derived from attributes or other factors?
|
||||
bool mRecalcDynamicStats;
|
||||
|
||||
|
||||
std::map<std::string, MWWorld::TimeStamp> mUsedPowers;
|
||||
protected:
|
||||
bool mIsWerewolf;
|
||||
@ -186,6 +190,29 @@ namespace MWMechanics
|
||||
|
||||
float getEvasion() const;
|
||||
|
||||
void setKnockedDown(bool value);
|
||||
bool getKnockedDown() const;
|
||||
void setHitRecovery(bool value);
|
||||
bool getHitRecovery() const;
|
||||
|
||||
enum Flag
|
||||
{
|
||||
Flag_ForceRun = 1,
|
||||
Flag_ForceSneak = 2,
|
||||
Flag_Run = 4,
|
||||
Flag_Sneak = 8
|
||||
};
|
||||
enum Stance
|
||||
{
|
||||
Stance_Run,
|
||||
Stance_Sneak
|
||||
};
|
||||
|
||||
bool getMovementFlag (Flag flag) const;
|
||||
void setMovementFlag (Flag flag, bool state);
|
||||
/// Like getMovementFlag, but also takes into account if the flag is Forced
|
||||
bool getStance (Stance flag) const;
|
||||
|
||||
void setLastHitObject(const std::string &objectid);
|
||||
const std::string &getLastHitObject() const;
|
||||
|
||||
|
@ -6,7 +6,6 @@
|
||||
|
||||
#include "creaturestats.hpp"
|
||||
#include "npcstats.hpp"
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
namespace MWMechanics
|
||||
{
|
||||
@ -60,7 +59,7 @@ namespace MWMechanics
|
||||
store.remove(mSoulGemPtr, 1, player);
|
||||
|
||||
//Exception for Azura Star, new one will be added after enchanting
|
||||
if(boost::iequals(mSoulGemPtr.get<ESM::Miscellaneous>()->mBase->mId, "Misc_SoulGem_Azura"))
|
||||
if(Misc::StringUtils::ciEqual(mSoulGemPtr.get<ESM::Miscellaneous>()->mBase->mId, "Misc_SoulGem_Azura"))
|
||||
store.add("Misc_SoulGem_Azura", 1, player);
|
||||
|
||||
if(mSelfEnchanting)
|
||||
|
82
apps/openmw/mwmechanics/levelledlist.hpp
Normal file
82
apps/openmw/mwmechanics/levelledlist.hpp
Normal file
@ -0,0 +1,82 @@
|
||||
#ifndef OPENMW_MECHANICS_LEVELLEDLIST_H
|
||||
#define OPENMW_MECHANICS_LEVELLEDLIST_H
|
||||
|
||||
#include "../mwworld/ptr.hpp"
|
||||
#include "../mwworld/manualref.hpp"
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/environment.hpp"
|
||||
|
||||
namespace MWMechanics
|
||||
{
|
||||
|
||||
/// @return ID of resulting item, or empty if none
|
||||
inline std::string getLevelledItem (const ESM::LeveledListBase* levItem, bool creature, unsigned char failChance=0)
|
||||
{
|
||||
const std::vector<ESM::LeveledListBase::LevelItem>& items = levItem->mList;
|
||||
|
||||
const MWWorld::Ptr& player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||
int playerLevel = player.getClass().getCreatureStats(player).getLevel();
|
||||
|
||||
failChance += levItem->mChanceNone;
|
||||
|
||||
int random = std::rand()/ (static_cast<double> (RAND_MAX) + 1) * 100; // [0, 99]
|
||||
if (random < failChance)
|
||||
return std::string();
|
||||
|
||||
std::vector<std::string> candidates;
|
||||
int highestLevel = 0;
|
||||
for (std::vector<ESM::LeveledListBase::LevelItem>::const_iterator it = items.begin(); it != items.end(); ++it)
|
||||
{
|
||||
if (it->mLevel > highestLevel && it->mLevel <= playerLevel)
|
||||
highestLevel = it->mLevel;
|
||||
}
|
||||
|
||||
// For levelled creatures, the flags are swapped. This file format just makes so much sense.
|
||||
bool allLevels = levItem->mFlags & ESM::ItemLevList::AllLevels;
|
||||
if (creature)
|
||||
allLevels = levItem->mFlags & ESM::CreatureLevList::AllLevels;
|
||||
|
||||
std::pair<int, std::string> highest = std::make_pair(-1, "");
|
||||
for (std::vector<ESM::LeveledListBase::LevelItem>::const_iterator it = items.begin(); it != items.end(); ++it)
|
||||
{
|
||||
if (playerLevel >= it->mLevel
|
||||
&& (allLevels || it->mLevel == highestLevel))
|
||||
{
|
||||
candidates.push_back(it->mId);
|
||||
if (it->mLevel >= highest.first)
|
||||
highest = std::make_pair(it->mLevel, it->mId);
|
||||
}
|
||||
}
|
||||
if (candidates.empty())
|
||||
return std::string();
|
||||
std::string item = candidates[std::rand()%candidates.size()];
|
||||
|
||||
// Is this another levelled item or a real item?
|
||||
try
|
||||
{
|
||||
MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), item, 1);
|
||||
if (ref.getPtr().getTypeName() != typeid(ESM::ItemLevList).name()
|
||||
&& ref.getPtr().getTypeName() != typeid(ESM::CreatureLevList).name())
|
||||
{
|
||||
return item;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ref.getPtr().getTypeName() == typeid(ESM::ItemLevList).name())
|
||||
return getLevelledItem(ref.getPtr().get<ESM::ItemLevList>()->mBase, failChance);
|
||||
else
|
||||
return getLevelledItem(ref.getPtr().get<ESM::CreatureLevList>()->mBase, failChance);
|
||||
}
|
||||
}
|
||||
catch (std::logic_error& e)
|
||||
{
|
||||
// Vanilla doesn't fail on nonexistent items in levelled lists
|
||||
std::cerr << "Warning: ignoring nonexistent item '" << item << "'" << std::endl;
|
||||
return std::string();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -19,7 +19,7 @@
|
||||
namespace
|
||||
{
|
||||
/// @return is \a ptr allowed to take/use \a item or is it a crime?
|
||||
bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item)
|
||||
bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, MWWorld::Ptr& victim)
|
||||
{
|
||||
const std::string& owner = item.getCellRef().mOwner;
|
||||
bool isOwned = !owner.empty();
|
||||
@ -33,6 +33,9 @@ namespace
|
||||
isFactionOwned = true;
|
||||
}
|
||||
|
||||
if (!item.getCellRef().mOwner.empty())
|
||||
victim = MWBase::Environment::get().getWorld()->searchPtr(item.getCellRef().mOwner, true);
|
||||
|
||||
return (!isOwned && !isFactionOwned);
|
||||
}
|
||||
}
|
||||
@ -367,9 +370,14 @@ namespace MWMechanics
|
||||
mObjects.update(duration, paused);
|
||||
}
|
||||
|
||||
void MechanicsManager::restoreDynamicStats()
|
||||
void MechanicsManager::rest(bool sleep)
|
||||
{
|
||||
mActors.restoreDynamicStats ();
|
||||
mActors.restoreDynamicStats (sleep);
|
||||
}
|
||||
|
||||
int MechanicsManager::getHoursToRest() const
|
||||
{
|
||||
return mActors.getHoursToRest(mWatched);
|
||||
}
|
||||
|
||||
void MechanicsManager::setPlayerName (const std::string& name)
|
||||
@ -464,21 +472,23 @@ namespace MWMechanics
|
||||
std::string npcFaction = "";
|
||||
if(!npcSkill.getFactionRanks().empty()) npcFaction = npcSkill.getFactionRanks().begin()->first;
|
||||
|
||||
if (playerStats.getFactionRanks().find(Misc::StringUtils::lowerCase(npcFaction)) != playerStats.getFactionRanks().end())
|
||||
Misc::StringUtils::toLower(npcFaction);
|
||||
|
||||
if (playerStats.getFactionRanks().find(npcFaction) != playerStats.getFactionRanks().end())
|
||||
{
|
||||
for(std::vector<ESM::Faction::Reaction>::const_iterator it = MWBase::Environment::get().getWorld()->getStore().get<ESM::Faction>().find(Misc::StringUtils::lowerCase(npcFaction))->mReactions.begin();
|
||||
it != MWBase::Environment::get().getWorld()->getStore().get<ESM::Faction>().find(Misc::StringUtils::lowerCase(npcFaction))->mReactions.end(); ++it)
|
||||
for(std::vector<ESM::Faction::Reaction>::const_iterator it = MWBase::Environment::get().getWorld()->getStore().get<ESM::Faction>().find(npcFaction)->mReactions.begin();
|
||||
it != MWBase::Environment::get().getWorld()->getStore().get<ESM::Faction>().find(npcFaction)->mReactions.end(); ++it)
|
||||
{
|
||||
if(Misc::StringUtils::lowerCase(it->mFaction) == Misc::StringUtils::lowerCase(npcFaction)
|
||||
if(Misc::StringUtils::ciEqual(it->mFaction, npcFaction)
|
||||
&& !playerStats.getExpelled(it->mFaction))
|
||||
reaction = it->mReaction;
|
||||
}
|
||||
rank = playerStats.getFactionRanks().find(Misc::StringUtils::lowerCase(npcFaction))->second;
|
||||
rank = playerStats.getFactionRanks().find(npcFaction)->second;
|
||||
}
|
||||
else if (npcFaction != "")
|
||||
{
|
||||
for(std::vector<ESM::Faction::Reaction>::const_iterator it = MWBase::Environment::get().getWorld()->getStore().get<ESM::Faction>().find(Misc::StringUtils::lowerCase(npcFaction))->mReactions.begin();
|
||||
it != MWBase::Environment::get().getWorld()->getStore().get<ESM::Faction>().find(Misc::StringUtils::lowerCase(npcFaction))->mReactions.end();++it)
|
||||
for(std::vector<ESM::Faction::Reaction>::const_iterator it = MWBase::Environment::get().getWorld()->getStore().get<ESM::Faction>().find(npcFaction)->mReactions.begin();
|
||||
it != MWBase::Environment::get().getWorld()->getStore().get<ESM::Faction>().find(npcFaction)->mReactions.end();++it)
|
||||
{
|
||||
if(playerStats.getFactionRanks().find(Misc::StringUtils::lowerCase(it->mFaction)) != playerStats.getFactionRanks().end() )
|
||||
{
|
||||
@ -752,11 +762,9 @@ namespace MWMechanics
|
||||
|
||||
bool MechanicsManager::sleepInBed(const MWWorld::Ptr &ptr, const MWWorld::Ptr &bed)
|
||||
{
|
||||
if (isAllowedToUse(ptr, bed))
|
||||
return false;
|
||||
MWWorld::Ptr victim;
|
||||
if (!bed.getCellRef().mOwner.empty())
|
||||
victim = MWBase::Environment::get().getWorld()->getPtr(bed.getCellRef().mOwner, true);
|
||||
if (isAllowedToUse(ptr, bed, victim))
|
||||
return false;
|
||||
|
||||
if(commitCrime(ptr, victim, OT_SleepingInOwnedBed))
|
||||
{
|
||||
@ -767,20 +775,26 @@ namespace MWMechanics
|
||||
return false;
|
||||
}
|
||||
|
||||
void MechanicsManager::objectOpened(const MWWorld::Ptr &ptr, const MWWorld::Ptr &item)
|
||||
{
|
||||
MWWorld::Ptr victim;
|
||||
if (isAllowedToUse(ptr, item, victim))
|
||||
return;
|
||||
commitCrime(ptr, victim, OT_Trespassing);
|
||||
}
|
||||
|
||||
void MechanicsManager::itemTaken(const MWWorld::Ptr &ptr, const MWWorld::Ptr &item, int count)
|
||||
{
|
||||
if (isAllowedToUse(ptr, item))
|
||||
return;
|
||||
MWWorld::Ptr victim;
|
||||
if (!item.getCellRef().mOwner.empty())
|
||||
victim = MWBase::Environment::get().getWorld()->getPtr(item.getCellRef().mOwner, true);
|
||||
|
||||
if (isAllowedToUse(ptr, item, victim))
|
||||
return;
|
||||
commitCrime(ptr, victim, OT_Theft, item.getClass().getValue(item) * count);
|
||||
}
|
||||
|
||||
bool MechanicsManager::commitCrime(const MWWorld::Ptr &ptr, const MWWorld::Ptr &victim, OffenseType type, int arg)
|
||||
{
|
||||
// TODO: expell from faction
|
||||
if (ptr.getRefData().getHandle() != "player")
|
||||
return false;
|
||||
|
||||
bool reported=false;
|
||||
for (Actors::PtrControllerMap::const_iterator it = mActors.begin(); it != mActors.end(); ++it)
|
||||
@ -797,10 +811,7 @@ namespace MWMechanics
|
||||
|
||||
// Actor has witnessed a crime. Will he report it?
|
||||
// (not sure, is > 0 correct?)
|
||||
if (it->first.getClass().getCreatureStats(it->first).getAiSetting(CreatureStats::AI_Alarm).getModified() > 0
|
||||
// This is a bit inconsistent, but AFAIK assaulted NPCs can not report if they are alone
|
||||
&& (type != OT_Assault || it->first != victim)
|
||||
)
|
||||
if (it->first.getClass().getCreatureStats(it->first).getAiSetting(CreatureStats::AI_Alarm).getModified() > 0)
|
||||
{
|
||||
// TODO: stats.setAlarmed(true) on NPCs within earshot
|
||||
// fAlarmRadius ?
|
||||
@ -830,10 +841,32 @@ namespace MWMechanics
|
||||
else if (type == OT_Theft)
|
||||
arg *= store.find("fCrimeStealing")->getFloat();
|
||||
|
||||
// TODO: In some cases (type == Assault), if no NPCs are within earshot, the report will have no effect.
|
||||
// however other crime types seem to be always produce a bounty.
|
||||
|
||||
MWBase::Environment::get().getWindowManager()->messageBox("#{sCrimeMessage}");
|
||||
ptr.getClass().getNpcStats(ptr).setBounty(ptr.getClass().getNpcStats(ptr).getBounty()
|
||||
+ arg);
|
||||
|
||||
if (!victim.isEmpty())
|
||||
{
|
||||
int fight = 0;
|
||||
// Increase in fight rating for each type of crime
|
||||
if (type == OT_Trespassing || type == OT_SleepingInOwnedBed)
|
||||
fight = store.find("iFightTrespass")->getFloat();
|
||||
else if (type == OT_Pickpocket)
|
||||
fight = store.find("iFightPickpocket")->getInt();
|
||||
else if (type == OT_Assault)
|
||||
fight = store.find("iFightAttack")->getInt();
|
||||
else if (type == OT_Murder)
|
||||
fight = store.find("iFightKilling")->getInt();
|
||||
else if (type == OT_Theft)
|
||||
fight = store.find("fFightStealing")->getFloat();
|
||||
// Not sure if this should be permanent?
|
||||
fight = victim.getClass().getCreatureStats(victim).getAiSetting(CreatureStats::AI_Fight).getBase() + fight;
|
||||
victim.getClass().getCreatureStats(victim).setAiSetting(CreatureStats::AI_Fight, fight);
|
||||
}
|
||||
|
||||
// If committing a crime against a faction member, expell from the faction
|
||||
if (!victim.isEmpty() && victim.getClass().isNpc())
|
||||
{
|
||||
@ -851,6 +884,9 @@ namespace MWMechanics
|
||||
|
||||
bool MechanicsManager::awarenessCheck(const MWWorld::Ptr &ptr, const MWWorld::Ptr &observer)
|
||||
{
|
||||
if (observer.getClass().getCreatureStats(observer).isDead())
|
||||
return false;
|
||||
|
||||
const MWWorld::Store<ESM::GameSetting>& store = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
||||
|
||||
CreatureStats& stats = ptr.getClass().getCreatureStats(ptr);
|
||||
@ -860,15 +896,13 @@ namespace MWMechanics
|
||||
return false;
|
||||
|
||||
float sneakTerm = 0;
|
||||
if (ptr.getClass().getStance(ptr, MWWorld::Class::Sneak)
|
||||
if (ptr.getClass().getCreatureStats(ptr).getStance(CreatureStats::Stance_Sneak)
|
||||
&& !MWBase::Environment::get().getWorld()->isSwimming(ptr)
|
||||
&& MWBase::Environment::get().getWorld()->isOnGround(ptr))
|
||||
{
|
||||
static float fSneakSkillMult = store.find("fSneakSkillMult")->getFloat();
|
||||
static float fSneakBootMult = store.find("fSneakBootMult")->getFloat();
|
||||
float sneak = 0;
|
||||
if (ptr.getClass().isNpc())
|
||||
sneak = ptr.getClass().getNpcStats(ptr).getSkill(ESM::Skill::Sneak).getModified();
|
||||
float sneak = ptr.getClass().getSkill(ptr, ESM::Skill::Sneak);
|
||||
int agility = stats.getAttribute(ESM::Attribute::Agility).getModified();
|
||||
int luck = stats.getAttribute(ESM::Attribute::Luck).getModified();
|
||||
float bootWeight = 0;
|
||||
@ -896,9 +930,7 @@ namespace MWMechanics
|
||||
int obsAgility = observerStats.getAttribute(ESM::Attribute::Agility).getModified();
|
||||
int obsLuck = observerStats.getAttribute(ESM::Attribute::Luck).getModified();
|
||||
float obsBlind = observerStats.getMagicEffects().get(ESM::MagicEffect::Blind).mMagnitude;
|
||||
int obsSneak = 0;
|
||||
if (observer.getClass().isNpc())
|
||||
obsSneak = observer.getClass().getNpcStats(observer).getSkill(ESM::Skill::Sneak).getModified();
|
||||
int obsSneak = observer.getClass().getSkill(observer, ESM::Skill::Sneak);
|
||||
|
||||
float obsTerm = obsSneak + 0.2 * obsAgility + 0.1 * obsLuck - obsBlind;
|
||||
|
||||
|
@ -81,8 +81,12 @@ namespace MWMechanics
|
||||
virtual void setPlayerClass (const ESM::Class& class_);
|
||||
///< Set player class to custom class.
|
||||
|
||||
virtual void restoreDynamicStats();
|
||||
///< If the player is sleeping, this should be called every hour.
|
||||
virtual void rest(bool sleep);
|
||||
///< If the player is sleeping or waiting, this should be called every hour.
|
||||
/// @param sleep is the player sleeping or waiting?
|
||||
|
||||
virtual int getHoursToRest() const;
|
||||
///< Calculate how many hours the player needs to rest in order to be fully healed
|
||||
|
||||
virtual int getBarterOffer(const MWWorld::Ptr& ptr,int basePrice, bool buying);
|
||||
///< This is used by every service to determine the price of objects given the trading skills of the player and NPC.
|
||||
@ -113,6 +117,8 @@ namespace MWMechanics
|
||||
OffenseType type, int arg=0);
|
||||
/// Utility to check if taking this item is illegal and calling commitCrime if so
|
||||
virtual void itemTaken (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, int count);
|
||||
/// Utility to check if opening (i.e. unlocking) this object is illegal and calling commitCrime if so
|
||||
virtual void objectOpened (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item);
|
||||
/// Attempt sleeping in a bed. If this is illegal, call commitCrime.
|
||||
/// @return was it illegal, and someone saw you doing it?
|
||||
virtual bool sleepInBed (const MWWorld::Ptr& ptr, const MWWorld::Ptr& bed);
|
||||
|
@ -22,8 +22,7 @@
|
||||
#include "../mwbase/soundmanager.hpp"
|
||||
|
||||
MWMechanics::NpcStats::NpcStats()
|
||||
: mMovementFlags (0)
|
||||
, mDrawState (DrawState_Nothing)
|
||||
: mDrawState (DrawState_Nothing)
|
||||
, mBounty (0)
|
||||
, mLevelProgress(0)
|
||||
, mDisposition(0)
|
||||
@ -34,9 +33,7 @@ MWMechanics::NpcStats::NpcStats()
|
||||
, mTimeToStartDrowning(20.0)
|
||||
, mLastDrowningHit(0)
|
||||
{
|
||||
mSkillIncreases.resize (ESM::Attribute::Length);
|
||||
for (int i=0; i<ESM::Attribute::Length; ++i)
|
||||
mSkillIncreases[i] = 0;
|
||||
mSkillIncreases.resize (ESM::Attribute::Length, 0);
|
||||
}
|
||||
|
||||
MWMechanics::DrawState_ MWMechanics::NpcStats::getDrawState() const
|
||||
@ -69,19 +66,6 @@ void MWMechanics::NpcStats::setBaseDisposition(int disposition)
|
||||
mDisposition = disposition;
|
||||
}
|
||||
|
||||
bool MWMechanics::NpcStats::getMovementFlag (Flag flag) const
|
||||
{
|
||||
return mMovementFlags & flag;
|
||||
}
|
||||
|
||||
void MWMechanics::NpcStats::setMovementFlag (Flag flag, bool state)
|
||||
{
|
||||
if (state)
|
||||
mMovementFlags |= flag;
|
||||
else
|
||||
mMovementFlags &= ~flag;
|
||||
}
|
||||
|
||||
const MWMechanics::SkillValue& MWMechanics::NpcStats::getSkill (int index) const
|
||||
{
|
||||
if (index<0 || index>=ESM::Skill::Length)
|
||||
@ -207,7 +191,7 @@ void MWMechanics::NpcStats::useSkill (int skillIndex, const ESM::Class& class_,
|
||||
if(mIsWerewolf)
|
||||
return;
|
||||
|
||||
MWMechanics::SkillValue value = getSkill (skillIndex);
|
||||
MWMechanics::SkillValue& value = getSkill (skillIndex);
|
||||
|
||||
value.setProgress(value.getProgress() + getSkillGain (skillIndex, class_, usageType));
|
||||
|
||||
|
@ -25,18 +25,6 @@ namespace MWMechanics
|
||||
|
||||
class NpcStats : public CreatureStats
|
||||
{
|
||||
public:
|
||||
|
||||
enum Flag
|
||||
{
|
||||
Flag_ForceRun = 1,
|
||||
Flag_ForceSneak = 2,
|
||||
Flag_Run = 4,
|
||||
Flag_Sneak = 8
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
/// NPCs other than the player can only have one faction. But for the sake of consistency
|
||||
/// we use the same data structure for the PC and the NPCs.
|
||||
/// \note the faction key must be in lowercase
|
||||
@ -44,7 +32,6 @@ namespace MWMechanics
|
||||
|
||||
DrawState_ mDrawState;
|
||||
int mDisposition;
|
||||
unsigned int mMovementFlags;
|
||||
SkillValue mSkill[27];
|
||||
SkillValue mWerewolfSkill[27];
|
||||
int mBounty;
|
||||
@ -89,10 +76,6 @@ namespace MWMechanics
|
||||
|
||||
void setReputation(int reputation);
|
||||
|
||||
bool getMovementFlag (Flag flag) const;
|
||||
|
||||
void setMovementFlag (Flag flag, bool state);
|
||||
|
||||
const SkillValue& getSkill (int index) const;
|
||||
SkillValue& getSkill (int index);
|
||||
|
||||
|
@ -150,6 +150,7 @@ namespace MWMechanics
|
||||
void PathFinder::buildPath(const ESM::Pathgrid::Point &startPoint, const ESM::Pathgrid::Point &endPoint,
|
||||
const ESM::Pathgrid *pathGrid, float xCell, float yCell, bool allowShortcuts)
|
||||
{
|
||||
mPath.clear();
|
||||
if(allowShortcuts)
|
||||
{
|
||||
if(MWBase::Environment::get().getWorld()->castRay(startPoint.mX, startPoint.mY, startPoint.mZ,
|
||||
|
@ -19,7 +19,7 @@ namespace MWMechanics
|
||||
NpcStats& stats = ptr.getClass().getNpcStats(ptr);
|
||||
float agility = stats.getAttribute(ESM::Attribute::Agility).getModified();
|
||||
float luck = stats.getAttribute(ESM::Attribute::Luck).getModified();
|
||||
float sneak = stats.getSkill(ESM::Skill::Sneak).getModified();
|
||||
float sneak = ptr.getClass().getSkill(ptr, ESM::Skill::Sneak);
|
||||
return (add + 0.2 * agility + 0.1 * luck + sneak) * stats.getFatigueTerm();
|
||||
}
|
||||
|
||||
@ -30,8 +30,7 @@ namespace MWMechanics
|
||||
|
||||
float t = 2*x - y;
|
||||
|
||||
NpcStats& pcStats = mThief.getClass().getNpcStats(mThief);
|
||||
float pcSneak = pcStats.getSkill(ESM::Skill::Sneak).getModified();
|
||||
float pcSneak = mThief.getClass().getSkill(mThief, ESM::Skill::Sneak);
|
||||
int iPickMinChance = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>()
|
||||
.find("iPickMinChance")->getInt();
|
||||
int iPickMaxChance = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>()
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
#include "../mwbase/mechanicsmanager.hpp"
|
||||
|
||||
#include "npcstats.hpp"
|
||||
#include "creaturestats.hpp"
|
||||
@ -45,6 +46,7 @@ namespace MWMechanics
|
||||
resultMessage = "#{sLockImpossible}";
|
||||
else
|
||||
{
|
||||
MWBase::Environment::get().getMechanicsManager()->objectOpened(mActor, lock);
|
||||
int roll = static_cast<float> (std::rand()) / RAND_MAX * 100;
|
||||
if (roll <= x)
|
||||
{
|
||||
@ -86,6 +88,7 @@ namespace MWMechanics
|
||||
resultMessage = "#{sTrapImpossible}";
|
||||
else
|
||||
{
|
||||
MWBase::Environment::get().getMechanicsManager()->objectOpened(mActor, trap);
|
||||
int roll = static_cast<float> (std::rand()) / RAND_MAX * 100;
|
||||
if (roll <= x)
|
||||
{
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
#include "../mwbase/soundmanager.hpp"
|
||||
|
||||
#include "../mwbase/mechanicsmanager.hpp"
|
||||
|
||||
#include "../mwworld/containerstore.hpp"
|
||||
#include "../mwworld/actionteleport.hpp"
|
||||
@ -57,6 +57,7 @@ namespace MWMechanics
|
||||
ESM::EffectList reflectedEffects;
|
||||
std::vector<ActiveSpells::Effect> appliedLastingEffects;
|
||||
bool firstAppliedEffect = true;
|
||||
bool anyHarmfulEffect = false;
|
||||
|
||||
for (std::vector<ESM::ENAMstruct>::const_iterator effectIt (effects.mList.begin());
|
||||
effectIt!=effects.mList.end(); ++effectIt)
|
||||
@ -77,6 +78,8 @@ namespace MWMechanics
|
||||
float magnitudeMult = 1;
|
||||
if (magicEffect->mData.mFlags & ESM::MagicEffect::Harmful && target.getClass().isActor())
|
||||
{
|
||||
anyHarmfulEffect = true;
|
||||
|
||||
// If player is attempting to cast a harmful spell, show the target's HP bar
|
||||
if (caster.getRefData().getHandle() == "player" && target != caster)
|
||||
MWBase::Environment::get().getWindowManager()->setEnemy(target);
|
||||
@ -161,13 +164,14 @@ namespace MWMechanics
|
||||
ActiveSpells::Effect effect_ = effect;
|
||||
effect_.mMagnitude *= -1;
|
||||
effects.push_back(effect_);
|
||||
// Also make sure to set casterHandle = target, so that the effect on the caster gets purged when the target dies
|
||||
caster.getClass().getCreatureStats(caster).getActiveSpells().addSpell("", true,
|
||||
effects, mSourceName, caster.getRefData().getHandle());
|
||||
effects, mSourceName, target.getRefData().getHandle());
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
applyInstantEffect(target, EffectKey(*effectIt), magnitude);
|
||||
applyInstantEffect(target, caster, EffectKey(*effectIt), magnitude);
|
||||
|
||||
// HACK: Damage attribute/skill actually has a duration, even though the actual effect is instant and permanent.
|
||||
// This was probably just done to have the effect visible in the magic menu for a while
|
||||
@ -177,7 +181,7 @@ namespace MWMechanics
|
||||
|| effectIt->mEffectID == ESM::MagicEffect::RestoreAttribute
|
||||
|| effectIt->mEffectID == ESM::MagicEffect::RestoreSkill
|
||||
)
|
||||
applyInstantEffect(target, EffectKey(*effectIt), magnitude);
|
||||
applyInstantEffect(target, caster, EffectKey(*effectIt), magnitude);
|
||||
|
||||
if (target.getClass().isActor() || magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration)
|
||||
{
|
||||
@ -197,15 +201,17 @@ namespace MWMechanics
|
||||
}
|
||||
|
||||
// Add VFX
|
||||
const ESM::Static* castStatic;
|
||||
if (!magicEffect->mHit.empty())
|
||||
{
|
||||
const ESM::Static* castStatic = MWBase::Environment::get().getWorld()->getStore().get<ESM::Static>().find (magicEffect->mHit);
|
||||
bool loop = magicEffect->mData.mFlags & ESM::MagicEffect::ContinuousVfx;
|
||||
// Note: in case of non actor, a free effect should be fine as well
|
||||
MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(target);
|
||||
if (anim)
|
||||
anim->addEffect("meshes\\" + castStatic->mModel, magicEffect->mIndex, loop, "");
|
||||
}
|
||||
castStatic = MWBase::Environment::get().getWorld()->getStore().get<ESM::Static>().find (magicEffect->mHit);
|
||||
else
|
||||
castStatic = MWBase::Environment::get().getWorld()->getStore().get<ESM::Static>().find ("VFX_DefaultHit");
|
||||
|
||||
bool loop = magicEffect->mData.mFlags & ESM::MagicEffect::ContinuousVfx;
|
||||
// Note: in case of non actor, a free effect should be fine as well
|
||||
MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(target);
|
||||
if (anim)
|
||||
anim->addEffect("meshes\\" + castStatic->mModel, magicEffect->mIndex, loop, "");
|
||||
}
|
||||
|
||||
// TODO: For Area effects, launch a growing particle effect that applies the effect to more actors as it hits them. Best managed in World.
|
||||
@ -218,9 +224,13 @@ namespace MWMechanics
|
||||
if (appliedLastingEffects.size())
|
||||
target.getClass().getCreatureStats(target).getActiveSpells().addSpell(mId, mStack, appliedLastingEffects,
|
||||
mSourceName, caster.getRefData().getHandle());
|
||||
|
||||
if (anyHarmfulEffect && target.getClass().isActor() && target != caster
|
||||
&& target.getClass().getCreatureStats(target).getAiSetting(MWMechanics::CreatureStats::AI_Fight).getModified() <= 30)
|
||||
MWBase::Environment::get().getMechanicsManager()->commitCrime(caster, target, MWBase::MechanicsManager::OT_Assault);
|
||||
}
|
||||
|
||||
void CastSpell::applyInstantEffect(const MWWorld::Ptr &target, MWMechanics::EffectKey effect, float magnitude)
|
||||
void CastSpell::applyInstantEffect(const MWWorld::Ptr &target, const MWWorld::Ptr &caster, MWMechanics::EffectKey effect, float magnitude)
|
||||
{
|
||||
short effectId = effect.mId;
|
||||
if (!target.getClass().isActor())
|
||||
@ -232,11 +242,13 @@ namespace MWMechanics
|
||||
}
|
||||
else if (effectId == ESM::MagicEffect::Open)
|
||||
{
|
||||
// TODO: This is a crime
|
||||
if (target.getCellRef().mLockLevel <= magnitude)
|
||||
{
|
||||
if (target.getCellRef().mLockLevel > 0)
|
||||
{
|
||||
MWBase::Environment::get().getSoundManager()->playSound3D(target, "Open Lock", 1.f, 1.f);
|
||||
MWBase::Environment::get().getMechanicsManager()->objectOpened(caster, target);
|
||||
}
|
||||
target.getCellRef().mLockLevel = 0;
|
||||
}
|
||||
else
|
||||
@ -426,8 +438,7 @@ namespace MWMechanics
|
||||
DynamicStat<float> fatigue = stats.getFatigue();
|
||||
const float normalizedEncumbrance = mCaster.getClass().getEncumbrance(mCaster) / mCaster.getClass().getCapacity(mCaster);
|
||||
float fatigueLoss = spell->mData.mCost * (fFatigueSpellBase + normalizedEncumbrance * fFatigueSpellMult);
|
||||
fatigue.setCurrent(std::max(0.f, fatigue.getCurrent() - fatigueLoss));
|
||||
stats.setFatigue(fatigue);
|
||||
fatigue.setCurrent(fatigue.getCurrent() - fatigueLoss); stats.setFatigue(fatigue);
|
||||
|
||||
bool fail = false;
|
||||
|
||||
|
@ -16,15 +16,15 @@
|
||||
|
||||
namespace MWMechanics
|
||||
{
|
||||
inline int spellSchoolToSkill(int school)
|
||||
inline ESM::Skill::SkillEnum spellSchoolToSkill(int school)
|
||||
{
|
||||
std::map<int, int> schoolSkillMap; // maps spell school to skill id
|
||||
schoolSkillMap[0] = 11; // alteration
|
||||
schoolSkillMap[1] = 13; // conjuration
|
||||
schoolSkillMap[3] = 12; // illusion
|
||||
schoolSkillMap[2] = 10; // destruction
|
||||
schoolSkillMap[4] = 14; // mysticism
|
||||
schoolSkillMap[5] = 15; // restoration
|
||||
std::map<int, ESM::Skill::SkillEnum> schoolSkillMap; // maps spell school to skill id
|
||||
schoolSkillMap[0] = ESM::Skill::Alteration;
|
||||
schoolSkillMap[1] = ESM::Skill::Conjuration;
|
||||
schoolSkillMap[3] = ESM::Skill::Illusion;
|
||||
schoolSkillMap[2] = ESM::Skill::Destruction;
|
||||
schoolSkillMap[4] = ESM::Skill::Mysticism;
|
||||
schoolSkillMap[5] = ESM::Skill::Restoration;
|
||||
assert(schoolSkillMap.find(school) != schoolSkillMap.end());
|
||||
return schoolSkillMap[school];
|
||||
}
|
||||
@ -38,10 +38,9 @@ namespace MWMechanics
|
||||
*/
|
||||
inline float getSpellSuccessChance (const ESM::Spell* spell, const MWWorld::Ptr& actor, int* effectiveSchool = NULL)
|
||||
{
|
||||
NpcStats& stats = MWWorld::Class::get(actor).getNpcStats(actor);
|
||||
CreatureStats& creatureStats = MWWorld::Class::get(actor).getCreatureStats(actor);
|
||||
CreatureStats& stats = actor.getClass().getCreatureStats(actor);
|
||||
|
||||
if (creatureStats.getMagicEffects().get(ESM::MagicEffect::Silence).mMagnitude)
|
||||
if (stats.getMagicEffects().get(ESM::MagicEffect::Silence).mMagnitude)
|
||||
return 0;
|
||||
|
||||
float y = FLT_MAX;
|
||||
@ -63,7 +62,7 @@ namespace MWMechanics
|
||||
"fEffectCostMult")->getFloat();
|
||||
x *= fEffectCostMult;
|
||||
|
||||
float s = 2 * stats.getSkill(spellSchoolToSkill(magicEffect->mData.mSchool)).getModified();
|
||||
float s = 2 * actor.getClass().getSkill(actor, spellSchoolToSkill(magicEffect->mData.mSchool));
|
||||
if (s - x < y)
|
||||
{
|
||||
y = s - x;
|
||||
@ -203,7 +202,7 @@ namespace MWMechanics
|
||||
void inflict (const MWWorld::Ptr& target, const MWWorld::Ptr& caster,
|
||||
const ESM::EffectList& effects, ESM::RangeType range, bool reflected=false);
|
||||
|
||||
void applyInstantEffect (const MWWorld::Ptr& target, MWMechanics::EffectKey effect, float magnitude);
|
||||
void applyInstantEffect (const MWWorld::Ptr& target, const MWWorld::Ptr& caster, MWMechanics::EffectKey effect, float magnitude);
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -246,6 +246,18 @@ namespace MWMechanics
|
||||
{
|
||||
return !(left == right);
|
||||
}
|
||||
|
||||
inline bool operator== (const SkillValue& left, const SkillValue& right)
|
||||
{
|
||||
return left.getBase() == right.getBase()
|
||||
&& left.getModifier() == right.getModifier()
|
||||
&& left.getDamage() == right.getDamage()
|
||||
&& left.getProgress() == right.getProgress();
|
||||
}
|
||||
inline bool operator!= (const SkillValue& left, const SkillValue& right)
|
||||
{
|
||||
return !(left == right);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -226,11 +226,10 @@ namespace MWRender
|
||||
mCamera->setPosition(0.f, 0.f, offset);
|
||||
}
|
||||
|
||||
void Camera::setSneakOffset()
|
||||
void Camera::setSneakOffset(float offset)
|
||||
{
|
||||
// TODO: iFirstPersonSneakDelta
|
||||
if(mAnimation)
|
||||
mAnimation->addFirstPersonOffset(Ogre::Vector3(0.f, 0.f, -9.8f));
|
||||
mAnimation->addFirstPersonOffset(Ogre::Vector3(0.f, 0.f, -offset));
|
||||
}
|
||||
|
||||
float Camera::getYaw()
|
||||
|
@ -87,7 +87,7 @@ namespace MWRender
|
||||
/// As animation is tied to the camera, this needs
|
||||
/// to be set each frame after the animation is
|
||||
/// applied.
|
||||
void setSneakOffset();
|
||||
void setSneakOffset(float offset);
|
||||
|
||||
bool isFirstPerson() const
|
||||
{ return !(mVanity.enabled || mPreviewMode || !mFirstPersonView); }
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <OgreSceneManager.h>
|
||||
#include <OgreRoot.h>
|
||||
#include <OgreHardwarePixelBuffer.h>
|
||||
#include <OgreCamera.h>
|
||||
|
||||
#include <libs/openengine/ogre/selectionbuffer.hpp>
|
||||
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include <OgreSubEntity.h>
|
||||
#include <OgreMeshManager.h>
|
||||
#include <OgreMaterialManager.h>
|
||||
#include <OgreCamera.h>
|
||||
|
||||
#include "renderconst.hpp"
|
||||
|
||||
|
@ -347,12 +347,14 @@ void RenderingManager::update (float duration, bool paused)
|
||||
}
|
||||
|
||||
// Sink the camera while sneaking
|
||||
bool isSneaking = MWWorld::Class::get(player).getStance(player, MWWorld::Class::Sneak);
|
||||
bool isSneaking = player.getClass().getCreatureStats(player).getStance(MWMechanics::CreatureStats::Stance_Sneak);
|
||||
bool isInAir = !world->isOnGround(player);
|
||||
bool isSwimming = world->isSwimming(player);
|
||||
|
||||
static const int i1stPersonSneakDelta = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>()
|
||||
.find("i1stPersonSneakDelta")->getInt();
|
||||
if(isSneaking && !(isSwimming || isInAir))
|
||||
mCamera->setSneakOffset();
|
||||
mCamera->setSneakOffset(i1stPersonSneakDelta);
|
||||
|
||||
|
||||
mOcclusionQuery->update(duration);
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include <OgreShadowCameraSetupLiSPSM.h>
|
||||
#include <OgreShadowCameraSetupPSSM.h>
|
||||
#include <OgreHardwarePixelBuffer.h>
|
||||
#include <OgreCamera.h>
|
||||
|
||||
#include <extern/shiny/Main/Factory.hpp>
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include <OgreMeshManager.h>
|
||||
#include <OgreHardwarePixelBuffer.h>
|
||||
#include <OgreRoot.h>
|
||||
#include <OgreCamera.h>
|
||||
|
||||
#include "sky.hpp"
|
||||
#include "renderingmanager.hpp"
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "../mwmechanics/aifollow.hpp"
|
||||
#include "../mwmechanics/aitravel.hpp"
|
||||
#include "../mwmechanics/aiwander.hpp"
|
||||
#include "../mwmechanics/aicombat.hpp"
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
@ -401,6 +402,59 @@ namespace MWScript
|
||||
}
|
||||
};
|
||||
|
||||
template<class R>
|
||||
class OpGetTarget : public Interpreter::Opcode0
|
||||
{
|
||||
public:
|
||||
virtual void execute (Interpreter::Runtime &runtime)
|
||||
{
|
||||
MWWorld::Ptr actor = R()(runtime);
|
||||
std::string testedTargetId = runtime.getStringLiteral (runtime[0].mInteger);
|
||||
runtime.pop();
|
||||
|
||||
const MWMechanics::CreatureStats& creatureStats = MWWorld::Class::get(actor).getCreatureStats(actor);
|
||||
std::string currentTargetId;
|
||||
|
||||
bool targetsAreEqual = false;
|
||||
if (creatureStats.getAiSequence().getCombatTarget (currentTargetId))
|
||||
{
|
||||
if (currentTargetId == testedTargetId)
|
||||
targetsAreEqual = true;
|
||||
}
|
||||
runtime.push(int(targetsAreEqual));
|
||||
}
|
||||
};
|
||||
|
||||
template<class R>
|
||||
class OpStartCombat : public Interpreter::Opcode0
|
||||
{
|
||||
public:
|
||||
virtual void execute (Interpreter::Runtime &runtime)
|
||||
{
|
||||
MWWorld::Ptr actor = R()(runtime);
|
||||
std::string actorID = runtime.getStringLiteral (runtime[0].mInteger);
|
||||
runtime.pop();
|
||||
|
||||
MWMechanics::CreatureStats& creatureStats = MWWorld::Class::get(actor).getCreatureStats(actor);
|
||||
creatureStats.getAiSequence().stack(MWMechanics::AiCombat(actor));
|
||||
if (actorID == "player")
|
||||
creatureStats.setHostile(true);
|
||||
}
|
||||
};
|
||||
|
||||
template<class R>
|
||||
class OpStopCombat : public Interpreter::Opcode0
|
||||
{
|
||||
public:
|
||||
virtual void execute (Interpreter::Runtime& runtime)
|
||||
{
|
||||
MWWorld::Ptr actor = R()(runtime);
|
||||
MWMechanics::CreatureStats& creatureStats = MWWorld::Class::get(actor).getCreatureStats(actor);
|
||||
creatureStats.getAiSequence().stopCombat();
|
||||
creatureStats.setHostile(false);
|
||||
}
|
||||
};
|
||||
|
||||
template<class R>
|
||||
class OpToggleAI : public Interpreter::Opcode0
|
||||
{
|
||||
@ -438,6 +492,12 @@ namespace MWScript
|
||||
interpreter.installSegment5 (Compiler::Ai::opcodeGetDetectedExplicit, new OpGetDetected<ExplicitRef>);
|
||||
interpreter.installSegment5 (Compiler::Ai::opcodeGetLineOfSight, new OpGetLineOfSight<ImplicitRef>);
|
||||
interpreter.installSegment5 (Compiler::Ai::opcodeGetLineOfSightExplicit, new OpGetLineOfSight<ExplicitRef>);
|
||||
interpreter.installSegment5 (Compiler::Ai::opcodeGetTarget, new OpGetTarget<ImplicitRef>);
|
||||
interpreter.installSegment5 (Compiler::Ai::opcodeGetTargetExplicit, new OpGetTarget<ExplicitRef>);
|
||||
interpreter.installSegment5 (Compiler::Ai::opcodeStartCombat, new OpStartCombat<ImplicitRef>);
|
||||
interpreter.installSegment5 (Compiler::Ai::opcodeStartCombatExplicit, new OpStartCombat<ExplicitRef>);
|
||||
interpreter.installSegment5 (Compiler::Ai::opcodeStopCombat, new OpStopCombat<ImplicitRef>);
|
||||
interpreter.installSegment5 (Compiler::Ai::opcodeStopCombatExplicit, new OpStopCombat<ExplicitRef>);
|
||||
interpreter.installSegment5 (Compiler::Ai::opcodeToggleAI, new OpToggleAI<ImplicitRef>);
|
||||
interpreter.installSegment5 (Compiler::Ai::opcodeToggleAIExplicit, new OpToggleAI<ExplicitRef>);
|
||||
|
||||
|
@ -282,7 +282,7 @@ namespace MWScript
|
||||
{
|
||||
MWWorld::Ptr ptr = R()(runtime);
|
||||
|
||||
const std::string &name = runtime.getStringLiteral (runtime[0].mInteger);
|
||||
const std::string &name = runtime.getStringLiteral (runtime[0].mInteger);
|
||||
runtime.pop();
|
||||
|
||||
MWWorld::InventoryStore& invStore = MWWorld::Class::get(ptr).getInventoryStore (ptr);
|
||||
|
@ -76,34 +76,34 @@ namespace MWScript
|
||||
template<class R>
|
||||
class OpClearMovementFlag : public Interpreter::Opcode0
|
||||
{
|
||||
MWMechanics::NpcStats::Flag mFlag;
|
||||
MWMechanics::CreatureStats::Flag mFlag;
|
||||
|
||||
public:
|
||||
|
||||
OpClearMovementFlag (MWMechanics::NpcStats::Flag flag) : mFlag (flag) {}
|
||||
OpClearMovementFlag (MWMechanics::CreatureStats::Flag flag) : mFlag (flag) {}
|
||||
|
||||
virtual void execute (Interpreter::Runtime& runtime)
|
||||
{
|
||||
MWWorld::Ptr ptr = R()(runtime);
|
||||
|
||||
MWWorld::Class::get (ptr).getNpcStats (ptr).setMovementFlag (mFlag, false);
|
||||
ptr.getClass().getCreatureStats(ptr).setMovementFlag (mFlag, false);
|
||||
}
|
||||
};
|
||||
|
||||
template<class R>
|
||||
class OpSetMovementFlag : public Interpreter::Opcode0
|
||||
{
|
||||
MWMechanics::NpcStats::Flag mFlag;
|
||||
MWMechanics::CreatureStats::Flag mFlag;
|
||||
|
||||
public:
|
||||
|
||||
OpSetMovementFlag (MWMechanics::NpcStats::Flag flag) : mFlag (flag) {}
|
||||
OpSetMovementFlag (MWMechanics::CreatureStats::Flag flag) : mFlag (flag) {}
|
||||
|
||||
virtual void execute (Interpreter::Runtime& runtime)
|
||||
{
|
||||
MWWorld::Ptr ptr = R()(runtime);
|
||||
|
||||
MWWorld::Class::get (ptr).getNpcStats (ptr).setMovementFlag (mFlag, true);
|
||||
ptr.getClass().getCreatureStats(ptr).setMovementFlag (mFlag, true);
|
||||
}
|
||||
};
|
||||
|
||||
@ -116,9 +116,8 @@ namespace MWScript
|
||||
{
|
||||
MWWorld::Ptr ptr = R()(runtime);
|
||||
|
||||
MWMechanics::NpcStats& npcStats = MWWorld::Class::get(ptr).getNpcStats (ptr);
|
||||
|
||||
runtime.push (npcStats.getMovementFlag (MWMechanics::NpcStats::Flag_ForceRun));
|
||||
MWMechanics::CreatureStats& stats = ptr.getClass().getCreatureStats (ptr);
|
||||
runtime.push (stats.getMovementFlag (MWMechanics::CreatureStats::Flag_ForceRun));
|
||||
}
|
||||
};
|
||||
|
||||
@ -131,9 +130,8 @@ namespace MWScript
|
||||
{
|
||||
MWWorld::Ptr ptr = R()(runtime);
|
||||
|
||||
MWMechanics::NpcStats& npcStats = MWWorld::Class::get(ptr).getNpcStats (ptr);
|
||||
|
||||
runtime.push (npcStats.getMovementFlag (MWMechanics::NpcStats::Flag_ForceSneak));
|
||||
MWMechanics::CreatureStats& stats = ptr.getClass().getCreatureStats(ptr);
|
||||
runtime.push (stats.getMovementFlag (MWMechanics::CreatureStats::Flag_ForceSneak));
|
||||
}
|
||||
};
|
||||
|
||||
@ -144,7 +142,7 @@ namespace MWScript
|
||||
virtual void execute (Interpreter::Runtime& runtime)
|
||||
{
|
||||
MWWorld::Ptr ptr = MWBase::Environment::get().getWorld ()->getPlayerPtr();
|
||||
runtime.push (MWWorld::Class::get(ptr).getStance (ptr, MWWorld::Class::Run));
|
||||
runtime.push (ptr.getClass().getCreatureStats(ptr).getStance(MWMechanics::CreatureStats::Stance_Run));
|
||||
}
|
||||
};
|
||||
|
||||
@ -155,7 +153,7 @@ namespace MWScript
|
||||
virtual void execute (Interpreter::Runtime& runtime)
|
||||
{
|
||||
MWWorld::Ptr ptr = MWBase::Environment::get().getWorld ()->getPlayerPtr();
|
||||
runtime.push (MWWorld::Class::get(ptr).getStance (ptr, MWWorld::Class::Sneak));
|
||||
runtime.push (ptr.getClass().getCreatureStats(ptr).getStance(MWMechanics::CreatureStats::Stance_Sneak));
|
||||
}
|
||||
};
|
||||
|
||||
@ -172,22 +170,22 @@ namespace MWScript
|
||||
interpreter.installSegment5 (Compiler::Control::opcodeToggleCollision, new OpToggleCollision);
|
||||
|
||||
interpreter.installSegment5 (Compiler::Control::opcodeClearForceRun,
|
||||
new OpClearMovementFlag<ImplicitRef> (MWMechanics::NpcStats::Flag_ForceRun));
|
||||
new OpClearMovementFlag<ImplicitRef> (MWMechanics::CreatureStats::Flag_ForceRun));
|
||||
interpreter.installSegment5 (Compiler::Control::opcodeForceRun,
|
||||
new OpSetMovementFlag<ImplicitRef> (MWMechanics::NpcStats::Flag_ForceRun));
|
||||
new OpSetMovementFlag<ImplicitRef> (MWMechanics::CreatureStats::Flag_ForceRun));
|
||||
interpreter.installSegment5 (Compiler::Control::opcodeClearForceSneak,
|
||||
new OpClearMovementFlag<ImplicitRef> (MWMechanics::NpcStats::Flag_ForceSneak));
|
||||
new OpClearMovementFlag<ImplicitRef> (MWMechanics::CreatureStats::Flag_ForceSneak));
|
||||
interpreter.installSegment5 (Compiler::Control::opcodeForceSneak,
|
||||
new OpSetMovementFlag<ImplicitRef> (MWMechanics::NpcStats::Flag_ForceSneak));
|
||||
new OpSetMovementFlag<ImplicitRef> (MWMechanics::CreatureStats::Flag_ForceSneak));
|
||||
|
||||
interpreter.installSegment5 (Compiler::Control::opcodeClearForceRunExplicit,
|
||||
new OpClearMovementFlag<ExplicitRef> (MWMechanics::NpcStats::Flag_ForceRun));
|
||||
new OpClearMovementFlag<ExplicitRef> (MWMechanics::CreatureStats::Flag_ForceRun));
|
||||
interpreter.installSegment5 (Compiler::Control::opcodeForceRunExplicit,
|
||||
new OpSetMovementFlag<ExplicitRef> (MWMechanics::NpcStats::Flag_ForceRun));
|
||||
new OpSetMovementFlag<ExplicitRef> (MWMechanics::CreatureStats::Flag_ForceRun));
|
||||
interpreter.installSegment5 (Compiler::Control::opcodeClearForceSneakExplicit,
|
||||
new OpClearMovementFlag<ExplicitRef> (MWMechanics::NpcStats::Flag_ForceSneak));
|
||||
new OpClearMovementFlag<ExplicitRef> (MWMechanics::CreatureStats::Flag_ForceSneak));
|
||||
interpreter.installSegment5 (Compiler::Control::opcodeForceSneakExplicit,
|
||||
new OpSetMovementFlag<ExplicitRef> (MWMechanics::NpcStats::Flag_ForceSneak));
|
||||
new OpSetMovementFlag<ExplicitRef> (MWMechanics::CreatureStats::Flag_ForceSneak));
|
||||
interpreter.installSegment5 (Compiler::Control::opcodeGetPcRunning, new OpGetPcRunning);
|
||||
interpreter.installSegment5 (Compiler::Control::opcodeGetPcSneaking, new OpGetPcSneaking);
|
||||
interpreter.installSegment5 (Compiler::Control::opcodeGetForceRun, new OpGetForceRun<ImplicitRef>);
|
||||
|
@ -374,6 +374,12 @@ op 0x2000233: GetPcJumping
|
||||
op 0x2000234: ShowRestMenu, explicit
|
||||
op 0x2000235: GoToJail
|
||||
op 0x2000236: PayFine
|
||||
op 0x2000237: PayFineThief
|
||||
opcodes 0x2000238-0x3ffffff unused
|
||||
op 0x2000237: PayFineThief
|
||||
op 0x2000238: GetTarget
|
||||
op 0x2000239: GetTargetExplicit
|
||||
op 0x200023a: StartCombat
|
||||
op 0x200023b: StartCombatExplicit
|
||||
op 0x200023c: StopCombat
|
||||
op 0x200023d: StopCombatExplicit
|
||||
|
||||
opcodes 0x200023e-0x3ffffff unused
|
||||
|
@ -1,8 +1,6 @@
|
||||
|
||||
#include "guiextensions.hpp"
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
#include <components/compiler/extensions.hpp>
|
||||
#include <components/compiler/opcodes.hpp>
|
||||
|
||||
|
@ -371,15 +371,20 @@ namespace MWScript
|
||||
|
||||
virtual void execute (Interpreter::Runtime& runtime)
|
||||
{
|
||||
|
||||
MWWorld::Ptr ptr = R()(runtime);
|
||||
|
||||
std::string soul = runtime.getStringLiteral (runtime[0].mInteger);
|
||||
runtime.pop();
|
||||
|
||||
MWWorld::ContainerStore& store = MWWorld::Class::get (ptr).getContainerStore (ptr);
|
||||
|
||||
store.remove(soul, 1, ptr);
|
||||
for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it)
|
||||
{
|
||||
if (::Misc::StringUtils::ciEqual(it->getCellRef().mSoul, soul))
|
||||
{
|
||||
store.remove(*it, 1, ptr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -766,12 +771,7 @@ namespace MWScript
|
||||
virtual void execute (Interpreter::Runtime& runtime)
|
||||
{
|
||||
MWBase::World* world = MWBase::Environment::get().getWorld();
|
||||
MWWorld::Ptr player = world->getPlayerPtr();
|
||||
world->teleportToClosestMarker(player, "prisonmarker");
|
||||
player.getClass().getNpcStats(player).setBounty(0);
|
||||
// TODO: pass time, change skills, show messagebox
|
||||
// TODO: move stolen items to closest evidence chest
|
||||
// iDaysinPrisonMod
|
||||
world->goToJail();
|
||||
}
|
||||
};
|
||||
|
||||
@ -782,8 +782,7 @@ namespace MWScript
|
||||
{
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||
player.getClass().getNpcStats(player).setBounty(0);
|
||||
|
||||
// TODO: move stolen items to closest evidence chest
|
||||
MWBase::Environment::get().getWorld()->confiscateStolenItems(player);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -3,8 +3,6 @@
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
#include <components/esm/loadnpc.hpp>
|
||||
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
@ -308,9 +306,7 @@ namespace MWScript
|
||||
{
|
||||
MWWorld::Ptr ptr = R()(runtime);
|
||||
|
||||
Interpreter::Type_Integer value =
|
||||
MWWorld::Class::get (ptr).getNpcStats (ptr).getSkill (mIndex).
|
||||
getModified();
|
||||
Interpreter::Type_Integer value = ptr.getClass().getSkill(ptr, mIndex);
|
||||
|
||||
runtime.push (value);
|
||||
}
|
||||
|
@ -1,9 +1,5 @@
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
#include <OgreMath.h>
|
||||
#include <OgreSceneNode.h>
|
||||
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
#include <components/esm/loadcell.hpp>
|
||||
|
||||
#include <components/compiler/extensions.hpp>
|
||||
@ -18,6 +14,7 @@
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwworld/manualref.hpp"
|
||||
#include "../mwworld/player.hpp"
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
|
||||
#include "interpretercontext.hpp"
|
||||
#include "ref.hpp"
|
||||
|
@ -403,7 +403,7 @@ void OpenAL_SoundStream::update()
|
||||
|
||||
alSourcef(mSource, AL_GAIN, gain);
|
||||
alSourcef(mSource, AL_PITCH, pitch);
|
||||
alSource3f(mSource, AL_POSITION, mPos[0], mPos[2], -mPos[1]);
|
||||
alSource3f(mSource, AL_POSITION, mPos[0], mPos[1], mPos[2]);
|
||||
alSource3f(mSource, AL_DIRECTION, 0.0f, 0.0f, 0.0f);
|
||||
alSource3f(mSource, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
|
||||
throwALerror();
|
||||
|
@ -156,11 +156,12 @@ namespace MWSound
|
||||
volume *= mFootstepsVolume;
|
||||
break;
|
||||
case Play_TypeMusic:
|
||||
case Play_TypeMovie:
|
||||
volume *= mMusicVolume;
|
||||
break;
|
||||
case Play_TypeMask:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return volume;
|
||||
}
|
||||
|
@ -54,8 +54,6 @@ namespace MWWorld
|
||||
|
||||
assert(it != invStore.end());
|
||||
|
||||
bool equipped = false;
|
||||
|
||||
// equip the item in the first free slot
|
||||
for (std::vector<int>::const_iterator slot=slots_.first.begin();
|
||||
slot!=slots_.first.end(); ++slot)
|
||||
@ -68,7 +66,6 @@ namespace MWWorld
|
||||
if (slot == --slots_.first.end())
|
||||
{
|
||||
invStore.equip(*slot, it, actor);
|
||||
equipped = true;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -76,15 +73,8 @@ namespace MWWorld
|
||||
{
|
||||
// slot is not occupied
|
||||
invStore.equip(*slot, it, actor);
|
||||
equipped = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::string script = MWWorld::Class::get(object).getScript(object);
|
||||
|
||||
/* Set OnPCEquip Variable on item's script, if the player is equipping it, and it has a script with that variable declared */
|
||||
if(equipped && actor == MWBase::Environment::get().getWorld()->getPlayerPtr() && script != "")
|
||||
object.getRefData().getLocals().setVarByInt(script, "onpcequip", 1);
|
||||
}
|
||||
}
|
||||
|
@ -11,11 +11,12 @@ MWWorld::Ptr::CellStore *MWWorld::Cells::getCellStore (const ESM::Cell *cell)
|
||||
{
|
||||
if (cell->mData.mFlags & ESM::Cell::Interior)
|
||||
{
|
||||
std::map<std::string, Ptr::CellStore>::iterator result = mInteriors.find (Misc::StringUtils::lowerCase(cell->mName));
|
||||
std::string lowerName(Misc::StringUtils::lowerCase(cell->mName));
|
||||
std::map<std::string, Ptr::CellStore>::iterator result = mInteriors.find (lowerName);
|
||||
|
||||
if (result==mInteriors.end())
|
||||
{
|
||||
result = mInteriors.insert (std::make_pair (Misc::StringUtils::lowerCase(cell->mName), Ptr::CellStore (cell))).first;
|
||||
result = mInteriors.insert (std::make_pair (lowerName, Ptr::CellStore (cell))).first;
|
||||
}
|
||||
|
||||
return &result->second;
|
||||
@ -271,3 +272,15 @@ void MWWorld::Cells::getExteriorPtrs(const std::string &name, std::vector<MWWorl
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void MWWorld::Cells::getInteriorPtrs(const std::string &name, std::vector<MWWorld::Ptr> &out)
|
||||
{
|
||||
for (std::map<std::string, Ptr::CellStore>::iterator iter = mInteriors.begin();
|
||||
iter!=mInteriors.end(); ++iter)
|
||||
{
|
||||
Ptr ptr = getPtrAndCache (name, iter->second);
|
||||
if (!ptr.isEmpty())
|
||||
out.push_back(ptr);
|
||||
}
|
||||
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user