mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-20 08:23:51 +00:00
Merge branch 'master' of https://github.com/zinnschlag/openmw.git into AIFix2
Conflicts: apps/openmw/mwmechanics/aifollow.cpp
This commit is contained in:
commit
707e579dfe
162 changed files with 3264 additions and 2119 deletions
|
@ -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
|
||||
|
@ -188,8 +186,6 @@ if (WIN32)
|
|||
add_definitions(-DSDL_MAIN_HANDLED)
|
||||
else (WIN32)
|
||||
set(PLATFORM_INCLUDE_DIR "")
|
||||
find_path (UUID_INCLUDE_DIR uuid/uuid.h)
|
||||
include_directories(${UUID_INCLUDE_DIR})
|
||||
endif (WIN32)
|
||||
if (MSVC10)
|
||||
set(PLATFORM_INCLUDE_DIR "")
|
||||
|
@ -241,7 +237,6 @@ include_directories("."
|
|||
${MYGUI_INCLUDE_DIRS}
|
||||
${MYGUI_PLATFORM_INCLUDE_DIRS}
|
||||
${OPENAL_INCLUDE_DIR}
|
||||
${UUID_INCLUDE_DIR}
|
||||
${LIBDIR}
|
||||
)
|
||||
|
||||
|
@ -411,46 +406,6 @@ IF(NOT WIN32 AND NOT APPLE)
|
|||
# Install resources
|
||||
INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION "${DATADIR}" FILE_PERMISSIONS OWNER_READ GROUP_READ WORLD_READ COMPONENT "Resources")
|
||||
INSTALL(DIRECTORY DESTINATION "${DATADIR}/data" COMPONENT "Resources")
|
||||
|
||||
IF (DPKG_PROGRAM)
|
||||
## Debian Specific
|
||||
IF(IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/.git")
|
||||
EXEC_PROGRAM("git" ${CMAKE_CURRENT_SOURCE_DIR} ARGS "describe" OUTPUT_VARIABLE GIT_VERSION )
|
||||
STRING(REGEX REPLACE "openmw-" "" VERSION_STRING "${GIT_VERSION}")
|
||||
EXEC_PROGRAM("git" ARGS "config --get user.name" OUTPUT_VARIABLE GIT_NAME )
|
||||
EXEC_PROGRAM("git" ARGS "config --get user.email" OUTPUT_VARIABLE GIT_EMAIL)
|
||||
SET(PACKAGE_MAINTAINER "${GIT_NAME} <${GIT_EMAIL}>")
|
||||
ELSE()
|
||||
SET(VERSION_STRING "${OPENMW_VERSION}")
|
||||
SET(PACKAGE_MAINTAINER "unknown")
|
||||
ENDIF()
|
||||
|
||||
SET(CPACK_GENERATOR "DEB")
|
||||
SET(CPACK_PACKAGE_NAME "openmw")
|
||||
SET(CPACK_DEBIAN_PACKAGE_HOMEPAGE "http://openmw.org")
|
||||
SET(CPACK_DEBIAN_PACKAGE_PRIORITY "optional")
|
||||
SET(CPACK_DEBIAN_PACKAGE_MAINTAINER "${PACKAGE_MAINTAINER}")
|
||||
SET(CPACK_DEBIAN_PACKAGE_DESCRIPTION "A reimplementation of The Elder Scrolls III: Morrowind
|
||||
OpenMW is a reimplementation of the Bethesda Game Studios game The Elder Scrolls III: Morrowind.
|
||||
Data files from the original game is required to run it.")
|
||||
SET(CPACK_DEBIAN_PACKAGE_NAME "openmw")
|
||||
SET(CPACK_DEBIAN_PACKAGE_VERSION "${VERSION_STRING}")
|
||||
SET(CPACK_PACKAGE_EXECUTABLES "openmw;OpenMW opencs;OpenCS bsatool;Bsatool esmtool;Esmtool omwlauncher;OMWLauncher mwiniimporter;MWiniImporter")
|
||||
SET(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.11.2), libfreetype6 (>= 2.2.1), libgcc1 (>= 1:4.1.1), libmpg123-0 (>= 1.12.1), libopenal1 (>= 1:1.12.854), libsndfile1 (>= 1.0.23), libstdc++6 (>= 4.4.5), libuuid1 (>= 2.17.2), libqtgui4 (>= 4.7.0)")
|
||||
|
||||
SET(CPACK_DEBIAN_PACKAGE_SECTION "Games")
|
||||
|
||||
STRING(TOLOWER "${CPACK_PACKAGE_NAME}" CPACK_PACKAGE_NAME_LOWERCASE)
|
||||
EXECUTE_PROCESS(
|
||||
COMMAND ${DPKG_PROGRAM} --print-architecture
|
||||
OUTPUT_VARIABLE CPACK_DEBIAN_PACKAGE_ARCHITECTURE
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
SET(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME_LOWERCASE}_${CPACK_DEBIAN_PACKAGE_VERSION}_${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}")
|
||||
|
||||
|
||||
INCLUDE(CPack)
|
||||
ENDIF(DPKG_PROGRAM)
|
||||
ENDIF(NOT WIN32 AND NOT APPLE)
|
||||
|
||||
if(WIN32)
|
||||
|
|
|
@ -680,7 +680,7 @@ std::string creatureFlags(int flags)
|
|||
if (flags & ESM::Creature::Walks) properties += "Walks ";
|
||||
if (flags & ESM::Creature::Swims) properties += "Swims ";
|
||||
if (flags & ESM::Creature::Flies) properties += "Flies ";
|
||||
if (flags & ESM::Creature::Biped) properties += "Biped ";
|
||||
if (flags & ESM::Creature::Bipedal) properties += "Bipedal ";
|
||||
if (flags & ESM::Creature::Respawn) properties += "Respawn ";
|
||||
if (flags & ESM::Creature::Weapon) properties += "Weapon ";
|
||||
if (flags & ESM::Creature::Skeleton) properties += "Skeleton ";
|
||||
|
@ -691,7 +691,7 @@ std::string creatureFlags(int flags)
|
|||
ESM::Creature::Walks|
|
||||
ESM::Creature::Swims|
|
||||
ESM::Creature::Flies|
|
||||
ESM::Creature::Biped|
|
||||
ESM::Creature::Bipedal|
|
||||
ESM::Creature::Respawn|
|
||||
ESM::Creature::Weapon|
|
||||
ESM::Creature::Skeleton|
|
||||
|
@ -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<>
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -623,6 +623,17 @@ MwIniImporter::MwIniImporter()
|
|||
"Moons:Masser Fade Out Finish",
|
||||
"Moons:Script Color",
|
||||
|
||||
// blood
|
||||
"Blood:Model 0",
|
||||
"Blood:Model 1",
|
||||
"Blood:Model 2",
|
||||
"Blood:Texture 0",
|
||||
"Blood:Texture 1",
|
||||
"Blood:Texture 2",
|
||||
"Blood:Texture Name 0",
|
||||
"Blood:Texture Name 1",
|
||||
"Blood:Texture Name 2",
|
||||
|
||||
0
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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;
|
||||
|
@ -139,3 +142,4 @@ 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,7 +177,7 @@ 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);
|
||||
|
|
|
@ -181,7 +181,7 @@ CSMWorld::RefIdCollection::RefIdCollection()
|
|||
unsigned int mFlag;
|
||||
} sCreatureFlagTable[] =
|
||||
{
|
||||
{ Columns::ColumnId_Biped, ESM::Creature::Biped },
|
||||
{ Columns::ColumnId_Biped, ESM::Creature::Bipedal },
|
||||
{ Columns::ColumnId_HasWeapon, ESM::Creature::Weapon },
|
||||
{ Columns::ColumnId_NoMovement, ESM::Creature::None },
|
||||
{ Columns::ColumnId_Swims, ESM::Creature::Swims },
|
||||
|
@ -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
|
||||
|
||||
|
|
|
@ -231,3 +231,103 @@ void CSMWorld::RefIdData::save (int index, ESM::ESMWriter& writer) const
|
|||
|
||||
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
|
||||
{
|
||||
|
|
|
@ -20,7 +20,7 @@ add_openmw_dir (mwrender
|
|||
renderingmanager debugging sky camera animation npcanimation creatureanimation activatoranimation
|
||||
actors objects renderinginterface localmap occlusionquery water shadows
|
||||
characterpreview globalmap videoplayer ripplesimulation refraction
|
||||
terrainstorage renderconst
|
||||
terrainstorage renderconst effectmanager
|
||||
)
|
||||
|
||||
add_openmw_dir (mwinput
|
||||
|
@ -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
|
||||
|
|
|
@ -77,8 +77,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.
|
||||
|
@ -113,6 +117,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,17 @@ 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;
|
||||
|
||||
/// Spawn a blood effect for \a ptr at \a worldPosition
|
||||
virtual void spawnBloodEffect (const MWWorld::Ptr& ptr, const Ogre::Vector3& worldPosition) = 0;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -61,6 +61,17 @@ 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");
|
||||
fKnockDownMult = gmst.find("fKnockDownMult");
|
||||
iKnockDownOddsMult = gmst.find("iKnockDownOddsMult");
|
||||
iKnockDownOddsBase = gmst.find("iKnockDownOddsBase");
|
||||
|
||||
inited = true;
|
||||
}
|
||||
|
@ -165,6 +176,62 @@ namespace MWClass
|
|||
|
||||
void Creature::hit(const MWWorld::Ptr& ptr, int type) const
|
||||
{
|
||||
MWWorld::LiveCellRef<ESM::Creature> *ref =
|
||||
ptr.get<ESM::Creature>();
|
||||
|
||||
// TODO: where is the distance defined?
|
||||
std::pair<MWWorld::Ptr, Ogre::Vector3> result = MWBase::Environment::get().getWorld()->getHitContact(ptr, 100);
|
||||
if (result.first.isEmpty())
|
||||
return; // Didn't hit anything
|
||||
|
||||
MWWorld::Ptr victim = result.first;
|
||||
|
||||
if (!victim.getClass().isActor())
|
||||
return; // Can't hit non-actors
|
||||
|
||||
Ogre::Vector3 hitPosition = result.second;
|
||||
|
||||
MWMechanics::CreatureStats &stats = getCreatureStats(ptr);
|
||||
MWMechanics::CreatureStats &otherstats = victim.getClass().getCreatureStats(victim);
|
||||
const MWMechanics::MagicEffects &mageffects = stats.getMagicEffects();
|
||||
float hitchance = ref->mBase->mData.mCombat +
|
||||
(stats.getAttribute(ESM::Attribute::Agility).getModified() / 5.0f) +
|
||||
(stats.getAttribute(ESM::Attribute::Luck).getModified() / 10.0f);
|
||||
hitchance *= stats.getFatigueTerm();
|
||||
hitchance += mageffects.get(ESM::MagicEffect::FortifyAttack).mMagnitude -
|
||||
mageffects.get(ESM::MagicEffect::Blind).mMagnitude;
|
||||
hitchance -= otherstats.getEvasion();
|
||||
|
||||
if((::rand()/(RAND_MAX+1.0)) > hitchance/100.0f)
|
||||
{
|
||||
victim.getClass().onHit(victim, 0.0f, false, MWWorld::Ptr(), ptr, false);
|
||||
return;
|
||||
}
|
||||
|
||||
int min,max;
|
||||
switch (type)
|
||||
{
|
||||
case 0:
|
||||
min = ref->mBase->mData.mAttack[0];
|
||||
max = ref->mBase->mData.mAttack[1];
|
||||
break;
|
||||
case 1:
|
||||
min = ref->mBase->mData.mAttack[2];
|
||||
max = ref->mBase->mData.mAttack[3];
|
||||
break;
|
||||
case 2:
|
||||
default:
|
||||
min = ref->mBase->mData.mAttack[4];
|
||||
max = ref->mBase->mData.mAttack[5];
|
||||
break;
|
||||
}
|
||||
|
||||
float damage = min + (max - min) * ::rand()/(RAND_MAX+1.0);
|
||||
|
||||
// TODO: do not do this if the attack is blocked
|
||||
MWBase::Environment::get().getWorld()->spawnBloodEffect(victim, hitPosition);
|
||||
|
||||
victim.getClass().onHit(victim, damage, true, MWWorld::Ptr(), ptr, true);
|
||||
}
|
||||
|
||||
void Creature::onHit(const MWWorld::Ptr &ptr, float damage, bool ishealth, const MWWorld::Ptr &object, const MWWorld::Ptr &attacker, bool successful) const
|
||||
|
@ -191,6 +258,19 @@ namespace MWClass
|
|||
ptr.getRefData().getLocals().setVarByInt(script, "onpchitme", 1);
|
||||
}
|
||||
|
||||
// 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();
|
||||
int 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(ishealth)
|
||||
{
|
||||
if(damage > 0.0f)
|
||||
|
@ -286,10 +366,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 = 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 +582,49 @@ 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");
|
||||
}
|
||||
}
|
||||
|
||||
int Creature::getBloodTexture(const MWWorld::Ptr &ptr) const
|
||||
{
|
||||
MWWorld::LiveCellRef<ESM::Creature> *ref = ptr.get<ESM::Creature>();
|
||||
|
||||
if (ref->mBase->mFlags & ESM::Creature::Skeleton)
|
||||
return 1;
|
||||
if (ref->mBase->mFlags & ESM::Creature::Metal)
|
||||
return 2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
const ESM::GameSetting *Creature::fKnockDownMult;
|
||||
const ESM::GameSetting *Creature::iKnockDownOddsMult;
|
||||
const ESM::GameSetting *Creature::iKnockDownOddsBase;
|
||||
|
||||
}
|
||||
|
|
|
@ -16,6 +16,18 @@ 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;
|
||||
static const ESM::GameSetting *fKnockDownMult;
|
||||
static const ESM::GameSetting *iKnockDownOddsMult;
|
||||
static const ESM::GameSetting *iKnockDownOddsBase;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
|
@ -101,6 +113,11 @@ namespace MWClass
|
|||
}
|
||||
|
||||
virtual bool isFlying (const MWWorld::Ptr &ptr) const;
|
||||
|
||||
virtual int getSkill(const MWWorld::Ptr &ptr, int skill) const;
|
||||
|
||||
/// Get a blood texture suitable for \a ptr (see Blood Texture 0-2 in Morrowind.ini)
|
||||
virtual int getBloodTexture (const MWWorld::Ptr& ptr) 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,11 +437,27 @@ 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());
|
||||
// TODO: Use second to work out the hit angle and where to spawn the blood effect
|
||||
MWWorld::Ptr victim = world->getHitContact(ptr, dist).first;
|
||||
// TODO: Use second to work out the hit angle
|
||||
std::pair<MWWorld::Ptr, Ogre::Vector3> result = world->getHitContact(ptr, dist);
|
||||
MWWorld::Ptr victim = result.first;
|
||||
Ogre::Vector3 hitPosition = result.second;
|
||||
if(victim.isEmpty()) // Didn't hit anything
|
||||
return;
|
||||
|
||||
|
@ -486,12 +514,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 +535,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 +561,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())
|
||||
|
@ -578,6 +604,10 @@ namespace MWClass
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: do not do this if the attack is blocked
|
||||
if (healthdmg)
|
||||
MWBase::Environment::get().getWorld()->spawnBloodEffect(victim, hitPosition);
|
||||
|
||||
othercls.onHit(victim, damage, healthdmg, weapon, ptr, true);
|
||||
}
|
||||
|
||||
|
@ -587,6 +617,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 +635,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 +649,27 @@ namespace MWClass
|
|||
// 'ptr' is losing health. Play a 'hit' voiced dialog entry if not already saying
|
||||
// something, alert the character controller, scripts, etc.
|
||||
|
||||
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);//used in CharacterController
|
||||
}
|
||||
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,10 +781,10 @@ 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))
|
||||
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}"));
|
||||
if(getCreatureStats(actor).getStance(MWMechanics::CreatureStats::Stance_Sneak))
|
||||
return boost::shared_ptr<MWWorld::Action>(new MWWorld::ActionOpen(ptr)); // stealing
|
||||
return boost::shared_ptr<MWWorld::Action>(new MWWorld::ActionTalk(ptr));
|
||||
}
|
||||
|
||||
|
@ -759,80 +812,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 +820,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 +851,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 +890,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 +1002,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 +1217,22 @@ 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();
|
||||
}
|
||||
|
||||
int Npc::getBloodTexture(const MWWorld::Ptr &ptr) const
|
||||
{
|
||||
MWWorld::LiveCellRef<ESM::NPC> *ref = ptr.get<ESM::NPC>();
|
||||
|
||||
if (ref->mBase->mFlags & ESM::NPC::Skeleton)
|
||||
return 1;
|
||||
if (ref->mBase->mFlags & ESM::NPC::Metal)
|
||||
return 2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
const ESM::GameSetting *Npc::fMinWalkSpeed;
|
||||
const ESM::GameSetting *Npc::fMaxWalkSpeed;
|
||||
const ESM::GameSetting *Npc::fEncumberedMoveEffect;
|
||||
|
@ -1250,4 +1249,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,11 @@ namespace MWClass
|
|||
|
||||
virtual std::string getModel(const MWWorld::Ptr &ptr) const;
|
||||
|
||||
virtual int getSkill(const MWWorld::Ptr& ptr, int skill) const;
|
||||
|
||||
/// Get a blood texture suitable for \a ptr (see Blood Texture 0-2 in Morrowind.ini)
|
||||
virtual int getBloodTexture (const MWWorld::Ptr& ptr) 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;
|
||||
}
|
||||
|
||||
|
|
|
@ -267,6 +267,7 @@ namespace MWGui
|
|||
else if ((mode == GM_Container) || (mode == GM_Inventory))
|
||||
{
|
||||
// pick up object
|
||||
if (!object.isEmpty())
|
||||
MWBase::Environment::get().getWindowManager()->getInventoryWindow()->pickUpObject(object);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -301,6 +301,12 @@ namespace MWGui
|
|||
if (type == Type_Magic)
|
||||
{
|
||||
std::string spellId = button->getChildAt(0)->getUserString("Spell");
|
||||
|
||||
// Make sure the player still has this spell
|
||||
MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player);
|
||||
MWMechanics::Spells& spells = stats.getSpells();
|
||||
if (!spells.hasSpell(spellId))
|
||||
return;
|
||||
store.setSelectedEnchantItem(store.end());
|
||||
MWBase::Environment::get().getWindowManager()->setSelectedSpell(spellId, int(MWMechanics::getSpellSuccessChance(spellId, player)));
|
||||
}
|
||||
|
@ -308,19 +314,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,6 +318,7 @@ namespace MWGui
|
|||
messageBox("#{sNotifyMessage9}");
|
||||
|
||||
int iBarterFailDisposition = gmst.find("iBarterFailDisposition")->getInt();
|
||||
if (mPtr.getClass().isNpc())
|
||||
MWBase::Environment::get().getDialogueManager()->applyDispositionChange(iBarterFailDisposition);
|
||||
return;
|
||||
}
|
||||
|
@ -327,6 +328,7 @@ namespace MWGui
|
|||
}
|
||||
|
||||
int iBarterSuccessDisposition = gmst.find("iBarterSuccessDisposition")->getInt();
|
||||
if (mPtr.getClass().isNpc())
|
||||
MWBase::Environment::get().getDialogueManager()->applyDispositionChange(iBarterSuccessDisposition);
|
||||
|
||||
// make the item transfer
|
||||
|
|
|
@ -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,9 +79,12 @@ 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.
|
||||
|
||||
|
|
|
@ -17,5 +17,5 @@ bool MWMechanics::AiActivate::execute (const MWWorld::Ptr& actor,float duration)
|
|||
|
||||
int MWMechanics::AiActivate::getTypeId() const
|
||||
{
|
||||
return 4;
|
||||
return TypeIdActivate;
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/mechanicsmanager.hpp"
|
||||
#include "../mwbase/dialoguemanager.hpp"
|
||||
|
||||
#include "creaturestats.hpp"
|
||||
#include "npcstats.hpp"
|
||||
|
@ -39,13 +40,13 @@ namespace MWMechanics
|
|||
|
||||
if(MWWorld::Class::get(actor).getCreatureStats(actor).getHealth().getCurrent() <= 0) return true;
|
||||
|
||||
actor.getClass().getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, true);
|
||||
|
||||
if(actor.getTypeName() == typeid(ESM::NPC).name())
|
||||
{
|
||||
MWWorld::Class::get(actor).
|
||||
MWWorld::Class::get(actor).setStance(actor, MWWorld::Class::Run,true);
|
||||
MWMechanics::DrawState_ state = MWWorld::Class::get(actor).getNpcStats(actor).getDrawState();
|
||||
MWMechanics::DrawState_ state = actor.getClass().getNpcStats(actor).getDrawState();
|
||||
if (state == MWMechanics::DrawState_Spell || state == MWMechanics::DrawState_Nothing)
|
||||
MWWorld::Class::get(actor).getNpcStats(actor).setDrawState(MWMechanics::DrawState_Weapon);
|
||||
actor.getClass().getNpcStats(actor).setDrawState(MWMechanics::DrawState_Weapon);
|
||||
//MWWorld::Class::get(actor).getCreatureStats(actor).setAttackingOrSpell(true);
|
||||
}
|
||||
ESM::Position pos = actor.getRefData().getPosition();
|
||||
|
@ -109,6 +110,17 @@ namespace MWMechanics
|
|||
}
|
||||
if( mTimer > 1)
|
||||
{
|
||||
if (actor.getClass().isNpc())
|
||||
{
|
||||
const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore();
|
||||
int chance = store.get<ESM::GameSetting>().find("iVoiceAttackOdds")->getInt();
|
||||
int roll = std::rand()/ (static_cast<double> (RAND_MAX) + 1) * 100; // [0, 99]
|
||||
if (roll < chance)
|
||||
{
|
||||
MWBase::Environment::get().getDialogueManager()->say(actor, "attack");
|
||||
}
|
||||
}
|
||||
|
||||
MWWorld::Class::get(actor).getCreatureStats(actor).setAttackingOrSpell(true);
|
||||
mTimer = 0;
|
||||
}
|
||||
|
@ -125,7 +137,7 @@ namespace MWMechanics
|
|||
|
||||
int AiCombat::getTypeId() const
|
||||
{
|
||||
return 5;
|
||||
return TypeIdCombat;
|
||||
}
|
||||
|
||||
unsigned int AiCombat::getPriority() const
|
||||
|
@ -133,6 +145,11 @@ namespace MWMechanics
|
|||
return 1;
|
||||
}
|
||||
|
||||
const std::string &AiCombat::getTargetId() const
|
||||
{
|
||||
return mTargetId;
|
||||
}
|
||||
|
||||
AiCombat *MWMechanics::AiCombat::clone() const
|
||||
{
|
||||
return new AiCombat(*this);
|
||||
|
|
|
@ -23,6 +23,8 @@ namespace MWMechanics
|
|||
|
||||
virtual unsigned int getPriority() const;
|
||||
|
||||
const std::string &getTargetId() const;
|
||||
|
||||
private:
|
||||
std::string mTargetId;
|
||||
|
||||
|
|
|
@ -169,7 +169,7 @@ namespace MWMechanics
|
|||
|
||||
int AiEscort::getTypeId() const
|
||||
{
|
||||
return 2;
|
||||
return TypeIdEscort;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,11 +16,6 @@ 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)
|
||||
{
|
||||
const MWWorld::Ptr target = MWBase::Environment::get().getWorld()->getPtr(mActorId, false);
|
||||
|
@ -118,3 +113,13 @@ std::string MWMechanics::AiFollow::getFollowedActor()
|
|||
{
|
||||
return mActorId;
|
||||
}
|
||||
|
||||
MWMechanics::AiFollow *MWMechanics::AiFollow::clone() const
|
||||
{
|
||||
return new AiFollow(*this);
|
||||
}
|
||||
|
||||
int MWMechanics::AiFollow::getTypeId() const
|
||||
{
|
||||
return TypeIdFollow;
|
||||
}
|
||||
|
|
|
@ -12,6 +12,15 @@ namespace MWMechanics
|
|||
class AiPackage
|
||||
{
|
||||
public:
|
||||
enum TypeId {
|
||||
TypeIdNone = -1,
|
||||
TypeIdWander = 0,
|
||||
TypeIdTravel = 1,
|
||||
TypeIdEscort = 2,
|
||||
TypeIdFollow = 3,
|
||||
TypeIdActivate = 4,
|
||||
TypeIdCombat = 5
|
||||
};
|
||||
|
||||
virtual ~AiPackage();
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -90,7 +109,10 @@ void MWMechanics::AiSequence::stack (const AiPackage& package)
|
|||
for(std::list<AiPackage *>::iterator it = mPackages.begin(); it != mPackages.end(); it++)
|
||||
{
|
||||
if(mPackages.front()->getPriority() <= package.getPriority())
|
||||
{
|
||||
mPackages.insert(it,package.clone());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(mPackages.empty())
|
||||
|
@ -121,7 +143,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?
|
||||
|
|
|
@ -104,7 +104,7 @@ namespace MWMechanics
|
|||
|
||||
int AiTravel::getTypeId() const
|
||||
{
|
||||
return 1;
|
||||
return TypeIdTravel;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/mechanicsmanager.hpp"
|
||||
#include "../mwbase/dialoguemanager.hpp"
|
||||
#include "../mwmechanics/npcstats.hpp"
|
||||
|
||||
#include <OgreVector3.h>
|
||||
|
||||
|
@ -64,6 +66,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)
|
||||
{
|
||||
|
@ -182,6 +186,14 @@ namespace MWMechanics
|
|||
playIdle(actor, mPlayedIdle);
|
||||
mChooseAction = false;
|
||||
mIdleNow = true;
|
||||
|
||||
// Play idle voiced dialogue entries randomly
|
||||
const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore();
|
||||
float chance = store.get<ESM::GameSetting>().find("fVoiceIdleOdds")->getFloat();
|
||||
int roll = std::rand()/ (static_cast<double> (RAND_MAX) + 1) * 100; // [0, 99]
|
||||
// TODO: do not show subtitle messagebox if player is too far away? or do not say at all?
|
||||
if (roll < chance)
|
||||
MWBase::Environment::get().getDialogueManager()->say(actor, "idle");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -253,7 +265,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;
|
||||
|
||||
|
|
|
@ -158,22 +158,19 @@ public:
|
|||
void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterState movement, bool force)
|
||||
{
|
||||
// hit recoils/knockdown animations handling
|
||||
if(MWWorld::Class::get(mPtr).isActor())
|
||||
if(mPtr.getClass().isActor())
|
||||
{
|
||||
if(MWWorld::Class::get(mPtr).getCreatureStats(mPtr).getAttacked())
|
||||
{
|
||||
MWWorld::Class::get(mPtr).getCreatureStats(mPtr).setAttacked(false);
|
||||
|
||||
bool recovery = mPtr.getClass().getCreatureStats(mPtr).getHitRecovery();
|
||||
bool knockdown = mPtr.getClass().getCreatureStats(mPtr).getKnockedDown();
|
||||
if(mHitState == CharState_None)
|
||||
{
|
||||
if(mJumpState != JumpState_None && !MWBase::Environment::get().getWorld()->isFlying(mPtr)
|
||||
&& !MWBase::Environment::get().getWorld()->isSwimming(mPtr) )
|
||||
if(knockdown)
|
||||
{
|
||||
mHitState = CharState_KnockDown;
|
||||
mCurrentHit = sHitList[sHitListSize-1];
|
||||
mAnimation->play(mCurrentHit, Priority_Knockdown, MWRender::Animation::Group_All, true, 1, "start", "stop", 0.0f, 0);
|
||||
}
|
||||
else
|
||||
else if (recovery)
|
||||
{
|
||||
mHitState = CharState_Hit;
|
||||
int iHit = rand() % (sHitListSize-1);
|
||||
|
@ -187,10 +184,13 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat
|
|||
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;
|
||||
}
|
||||
}
|
||||
|
@ -441,6 +441,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim
|
|||
{
|
||||
getWeaponGroup(mWeaponType, mCurrentWeapon);
|
||||
mUpperBodyState = UpperCharState_WeapEquiped;
|
||||
mAnimation->showWeapons(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -478,7 +479,45 @@ void CharacterController::updatePtr(const MWWorld::Ptr &ptr)
|
|||
mPtr = ptr;
|
||||
}
|
||||
|
||||
bool CharacterController::updateNpcState(bool onground, bool inwater, bool isrunning, bool sneak)
|
||||
bool CharacterController::updateCreatureState()
|
||||
{
|
||||
const MWWorld::Class &cls = mPtr.getClass();
|
||||
CreatureStats &stats = cls.getCreatureStats(mPtr);
|
||||
|
||||
if(stats.getAttackingOrSpell())
|
||||
{
|
||||
if(mUpperBodyState == UpperCharState_Nothing && mHitState == CharState_None)
|
||||
{
|
||||
MWBase::Environment::get().getWorld()->breakInvisibility(mPtr);
|
||||
|
||||
switch (stats.getAttackType())
|
||||
{
|
||||
case CreatureStats::AT_Chop:
|
||||
mCurrentWeapon = "attack1";
|
||||
break;
|
||||
case CreatureStats::AT_Slash:
|
||||
mCurrentWeapon = "attack2";
|
||||
break;
|
||||
case CreatureStats::AT_Thrust:
|
||||
mCurrentWeapon = "attack3";
|
||||
break;
|
||||
}
|
||||
|
||||
mAnimation->play(mCurrentWeapon, Priority_Weapon,
|
||||
MWRender::Animation::Group_UpperBody, true,
|
||||
1, "start", "stop",
|
||||
0.0f, 0);
|
||||
mUpperBodyState = UpperCharState_StartToMinAttack;
|
||||
}
|
||||
}
|
||||
|
||||
bool animPlaying = mAnimation->getInfo(mCurrentWeapon);
|
||||
if (!animPlaying)
|
||||
mUpperBodyState = UpperCharState_Nothing;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CharacterController::updateNpcState(bool inwater, bool isrunning)
|
||||
{
|
||||
const MWWorld::Class &cls = MWWorld::Class::get(mPtr);
|
||||
NpcStats &stats = cls.getNpcStats(mPtr);
|
||||
|
@ -582,8 +621,10 @@ bool CharacterController::updateNpcState(bool onground, bool inwater, bool isrun
|
|||
// This has to be done at the start of the casting animation,
|
||||
// *not* when selecting a spell in the GUI (otherwise you could change the spell mid-animation)
|
||||
if (mPtr.getRefData().getHandle() == "player")
|
||||
stats.getSpells().setSelectedSpell(MWBase::Environment::get().getWindowManager()->getSelectedSpell());
|
||||
|
||||
{
|
||||
std::string selectedSpell = MWBase::Environment::get().getWindowManager()->getSelectedSpell();
|
||||
stats.getSpells().setSelectedSpell(selectedSpell);
|
||||
}
|
||||
std::string spellid = stats.getSpells().getSelectedSpell();
|
||||
|
||||
if(!spellid.empty() && MWBase::Environment::get().getWorld()->startSpellCast(mPtr))
|
||||
|
@ -598,7 +639,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");
|
||||
|
@ -853,10 +899,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);
|
||||
|
@ -895,6 +942,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;
|
||||
|
||||
|
@ -911,8 +993,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;
|
||||
|
||||
|
@ -977,14 +1057,16 @@ void CharacterController::update(float duration)
|
|||
cls.getCreatureStats(mPtr).setHealth(health);
|
||||
cls.onHit(mPtr, realHealthLost, true, MWWorld::Ptr(), MWWorld::Ptr(), true);
|
||||
|
||||
const float acrobaticsSkill = cls.getSkill(mPtr, ESM::Skill::Acrobatics);
|
||||
if (healthLost > (acrobaticsSkill * fatigueTerm))
|
||||
{
|
||||
cls.getCreatureStats(mPtr).setKnockedDown(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 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();
|
||||
if (healthLost > (acrobaticsSkill * fatigueTerm))
|
||||
{
|
||||
//TODO: actor falls over
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1047,7 +1129,9 @@ void CharacterController::update(float duration)
|
|||
}
|
||||
|
||||
if(cls.isNpc())
|
||||
forcestateupdate = updateNpcState(onground, inwater, isrunning, sneak) || forcestateupdate;
|
||||
forcestateupdate = updateNpcState(inwater, isrunning) || forcestateupdate;
|
||||
else
|
||||
forcestateupdate = updateCreatureState() || forcestateupdate;
|
||||
|
||||
refreshCurrentAnims(idlestate, movestate, forcestateupdate);
|
||||
|
||||
|
@ -1080,9 +1164,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;
|
||||
|
@ -1092,7 +1178,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);
|
||||
|
|
|
@ -176,7 +176,8 @@ class CharacterController
|
|||
|
||||
void clearAnimQueue();
|
||||
|
||||
bool updateNpcState(bool onground, bool inwater, bool isrunning, bool sneak);
|
||||
bool updateNpcState(bool inwater, bool isrunning);
|
||||
bool updateCreatureState();
|
||||
|
||||
void updateVisibility();
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
@ -112,9 +116,9 @@ namespace MWMechanics
|
|||
|
||||
enum AttackType
|
||||
{
|
||||
AT_Chop,
|
||||
AT_Slash,
|
||||
AT_Thrust,
|
||||
AT_Chop
|
||||
AT_Thrust
|
||||
};
|
||||
void setAttackType(int attackType) { mAttackType = attackType; }
|
||||
int getAttackType() { return mAttackType; }
|
||||
|
@ -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);
|
||||
|
||||
|
|
|
@ -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,16 +201,18 @@ 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);
|
||||
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);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -44,6 +44,8 @@ namespace MWMechanics
|
|||
|
||||
TIterator end() const;
|
||||
|
||||
bool hasSpell(const std::string& spell) { return mSpells.find(Misc::StringUtils::lowerCase(spell)) != mSpells.end(); }
|
||||
|
||||
void add (const std::string& spell);
|
||||
///< Adding a spell that is already listed in *this is a no-op.
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
namespace MWRender
|
||||
{
|
||||
|
||||
Ogre::Real Animation::AnimationValue::getValue() const
|
||||
Ogre::Real Animation::AnimationTime::getValue() const
|
||||
{
|
||||
AnimStateMap::const_iterator iter = mAnimation->mStates.find(mAnimationName);
|
||||
if(iter != mAnimation->mStates.end())
|
||||
|
@ -38,16 +38,16 @@ Ogre::Real Animation::AnimationValue::getValue() const
|
|||
return 0.0f;
|
||||
}
|
||||
|
||||
void Animation::AnimationValue::setValue(Ogre::Real)
|
||||
void Animation::AnimationTime::setValue(Ogre::Real)
|
||||
{
|
||||
}
|
||||
|
||||
Ogre::Real Animation::EffectAnimationValue::getValue() const
|
||||
Ogre::Real Animation::EffectAnimationTime::getValue() const
|
||||
{
|
||||
return mTime;
|
||||
}
|
||||
|
||||
void Animation::EffectAnimationValue::setValue(Ogre::Real)
|
||||
void Animation::EffectAnimationTime::setValue(Ogre::Real)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -60,10 +60,10 @@ Animation::Animation(const MWWorld::Ptr &ptr, Ogre::SceneNode *node)
|
|||
, mNonAccumRoot(NULL)
|
||||
, mNonAccumCtrl(NULL)
|
||||
, mAccumulate(0.0f)
|
||||
, mNullAnimationValuePtr(OGRE_NEW NullAnimationValue)
|
||||
, mNullAnimationTimePtr(OGRE_NEW NullAnimationTime)
|
||||
{
|
||||
for(size_t i = 0;i < sNumGroups;i++)
|
||||
mAnimationValuePtr[i].bind(OGRE_NEW AnimationValue(this));
|
||||
mAnimationTimePtr[i].bind(OGRE_NEW AnimationTime(this));
|
||||
}
|
||||
|
||||
Animation::~Animation()
|
||||
|
@ -139,7 +139,7 @@ void Animation::setObjectRoot(const std::string &model, bool baseonly)
|
|||
for(size_t i = 0;i < mObjectRoot->mControllers.size();i++)
|
||||
{
|
||||
if(mObjectRoot->mControllers[i].getSource().isNull())
|
||||
mObjectRoot->mControllers[i].setSource(mAnimationValuePtr[0]);
|
||||
mObjectRoot->mControllers[i].setSource(mAnimationTimePtr[0]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -286,7 +286,7 @@ void Animation::addAnimSource(const std::string &model)
|
|||
}
|
||||
}
|
||||
|
||||
ctrls[i].setSource(mAnimationValuePtr[grp]);
|
||||
ctrls[i].setSource(mAnimationTimePtr[grp]);
|
||||
grpctrls[grp].push_back(ctrls[i]);
|
||||
}
|
||||
}
|
||||
|
@ -296,7 +296,7 @@ void Animation::clearAnimSources()
|
|||
mStates.clear();
|
||||
|
||||
for(size_t i = 0;i < sNumGroups;i++)
|
||||
mAnimationValuePtr[i]->setAnimName(std::string());
|
||||
mAnimationTimePtr[i]->setAnimName(std::string());
|
||||
|
||||
mNonAccumCtrl = NULL;
|
||||
|
||||
|
@ -660,13 +660,22 @@ void Animation::handleTextKey(AnimState &state, const std::string &groupname, co
|
|||
else if(evt.compare(off, len, "unequip detach") == 0)
|
||||
showWeapons(false);
|
||||
else if(evt.compare(off, len, "chop hit") == 0)
|
||||
MWWorld::Class::get(mPtr).hit(mPtr, MWMechanics::CreatureStats::AT_Chop);
|
||||
mPtr.getClass().hit(mPtr, MWMechanics::CreatureStats::AT_Chop);
|
||||
else if(evt.compare(off, len, "slash hit") == 0)
|
||||
MWWorld::Class::get(mPtr).hit(mPtr, MWMechanics::CreatureStats::AT_Slash);
|
||||
mPtr.getClass().hit(mPtr, MWMechanics::CreatureStats::AT_Slash);
|
||||
else if(evt.compare(off, len, "thrust hit") == 0)
|
||||
MWWorld::Class::get(mPtr).hit(mPtr, MWMechanics::CreatureStats::AT_Thrust);
|
||||
mPtr.getClass().hit(mPtr, MWMechanics::CreatureStats::AT_Thrust);
|
||||
else if(evt.compare(off, len, "hit") == 0)
|
||||
MWWorld::Class::get(mPtr).hit(mPtr);
|
||||
{
|
||||
if (groupname == "attack1")
|
||||
mPtr.getClass().hit(mPtr, MWMechanics::CreatureStats::AT_Chop);
|
||||
else if (groupname == "attack2")
|
||||
mPtr.getClass().hit(mPtr, MWMechanics::CreatureStats::AT_Slash);
|
||||
else if (groupname == "attack3")
|
||||
mPtr.getClass().hit(mPtr, MWMechanics::CreatureStats::AT_Thrust);
|
||||
else
|
||||
mPtr.getClass().hit(mPtr);
|
||||
}
|
||||
|
||||
else if (groupname == "spellcast" && evt.substr(evt.size()-7, 7) == "release")
|
||||
MWBase::Environment::get().getWorld()->castSpell(mPtr);
|
||||
|
@ -789,7 +798,7 @@ void Animation::resetActiveGroups()
|
|||
active = state;
|
||||
}
|
||||
|
||||
mAnimationValuePtr[grp]->setAnimName((active == mStates.end()) ?
|
||||
mAnimationTimePtr[grp]->setAnimName((active == mStates.end()) ?
|
||||
std::string() : active->first);
|
||||
}
|
||||
mNonAccumCtrl = NULL;
|
||||
|
@ -797,7 +806,7 @@ void Animation::resetActiveGroups()
|
|||
if(!mNonAccumRoot || mAccumulate == Ogre::Vector3(0.0f))
|
||||
return;
|
||||
|
||||
AnimStateMap::const_iterator state = mStates.find(mAnimationValuePtr[0]->getAnimName());
|
||||
AnimStateMap::const_iterator state = mStates.find(mAnimationTimePtr[0]->getAnimName());
|
||||
if(state == mStates.end())
|
||||
return;
|
||||
|
||||
|
@ -869,13 +878,13 @@ Ogre::Vector3 Animation::runAnimation(float duration)
|
|||
targetTime = state.mTime + timepassed;
|
||||
if(textkey == textkeys.end() || textkey->first > targetTime)
|
||||
{
|
||||
if(mNonAccumCtrl && stateiter->first == mAnimationValuePtr[0]->getAnimName())
|
||||
if(mNonAccumCtrl && stateiter->first == mAnimationTimePtr[0]->getAnimName())
|
||||
updatePosition(state.mTime, targetTime, movement);
|
||||
state.mTime = std::min(targetTime, state.mStopTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(mNonAccumCtrl && stateiter->first == mAnimationValuePtr[0]->getAnimName())
|
||||
if(mNonAccumCtrl && stateiter->first == mAnimationTimePtr[0]->getAnimName())
|
||||
updatePosition(state.mTime, textkey->first, movement);
|
||||
state.mTime = textkey->first;
|
||||
}
|
||||
|
@ -926,7 +935,7 @@ Ogre::Vector3 Animation::runAnimation(float duration)
|
|||
// Apply group controllers
|
||||
for(size_t grp = 0;grp < sNumGroups;grp++)
|
||||
{
|
||||
const std::string &name = mAnimationValuePtr[grp]->getAnimName();
|
||||
const std::string &name = mAnimationTimePtr[grp]->getAnimName();
|
||||
if(!name.empty() && (stateiter=mStates.find(name)) != mStates.end())
|
||||
{
|
||||
const Ogre::SharedPtr<AnimSource> &src = stateiter->second.mSource;
|
||||
|
@ -1042,6 +1051,7 @@ void Animation::addEffect(const std::string &model, int effectId, bool loop, con
|
|||
else
|
||||
params.mObjects = NifOgre::Loader::createObjects(mSkelBase, bonename, mInsert, model);
|
||||
|
||||
// TODO: turn off shadow casting
|
||||
setRenderProperties(params.mObjects, RV_Misc,
|
||||
RQG_Main, RQG_Alpha, 0.f, false, NULL);
|
||||
|
||||
|
@ -1052,7 +1062,7 @@ void Animation::addEffect(const std::string &model, int effectId, bool loop, con
|
|||
for(size_t i = 0;i < params.mObjects->mControllers.size();i++)
|
||||
{
|
||||
if(params.mObjects->mControllers[i].getSource().isNull())
|
||||
params.mObjects->mControllers[i].setSource(Ogre::SharedPtr<EffectAnimationValue> (new EffectAnimationValue()));
|
||||
params.mObjects->mControllers[i].setSource(Ogre::SharedPtr<EffectAnimationTime> (new EffectAnimationTime()));
|
||||
}
|
||||
|
||||
if (!texture.empty())
|
||||
|
@ -1110,7 +1120,7 @@ void Animation::updateEffects(float duration)
|
|||
NifOgre::ObjectScenePtr objects = it->mObjects;
|
||||
for(size_t i = 0; i < objects->mControllers.size() ;i++)
|
||||
{
|
||||
EffectAnimationValue* value = dynamic_cast<EffectAnimationValue*>(objects->mControllers[i].getSource().get());
|
||||
EffectAnimationTime* value = dynamic_cast<EffectAnimationTime*>(objects->mControllers[i].getSource().get());
|
||||
if (value)
|
||||
value->addTime(duration);
|
||||
|
||||
|
@ -1125,7 +1135,7 @@ void Animation::updateEffects(float duration)
|
|||
float remainder = objects->mControllers[0].getSource()->getValue() - objects->mMaxControllerLength;
|
||||
for(size_t i = 0; i < objects->mControllers.size() ;i++)
|
||||
{
|
||||
EffectAnimationValue* value = dynamic_cast<EffectAnimationValue*>(objects->mControllers[i].getSource().get());
|
||||
EffectAnimationTime* value = dynamic_cast<EffectAnimationTime*>(objects->mControllers[i].getSource().get());
|
||||
if (value)
|
||||
value->resetTime(remainder);
|
||||
}
|
||||
|
|
|
@ -32,14 +32,14 @@ protected:
|
|||
/* This is the number of *discrete* groups. */
|
||||
static const size_t sNumGroups = 4;
|
||||
|
||||
class AnimationValue : public Ogre::ControllerValue<Ogre::Real>
|
||||
class AnimationTime : public Ogre::ControllerValue<Ogre::Real>
|
||||
{
|
||||
private:
|
||||
Animation *mAnimation;
|
||||
std::string mAnimationName;
|
||||
|
||||
public:
|
||||
AnimationValue(Animation *anim)
|
||||
AnimationTime(Animation *anim)
|
||||
: mAnimation(anim)
|
||||
{ }
|
||||
|
||||
|
@ -52,12 +52,12 @@ protected:
|
|||
virtual void setValue(Ogre::Real value);
|
||||
};
|
||||
|
||||
class EffectAnimationValue : public Ogre::ControllerValue<Ogre::Real>
|
||||
class EffectAnimationTime : public Ogre::ControllerValue<Ogre::Real>
|
||||
{
|
||||
private:
|
||||
float mTime;
|
||||
public:
|
||||
EffectAnimationValue() : mTime(0) { }
|
||||
EffectAnimationTime() : mTime(0) { }
|
||||
void addTime(float time) { mTime += time; }
|
||||
void resetTime(float value) { mTime = value; }
|
||||
|
||||
|
@ -67,7 +67,7 @@ protected:
|
|||
|
||||
|
||||
|
||||
class NullAnimationValue : public Ogre::ControllerValue<Ogre::Real>
|
||||
class NullAnimationTime : public Ogre::ControllerValue<Ogre::Real>
|
||||
{
|
||||
public:
|
||||
virtual Ogre::Real getValue() const
|
||||
|
@ -134,8 +134,8 @@ protected:
|
|||
|
||||
AnimStateMap mStates;
|
||||
|
||||
Ogre::SharedPtr<AnimationValue> mAnimationValuePtr[sNumGroups];
|
||||
Ogre::SharedPtr<NullAnimationValue> mNullAnimationValuePtr;
|
||||
Ogre::SharedPtr<AnimationTime> mAnimationTimePtr[sNumGroups];
|
||||
Ogre::SharedPtr<NullAnimationTime> mNullAnimationTimePtr;
|
||||
|
||||
ObjectAttachMap mAttachedObjects;
|
||||
|
||||
|
@ -189,16 +189,18 @@ protected:
|
|||
/** Adds an additional light to the given object list using the specified ESM record. */
|
||||
void addExtraLight(Ogre::SceneManager *sceneMgr, NifOgre::ObjectScenePtr objlist, const ESM::Light *light);
|
||||
|
||||
static void setRenderProperties(NifOgre::ObjectScenePtr objlist, Ogre::uint32 visflags, Ogre::uint8 solidqueue,
|
||||
Ogre::uint8 transqueue, Ogre::Real dist=0.0f,
|
||||
bool enchantedGlow=false, Ogre::Vector3* glowColor=NULL);
|
||||
|
||||
void clearAnimSources();
|
||||
|
||||
// TODO: Should not be here
|
||||
Ogre::Vector3 getEnchantmentColor(MWWorld::Ptr item);
|
||||
|
||||
public:
|
||||
// FIXME: Move outside of this class
|
||||
static void setRenderProperties(NifOgre::ObjectScenePtr objlist, Ogre::uint32 visflags, Ogre::uint8 solidqueue,
|
||||
Ogre::uint8 transqueue, Ogre::Real dist=0.0f,
|
||||
bool enchantedGlow=false, Ogre::Vector3* glowColor=NULL);
|
||||
|
||||
|
||||
Animation(const MWWorld::Ptr &ptr, Ogre::SceneNode *node);
|
||||
virtual ~Animation();
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr)
|
|||
setObjectRoot(model, false);
|
||||
setRenderProperties(mObjectRoot, RV_Actors, RQG_Main, RQG_Alpha);
|
||||
|
||||
if((ref->mBase->mFlags&ESM::Creature::Biped))
|
||||
if((ref->mBase->mFlags&ESM::Creature::Bipedal))
|
||||
addAnimSource("meshes\\base_anim.nif");
|
||||
addAnimSource(model);
|
||||
}
|
||||
|
|
117
apps/openmw/mwrender/effectmanager.cpp
Normal file
117
apps/openmw/mwrender/effectmanager.cpp
Normal file
|
@ -0,0 +1,117 @@
|
|||
#include "effectmanager.hpp"
|
||||
|
||||
#include <OgreSceneManager.h>
|
||||
#include <OgreParticleSystem.h>
|
||||
|
||||
#include "animation.hpp"
|
||||
#include "renderconst.hpp"
|
||||
|
||||
namespace MWRender
|
||||
{
|
||||
|
||||
class EffectAnimationTime : public Ogre::ControllerValue<Ogre::Real>
|
||||
{
|
||||
private:
|
||||
float mTime;
|
||||
public:
|
||||
EffectAnimationTime() : mTime(0) { }
|
||||
void addTime(float time) { mTime += time; }
|
||||
|
||||
virtual Ogre::Real getValue() const { return mTime; }
|
||||
virtual void setValue(Ogre::Real value) {}
|
||||
};
|
||||
|
||||
EffectManager::EffectManager(Ogre::SceneManager *sceneMgr)
|
||||
: mSceneMgr(sceneMgr)
|
||||
{
|
||||
}
|
||||
|
||||
void EffectManager::addEffect(const std::string &model, std::string textureOverride, const Ogre::Vector3 &worldPosition)
|
||||
{
|
||||
Ogre::SceneNode* sceneNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(worldPosition);
|
||||
|
||||
// fix texture extension to .dds
|
||||
if (textureOverride.size() > 4)
|
||||
{
|
||||
textureOverride[textureOverride.size()-3] = 'd';
|
||||
textureOverride[textureOverride.size()-2] = 'd';
|
||||
textureOverride[textureOverride.size()-1] = 's';
|
||||
}
|
||||
|
||||
|
||||
NifOgre::ObjectScenePtr scene = NifOgre::Loader::createObjects(sceneNode, model);
|
||||
|
||||
// TODO: turn off shadow casting
|
||||
MWRender::Animation::setRenderProperties(scene, RV_Misc,
|
||||
RQG_Main, RQG_Alpha, 0.f, false, NULL);
|
||||
|
||||
for(size_t i = 0;i < scene->mControllers.size();i++)
|
||||
{
|
||||
if(scene->mControllers[i].getSource().isNull())
|
||||
scene->mControllers[i].setSource(Ogre::SharedPtr<EffectAnimationTime> (new EffectAnimationTime()));
|
||||
}
|
||||
|
||||
if (!textureOverride.empty())
|
||||
{
|
||||
for(size_t i = 0;i < scene->mParticles.size(); ++i)
|
||||
{
|
||||
Ogre::ParticleSystem* partSys = scene->mParticles[i];
|
||||
|
||||
Ogre::MaterialPtr mat = scene->mMaterialControllerMgr.getWritableMaterial(partSys);
|
||||
|
||||
for (int t=0; t<mat->getNumTechniques(); ++t)
|
||||
{
|
||||
Ogre::Technique* tech = mat->getTechnique(t);
|
||||
for (int p=0; p<tech->getNumPasses(); ++p)
|
||||
{
|
||||
Ogre::Pass* pass = tech->getPass(p);
|
||||
for (int tex=0; tex<pass->getNumTextureUnitStates(); ++tex)
|
||||
{
|
||||
Ogre::TextureUnitState* tus = pass->getTextureUnitState(tex);
|
||||
tus->setTextureName("textures\\" + textureOverride);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mEffects.push_back(std::make_pair(sceneNode, scene));
|
||||
}
|
||||
|
||||
void EffectManager::update(float dt)
|
||||
{
|
||||
for (std::vector<std::pair<Ogre::SceneNode*, NifOgre::ObjectScenePtr> >::iterator it = mEffects.begin(); it != mEffects.end(); )
|
||||
{
|
||||
NifOgre::ObjectScenePtr objects = it->second;
|
||||
for(size_t i = 0; i < objects->mControllers.size() ;i++)
|
||||
{
|
||||
EffectAnimationTime* value = dynamic_cast<EffectAnimationTime*>(objects->mControllers[i].getSource().get());
|
||||
if (value)
|
||||
value->addTime(dt);
|
||||
|
||||
objects->mControllers[i].update();
|
||||
}
|
||||
|
||||
// Finished playing?
|
||||
if (objects->mControllers[0].getSource()->getValue() >= objects->mMaxControllerLength)
|
||||
{
|
||||
Ogre::SceneNode* node = it->first;
|
||||
it = mEffects.erase(it);
|
||||
mSceneMgr->destroySceneNode(node);
|
||||
continue;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
void EffectManager::clear()
|
||||
{
|
||||
for (std::vector<std::pair<Ogre::SceneNode*, NifOgre::ObjectScenePtr> >::iterator it = mEffects.begin(); it != mEffects.end(); )
|
||||
{
|
||||
Ogre::SceneNode* node = it->first;
|
||||
it = mEffects.erase(it);
|
||||
mSceneMgr->destroySceneNode(node);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
31
apps/openmw/mwrender/effectmanager.hpp
Normal file
31
apps/openmw/mwrender/effectmanager.hpp
Normal file
|
@ -0,0 +1,31 @@
|
|||
#ifndef OPENMW_MWRENDER_EFFECTMANAGER_H
|
||||
#define OPENMW_MWRENDER_EFFECTMANAGER_H
|
||||
|
||||
#include <components/nifogre/ogrenifloader.hpp>
|
||||
|
||||
namespace MWRender
|
||||
{
|
||||
// Note: effects attached to another object should be managed by MWRender::Animation::addEffect.
|
||||
// This class manages "free" effects, i.e. attached to a dedicated scene node in the world.
|
||||
class EffectManager
|
||||
{
|
||||
public:
|
||||
EffectManager(Ogre::SceneManager* sceneMgr);
|
||||
~EffectManager() { clear(); }
|
||||
|
||||
/// Add an effect. When it's finished playing, it will be removed automatically.
|
||||
void addEffect (const std::string& model, std::string textureOverride, const Ogre::Vector3& worldPosition);
|
||||
|
||||
void update(float dt);
|
||||
|
||||
/// Remove all effects
|
||||
void clear();
|
||||
|
||||
private:
|
||||
std::vector<std::pair<Ogre::SceneNode*, NifOgre::ObjectScenePtr> > mEffects;
|
||||
Ogre::SceneManager* mSceneMgr;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -61,8 +61,9 @@ std::string getVampireHead(const std::string& race, bool female)
|
|||
namespace MWRender
|
||||
{
|
||||
|
||||
float SayAnimationValue::getValue() const
|
||||
float HeadAnimationTime::getValue() const
|
||||
{
|
||||
// TODO: Handle eye blinking (time is in the text keys)
|
||||
if (MWBase::Environment::get().getSoundManager()->sayDone(mReference))
|
||||
return 0;
|
||||
else
|
||||
|
@ -124,7 +125,7 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, int v
|
|||
{
|
||||
mNpc = mPtr.get<ESM::NPC>()->mBase;
|
||||
|
||||
mSayAnimationValue = Ogre::SharedPtr<SayAnimationValue>(new SayAnimationValue(mPtr));
|
||||
mHeadAnimationTime = Ogre::SharedPtr<HeadAnimationTime>(new HeadAnimationTime(mPtr));
|
||||
|
||||
for(size_t i = 0;i < ESM::PRT_Count;i++)
|
||||
{
|
||||
|
@ -595,10 +596,10 @@ bool NpcAnimation::addOrReplaceIndividualPart(ESM::PartReferenceType type, int g
|
|||
{
|
||||
if(ctrl->getSource().isNull())
|
||||
{
|
||||
ctrl->setSource(mNullAnimationValuePtr);
|
||||
ctrl->setSource(mNullAnimationTimePtr);
|
||||
|
||||
if (type == ESM::PRT_Head)
|
||||
ctrl->setSource(mSayAnimationValue);
|
||||
ctrl->setSource(mHeadAnimationTime);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,12 +13,12 @@ namespace ESM
|
|||
namespace MWRender
|
||||
{
|
||||
|
||||
class SayAnimationValue : public Ogre::ControllerValue<Ogre::Real>
|
||||
class HeadAnimationTime : public Ogre::ControllerValue<Ogre::Real>
|
||||
{
|
||||
private:
|
||||
MWWorld::Ptr mReference;
|
||||
public:
|
||||
SayAnimationValue(MWWorld::Ptr reference) : mReference(reference) {}
|
||||
HeadAnimationTime(MWWorld::Ptr reference) : mReference(reference) {}
|
||||
|
||||
virtual Ogre::Real getValue() const;
|
||||
virtual void setValue(Ogre::Real value)
|
||||
|
@ -70,7 +70,7 @@ private:
|
|||
|
||||
Ogre::Vector3 mFirstPersonOffset;
|
||||
|
||||
Ogre::SharedPtr<SayAnimationValue> mSayAnimationValue;
|
||||
Ogre::SharedPtr<HeadAnimationTime> mHeadAnimationTime;
|
||||
|
||||
float mAlpha;
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include <OgreSubEntity.h>
|
||||
#include <OgreMeshManager.h>
|
||||
#include <OgreMaterialManager.h>
|
||||
#include <OgreCamera.h>
|
||||
|
||||
#include "renderconst.hpp"
|
||||
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#include "globalmap.hpp"
|
||||
#include "videoplayer.hpp"
|
||||
#include "terrainstorage.hpp"
|
||||
#include "effectmanager.hpp"
|
||||
|
||||
using namespace MWRender;
|
||||
using namespace Ogre;
|
||||
|
@ -57,9 +58,11 @@ RenderingManager::RenderingManager(OEngine::Render::OgreRenderer& _rend, const b
|
|||
, mSunEnabled(0)
|
||||
, mPhysicsEngine(engine)
|
||||
, mTerrain(NULL)
|
||||
, mEffectManager(NULL)
|
||||
{
|
||||
mActors = new MWRender::Actors(mRendering, this);
|
||||
mObjects = new MWRender::Objects(mRendering);
|
||||
mEffectManager = new EffectManager(mRendering.getScene());
|
||||
// select best shader mode
|
||||
bool openGL = (Ogre::Root::getSingleton ().getRenderSystem ()->getName().find("OpenGL") != std::string::npos);
|
||||
bool glES = (Ogre::Root::getSingleton ().getRenderSystem ()->getName().find("OpenGL ES") != std::string::npos);
|
||||
|
@ -193,6 +196,7 @@ RenderingManager::~RenderingManager ()
|
|||
delete mVideoPlayer;
|
||||
delete mActors;
|
||||
delete mObjects;
|
||||
delete mEffectManager;
|
||||
delete mFactory;
|
||||
}
|
||||
|
||||
|
@ -347,12 +351,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);
|
||||
|
@ -372,6 +378,8 @@ void RenderingManager::update (float duration, bool paused)
|
|||
if(paused)
|
||||
return;
|
||||
|
||||
mEffectManager->update(duration);
|
||||
|
||||
mActors->update (mRendering.getCamera());
|
||||
mPlayerAnimation->preRender(mRendering.getCamera());
|
||||
mObjects->update (duration, mRendering.getCamera());
|
||||
|
@ -673,14 +681,14 @@ Shadows* RenderingManager::getShadows()
|
|||
|
||||
void RenderingManager::switchToInterior()
|
||||
{
|
||||
// causes light flicker in opengl when moving..
|
||||
//mRendering.getScene()->setCameraRelativeRendering(false);
|
||||
// TODO: also do this when switching worldspace
|
||||
mEffectManager->clear();
|
||||
}
|
||||
|
||||
void RenderingManager::switchToExterior()
|
||||
{
|
||||
// causes light flicker in opengl when moving..
|
||||
//mRendering.getScene()->setCameraRelativeRendering(true);
|
||||
// TODO: also do this when switching worldspace
|
||||
mEffectManager->clear();
|
||||
}
|
||||
|
||||
Ogre::Vector4 RenderingManager::boundingBoxToScreen(Ogre::AxisAlignedBox bounds)
|
||||
|
@ -1018,4 +1026,9 @@ float RenderingManager::getCameraDistance() const
|
|||
return mCamera->getCameraDistance();
|
||||
}
|
||||
|
||||
void RenderingManager::spawnEffect(const std::string &model, const std::string &texture, const Vector3 &worldPosition)
|
||||
{
|
||||
mEffectManager->addEffect(model, texture, worldPosition);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -21,10 +21,7 @@
|
|||
|
||||
namespace Ogre
|
||||
{
|
||||
class SceneManager;
|
||||
class SceneNode;
|
||||
class Quaternion;
|
||||
class Vector3;
|
||||
}
|
||||
|
||||
namespace MWWorld
|
||||
|
@ -51,6 +48,7 @@ namespace MWRender
|
|||
class GlobalMap;
|
||||
class VideoPlayer;
|
||||
class Animation;
|
||||
class EffectManager;
|
||||
|
||||
class RenderingManager: private RenderingInterface, public Ogre::RenderTargetListener, public OEngine::Render::WindowSizeListener
|
||||
{
|
||||
|
@ -209,6 +207,8 @@ public:
|
|||
void stopVideo();
|
||||
void frameStarted(float dt, bool paused);
|
||||
|
||||
void spawnEffect (const std::string& model, const std::string& texture, const Ogre::Vector3& worldPosition);
|
||||
|
||||
protected:
|
||||
virtual void windowResized(int x, int y);
|
||||
|
||||
|
@ -239,6 +239,8 @@ private:
|
|||
MWRender::Objects* mObjects;
|
||||
MWRender::Actors* mActors;
|
||||
|
||||
MWRender::EffectManager* mEffectManager;
|
||||
|
||||
MWRender::NpcAnimation *mPlayerAnimation;
|
||||
|
||||
// 0 normal, 1 more bright, 2 max
|
||||
|
|
|
@ -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(actorID));
|
||||
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>);
|
||||
|
||||
|
|
|
@ -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>);
|
||||
|
|
|
@ -375,5 +375,11 @@ op 0x2000234: ShowRestMenu, explicit
|
|||
op 0x2000235: GoToJail
|
||||
op 0x2000236: PayFine
|
||||
op 0x2000237: PayFineThief
|
||||
opcodes 0x2000238-0x3ffffff unused
|
||||
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>
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue